Module Contract Plan
Goal
- Establish
@webstir-io/module-contractas the single authority for module/provider interfaces and runtime schemas (greenfield: no migration concerns).
Scope & Principles
- Authority:
module-contract/defines the contract; provider repos implement it. Do not duplicate core interfaces elsewhere. - Separation of concerns: build-time provider API remains (ModuleProvider); runtime module surface (routes/views/jobs/events) lives alongside it in the same package.
- Minimal runtime deps: ship TypeScript types, Zod schemas, and generated JSON Schema; avoid adding heavy runtime dependencies to consumers.
Acceptance Criteria
- TypeScript types for Contexts, RouteSpec, ViewSpec, ModuleManifest added under
module-contract/src/and compile. - Zod schemas for these types exported, plus JSON Schema emitted to
module-contract/schema/*during build. - Helper creators
createModule,defineRoute,defineViewprovide strong inference and pass compile-time tests. - Example module (Accounts) compiles and validates using only
module-contractexports. - No breaking changes to existing
ModuleProviderinterfaces; README reflects new surfaces and build steps.
Validation & Errors
- Library: use Zod for runtime validation; publish Zod objects and JSON Schema (via build step) for non-TS consumers.
- Error taxonomy:
ValidationError,AuthError(unauthorized/forbidden),NotFoundError,DomainError. - Error shape:
{ code: string; message: string; details?: unknown; cause?: unknown; correlationId?: string }. - Map to HTTP: 400 validation, 401/403 auth, 404 not found, 409 conflict (domain), 422 semantic; default 500.
Contexts & Provider Authority
- RequestContext:
{ req, res, auth, session, db, env, logger, requestId, now }. - SSRContext (optional):
{ url, params, cookies, headers, auth, session, env, logger }. - Provider interfaces (authoritative definitions live here):
- BackendProvider: implements build + exposes route handlers bound to RequestContext.
- TestingProvider: emits testing events and manifest types.
- AuthProvider: session primitives
getSession,createSession,invalidateSession,csrfToken. - DatabaseProvider: generic
dbhandle with minimal query/tx abstraction; avoid binding to a specific ORM. - Optional: CacheProvider, QueueProvider (thin, capability flags in manifest).
- Logging:
Loggerinterface with levels, structured fields,with({}), and correlation/request IDs. - Config/Env:
Envaccessor interface for typed retrieval and secret hints.
Manifest & Capabilities
- ModuleManifest:
{ name, version, kind: 'frontend'|'backend', routes?, views?, jobs?, events?, services?, init?, dispose?, capabilities?: string[], contractVersion: '1.x' }. - Capabilities: enumerate features (e.g.,
auth,db,queue,cache,views) for orchestrator wiring. - Versioning: single
contractVersionstring; reserve feature flags per capability for evolution.
Routes & Views
- RouteSpec:
{ method, path, input: { params?, query?, body? }, output: { status, body }, handler(ctx) }with Zod schemas forinput/output. - ViewSpec:
{ path, params?, load(ctx) }for SSR/loader-style data. - ts-rest integration: provide an optional adapter
fromTsRest(route)and (later) typed client generation;ts-restremains an optional peer for providers, not a hard dep of the contract.
Discovery & Helpers
- Discovery:
package.jsontop-level"webstir.module"object with{ kind, entry }. Orchestrator discovers by this field and validates against JSON Schema. - Helpers:
createModule({ manifest, routes, views, ... }),defineRoute({...}),defineView({...})with strong generics and Zod-powered inference.
Types, Examples & Tests
- Location:
module-contract/src/for types + Zod; JSON Schema emitted tomodule-contract/schema/. - Example:
examples/accounts(or colocatedexamples/folder) defining 1–2 routes and one view using helpers. - Conventions doc additions: route naming, status codes, pagination/filter conventions, error codes.
- Tests: unit tests for helper inference + runtime validation; compile-time checks using
tsdorexpectTypeOf.
Non-Goals (for now)
- Cross-repo migration/rollout — not needed; no active consumers.
- Rich ORM/auth implementations — keep provider interfaces minimal and portable.
Implementation Notes
- Update
module-contract/README.mdwith new surfaces and build instructions. - Ensure build regenerates JSON Schema when Zod_types change; fail CI on drift.
- Keep
ModuleProvider(build-time) unchanged to support orchestrator integration.