> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackra.figentra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Repository structure

> The categories, kind folders, banned folders, file suffixes and test tiers every member follows, generated from tools/scripts/structure.mjs.

The rules below are the single source for the scaffold (`pnpm new`) and the validator (`pnpm validate`). Each row names the ADR, or the settlement item, it comes from.

## Package categories

A package lives at `packages/<category>/<name>`. Tooling presets live at `packages/tooling/<name>` and carry `tier:config`.

| Category | Holds | Source |
| - | - | - |
| `foundation` | contracts, validation and errors every layer imports | ADR 0127 |
| `application` | actions, AI, IR and the registry | ADR 0127 |
| `communication` | webhooks, versioning, integrations and mail | ADR 0127, 0270 |
| `commerce` | money, ledger and pricing primitives | ADR 0127 |
| `cross-cutting` | concerns that span layers (settlement Q3.1) | ADR 0127 |
| `data` | model, database, content, media, search, assets, filesystem, storage | ADR 0127 |
| `design-system` | the Stackra Design System: tokens, ui and icons | ADR 0302 |
| `developer` | CLI, gen, coding standard and the Vite plugin | ADR 0127 |
| `experience` | experience, navigation, console, panel, builder and collaboration | ADR 0127, 0270 |
| `infrastructure` | Pulumi-based packages named `infra-<name>` | ADR 0127 |
| `runtime` | outbox, queue, scheduler, workflow, realtime, locking and cache | ADR 0127 |
| `security` | identity, IAM, tenancy, connections, entitlements and licensing | ADR 0127 |
| `state` | settings, feature flags and theming | ADR 0127 |
| `tooling` | build, lint and test presets with no workspace dependencies (tier:config) | ADR 0003 |

## Package entries

Core `.` is always present. An entry is exported once its folder holds a file, and its barrel is generated, never authored (ADR 0294 decision 15). `pnpm new package` adds the optional entries only with `--entries`.

| Entry | Scaffolded | Holds | Source |
| - | - | - | - |
| `contracts` | always | the leaf: `ports/`, `enums/` and `types/`; imports nothing else from the package | ADR 0294 d15 |
| `node` | always | the module folder: the root module and the module groups | ADR 0294 d15 |
| `react` | on request | web renderers in `react/<name>/` | ADR 0294 d15 |
| `native` | on request | native renderers in `native/<name>/` | ADR 0294 d15 |
| `testing` | always | `fakes/` and `matchers/` for consumers' tests | ADR 0294 d15 |

Exception: `@stackra/testing` alone also has `e2e` and `contract` (ADR 0269 d6). No other package does.

## Member root (programming model v3)

Every member authors `stackra.config.ts` and one root module, `src/<name>.module.ts` (`src/node/<name>.module.ts` in a package), and never `src/main.ts` or an entry barrel (ADR 0294 R12, 0295). Exempt: the Mintlify docs app (`apps/docs`) and the `tier:config` presets (`packages/tooling/`).

## Module groups (programming model v3)

A module is `src/modules/<key>/` in a service and `src/node/` in a package. Each kind suffix has one home group; a group folder appears with its first file. The validator's `kind-path` check of these tables is planned (STA-338).

| Group | Suffixes | Holds | Source |
| - | - | - | - |
| (root) | `.module`, `.settings` | the module file, its one settings group and `README.md` | ADR 0294 d13 |
| `models/` | `.model`, `.state-machine`, `.bucket`, `.projection` | persisted models | ADR 0294 d13 |
| `actions/` | `.action` | write operations | ADR 0294 d13 |
| `queries/` | `.query` | read operations | ADR 0294 d13 |
| `schemas/` | `.schema`, `.change` | shapes shared by two files; dated response changes | ADR 0294 d13 |
| `enums/` | `.enum` | `Enum.of` enums | ADR 0294 d13 |
| `errors/` | `.error` | Refusal classes | ADR 0294 d13 |
| `events/` | `.event`, `.change` | events and their versions | ADR 0294 d13 |
| `listeners/` | `.listener` | event handlers | ADR 0294 d13 |
| `workflows/` | `.workflow`, `.signal` | durable runs and the signals they wait for | ADR 0294 d13 |
| `access/` | `.permissions`, `.policy`, `.role`, `.entitlement`, `.precondition`, `.flag` | who may do what, and when | ADR 0294 d13 |
| `services/` | `.service`, `.repository` | services; a repository only for named reads | ADR 0294 d13 |
| `drivers/` | `.driver` | port implementations | ADR 0294 d13 |
| `extensions/` | `.extension-point`, `.extension`, `.interceptor` | extension points and wraps | ADR 0294 d13 |
| `raw/` | `.controller` | raw endpoints, in a service only (ADR 0130 decision 3) | ADR 0294 d13 |
| `resources/<model>/` | `.resource`, `.widget`, `.document`, `.notification`, `.mail` | one model's admin surface | ADR 0294 d13 |
| `database/migrations/` | `.migration` | `NNNN-<name>.migration.ts`, numbered per module | ADR 0294 d13 |
| `database/factories/` | `.factory` | `<model>.factory.ts` | ADR 0294 d13 |
| `database/seeders/` | `.seeder` | minimal, demo and test seeders | ADR 0294 d13 |
| `ai/` | `.prompt`, `.skill`, `.facts` | prompts, skills and facts | ADR 0294 d13 |
| `functions/` | `.function` | plain functions | ADR 0294 d13 |
| `constants/` | `.constant` | module-level constants | ADR 0294 d13 |
| `types/` | `.type` | types two or more files import | ADR 0294 d13 |

