> ## Documentation Index
> Fetch the complete documentation index at: https://supastack.dev/llms.txt
> Use this file to discover all available pages before exploring further.
> For the full documentation corpus in one file, fetch: https://supastack.dev/llms-full.txt

# Build your first feature

An end-to-end walk from schema to shipped screen.

## Beginner walkthrough

Prerequisites: Read the two beginner guides below, finish Web local setup, and open this monorepo at its root in your editor. Web settings belong in `apps/web/.env.local`; Next.js does not read the root `.env`. `/dashboard` in the default fake mode is a no-database demo; `/auth` needs a migrated database.

Quick terms: a workspace is one team's separate users, data, and settings. The server is the trusted backend; keep provider keys out of browser and phone code. A migration is a versioned database change that creates or updates tables. An AI model is the engine that answers; the model catalog is the server's list of available model IDs and prices. A provider is an outside service such as an AI, email, or billing service. An entitlement is a grant that lets a workspace use a feature. A webhook is a message one service sends to another service's URL.

1. Open VS Code at the repository root and ask your coding agent to create `apps/web/app/reports/page.tsx` and `apps/web/src/reports.ts`. Give it the report fields and allowed roles; require server-side membership checks and a query filtered by `workspaceId`.

2. Open `/reports` as a signed-in member and confirm only that workspace's records appear.

3. Try a signed-out and a second-workspace account; if either can read the records, stop and fix the server check.

For custom code, start with the supplied `prompts/README.md` and copy the closest prompt: `prompts/new-app-screen.md` for an app screen or `prompts/new-landing-page.md` for a public page. For server, database, or provider work, give your coding agent this guide's task and ask it to read `AGENTS.md`, `.ai/PROJECT_CONTEXT.md`, and matching `.ai/` mirrors; inspect the exact source files named here; list files and checks before editing; preserve workspace ownership and server-only secrets; and show you the diff. Tell it the behavior you want, input and output fields, allowed roles, expected success and errors, and the test account, provider, or device. Use sample values; never paste a real secret.

[Before you start](https://supastack.dev/docs/web/before-you-start.md)

[Terminal basics](https://supastack.dev/docs/web/terminal-basics.md)

[Web local setup](https://supastack.dev/docs/web/ship-in-5-minutes.md)

[Agent prompts & project memory](https://supastack.dev/docs/web/agents.md)


## Create the route

Add a page beneath `apps/web/app/`. Start from the dashboard or content route so you reuse its session and active-workspace resolution. A route exists when its folder contains `page.tsx`; use a Server Component for protected reads.

```
apps/web/app/reports/page.tsx
apps/web/src/reports.ts
.ai/apps/web/app/reports/page.md
.ai/apps/web/src/reports.md
```


## Resolve ownership on the server

Read the signed-in identity and active workspace through the existing auth/workspace helpers. Verify membership before loading records. Filter every query by the resolved `workspaceId`; never take an owner identifier from a form or model output.

Check owner/admin permissions for management actions. When a feature is paid, check its entitlement at the read or action boundary before returning protected data; a hidden button does not enforce access.


## Verify access and recovery

Test anonymous access, a valid member, a member of another workspace, a revoked session, and the required role. Add empty and failed-load states with a recovery action. Keep the route out of the public sitemap and add its prefix to robots disallows.

[Workspace isolation](https://supastack.dev/docs/web/security.md)

[Entitlement checks](https://supastack.dev/docs/web/setup-payments.md)


## Model the record

Every product record starts in the database schema. Add a table in packages/db with a workspaceId column, generate the migration, and write the repository helpers that resolve the workspace before reading or writing.

```
// packages/db/src/schema.ts
export const ideas = pgTable("idea", {
  id: uuid().primaryKey(),
  workspaceId: uuid().notNull().references(() => workspaces.id),
  title: text().notNull(),
  createdAt: timestamp().defaultNow(),
});

corepack pnpm --filter @supastack/db db:generate
```


## Authorize the action

Create a server action that resolves the session, the workspace, and the entitlement in that order. Validate input with a zod schema, run the mutation through the repository, and return a typed result the interface can render.

The order matters: a mutation that writes before checking workspace ownership has already crossed the boundary. Derive ownership on the server — never trust a workspace id sent by the browser.


## Compose the surface

Build the page from shared components and tokens — the kit's blocks and ui-web primitives cover the common patterns. Handle loading, error, and empty states; a feature that only renders its happy path is not done.


## Next

[Build with a coding agent](https://supastack.dev/docs/web/agents.md)
