# Development

Worktrees, testing, documentation, and production builds.

Source: https://docs.champagne.dev-ukab.fr/fr/development

## Parallel worktrees [#parallel-worktrees]

```sh
make worktree-add WORKTREE_PATH="$PWD/.worktree/example" WORKTREE_BRANCH=feat/example
```

From the new worktree, run `make worktree-up`. Each worktree gets a unique
`.localhost` hostname, port allocation, and Compose project. Stack identity is
recorded under `.local/`, so shutdown cannot target a different checkout.

* `make worktree-logs`: inspect this stack.
* `make worktree-down`: stop it without deleting volumes.
* `make worktree-clean`: explicitly delete this stack's volumes and identity.
* `make worktree-remove WORKTREE_PATH="$PWD/.worktree/example"`: remove a clean,
  stopped worktree from a retained checkout.

Do not run all-worktree stop or cleanup commands while other sessions are working.

For Stripe Connect, use the development sandbox settings in `config.mk` and a
key in the worktree's private `.env`. The worktree helper copies regular parent
`.env` files privately at creation; never copy generated database credentials or
listener secrets yourself. With Stripe configured, startup refreshes the fixture
and starts the stack's own Connect listener. Worktrees share sandbox resources.
See [Stripe Connect](/fr/stripe-connect) for configuration and webhook contracts.

## Quality checks [#quality-checks]

Backend imports follow `routes/GraphQL -> services -> repository -> db`.
Shared contracts live in `domain/`, generated backend contracts in
`domain/generated.ts`, and startup-only composition in `bootstrap/`. Repositories
own SQL, transaction locking, and persisted retry state; services own use-case
and provider orchestration. HTTP responses and the GraphQL schema are unchanged.

Use `~/` imports across backend directories and direct `./` imports within one
directory. Backend try/catch/finally is rejected in favor of typed Effect recovery
and resource scopes. Runtime-exporting implementations need tests; domain,
database infrastructure, generated code, and startup composition are exempt.

Both frontends enforce `@/` imports across directories. API/GraphQL modules cannot
import UI or state/hooks, hooks cannot import UI, and lower modules cannot import
app entrypoints. Exported React components need companion tests and stories;
exported hooks need tests. Story fixtures use the local GraphQL schema and reject
mutations, so they need neither a running API nor credentials.

`make storybook-build` builds both frontends. Run `make storybook` for the admin
preview or `bun run --filter @champagne/consumer storybook --port 6007` for the
consumer preview. Component render tests supplement existing interaction tests.
Tailwind and CSS lint policies are unchanged.

`make check` runs code generation drift checks, type checking, formatting, linting
and unused-code detection. Tooling contract tests under `scripts/*.test.ts` are CI-only;
do not run them locally. `make test` runs backend and frontend
tests plus a disposable PostgreSQL integration suite. The database tests verify
autocommit, rollback, seeding, and GraphQL persistence. CI additionally builds and
smoke-tests the production Docker image against its own PostgreSQL instance.
The visual E2E studio runs only on explicit local request, outside `make test`
and CI. Launch it with `make e2e-studio` in a task worktree.

## Documentation [#documentation]

```sh
make docs
make docs-check
```

Fumadocs runs on Next.js for authoring and exports static HTML, assets, and a
client-side search index. Content lives in `docs/content/docs/`; source and
navigation configuration live in `docs/source.config.ts` and the collection's
`meta.json`. `make docs-check` typechecks, builds, and validates internal links
and heading anchors without crawling external sites.

The **Help** links of the back office and member area open the guide on the
build's `VITE_DOCS_ORIGIN`. `make dev` and `make worktree-up` run a docs service
with hot reload at `http://docs.<DEV_HOST>:<HTTP_PORT>`, the local default unless
`DOCS_ORIGIN` is set in `config.mk` or `config.local.mk`;
deployed images take the GitHub environment's `DOCS_ORIGIN`, and fall back to
the production documentation without it.