## App groups (programming model v3)

| Group | Suffixes | Holds | Source |
| - | - | - | - |
| (root) | `.module`, `.error` | `<key>.module.ts` and `app.error.tsx`, the root error boundary | ADR 0294 d14 |
| `config/` | `.config` | config classes, including `desktop.config.ts` and `chrome.config.ts` | ADR 0294 d14 |
| `panels/` | `.panel` | app areas | ADR 0294 d14 |
| `menus/` | `.menu` | navigation data | ADR 0294 d14 |
| `shortcuts/` | `.shortcut` | palette and key entries | ADR 0294 d14 |
| `documents/` | `.document` | document kinds | ADR 0294 d14 |
| `stores/` | `.store` | client state classes | ADR 0294 d14 |
| `flags/` | `.flag` | release switches | ADR 0294 d14 |
| `analytics/` | `.analytics-event` | analytics events | ADR 0294 d14 |
| `bridges/` | `.bridge` | desktop bridges | ADR 0294 d14 |
| `routes/<name>/` | `.route`, `.layout`, `.error`, `.fallback`, `.server` | a route or layout class, its page `<name>.tsx`, `use-<name>.ts` and `__tests__/` | ADR 0294 d14 |
| `blocks/<name>/` | `.block`, `.native` | `<name>.block.ts`, its renderer `<name>.tsx`, an optional native renderer `<name>.native.tsx` and `__tests__/` | ADR 0294 d14 |
| `components/<name>/` | none | `<name>.tsx`, `index.ts` (the component and its Props) and `__tests__/` | ADR 0294 d14 |
| `hooks/` | none | `use-<name>.ts` with two or more importers | ADR 0294 d14 |
| `overrides/<owner>/` | `.override` | block and widget overrides | ADR 0294 d14 |
| `providers/<name>/` | none | only for the `Module({ wrap })` escape hatch | ADR 0294 d14 |
| `enums/` | `.enum` | `Enum.of` enums | ADR 0294 d14 |
| `types/` | `.type` | shared types | ADR 0294 d14 |
| `styles/` | none | stylesheets (`.css`) | ADR 0294 d14 |

## Package folders (programming model v3)

| Folder | Entry | Holds | Source |
| - | - | - | - |
| `src/contracts/` | `./contracts` | the leaf: `ports/`, `enums/` and `types/` | ADR 0294 d15 |
| `src/config/` | `.` | the config classes, which a host subclasses to override | ADR 0294 d15 |
| `src/core/` | `.` | isomorphic code: services, drivers, errors, functions, schemas and blocks | ADR 0294 d15 |
| `src/node/` | `./node` | the module folder: `<key>.module.ts` and the module groups | ADR 0294 d15 |
| `src/react/<name>/` | `./react` | web renderers | ADR 0294 d15 |
| `src/native/<name>/` | `./native` | native renderers | ADR 0294 d15 |
| `src/testing/` | `./testing` | `fakes/` and `matchers/` | ADR 0294 d15 |

Explorer: `src/<entry>/<pkg>.explorer.ts` (`.explorer`), only in a package that ships decorators, which it registers (ADR 0294 d15).

## Kind folders (pre-v3)

The pre-v3 list, still read by `kindOfFile` and the doc-standard migration rule until STA-340 rebuilds them on the tables above. A file's suffix names its kind; the test column is the tier its file needs.

