# AGENTS.md

This is a SvelteKit application with server rendered routes, form actions, and a Postgres backend.

## Project

Stack: SvelteKit 2, Svelte 5 (runes), TypeScript, Tailwind, Postgres, Vitest, Playwright.

Layout:

- `src/routes/+page.svelte` page markup, `+page.server.ts` server load and form actions
- `src/routes/+layout.svelte` and `+layout.server.ts` shared shell and session
- `src/routes/api/<name>/+server.ts` JSON endpoints
- `src/lib/` shared code, imported through the `$lib` alias
- `src/lib/server/` server only modules, never importable from a component
- `src/lib/components/` presentational components
- `src/hooks.server.ts` session handling and route guards
- `src/app.d.ts` App.Locals and App.PageData types

Rule of thumb: `+page.server.ts` runs on the server only, `+page.ts` runs on both, so anything with a secret or a database call belongs in the former.

Entry points: `src/hooks.server.ts`, `src/routes/+layout.server.ts`, `svelte.config.js`.

## Commands

```bash
pnpm install
pnpm dev                     # dev server on :5173
pnpm build                   # production build, must pass before a PR
pnpm preview                 # serve the build locally
pnpm check                   # svelte-check, type checks .svelte files too
pnpm lint                    # eslint and prettier check
pnpm format                  # prettier write
pnpm test                    # vitest run
pnpm test src/lib/pricing    # one file or directory
pnpm test:e2e                # playwright
pnpm exec svelte-kit sync    # regenerate ./$types after route changes
pnpm db:migrate              # apply database migrations
```

If `./$types` imports fail to resolve, run `pnpm exec svelte-kit sync` before assuming a real type error.

Run `pnpm check` and `pnpm build` before returning work.

## Code style

- Svelte 5 runes only: `$state`, `$derived`, `$props`, `$effect`. No `export let`, no `$:` reactive statements, no legacy stores in new code.
- `$effect` is a last resort. Derive values with `$derived` instead of syncing them in an effect.
- Data comes from a `load` function, never from a fetch inside `onMount` for content that should be server rendered.
- Mutations use form actions with progressive enhancement via `use:enhance`. Do not hand roll a fetch POST for a form.
- `load` returns serializable data. Never return a class instance or a database client.
- Import secrets from `$env/static/private` or `$env/dynamic/private`, only inside `src/lib/server/` or a `.server.ts` file.
- Validate every form action payload and every endpoint body with a schema before use.
- Tailwind utilities in markup. Use `<style>` blocks only for something utilities cannot express.
- Components take props and emit callbacks. No component reaches into a global store for data its parent already has.
- Use `$lib` imports, not relative paths that climb directories.

## Boundaries

Do not touch without explicit instruction:

- `.svelte-kit/` and any `./$types` file, both are generated.
- `svelte.config.js` adapter configuration and `vite.config.ts`.
- `pnpm-lock.yaml`. Add dependencies with `pnpm add`.
- `.env`. New variables are documented in `.env.example`.
- Database migration files that have already been applied.
- `.github/workflows/` and hosting configuration.

Needs human review: `src/hooks.server.ts`, anything that changes session or cookie handling, new public API endpoints, and any change that moves code between server only and shared modules.

Never import from `src/lib/server/` in a `.svelte` file. If that seems necessary, the data should come from `load` instead.

## Testing

- `pnpm test` runs Vitest, `pnpm test <path>` runs one file.
- Required tests: every exported function in `src/lib/`, every form action, and every `+server.ts` endpoint.
- `load` functions are tested by calling them with a stubbed event object.
- Component tests only for components with real logic. Do not test markup structure.
- Playwright covers sign in and the primary conversion flow. Keep the e2e suite small.
- A bug fix ships with a test that fails without it.

## Git workflow

- Branch from `main`: `feat/short-description`, `fix/short-description`.
- Conventional commits: `fix(checkout): validate coupon before creating the session`.
- `pnpm build` and `pnpm check` must pass locally before opening a PR, prerender errors only appear at build time.
- PR description states what changed, why, and how it was verified, plus any new environment variable.
- Never commit to `main`.
