Add Zod dependency and update API interfaces

- Added Zod as a dependency in package.json.
- Updated pnpm-lock.yaml to include Zod.
- Refactored API interfaces: exported new modules for perk, survivor, mission, and encounter.
- Removed obsolete api-interfaces.ts file.
- Enhanced tests for new schemas in api-interfaces.spec.ts, covering various validation scenarios.
This commit is contained in:
Maurycy
2026-05-07 00:46:03 +00:00
parent 308a1cf5c4
commit 65af268b86
17 changed files with 829 additions and 87 deletions

View File

@@ -0,0 +1,70 @@
# 0002 — Nx monorepo with enforced module boundaries
- **Status:** Accepted
- **Date:** 2026-05-06
## Context and problem statement
Fog Expedition has at least three distinct deployable surfaces (Twitch Video Overlay frontend, NestJS EBS backend, content/balance library), and types must be shared between them (DTOs, domain models, encounter records). The project is being built with heavy AI assistance, which adds a specific failure mode: AI assistants happily reach across project boundaries with relative imports if not constrained.
How should the codebase be structured?
## Decision drivers
- **Type sharing without duplication.** The overlay and EBS exchange `Mission`, `Survivor`, `EncounterResult` etc. Hand-keeping types in sync across separate repos is bug-prone.
- **AI-assisted-build discipline.** AI tools generate plausible-looking code that violates architectural conventions unless those conventions are mechanically enforced.
- **Solo-developer simplicity.** Multiple repos mean multiple CI configs, multiple versioning streams, multiple onboarding paths.
- **Future scaling.** Should the project ever grow to more contributors, the architecture should still be coherent.
- **Tooling support for the chosen language stack** (TypeScript, Angular, NestJS).
## Considered options
1. **Multi-repo (polyrepo).** Frontend, backend, and shared types each in their own repository. Shared types published to a private npm registry.
2. **Loose monorepo (npm/pnpm workspaces only).** All projects in one repo, no orchestrator. No automated boundary enforcement.
3. **Nx monorepo with `enforce-module-boundaries`.** All projects in one repo. Project tags (`scope:api`, `scope:overlay`, `scope:shared`, `type:app`, `type:lib`) define dependency rules enforced at lint time.
4. **Turborepo.** Lighter monorepo orchestrator, focused on caching and task running. No native module boundary enforcement.
## Decision outcome
**Chosen: Nx monorepo with enforced module boundaries.**
Project structure:
```
apps/
api/ # scope:api, type:app
overlay/ # scope:overlay, type:app
libs/
api-interfaces/ # scope:shared, type:lib (Zod schemas, DTOs)
mission-logic/ # scope:shared, type:lib (encounter resolver, perk math)
encounter-library/ # scope:shared, type:lib (content + helpers)
```
Boundary rules enforced via `@nx/enforce-module-boundaries`:
- Apps can only depend on libs (not other apps).
- `scope:api` can depend on `scope:api` and `scope:shared`.
- `scope:overlay` can depend on `scope:overlay` and `scope:shared`.
- `scope:shared` can only depend on `scope:shared`.
Violations fail lint (verified at workspace setup with a deliberate negative test).
## Consequences
### Positive
- Type sharing is direct via TypeScript imports, no version coordination needed.
- Module boundary enforcement catches architecturally incorrect AI-generated code at lint time before code review.
- Single CI pipeline, single dependency tree, single onboarding flow.
- `nx affected` runs only what changed, keeping CI fast as the project grows.
- Per-project `package.json` files keep workspace libs publish-ready (e.g., `api-interfaces` could later be published as a community SDK without restructuring).
### Negative
- Steeper learning curve than plain pnpm workspaces — Nx generators, executors, and project configuration are non-trivial.
- Tighter coupling to Nx's release cadence; `nx migrate` is required for major version upgrades but generally handles them well.
- Some Nx generators lag behind the underlying tooling (e.g., `@nx/nest` doesn't yet support Vitest natively — see ADR-0003).
### Neutral
- The monorepo single source of truth makes architectural mistakes more visible; it also makes them more impactful when they happen.