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
npm run demoThis 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
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
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.