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 assetsDatabase Architecture
Dual-Schema Design
TinyKit Pro uses a dual-schema architecture with Convex's document database:
- Better Auth Component Database (
convex/betterAuth/schema.ts) - User and organization data - 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 directctx.dbqueries.
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 -> pricesIndexing 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 ExecutionNext.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:
index.ts- Main exports (requireAccess, hasAccess, requireAccessForAction, etc.)types.ts- Type definitions (HasAccessOptions, AccessContext)requireAccess.ts- requireAccess() (throws) and hasAccess() (returns boolean)requireAccessForAction.ts- Action-specific access controlstatements.ts- Better Auth role configurationorgPermissions.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 validationSecurity 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 passMonitoring & 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