Skip to main content

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)

RepositoryPath (example)What lives there
DocumentationD:\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

#FileOwns
1SERVICE_OVERVIEW.mdPurpose, bounded context, responsibilities, aggregates owned, upstream/downstream dependencies, context diagram, key decisions
2DOMAIN_MODEL.mdAggregates, entities, value objects, invariants, domain events (names + payloads), state machines
3APPLICATION_LOGIC.mdUse cases, commands, queries, ports (*.port.ts), orchestration flows, saga participation
4API_CONTRACTS.mdREST endpoints: path (/api/v1/<plural-noun>), method, auth, headers, request/response schema, error codes (from ERROR_CODES.md), pagination
5EVENT_SCHEMAS.mdEvents produced + consumed, version (*.v1, *.v2), payload schemas, retention class (operational / regulated / audit)
6DATA_MODEL.mdTypeScript interfaces + Postgres schema (snake_case_plural tables) + indexes + RLS policies + ID prefix declaration (tnt_, rsv_, …)
7SYNC_CONTRACT.mdPer-aggregate conflict policy: server_authoritative / append_only / crdt_yjs / lww / lww+diff / max-of. Mandatory for any aggregate replicated to the desktop SQLite store.
8AI_INTEGRATION.mdEvery 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.
9SECURITY_MODEL.mdRBAC/ABAC matrix, encryption class, audit events, GDPR participation, data residency, payment/lock secret handling
10OBSERVABILITY.mdSLIs/SLOs, dashboards, alerts (with runbooks), required span attributes, log fields (tenant_id, trace_id, request_id)
11TESTING_STRATEGY.mdUnit/integration/contract/e2e coverage targets + scenario list + low-bandwidth chaos cases
12DEPLOYMENT_TOPOLOGY.mdRuntime (Node 20 on Cloud Run / GKE), replicas, scaling, regions, dependencies, Helm/Terraform module references
13FAILURE_MODES.mdFailure catalog: what breaks, user impact (consumer / tenant / backoffice), detection, mitigation, runbook link
14LOCAL_DEV_SETUP.mddocker compose up recipe, seed data, common commands, simulator usage (lock simulator, payment sandbox)
15SERVICE_READINESS.mdReadiness gate checklist (must be green before prod)
16SERVICE_RISK_REGISTER.mdKnown risks, owners, mitigations
17MIGRATION_PLAN.mdHow 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 (domainapplicationinfrastructure + 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:

  1. 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-layer TenantId invariant together.
  2. 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.
  3. 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>:

  1. Confirm the bounded context against docs/03-microservices/README.md. A service maps 1:1 to a bounded context.
  2. 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).
  3. 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 reviewed SERVICE_OVERVIEW.md, DOMAIN_MODEL.md, API_CONTRACTS.md, and EVENT_SCHEMAS.md.
  4. 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.
  5. Wire up a minimal "hello world" use case that exercises the full path: controller → use case → port → adapter → domain. This catches layering violations early.
  6. Make the three mandatory integration tests pass (tenant-isolation, outbox, inbox) before any feature work.
  7. Commit with conventional commits: feat(<name>): scaffold service with required docs and skeleton (documentation repo) and chore(<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 --noEmit strict, 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, and inbox.spec.ts all pass.
  • OpenTelemetry instrumentation verified in staging (traces + logs + metrics visible in Cloud Monitoring / Grafana with tenant_id label).
  • SLOs declared and alerts configured with named runbooks.
  • Canary deploy completed (5% / 30 min) in staging; rollback verified.
  • For desktop-replicable services: SYNC_CONTRACT.md declares 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.md declares every prompt/model and AIProvenance is persisted on every AI artifact.
  • For payment- or lock-touching services: security-reviewer has signed off; secrets live in Secret Manager only.
  • On-call rotation assigned.
  • SERVICE_READINESS.md signed off by tech lead + SRE.