`Dockerfile.docs` serves the export with Caddy at
[docs.champagne.dev-ukab.fr](https://docs.champagne.dev-ukab.fr). Terraform owns
its separate Scaleway container, DNS, and custom-domain binding. Main-branch
CI/CD builds and deploys both the app and docs when the documentation container
ID is configured. No Fumadocs account, API key, or Node.js runtime is required
on the documentation container.

## Status page [#status-page]

The documentation site serves the status page at `/en/status` and `/fr/status`, with an Atom
feed at `status/feed.xml`. It lives on the documentation container so it stays reachable when
the app or the API is down.

The page checks the API from the reader's browser every minute through the documentation's
`/api/graphql` proxy. Incidents are declared in `docs/lib/incidents.ts`; pushing the change to
`main` publishes it with the next documentation deploy.

```ts
export const incidents: readonly Incident[] = [
  {
    id: "2026-11-09-api-outage",
    title: { en: "API errors", fr: "Erreurs de l'API" },
    impact: "major",
    services: ["api", "memberSites"],
    updates: [
      {
        at: "2026-11-09T14:05:00Z",
        phase: "investigating",
        message: { en: "Requests to the API fail.", fr: "Les requêtes vers l'API échouent." },
      },
    ],
  },
];
```

Append an update each time the situation changes, oldest first, through `investigating`,
`identified`, `monitoring` and `resolved`: an incident stays open until its last update is
`resolved`. `impact` is `degraded`, `partial` or `major`, and `services` lists the affected
rows among `backOffice`, `memberSites`, `api` and `docs`. The `id` is the incident's anchor
and feed entry, so keep it stable.

## Production image [#production-image]

```sh
docker build -t champagne:local .
# Terraform supplies production runtime connection settings and secrets.
```

Caddy serves the built frontend and React Router fallback on port 8080, and
proxies `/api/*` to Elysia on internal port 3000. The backend serves GraphQL only.
A supervisor shuts down both processes together. Terraform supplies production
connection settings and generated credentials. Startup runs `drizzle-kit push`;
no SQL files are needed. See [Database](/fr/database).

## Frontend data and navigation [#frontend-data-and-navigation]

React Query executes the generated people operation, owns caching and request
cancellation, and exposes loading/error/refresh state to the HeroUI table. Fresh
results are reused for 30 seconds. React Router redirects `/` to the first section the signed-in staff member can open
and shows a not-found page for unknown routes. Caddy serves the HTML entrypoint for
browser deep links while missing assets and unknown API routes stay 404s.

The codegen configuration is `scripts/codegen.ts`. Project-specific testing and
observability guidance is in `robot-docs/testing.md` and
`robot-docs/observability.md`.

## Markdown and LLM access [#markdown-and-llm-access]

Every documentation page offers **Copy Markdown** and an **Open** menu. The menu
links to the page's GitHub source, its Markdown export, and supported AI tools.
The Markdown actions use the static export, including the page's title, description,
and canonical source URL. Cards, steps, and callouts are rendered as readable
Markdown rather than copied HTML or JSX.

* [llms.txt](/llms.txt): a generated index linking to the Markdown version of each page,
  followed by the French user guide.
* [llms-full.txt](/llms-full.txt): all published documentation in one plain-text file.
* [Introduction Markdown](/markdown/en/index.md): the homepage's Markdown export.

Nested pages use `/markdown/<language>/<page-slugs>.md`. The exports are generated from the
same public content collection during the static build and served by Caddy;
they do not require a Node.js server, API key, or an AI provider. `make docs-check`
verifies the index links and full-text coverage alongside regular page links.

## Storybook [#storybook]

The admin and consumer previews include component stories with local fixtures;
they need no backend or database. `make storybook` uses port 6006 with
`--exact-port` and fails if it is occupied. Coordinate with the owning session
rather than interrupting it. The consumer command is listed under Quality checks.

`make storybook-build` produces both `web/storybook-static/` and
`consumer/storybook-static/` and runs in CI. Storybook is not publicly deployed.
