# Changelog

New features, architectural changes and improvements to the template.

Release notes are curated from repository history. Dates reflect integration into the main branch; grouped entries are not semantic-version tags. Each entry links to its implementation and current developer guide.


## One folder per backend feature, tagged errors and written rules

2026-10-17

packages/api moves to features and platform folders with fixed file names, two pilot features run one Effect program per procedure, and every rule now names what enforces it.

**Breaking for imports of `@template-cloudflare/api`.** Server code moved from `routers/`, `lib/` and topic folders to `packages/api/src/features/<feature>/<feature>.<role>.ts`, with shared building blocks in `packages/api/src/platform/`. Public subpaths now follow `./<feature>/<role>`, for example `./todo/contract`, `./app-router`, `./uploads/service` and `./assistant/http`. If your fork imports an earlier subpath, use the table in the [api package reference](/docs/packages/api#renamed-subpaths). The four subpaths the mobile app imports (`./routers/{todo,integrations,billing,notifications}.schema`) remain as aliases, so the native app builds unchanged.

- **Feature shape.** Every feature has the same role files: a leaf contract, procedures, a service, errors, and optional jobs and HTTP edges. There is no barrel and no repository layer; row-level security already isolates Organizations. The `@template-cloudflare/api/mcp/*` subpaths are server-only in the client boundary. New tests and lint rules hold the shape: leaf modules import only leaves, features import each other through declared edges, there are no import cycles, type imports are explicit, and configuration is read through `packages/env`. [Backend shape](/docs/architecture/backend-shape), [ADR-0011](/docs/adr/0011-backend-feature-shape).
- **Tagged domain errors and Effect in procedures.** In `todo` and `documents`, services fail with tagged errors, and one mapper per feature turns them into the same `APP_ERRORS` codes and messages clients saw before. Each procedure runs its service once through `runProcedure`. A client abort is honoured only before the program starts; once it runs, a client that goes away no longer rolls back the write, so the write and its Audit Event commit and the response goes unread. Other features keep their services until they are migrated. [ADR-0010](/docs/adr/0010-procedures-run-one-effect-program), [error handling](/docs/development/backend-conventions#domain-failures-are-tagged-errors-mapped-once).
- **Request ID and quieter logs.** Every RPC response carries `x-request-id`, including the 500 when building the request context fails: Cloudflare's `cf-ray` when it is well formed, otherwise a UUID. The MCP context derives its own request ID for the logs of its document tools. The same ID is `context.requestId` on the server and is part of the error log, so a user can quote it. It correlates logs only: outside Cloudflare a client can supply the `cf-ray`, so nothing decides by it. Expected 4xx failures are logged at debug level instead of as errors. Runtime switches (`DB_TENANT_PIPELINE`, `TRUSTED_PROXY_HEADER`, `TRUSTED_PROXIES`, `TENANCY_PROBE`) are declared in the env schema. Their meaning is unchanged, but an invalid value is now reported instead of silently replaced by a default; check these variables in your Worker and Node deployments.
- **Input validation answers HTTP 400.** An invalid input now returns HTTP 400 with the same `INPUT_VALIDATION` code, message and field errors as before; it used to come back as HTTP 500, because oRPC's default status map did not know the code. The RPC and OpenAPI handlers use `errorStatusMap` from `@template-cloudflare/errors/server`, and `APP_ERRORS.INPUT_VALIDATION.status` is 400 instead of 422, which also changes the status in the generated OpenAPI document. The assistant's HTTP route maps statuses with the same shared map, so `INPUT_VALIDATION` is 400 there as well. Clients that branch on `code` see no change. [Error handling](https://github.com/CarlosZiegler/template-cloudflare/blob/main/docs/error-handling.md).
- **Org roles, ready when needed.** `orgProcedure` reads the Member's Org role with its membership check, and `requireOrgRole(...)` restricts a procedure to some roles, failing closed. Roles are not hierarchical (list every role that may act), and using it outside `orgProcedure` is a type error. No procedure applies it yet. [Backend conventions](/docs/development/backend-conventions#org-roles-are-checked-only-where-a-product-rule-needs-them).
- **Written rules with their checks.** [Backend conventions](/docs/development/backend-conventions) state each rule with its reason, example, anti-pattern and enforcement. The [enforcement matrix](/docs/development/enforcement) shows which rules a check holds and which rely on review. A [review checklist](/docs/development/review-checklist), a pull request template and a root `CODING_STANDARDS.md` index the same rules.
- **Runbooks.** [Runbooks](/docs/development/runbooks) cover a database restore or host move, the pipelining kill switch, Hyperdrive caching, the RLS proof on a preview, and the emergency shutdown. The emergency-shutdown workflow does not block a custom domain; the runbook gives the extra step.
- **Decisions show their status.** Every ADR starts with its status and acceptance date, and the [decision index](/docs/adr) lists them. The [pagination](/docs/features/api#pagination) and [testing](/docs/development/testing#what-to-test) rules are written down.
- **A skill for new features.** The `domain-feature` skill walks from a glossary term to an RLS table, contract, tagged errors, service, procedures, isolation tests and docs.

Measurements ([report](https://github.com/CarlosZiegler/template-cloudflare/blob/main/docs/measurements/2026-10-17-backend-structure.md)): the server code grows by 6.9 KiB gzip, within the 10 KiB budget for the Effect pilots, and the client carries no Effect. The happy-path p50 of the pilot procedures is within the noise of an A/A run; the `todo.byId` error path costs +0.040 ms. Separately, the Worker as a whole grows by 70.2 KiB gzip, of which 63.4 KiB are the documentation pages, ADRs and changelog the site renders on the server: that is content and has nothing to do with Effect, and whether it counts against the Worker budget is still open.

Sources: [platform move](https://github.com/CarlosZiegler/template-cloudflare/commit/0aa202e), [feature folders, first of 18 moves](https://github.com/CarlosZiegler/template-cloudflare/commit/3d1913f), [graph tests](https://github.com/CarlosZiegler/template-cloudflare/commit/2226f26), [direction rules](https://github.com/CarlosZiegler/template-cloudflare/commit/05836ac), [runProcedure](https://github.com/CarlosZiegler/template-cloudflare/commit/91a2d11), [todo pilot](https://github.com/CarlosZiegler/template-cloudflare/commit/6c77fb1), [documents pilot](https://github.com/CarlosZiegler/template-cloudflare/commit/49a4de0), [request ID](https://github.com/CarlosZiegler/template-cloudflare/commit/fa1cbbb), [error log levels](https://github.com/CarlosZiegler/template-cloudflare/commit/ec63950), [runtime switches](https://github.com/CarlosZiegler/template-cloudflare/commit/0df1feb), [trusted proxy](https://github.com/CarlosZiegler/template-cloudflare/commit/47a3700), [requireOrgRole](https://github.com/CarlosZiegler/template-cloudflare/commit/3e51803), [400 for input validation](https://github.com/CarlosZiegler/template-cloudflare/commit/146d310), [measurement](https://github.com/CarlosZiegler/template-cloudflare/commit/ec94469).


## The web app is organized by feature, like the backend

2026-10-17

apps/web/src moves to routes, features and platform with fixed role names, server-only modules carry a .server suffix, and the rules are checked by a boundary test.

**Breaking for forks that changed `apps/web/src`.** The folders `components/`, `hooks/`, `lib/`, `utils/`, `functions/`, `middleware/`, `og/` and `data/` are gone. Code now lives in `apps/web/src/features/<feature>/<feature>.<role>.ts(x)`, with the same feature names as the backend where one exists (`todo`, `documents`, `billing`, …), and in `apps/web/src/platform/<area>/` for what has no domain (the oRPC client, session, i18n, errors, SEO, OG). Routes stay where they are and get thinner. No URL, route or translation key changes, and every route answers as before. The only visible copy change is the web code sample on the landing page (and in `llms-full.txt`), which now names `apps/web/src/features/landing/landing.hooks.ts`. If your fork edited a moved file, re-apply the change at its new path; `git log --follow` finds every file.

- **Fixed roles.** A feature has `*.queries.ts` (query options and the loader's prefetch), `*.hooks.ts` (the logic), `*.page.tsx`, presentational components, pure model files and, for server-only code, `*.server.ts(x)`. Components no longer import TanStack Query, the oRPC client or the auth client directly. [Web conventions](/docs/development/web-conventions), [ADR-0012](/docs/adr/0012-web-features-mirror-the-backend-shape).
- **Server-only code is named `.server`.** TanStack Start refuses `*.server.*` modules in the client build, so the name is checked by the framework. Client code reaches server code only through two isomorphic bridges (the session query and the docs page loader), and the web keeps zero `createServerFn`. [Client/server boundary](/docs/architecture/client-server-boundary).
- **Rules with checks.** A boundary test (`scripts/web-feature-boundaries.test.mjs`) checks layers, cross-feature imports, the server suffix, barrels, `.client.` names, dynamic imports and stale `vi.mock` or worker URLs. The same test checks import cycles, and file size is a lint warning. The [enforcement matrix](/docs/development/enforcement) lists W1–W13.
- **Locales stay central.** `apps/web/src/locales/{en,de,fr}.ts` keep every key; new keys use their feature's prefix.
- **A skill section for new screens.** The `domain-feature` skill gains a web section with templates for queries, hooks, the page and a thin route.

Known leftover: a comment in `apps/mobile/src/lib/user-agent.ts` still names the old web path; it changes with the next mobile change. Unused vendored components moved as they were; removing them is a separate decision.

Measurements ([report](https://github.com/CarlosZiegler/template-cloudflare/blob/main/docs/measurements/2026-10-17-web-structure.md)): the client grows by 425 B gzip in total, and its entry chunk shrinks by 1,128 B because loaders import `*.queries` instead of the hooks. The server code grows by 850 B gzip, and no Effect module reaches the client. The docs pages added or edited with this change (ADR-0012, the web conventions, this entry and the updated guides) add about 23.6 KiB gzip to the server's docs chunk, so the server grows by about 24.5 KiB gzip in total; the docs do not reach the client.

Sources: [platform moves](https://github.com/CarlosZiegler/template-cloudflare/commit/e6a9ff6), [platform, second part](https://github.com/CarlosZiegler/template-cloudflare/commit/3356c49), [OG with server suffixes](https://github.com/CarlosZiegler/template-cloudflare/commit/0e2d979), [feature folders, first of 23 moves](https://github.com/CarlosZiegler/template-cloudflare/commit/d18d2e9), [last feature move](https://github.com/CarlosZiegler/template-cloudflare/commit/0a1934b), [boundary test](https://github.com/CarlosZiegler/template-cloudflare/commit/6ce11f4), [boundary test in the root tests](https://github.com/CarlosZiegler/template-cloudflare/commit/1d085c9), [file size warning](https://github.com/CarlosZiegler/template-cloudflare/commit/236d010), [bundle markers for web server modules](https://github.com/CarlosZiegler/template-cloudflare/commit/63c00d0), [thin todos route](https://github.com/CarlosZiegler/template-cloudflare/commit/41a87fc), [files gateway](https://github.com/CarlosZiegler/template-cloudflare/commit/60d1316), [root document](https://github.com/CarlosZiegler/template-cloudflare/commit/0bcdf98), [loaders out of routes](https://github.com/CarlosZiegler/template-cloudflare/commit/bcd2eb7), [measurement](https://github.com/CarlosZiegler/template-cloudflare/commit/4670ccc).


## AI assistant and one tool catalog

2026-10-15

The assistant, MCP and agent-readable pages now share the application’s authorized operations.

The web assistant adds persisted Threads, streamed responses and explicit approval for mutating tools. Tool execution uses one server catalog shared with MCP, preserving current Session and Organization authorization. Provider configuration and the `ai.assistant` flag jointly control availability.

Agent discovery now exposes public instructions and Markdown pages alongside OAuth connection metadata. The supported transport keeps TanStack AI’s Promise/SSE lifecycle separate from the Effect job boundary.

- [AI assistant and approvals](/docs/features/assistant)
- [MCP server](/docs/features/mcp) and [connecting an agent](/docs/connect-your-agent)
- [Agent-readable pages](/docs/features/agent-pages)

[Source: assistant integration](https://github.com/CarlosZiegler/template-cloudflare/commit/63e36e6)


## Earlier updates

- 2026-10-15: [Dependency round, i18next fix and ReUI controls](/docs/changelog/2026-10-15-dependency-round-and-reui)
- 2026-10-15: [Developer documentation and changelog](/docs/changelog/2026-10-15-developer-docs-and-changelog)
- 2026-10-15: [Documents and large uploads](/docs/changelog/2026-10-15-documents-and-large-uploads)
- 2026-10-15: [Landing page redesign](/docs/changelog/2026-10-15-landing-redesign)
- 2026-10-14: [Trace and code block primitives](/docs/changelog/2026-10-14-trace-and-code-blocks)
- 2026-10-13: [TanStack Start 1.0, OG images and durable imports](/docs/changelog/2026-10-13-start-og-and-imports)
- 2026-10-12: [Payments, native screens and a new landing page](/docs/changelog/2026-10-12-payments-and-native-experience)
- 2026-10-03: [Runtime and recovery hardening](/docs/changelog/2026-10-03-runtime-and-recovery)
- 2026-09-25: [Authentication foundations and performance](/docs/changelog/2026-09-25-auth-and-performance)
- 2026-09-24: [Platform dependency alignment](/docs/changelog/2026-09-24-platform-dependencies)
- 2026-09-03: [oRPC and Drizzle upgrades](/docs/changelog/2026-09-03-typed-api-upgrade)
- 2026-08-25: [Typed domain operations and a real dashboard](/docs/changelog/2026-08-25-typed-domain-and-dashboard)
- 2026-08-24: [Agent connections and native account security](/docs/changelog/2026-08-24-agent-connections-and-account-security)
- 2026-08-13: [Cloudflare email and shared UI](/docs/changelog/2026-08-13-email-and-ui)
- 2026-07-30: [An enforced client/server boundary](/docs/changelog/2026-07-30-client-boundary)
- 2026-07-24: [Native interface foundations](/docs/changelog/2026-07-24-native-foundation)
- 2026-07-13: [Administration and data workflows](/docs/changelog/2026-07-13-admin-and-data-workflows)
- 2026-06-10: [Setup, storage and localization](/docs/changelog/2026-06-10-setup-storage-and-i18n)