| Folder | File suffix | Required test | Holds | Source |
| - | - | - | - | - |
| `actions` | `*.action.ts` | `unit` | one action per file; its test covers the happy path and one refusal | ADR 0098 |
| `queries` | `*.query.ts` | `unit` | read-only operations | ADR 0126 |
| `models` | `*.model.ts` | `int` | persistence models; their tests need the real database | ADR 0014 |
| `migrations` | `*.migration.ts` | none | schema changes, applied in order | ADR 0014 |
| `seeds` | `*.seed.ts` | none | seed data for local and test databases | ADR 0014 |
| `factories` | `*.factory.ts` | none | test-data factories | ADR 0022 |
| `policies` | `*.policy.ts` | `unit` | authorisation rules, one case per verb | ADR 0130 |
| `permissions` | `*.permission.ts` | `contract` | declared permission names, covered by the member manifest test | ADR 0130 |
| `settings` | `*.setting.ts` | `contract` | declared settings, covered by the member manifest test | ADR 0130 |
| `events` | `*.event.ts` | `contract` | versioned event declarations, covered by the member manifest test | ADR 0141 |
| `listeners` | `*.listener.ts` | `unit` | @OnEvent handlers, one toEmit case each | ADR 0264 d8 |
| `workflows` | `*.workflow.ts` | `int` | durable, compensating workflows | ADR 0130 |
| `services` | `*.service.ts` | `unit` | application services that actions and listeners depend on | ADR 0264 d10 |
| `hooks` | `*.hook.ts` | `unit` | extension hooks only; React hooks are `use-*.ts` files, not a folder | ADR 0264 d7 |
| `links` | `*.link.ts` | none | named links between modules (purpose not yet specified) | ADR 0264 d7 |
| `drivers` | `*.driver.ts` | `unit` | port drivers; the memory driver is unit, a real one also needs int | ADR 0264 d7 |
| `widgets` | `*.widget.ts` | `unit` | UI widgets; the test sits beside the component | ADR 0264 d7 |
| `pages` | `*.page.ts` | `unit` | route pages | ADR 0264 d7 |
| `resources` | `*.resource.ts` | `unit` | admin-UI @Resource declarations; the word resource is reserved for them | ADR 0234 |
| `ai` | none | none | AI code: prompts, tools and agents | ADR 0264 d7 |
| `raw` | none | `unit` | raw @Controller endpoints only: webhooks, streaming and the /api/auth paths; actions never use it | ADR 0130 |
| `decorators` | none | `unit` | decorator packages with their Explorer (backend-decorator-package skill) | ADR 0130 |
| `contracts` | none | `contract` | vocabulary under src/contracts/, used by the package entry of that name | ADR 0117 |
| `config` | `*.config.ts` | `contract` | typed configuration inside src/config/, not beside src | ADR 0025 |
| `interfaces` | `*.interface.ts` | `contract` | type-only shapes | ADR 0128 |
| `types` | `*.type.ts` | `contract` | type aliases and unions | ADR 0128 |
| `tokens` | `*.token.ts` | `contract` | DI tokens made with defineToken | ADR 0231 |
| `constants` | `*.constant.ts` | `contract` | module-level constants, SCREAMING\_SNAKE | ADR 0231 |
| `enums` | `*.enum.ts` | `contract` | const-object enums with a same-named union type; the enum keyword is banned | ADR 0130 |
| `errors` | `*.error.ts` | `contract` | StackraError subclasses | ADR 0232 |
| `schemas` | `*.schema.ts` | `contract` | Zod schemas | ADR 0095 |
| `internal` | none | `unit` | helpers shared by two or more files of one package; never exported from a barrel; test in `internal/__tests__/` | ADR 0006 |
| `components` | none | `unit` | components as folders: `components/<name>/<name>.tsx` with its `__tests__` beside it | ADR 0128 |

Root module: `src/<name>.module.ts`, test `<name>.module.int.test.ts`, ADR 0090.

React hooks: `use-<name>.ts` beside their component, test `use-<name>.test.ts` (unit), ADR 0129. Extension hooks are the only `hooks/` files.

Static files: `assets/<kind>/` at the package root (`public`, `lang`, `templates`, `stubs`, `data`), ADR 0234. static files shipped with a module; the word resource is reserved for @Resource.

## Banned folders

| Folder | Why | Source |
| - | - | - |
| `controllers` | raw endpoints live in raw/ only; actions are the unit | ADR 0130 |
| `dtos` | Zod schemas replace DTO classes | ADR 0095 |
| `repositories` | MikroORM models and queries replace repositories | ADR 0014 |
| `helpers` | name the kind the code serves instead | ADR 0126 |
| `utils` | shared pure functions go to @stackra/support or the kind they serve | ADR 0126 |
| `presentation` | there is no presentation layer folder | ADR 0130 |

## Test tiers

| Tier | File infix | Holds | Source |
| - | - | - | - |
| `unit` | `.test` | fast, no external services | ADR 0182 |
| `int` | `.int.test` | needs a real database or container | ADR 0182 |
| `contract` | `.contract.test` | checks a declared contract, such as the manifest | ADR 0182 |
| `load` | `.load.test` | k6 load tests, run weekly against staging | ADR 0182 |
| `e2e` | `.e2e.test` | runs a whole app | ADR 0022 |

Every test file sits directly in a `__tests__/` folder beside its subject (ADR 0022). `.spec.*` is not used.

## Documented exceptions

| Rule | Why | Source |
| - | - | - |
| App e2e: `apps/<app>/e2e/__tests__/<name>.e2e.test.ts` | app e2e lives in the app, a documented exception to the member test rule | ADR 0022 |
| Manifest contract test: `app-manifest.contract.test.ts` | gen does not exist before W6; flip required to true at M2; required from M2 | ADR 0182 |

## Forbidden files

| Name | Rule | Source |
| - | - | - |
| `stories` | no Storybook; test the component in `__tests__/` | ADR 0126 |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.