# Cake20 Canonical Patterns

These patterns describe file placement and boundaries. Confirm exact APIs with the
installed Runtime declarations.

## Page composition

Keep route pages small. A page coordinates data and sections; reusable sections live
in `app/components` and state domains live in `app/stores`.

```tsx
type Item = {
  id: string;
  name: string;
};

export const data = {
  items: [] as Item[],
};

export const onServer = async () => {
  data.items = await fetchGet<Item[]>("/api/items");
};

export default () => (
  <main>
    <ItemList items={data.items} />
  </main>
);
```

## Simple API

Place method-specific handlers under `server/api`.

```ts
export default async () => {
  return { ok: true, at: now().toISOString() };
};
```

For input-bearing handlers, use the installed handler and `z` signatures. Never trust
browser input or client-only route protection.

## Protected server action

```ts
export default async (_input: unknown, context: ApiContext) => {
  const user = await auth.require(context.request);
  return { id: user.id };
};
```

Use role enforcement where required. Do not create parallel cookie or JWT logic.

## Database model

```ts
export const Post = {
  id: z.id(),
  title: z.string(),
  published: z.boolean().default(false),
  createdAt: z.date().timestampTz().defaultNow()
};

export const seed = async () => [
  { id: "welcome", title: "Welcome", published: true }
];
```

Use one primary model per `server/db/<name>.db.ts`. Use `z.ref()` for relations and
`.nullable()` for nullable columns. Export fields as a named plain object; Runtime wraps
the model internally. Model seeds return deterministic rows, never call `db`, and give
each row an explicit ID or unique field.

## Shared utility

```ts
export function slug(value: string) {
  return value.trim().toLowerCase().replaceAll(/[^a-z0-9]+/g, "-")
    .replaceAll(/^-|-$/g, "");
}
```

Put it in `shared/utils`. Call `slug()` directly through Runtime auto-imports. Shared
utilities must remain safe in both browser and server execution.

## Persistent file

```ts
await storage.put("exports/report.txt", content);
const url = storage.url("exports/report.txt");
```

Use website-relative paths. Do not construct file URLs or write persistent content to
release output.

## Queue job

```ts
export default async function (input: { reportId: string }) {
  return { reportId: input.reportId, ready: true };
}
```

Place it at `server/tasks/report.job.ts`, then call `job.report(input)`. Keep input
JSON-compatible and at most 64 KB. Create durable business records before enqueueing
work that depends on them.

## Scheduled task

Use `server/tasks/<name>.task.ts`. Export the task configuration and handler supported
by installed declarations. Handlers must be idempotent because retries, restarts, or
overlapping external events can occur.

## External package

Declare an approved website-only package in `package.json` `dependencies`, import it in
the source file that uses it, and keep browser/server compatibility explicit. Never
declare Cake20 View, Cake20.js, Cake20 UI, Tailwind, h3, Prisma, Runtime, or
CLI as website dependencies.

## Implementation decision order

1. Existing source pattern in the current website.
2. Runtime global or built-in component.
3. Cake20 UI and Tailwind supplied by Runtime.
4. Documented Cake20 public module.
5. External dependency only when necessary and enabled.
