Service Template
Rule: All 17 markdown docs must exist under the documentation repository (ghasi-e-documentation/ghasi-melmastoon/services/<name>/) before any service code is written in the future application monorepo (ghasi-melmastoon). Stubs (headings only) are acceptable for an early service, but every file is present and owned.
Repository layout (read this first)
| Repository | Path (example) | What lives there |
|---|---|---|
| Documentation | D:\GhasiTech\ghasi-e-documentation\ghasi-melmastoon\ | The 17 markdown files for each service under services/<name>/. The services/ folder name matches the service name; it is not the NestJS code tree. |
| Application (code) | Future D:\GhasiTech\ghasi-melmastoon\ (separate repo) | NestJS code under services/<name>/. The /scaffold-service playbook (to be added in that repo) generates code only — it does not create or regenerate these 17 specs. |
If a single clone combines both, still keep the separation: specs in the documentation repo path; runnable code in the application monorepo.
17 required docs
| # | File | Owns |
|---|---|---|
| 1 | SERVICE_OVERVIEW.md | Purpose, bounded context, responsibilities, aggregates owned, upstream/downstream dependencies, context diagram, key decisions |
| 2 | DOMAIN_MODEL.md | Aggregates, entities, value objects, invariants, domain events (names + payloads), state machines |
| 3 | APPLICATION_LOGIC.md | Use cases, commands, queries, ports (*.port.ts), orchestration flows, saga participation |
| 4 | API_CONTRACTS.md | REST endpoints: path (/api/v1/<plural-noun>), method, auth, headers, request/response schema, error codes (from ERROR_CODES.md), pagination |
| 5 | EVENT_SCHEMAS.md | Events produced + consumed, version (*.v1, *.v2), payload schemas, retention class (operational / regulated / audit) |
| 6 | DATA_MODEL.md | TypeScript interfaces + Postgres schema (snake_case_plural tables) + indexes + RLS policies + ID prefix declaration (tnt_, rsv_, …) |
| 7 | SYNC_CONTRACT.md | Per-aggregate conflict policy: server_authoritative / append_only / crdt_yjs / lww / lww+diff / max-of. Mandatory for any aggregate replicated to the desktop SQLite store. |
| 8 | AI_INTEGRATION.md | Every AI call: purpose, prompt template, model routing (Vertex AI cloud / ONNX Runtime edge), moderation policy, HITL flow, AIProvenance touch points. All calls go through ai-orchestrator-service. |
| 9 | SECURITY_MODEL.md | RBAC/ABAC matrix, encryption class, audit events, GDPR participation, data residency, payment/lock secret handling |
| 10 | OBSERVABILITY.md | SLIs/SLOs, dashboards, alerts (with runbooks), required span attributes, log fields (tenant_id, trace_id, request_id) |
| 11 | TESTING_STRATEGY.md | Unit/integration/contract/e2e coverage targets + scenario list + low-bandwidth chaos cases |
| 12 | DEPLOYMENT_TOPOLOGY.md | Runtime (Node 20 on Cloud Run / GKE), replicas, scaling, regions, dependencies, Helm/Terraform module references |
| 13 | FAILURE_MODES.md | Failure catalog: what breaks, user impact (consumer / tenant / backoffice), detection, mitigation, runbook link |
| 14 | LOCAL_DEV_SETUP.md | docker compose up recipe, seed data, common commands, simulator usage (lock simulator, payment sandbox) |
| 15 | SERVICE_READINESS.md | Readiness gate checklist (must be green before prod) |
| 16 | SERVICE_RISK_REGISTER.md | Known risks, owners, mitigations |
| 17 | MIGRATION_PLAN.md | How legacy data / existing tenants migrate in (e.g., from spreadsheets, prior PMS exports) |
Directory skeleton
Specs (this documentation repo only): ghasi-melmastoon/services/<name>/ contains the 17 markdown files listed above plus an optional _sources/ folder for preserved migration content.
Code (future application monorepo):
services/<name>/
├── README.md pointer to documentation repo `services/<name>/`
├── package.json { "name": "@ghasi/service-<name>", "version": "0.0.1" }
├── tsconfig.json extends ../../tsconfig.base.json
├── vitest.config.ts
├── .env.example never commit a real .env
├── openapi.json generated from controllers
├── drizzle.config.ts drizzle-kit config (schema path, out dir, driver)
├── src/
│ ├── domain/
│ │ ├── <aggregate>.ts e.g. reservation.ts, key-credential.ts
│ │ ├── <value-object>.ts e.g. tenant-id.ts, money.ts
│ │ ├── events/ <event>.event.ts
│ │ ├── errors/ <name>.error.ts
│ │ ├── __builders__/ test utilities colocated
│ │ └── index.ts
│ ├── application/
│ │ ├── ports/ <name>.port.ts (LockPort, PaymentPort, …)
│ │ ├── use-cases/ <verb-noun>.use-case.ts
│ │ ├── dtos/
│ │ └── mappers/
│ ├── infrastructure/
│ │ ├── adapters/ postgres-*.adapter.ts, pubsub-*.adapter.ts, ttlock-*.adapter.ts
│ │ ├── config/ env schema (Zod), DI wiring
│ │ └── events/ outbox-relay, inbox-dedupe
│ ├── presentation/
│ │ ├── controllers/ <resource>.controller.ts
│ │ ├── guards/ jwt-auth.guard.ts, tenant-context.guard.ts
│ │ └── dtos/ response shapes
│ ├── app.module.ts
│ └── main.ts initializes @ghasi/telemetry BEFORE NestFactory
└── test/
├── unit/
├── integration/
│ ├── tenant-isolation.spec.ts (mandatory)
│ ├── outbox.spec.ts (mandatory)
│ └── inbox.spec.ts (mandatory)
├── contract/
│ ├── <endpoint>.pact.spec.ts
│ └── <event>.schema.spec.ts
└── e2e/
The four-layer split (domain → application → infrastructure + presentation) is non-negotiable. The domain layer must not import NestJS, Drizzle, the Pub/Sub client, fetch, or any I/O library. CI enforces import boundaries with an ESLint rule pack.
Mandatory integration tests
Every service ships these three before any feature work:
tenant-isolation.spec.ts— proves that data created under tenant A is unreachable through any API call carrying tenant B credentials, including direct ID guesses. Verifies Postgres RLS, controller guards, and the domain-layerTenantIdinvariant together.outbox.spec.ts— proves that domain events are written transactionally with the aggregate, the outbox relay publishes them to Pub/Sub at-least-once, and a publisher crash mid-batch leaves no event lost or double-committed.inbox.spec.ts— proves that consumed events are deduplicated by message ID, idempotently applied, and that a consumer crash mid-handle resumes correctly without double application.
These three tests gate the readiness checklist and run on every PR.
Scaffolding workflow (for AI assistants)
When the user asks for a new service <name>:
- Confirm the bounded context against docs/03-microservices/README.md. A service maps 1:1 to a bounded context.
- Confirm the service exists in the catalog (22 services total). If not, the user must approve adding it (and update the catalog in the same PR).
- Create the 17 docs first under this documentation repo (
services/<name>/). Stubs with headings are acceptable. Do not write application code until the docs exist and the user has reviewedSERVICE_OVERVIEW.md,DOMAIN_MODEL.md,API_CONTRACTS.md, andEVENT_SCHEMAS.md. - In the application monorepo, run
/scaffold-service <name>(forthcoming) to generate code only — the four-layer NestJS skeleton, configs, and the three mandatory tests. It does not write the 17 markdown files. - Wire up a minimal "hello world" use case that exercises the full path: controller → use case → port → adapter → domain. This catches layering violations early.
- Make the three mandatory integration tests pass (
tenant-isolation,outbox,inbox) before any feature work. - Commit with conventional commits:
feat(<name>): scaffold service with required docs and skeleton(documentation repo) andchore(<name>): scaffold service skeleton and mandatory tests(code monorepo).
Required per-service checks in CI
- ESLint: domain layer import-restriction passes (no NestJS, no Drizzle, no I/O).
- Typecheck:
tsc --noEmitstrict, zero errors. - Unit + integration + contract tests green.
- OpenAPI diff gate: no breaking changes without a major version bump (
/api/v1→/api/v2). - Pact consumer tests green against the Pact broker.
- Event schema conformance green against the schema registry; subjects follow
melmastoon.<service>.<aggregate>.<verb-past-tense>.v<n>. - Migration check: any new table has
tenant_id+ an RLS policy named<table>_tenant_isolation.
Service readiness gate
A service is ready for production only when:
- All 17 docs are complete (not stubs).
- Coverage thresholds met (see DEFINITION_OF_DONE.md).
test/integration/tenant-isolation.spec.ts,outbox.spec.ts, andinbox.spec.tsall pass.- OpenTelemetry instrumentation verified in staging (traces + logs + metrics visible in Cloud Monitoring / Grafana with
tenant_idlabel). - SLOs declared and alerts configured with named runbooks.
- Canary deploy completed (5% / 30 min) in staging; rollback verified.
- For desktop-replicable services:
SYNC_CONTRACT.mddeclares a conflict policy for every replicated aggregate, and the desktop sync engine has an integration test against this service. - For AI-touching services:
AI_INTEGRATION.mddeclares every prompt/model andAIProvenanceis persisted on every AI artifact. - For payment- or lock-touching services:
security-reviewerhas signed off; secrets live in Secret Manager only. - On-call rotation assigned.
SERVICE_READINESS.mdsigned off by tech lead + SRE.