Project Generation

Project Generation

This guide explains how to use AI (Cursor) to generate a complete application from your idea using the foundation's architecture.


When to Use

Tell Cursor (or any AI tool) something like:

  • "I want to create a finance tracker"
  • "Build a task management app"
  • "Add a blog feature"

The AI should follow this structured process to generate code that respects the foundation's architecture.


Step 1: Define Your App

App Type

Decide whether your app is:

TypeDescriptionMulti-tenant UI
PersonalSingle user, one workspaceHidden (WorkspaceSwitcher removed)
WorkspaceMultiple users, multiple workspacesVisible

Both types use the same code under the hood — only the UI differs.

Entities

For each entity, define:

  1. Fields and their types
  2. Which fields are required
  3. Relations to other entities

Supported field types:

TypeMaps to
texttext() — short text
longtexttext() — long text
numberinteger()
decimaldecimal(precision, scale)
booleanboolean()
datetimestamp()
datetimetimestamp({ withTimezone: true })
enumtext() (validate in Zod)
uuid (relation)uuid().references()

Step 2: Create a PRD File

Create project.prd.json in the project root. This file serves as the single source of truth for code generation:

{
  "version": "1.0",
  "app": {
    "name": "Personal Finance Tracker",
    "description": "Track income, expenses, and budgets",
    "type": "personal"
  },
  "entities": [
    {
      "name": "transaction",
      "label": "Transaction",
      "pluralLabel": "Transactions",
      "icon": "DollarSign",
      "fields": [
        { "name": "amount", "type": "decimal", "required": true },
        { "name": "description", "type": "text", "required": true },
        { "name": "date", "type": "date", "required": true },
        {
          "name": "type",
          "type": "enum",
          "values": ["income", "expense"],
          "required": true
        },
        {
          "name": "categoryId",
          "type": "uuid",
          "relation": { "entity": "category", "type": "many-to-one" },
          "required": true
        }
      ]
    },
    {
      "name": "category",
      "label": "Category",
      "pluralLabel": "Categories",
      "icon": "Tag",
      "fields": [
        { "name": "name", "type": "text", "required": true },
        { "name": "color", "type": "text", "required": false }
      ]
    }
  ],
  "features": {
    "charts": true,
    "export": false
  }
}

Step 3: Generate Code

For each entity in the PRD, generate files in this order:

  1. Database schemalib/db/schema/{entity}.ts
  2. Migrationnpm run db:generate + add RLS policies
  3. Querieslib/db/queries/{entity}.ts
  4. Validationlib/validation/{entity}Schemas.ts
  5. API routesapp/api/{entity}/route.ts + [id]/route.ts
  6. Client APIlib/api/client/{entity}.ts
  7. React Query hookshooks/use{Entity}.ts
  8. UI componentscomponents/{entity}/
  9. Dialogscomponents/dialogs/{Entity}Dialog.tsx
  10. Pageapp/(admin)/{entity}/page.tsx
  11. Navigation → add to app-sidebar.tsx
  12. Site config → update siteConfig.ts

See the Creating Features guide for detailed code examples at each step.


Step 4: Remove the Example Entity

If you're replacing the habits example with your own entities:

  1. Delete all habits-related files (schema, queries, API, hooks, components)
  2. Remove from navigation
  3. Delete habits migration (keep core migrations 0002_rls.sql and 0003_user_tenant_trigger.sql)

Step 5: Environment Setup

You'll need these Supabase credentials in .env.local:

NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
DATABASE_URL=

Step 6: Test

npm run dev

Open http://localhost:3000 and verify everything works.


Important Rules

  1. Always filter by tenantId in queries
  2. Always add RLS policies to migrations
  3. Always include tenantId in React Query keys
  4. Follow naming conventions — camelCase for JavaScript, snake_case for database
  5. Use existing patterns from the habits example
  6. For Personal Apps — hide WorkspaceSwitcher but keep the tenantId architecture

On this page