TinyKit Pro Docs
Technical

Project Architecture

TinyKit Pro is built with a modern, scalable architecture using cutting-edge technologies for real-time collaboration and organization productivity.

TinyKit Pro is built with a modern, scalable architecture using cutting-edge technologies for real-time collaboration and organization productivity.

Technology Stack

Frontend Stack

  • Next.js 16: React framework with App Router and React 19
  • TypeScript: Strict mode enabled for type safety
  • Tailwind CSS v4: Utility-first styling with semantic color system
  • shadcn/ui: High-quality, accessible UI component library
  • React Hook Form: Forms with Zod validation
  • Lucide Icons: Consistent icon system
  • Turbopack: High-performance bundler for development

Backend Stack

  • Convex: Real-time database with serverless functions
  • Three-Tier Security Architecture: Public/private/internal function separation
  • Better Auth: Modern authentication with OAuth and email/password support
  • TypeScript: End-to-end type safety with generated types
  • Zod: Runtime schema validation
  • Stripe: Payment processing and subscription management

Development Tools

  • Bun: Package manager and runtime optimized for Claude Code
  • ESLint: Code quality and consistency enforcement
  • TypeScript: Strict compilation with comprehensive type checking

Project Structure

├── src/                          # Frontend Next.js application
│   ├── app/                      # Next.js App Router pages
│   │   ├── (root)/              # Public landing pages (/, /waitlist)
│   │   ├── auth/                # Authentication pages
│   │   ├── home/                # User dashboard and notifications
│   │   │   └── _nav/            # User navigation components
│   │   ├── orgs/[orgSlug]/      # Organization workspaces with dynamic routing
│   │   │   └── _nav/            # Organization navigation components
│   │   └── admin/               # Admin interface
│   │       └── _nav/            # Admin navigation components
│   ├── components/              # External UI component libraries
│   │   ├── ui/                  # shadcn/ui base components
│   │   └── magicui/             # MagicUI enhanced components
│   ├── features/                # TinyKit feature modules
│   │   ├── shared/              # Reusable building blocks
│   │   │   ├── ui/              # UI primitives (LoadingSpinner, EmptyState)
│   │   │   ├── forms/           # Form controls (SearchBar, icon-picker)
│   │   │   ├── data-display/    # Data visualization (StatsGrid, StatusBadge)
│   │   │   └── layout/          # Layout components (PageHeader, Divider)
│   │   ├── auth/                # Authentication components
│   │   ├── navigation/          # Navigation (Header, Footer, Sidebars)
│   │   ├── admin/               # Admin feature modules
│   │   ├── organizations/       # Organization management
│   │   └── [other-features]/    # Domain-specific features
│   ├── hooks/                   # Custom React hooks (useAccess, etc.)
│   ├── lib/                     # Frontend utilities and helpers
│   │   ├── access/              # Lightweight frontend access control
│   │   │   ├── index.ts         # Public exports
│   │   │   └── has-access.ts    # hasAccess() function with buildContextFromUserData()
│   │   ├── metadata.ts          # Dynamic metadata generation from site settings
│   │   └── routes.config.ts     # Core modular routing system
│   ├── app/*/\_lib/             # Feature-specific route configurations
│   │   ├── admin/_lib/routes.config.ts    # Admin module routes
│   │   ├── home/_lib/routes.config.ts     # Home module routes
│   │   └── orgs/_lib/routes.config.ts     # Organizations module routes
│   └── styles/                  # Global styles and CSS

├── convex/                      # Backend Convex functions (three-tier architecture)
│   ├── auth/                    # Authentication logic
│   ├── users/                   # User management with public/private/internal tiers
│   ├── orgs/                    # Organization functionality with access control
│   ├── waitlist/                # Waitlist system with public signup
│   ├── billing/                 # Stripe integration
│   ├── notifications/           # Notification system (private access)
│   ├── siteBanners/            # Site banner system
│   ├── messages/               # Chat system
│   ├── seeds/                  # Database seeding
│   ├── lib/                    # Backend utilities
│   │   ├── access/             # Modular access control system
│   │   │   ├── index.ts        # Main exports (requireAccess, hasAccess, etc.)
│   │   │   ├── types.ts        # Type definitions (HasAccessOptions, AccessContext)
│   │   │   ├── requireAccess.ts # requireAccess() and hasAccess() functions
│   │   │   ├── requireAccessForAction.ts # Action-specific access control
│   │   │   ├── statements.ts   # Better Auth role configuration
│   │   │   └── orgPermissions.ts # Organization role hierarchy
│   │   └── permissions.ts      # Centralized permission definitions
│   ├── schema.ts               # Database schema
│   └── http.ts                 # HTTP endpoints

├── emails/                      # React Email templates (organized by feature)
│   ├── auth/                   # Authentication emails (verification, password reset)
│   ├── notifications/          # System notifications and announcements
│   ├── billing/               # Subscription and payment emails
│   ├── organization/          # Team and role management emails
│   ├── onboarding/            # Welcome and user invitation emails
│   └── common/                # Shared layout components (Layout, Header, Footer)

├── docs/                       # Documentation
│   ├── features/               # Feature documentation
│   ├── technical/              # Technical documentation
│   └── guides/                 # Setup and usage guides

└── public/                     # Static assets

Database Architecture

Dual-Schema Design

TinyKit Pro uses a dual-schema architecture with Convex's document database:

  1. Better Auth Component Database (convex/betterAuth/schema.ts) - User and organization data
  2. Main Application Schema (convex/schema.ts) - Application-specific tables

Better Auth Component (User & Organization Data)

User and organization data is stored in the Better Auth component database, separate from the main application schema:

  • user: User accounts with profile fields (name, email, role, stripeCustomerId, profile fields)
  • organization: Organization information with custom slugs and branding
  • member: Organization membership with roles (owner, admin, member)
  • session, account, verification: Auth session management tables

Note: Access user/org data via helpers (getUserById, getOrganizationById) or the Better Auth client, not direct ctx.db queries.

Main Application Schema

Application-specific tables that reference Better Auth user IDs via string fields:

Billing System:

  • products: Stripe product catalog synced from Stripe
  • prices: Pricing information for products
  • userSubscriptions: Join table linking users to Stripe component subscriptions
  • orgSubscriptions: Join table linking organizations to Stripe component subscriptions
  • promotionCodes: Discount codes with embedded coupon data

Content Management:

  • userInvitations: Email-based team/organization invitations with expiration
  • notifications: Individual notification records with delivery tracking
  • siteBanners: Site-wide promotional and informational banners
  • siteSettings: Site branding, theme, and email configuration
  • mailingList: Newsletter and waitlist subscribers
  • faqs, testimonials: Marketing content tables

Email Template System

  • Unified Configuration: Single database query (getEmailConfig) provides theme colors and site branding
  • Feature-Based Organization: Templates organized into subdirectories (auth, notifications, billing, organization, onboarding)
  • Database-Driven Theming: All templates use semantic colors from siteSettings.emailThemeColors
  • Performance Optimized: Reduced from 2 to 1 database call per email (50% improvement)
  • Dynamic Branding: Site name and theme colors loaded from database instead of hardcoded values

Schema Relationships

// User to Organizations (many-to-many through orgMembers)
users -> orgMembers <- orgs

// Organizations to Subscriptions (one-to-one)
orgs -> subscriptions

// Users to Notifications (one-to-many)
users -> notifications

// Organizations to Messages (one-to-many)
orgs -> messages <- users

// Products to Prices (one-to-many)
products -> prices

Indexing Strategy

Convex automatically manages indexes, but key indexes include:

  • by_email: User lookups by email address
  • by_org: Organization-scoped queries for members, messages, etc.
  • by_stripe_customer: Billing lookups by Stripe customer ID
  • by_user: User-scoped notifications and activities
  • by_active: Active record filtering (banners, invitations, etc.)

Authentication Architecture

Better Auth Integration

// Authentication flow
Client Request -> Next.js Proxy -> Better Auth -> Token Validation -> User Context -> Function Execution

Next.js Proxy Route Protection

TinyKit Pro implements comprehensive route protection using Next.js 16 proxy routing with real-time access verification:

// Proxy protection layers (src/proxy.ts)
export default async function proxy(request: NextRequest) {
  const pathname = request.nextUrl.pathname;
  const { isAuthenticated, token } = await checkAuth();

  // 1. Auth page redirects for authenticated users
  if (isAuthPage(pathname) && isAuthenticated) {
    return NextResponse.redirect(new URL("/home", request.url));
  }

  // 2. Protected route authentication
  if (isProtectedRoute(pathname) && !isAuthenticated) {
    return NextResponse.redirect(new URL("/", request.url));
  }

  // 3. Organization membership verification
  if (isOrgSpecificRoute(request) && (await convexAuth.isAuthenticated())) {
    const orgSlug = extractOrgSlug(request);
    const token = await convexAuthNextjsToken();

    const org = await fetchQuery(
      api.orgs.private.queries.getOrgBySlug,
      { orgSlug },
      { token },
    );

    if (!org) {
      return nextjsMiddlewareRedirect(request, "/home");
    }
  }
});

Route Protection Benefits:

  • Real-time Access Control: Organization membership verified on every request
  • Graceful Redirects: Non-members redirected instead of seeing loading states
  • Security Layer: Prevents unauthorized access before components render
  • Performance: Blocks unnecessary data fetching for invalid access

Modular Access Control Architecture

Role System with Permission Arrays

  • User Roles: admin, user
  • Organization Roles: owner, admin, member
  • Permission Arrays: Pre-calculated arrays for frontend performance optimization
  • Database-Driven Access Levels: No hardcoded access level mappings

Modular Backend Architecture

The access control system is organized into six specialized modules:

  1. index.ts - Main exports (requireAccess, hasAccess, requireAccessForAction, etc.)
  2. types.ts - Type definitions (HasAccessOptions, AccessContext)
  3. requireAccess.ts - requireAccess() (throws) and hasAccess() (returns boolean)
  4. requireAccessForAction.ts - Action-specific access control
  5. statements.ts - Better Auth role configuration
  6. orgPermissions.ts - Organization role hierarchy

Simplified Permission System

TinyKit Pro uses a simplified permission model for performance:

  • Admin role: Returns ["*"] (all permissions)
  • User role: Returns [] (no special permissions, but can access user-level features)
// Backend: Role-based access control
import { requireAccess, hasAccess } from "@/convex/lib/access";

export const adminOnlyFunction = mutation({
  handler: async (ctx) => {
    // Throws if user is not admin
    const { userId } = await requireAccess(ctx, { userRole: "admin" });
    // ... admin logic
  },
});

export const conditionalLogic = query({
  handler: async (ctx) => {
    const { userId } = await requireAccess(ctx, { userRole: ["user"] });

    // Check permissions conditionally
    const isAdmin = await hasAccess(ctx, { userRole: "admin" });
    if (isAdmin) {
      // Return extra data for admins
    }
  },
});

// Frontend: Role-based UI rendering
const { hasAccess } = useAccess();

// Role-based checks
const isAdmin = hasAccess({ userRole: "admin" });
const canManageOrg = hasAccess({ orgId: org._id, orgRole: "owner" });

// Conditional rendering
{isAdmin && <AdminPanel />}
{canManageOrg && <OrgSettings />}

Real-time Architecture

Convex Subscription System

Convex provides automatic real-time subscriptions for reactive data:

// Automatic real-time updates
const messages = useQuery(api.messages.queries.getOrgMessages, { orgId });
const org = useQuery(api.orgs.queries.getBySlug, { slug });

// Mutations trigger automatic revalidation
const sendMessage = useMutation(api.messages.mutations.send);
const updateOrg = useMutation(api.orgs.mutations.update);

Performance Optimizations

  • Selective Subscriptions: Components subscribe only to needed data
  • Indexed Queries: Use .withIndex() for efficient database queries
  • Pagination: Cursor-based pagination for large datasets
  • Optimistic Updates: Immediate UI feedback with rollback on error

API Design Patterns

Three-Tier Security Architecture

TinyKit Pro implements a comprehensive three-tier access control system for enhanced security:

convex/
├── domain/
│   ├── public/              # Frontend-callable without authentication
│   │   ├── queries.ts       # Public read operations (landing page data)
│   │   ├── mutations.ts     # Public write operations (signup, contact)
│   │   └── actions.ts       # Public external API calls
│   ├── private/             # Frontend-callable requiring authentication
│   │   ├── queries.ts       # Authenticated read operations
│   │   ├── mutations.ts     # Authenticated write operations
│   │   └── actions.ts       # Authenticated external API calls
│   ├── internal/            # Backend-only functions
│   │   ├── queries.ts       # Internal read operations
│   │   ├── mutations.ts     # Internal write operations
│   │   └── actions.ts       # Email sending, webhook processing
│   ├── helpers.ts           # Shared utility functions
│   └── validators.ts        # Zod schemas and validation

Security Benefits

  • Minimal Public Attack Surface: Only essential unauthenticated functions exposed
  • Clear Authentication Boundaries: No ambiguity about auth requirements
  • Enhanced Auditing: Easy identification of public vs authenticated endpoints
  • Developer Clarity: Import path immediately indicates security level

Function Placement Guidelines

  • Public: Unauthenticated access (waitlist signup, public settings)
  • Private: Authenticated users and admin functions
  • Internal: Backend-only operations (email sending, webhooks)

For detailed implementation guide, see Three-Tier Security Architecture.

Function Naming Conventions

  • Admin Functions: Suffix with Admin (e.g., getAllUsersAdmin)
  • Organization-scoped: Include organization context in function signature
  • CRUD Operations: Standard create, read, update, delete patterns
  • Type Safety: Full TypeScript integration with Convex generated types

Error Handling Strategy

// Consistent error handling across functions
export const safeMutation = mutation({
  handler: async (ctx, args) => {
    try {
      // Validate permissions
      const { userId } = await requireAccess(ctx, { userRole: ["admin"] });

      // Validate inputs
      const validatedArgs = schema.parse(args);

      // Execute operation
      const result = await performOperation(ctx, validatedArgs);

      return { success: true, data: result };
    } catch (error) {
      // Log error for debugging
      console.error("Operation failed:", error);

      // Return user-friendly error
      throw new ConvexError("Operation failed. Please try again.");
    }
  },
});

Security Architecture

Data Protection

  • Input Validation: Both client-side (Zod) and server-side (Convex validators)
  • Permission Checks: Required for all protected functions
  • SQL Injection Prevention: Convex's document model prevents SQL injection
  • XSS Protection: React's built-in XSS protection with proper sanitization

Authentication Security

  • JWT Tokens: Secure token-based authentication
  • Session Management: Automatic session expiration and refresh
  • OAuth Integration: Secure third-party authentication
  • Password Security: Secure hashing with industry standards

Admin Security

  • Role Hierarchy: Strict role-based access control
  • Audit Logging: Complete audit trail for admin actions
  • Environment Separation: Clear development vs. production boundaries

Rate Limiting

TinyKit Pro implements comprehensive rate limiting to protect against abuse and ensure system stability:

  • Pre-configured Limits: Authentication (10/hour), profile updates (5/min), content creation (20/min), admin operations (100/hour), external APIs (50/hour), file uploads (10/hour), search queries (30/min)
  • Token Bucket Algorithm: Burst capacity support for natural usage patterns
  • Fixed Window Limits: Time-based restrictions for critical operations
  • Custom Token Consumption: Variable rate limiting based on operation cost
  • Graceful Degradation: Non-throwing checks for availability status

Implementation Example:

import { requireAccess, requireRateLimit } from "./lib/access";

export const updateProfile = mutation({
  handler: async (ctx, args) => {
    const { userId } = await requireAccess(ctx, { userRole: ["user"] });
    await requireRateLimit(ctx, "profileUpdates", { key: userId });
    // Business logic
  },
});

Performance Architecture

Frontend Performance

  • Code Splitting: Automatic code splitting with Next.js
  • Image Optimization: Next.js built-in image optimization
  • Caching Strategy: Convex automatic query caching
  • Bundle Analysis: Monitor JavaScript bundle size
  • SEO Optimization: Database-driven dynamic metadata generation with fail-fast validation

Backend Performance

  • Function Optimization: Efficient Convex function design
  • Database Queries: Proper indexing and query patterns
  • Connection Pooling: Convex handles connection management
  • Caching: Convex provides automatic caching and invalidation

Development Performance

  • Bun Integration: Fast package management and script execution
  • Turbopack: High-performance development bundling
  • Hot Reloading: Fast development iteration cycles
  • Type Checking: Concurrent TypeScript compilation

Deployment Architecture

Development Environment

  • Local Development: Full stack running locally with real-time sync
  • Hot Reloading: Instant feedback for frontend and backend changes
  • Test Data: Seeded development data for consistent testing
  • Debug Logging: Comprehensive logging for development debugging

Production Environment

  • Vercel Frontend: Serverless frontend deployment with edge optimization
  • Convex Backend: Managed backend with automatic scaling
  • CDN Integration: Global content delivery for static assets
  • Environment Variables: Secure configuration management

CI/CD Pipeline

# Quality gates enforced before deployment
bun lint            # ESLint validation - must pass
bun typecheck       # TypeScript validation - must pass
bun build           # Production build validation - must pass

Monitoring & Observability

Application Monitoring

  • Convex Dashboard: Real-time function performance and database metrics
  • Error Tracking: Comprehensive error logging and alerting
  • Performance Metrics: Query performance and response time monitoring
  • User Analytics: Usage patterns and feature adoption tracking

Development Monitoring

  • Console Integration: Claude Code real-time console visibility
  • Webhook Monitoring: Stripe webhook delivery tracking
  • Email Delivery: Resend email delivery status monitoring
  • Database Health: Convex automatic health monitoring

Scalability Considerations

Horizontal Scaling

  • Serverless Architecture: Automatic scaling with Convex and Vercel
  • Stateless Design: Functions designed for horizontal scaling
  • Database Scaling: Convex handles automatic database scaling
  • CDN Distribution: Global content delivery scaling

Performance Scaling

  • Query Optimization: Efficient database query patterns
  • Caching Strategy: Multi-level caching for performance
  • Real-time Optimization: Selective subscriptions to minimize load
  • Bundle Optimization: Code splitting and lazy loading

← Back to Technical | Next: Development →

On this page

Ship your startup faster. In minutes.

Get TinyKit Pro