Back to Home

Architecture & Demo

Project structure, key design decisions, and demo mode for trying PropelKit without external services.

This page covers PropelKit's project structure, key architectural decisions, and demo mode for trying the product without external services.

Demo Mode

Try PropelKit without setting up any external services.

Running Demo Mode

Terminal
npm run demo

This starts Next.js with NEXT_PUBLIC_DEMO_MODE=true and dummy environment variables.

What's Mocked

  • Auth: Real mode uses Supabase Auth → Demo mode returns a static demo user
  • Database: Real mode uses PostgreSQL via Supabase → Demo mode uses in-memory key-value store
  • Payments: Real mode uses Stripe/Razorpay → Demo mode fakes success after 1.5s delay
  • Email: Real mode uses Resend → Demo mode logs to console

Using Demo Mode in Code

TypeScript
import { isDemoMode, DEMO_USER, DEMO_BANNER_TEXT } from '@/lib/demo';

if (isDemoMode) {
  // Show banner: "Demo Mode — No real data is being stored or charged"
  // Use mockAuth instead of Supabase
  // Use mockFrom() instead of supabase.from()
  // Use mockCheckout() instead of real payment
}

Demo Data

The in-memory store is pre-seeded with:

  • A demo user profile
  • A demo organization (for multi-tenancy)
  • An active starter subscription

Data persists for the browser session only. Refreshing clears everything.

Project Structure

Terminal
src/
|-- app/                    # Next.js App Router
|   |-- api/                # API route handlers
|   |   |-- auth/           # Authentication endpoints
|   |   |-- payments/       # Checkout, webhooks, subscriptions
|   |   |-- admin/          # Admin API endpoints
|   |-- dashboard/          # Protected dashboard pages
|   |-- admin/              # Admin panel pages
|   |-- (auth)/             # Auth pages (login, signup)
|-- components/
|   |-- ui/                 # shadcn/ui components (50+)
|   |-- shared/             # Navbar, Footer, UserMenu
|-- config/
|   |-- brand.ts            # Brand configuration (SINGLE SOURCE OF TRUTH)
|   |-- features.ts         # Feature flags
|   |-- theme.ts            # Theme settings
|   |-- plans.ts            # Plan definitions
|   |-- credits.ts          # Credits configuration
|-- lib/
|   |-- supabase/           # Database clients (server + browser)
|   |-- payment/            # Payment processor abstraction
|   |   |-- stripe/         # Stripe implementation
|   |   |-- razorpay/       # Razorpay implementation
|   |-- tenancy/            # Multi-tenancy abstraction
|   |-- credits/            # Credits system (add, deduct, balance)
|   |-- gst/                # GST calculation + invoice generation
|   |-- plans/              # Plan access checks
|   |-- inngest/            # Background job definitions
|   |-- demo/               # Demo mode mocks
|   |-- email.ts            # Email sending functions
|   |-- currency.ts         # Currency detection + routing
|   |-- import/             # Lovable project importer
|   |-- translation/        # React Router → App Router translator
|   |-- integration/        # Integration analysis + report
|-- hooks/                  # React hooks
|-- types/                  # TypeScript types

packages/
|-- create-propelkit/       # CLI package (npx create-propelkit)
|-- propelkit/              # Thin wrapper CLI

.claude/
|-- commands/propelkit/     # AI PM slash commands
|-- agents/                 # Specialized agent definitions
|-- propelkit/
|   |-- workflows/          # Multi-step orchestration
|   |-- templates/          # File templates (roadmap, state, plan, etc.)
|   |-- references/         # Industry style map, conventions

supabase/
|-- migrations/
|   |-- core/               # Required migrations (001-019)
|   |-- optional/           # Optional migrations (multi-tenancy)

Key Design Decisions

Dynamic Branding Everywhere

brand.ts is the single source of truth. No component, email, or API response hardcodes brand values. This means the same codebase works for any project name.

Processor Abstraction for Payments

A factory pattern routes to Stripe or Razorpay based on configuration and currency. Application code never imports Stripe or Razorpay directly — it uses the getPaymentProcessor() factory.

Tenant Context Abstraction

getTenantContext() returns a unified type that works for both single-user and multi-tenant modes. The rest of the codebase doesn't need to know which mode is active.

Goal-Backward Planning

The AI PM doesn't generate task lists. It starts from "What must be TRUE for users?" and works backward to derive what code needs to exist. This prevents scope creep and ensures every feature serves a verifiable outcome.

Atomic Commits

During AI PM execution, every task gets its own git commit. If something goes wrong, you can pinpoint exactly which change caused it.

Session Continuity

STATE.md acts as the AI PM's persistent memory. It survives context resets, session breaks, and even multi-day gaps between work sessions.