# Strict Effect Starter
An opinionated Bun and Effect monorepo starter with hexagonal vertical slices, strict TypeScript and Effect diagnostics, architecture-aware OXLint rules, repository graph checks, Vitest, Knip, Sherif, and Lefthook.
The repository ships one deliberately boring proof slice — `packages/notes` served by `apps/server` — as the compiled, tested, runnable reference for the architecture. Every app and package added to the workspace is checked against the same rules. Delete the notes slice once your first real slice exists.
## Try it
```sh
bun run dev
curl -X POST localhost:3000/notes -H 'content-type: application/json' -d '{"title":"Hello","description":null}'
curl localhost:3000/notes
curl localhost:3000/openapi.json
```
## Requirements
- Bun 1.3.14
- Node.js 26.x
## Setup
```sh
bun install
```
## Customize the template
The starter works unchanged with the private workspace scope `@app`. To use another scope, replace `@app` consistently in:
- `architecture.config.json`;
- package manifests and source imports under `apps/`;
- package manifests, source imports, and tests under `packages/`.
Keep the isolated architecture fixtures under `tools/` unchanged: they intentionally test the generic `@app` scope. Also rename the root package in `package.json` and delete `packages/notes` only after the first real slice provides an equivalent executable reference.
## Architecture
Product code follows a fixed slice vocabulary:
```txt
packages/<slice>/
domain/
use-cases/
config/
server/
client/
tables/
ui/
```
Roles are optional. Create a package only when it has a concrete responsibility and meaningful behavior. The smallest default slice contains `domain`, `use-cases`, and `server`.
Concept topology is mirrored across roles:
```txt
packages/iam/domain/src/entities/Membership/Membership.model.ts
packages/iam/use-cases/src/entities/Membership/Membership.commands.ts
packages/iam/server/src/entities/Membership/Membership.http-handlers.ts
packages/iam/ui/src/entities/Membership/Membership.form.tsx
```
See [ARCHITECTURE.md](./ARCHITECTURE.md) for the dependency matrix, role vocabulary, explicit entrypoints, shared-kernel promotion policy, and non-slice families.
## Add architecture
Create apps, packages, and concept modules directly at their canonical paths. Each workspace package must declare its architecture metadata, explicit exports, source directory, and TypeScript configuration. Run `bun run lint` while scaffolding: the source rules and repository checker report invalid topology, naming, boundaries, manifests, and dependency edges.
Public facades remain curated manually so a private module is never accidentally published.
## Enforcement
`bun run lint` runs two complementary checks:
1. OXLint reports source-level topology, role naming, package import boundaries, explicit entrypoints, private deep imports, cross-slice imports, and undeclared direct workspace dependencies on the offending AST node.
2. The repository checker validates workspace layout, package names and metadata, export maps, export targets, dependency ceilings, `workspace:` versions, package graph cycles, and promotion records for high-bar shared packages.
Type-only imports and static dynamic imports follow the same boundaries as ordinary imports. Wildcard exports are forbidden.
## Commands
- `bun run lint`: run OXLint and all architecture checks.
- `bun run lint:architecture`: validate manifests and the workspace graph only.
- `bun run lint-deps`: check package dependency consistency.
- `bun run fmt`: format the repository.
- `bun run test`: run the product and architecture suites.
- `bun run test:unit`: run only tests belonging to apps and product packages.
- `bun run test:architecture`: run exhaustive architecture matrices, mutated-repository checks, and real OXLint subprocess integrations.
- `bun run typecheck`: verify TypeScript and Effect contracts.
- `bun run knip`: check dead files, exports, and dependencies.
The architecture suite keeps its expected dependency tables separate from the production policy. It covers every role-to-role, foundation-kind, tooling-kind, and role-to-foundation pair; every declared concept suffix; malformed repository states; and all supported static TypeScript import/re-export syntaxes through the installed OXLint binary.
## License
[MIT](./LICENSE) © Baptiste Arnaud