Service Documenter Skill
Entry Point
Read the user's request first and determine the generation mode:
- Default mode — generate
docs/ only (Phases 1–3)
- ADR mode — generate
docs/ AND docs/adr/ (Phases 1–4)
ADR mode is triggered only when the user explicitly says phrases like:
"with ADRs", "include ADRs", "also create ADRs", "generate ADRs", or "architecture decision records".
If the user did not ask for ADRs, skip Phase 4 entirely and do not mention it in output.
Phase 1: Stack Detection
Scan the repo and identify:
- Language (Go, Node, Python, Java, Rust, PHP, etc.)
- Framework (Express, FastAPI, Spring Boot, Laravel, NestJS, Gin, Django, etc.)
- Database type (Postgres, MySQL, MongoDB, Redis, DynamoDB, Cassandra, etc.)
- Schema files (
*.sql, migrations/, prisma/schema.prisma, **/models.py, entity files, etc.)
- Event system (Kafka, RabbitMQ, SQS, EventBridge, NATS) — if none found, mark events as not applicable
- API style (REST, gRPC, GraphQL) — look for proto files, swagger/openapi specs,
schema.graphql
- Deployment config (Dockerfile, k8s YAML, docker-compose, Helm charts, Terraform)
If a component is not found (e.g. no event system, no cache, no gRPC), do not skip the corresponding
doc file — instead write it with a brief "Not applicable for this service" note and explain what was
checked. This prevents confusion about whether the file was forgotten or intentionally omitted.
Phase 2: Deep Analysis
For each detected component, extract the following. Read source files directly — do not invent or guess.
2a. API Endpoints
- All controllers: every method, path, HTTP verb
- For each endpoint: auth guard class name, request DTO fields, response DTO fields
- Read the actual response DTO files — expand nested DTOs to their full field list
- Read the response interceptor to get the exact envelope shape (
{success, data} vs {status_code, data, message, error} etc.)
- Find ALL endpoints including non-obvious ones (cancel, refund, invalidate, resync, webhook handlers)
- For webhook endpoints: read the webhook-specific DTOs to get exact inbound payload fields
2b. Database Schema
- All entity files: every column with name, type, nullable, default, unique, indexed
- Extract all enum values — for any
enum type or string column with a documented value list, list every possible value
- FK relations and their cascade behavior
- All indexes: column(s), purpose
- Understand
parent_id / self-referential relationships and document their meaning
2c. Events
- Read actual publish calls — extract the exact
routingKey or eventName string literals used, not just exchange env vars
- Distinguish event name prefixes (e.g.,
online.order.created vs order.created)
- For each consumed queue: what it triggers in the handler
- Note if offline/partner channels use different event naming from online channels
- Note idempotency requirements (at-least-once delivery)
2d. Response Envelope
- Read the global response interceptor file
- Record the exact JSON wrapper structure applied to all responses
- Note if specific controllers use different interceptors (e.g., webhooks bypass the global interceptor)
2e. Architecture Internals
- List all application modules (NestJS modules, Django apps, Spring beans, etc.)
- Read entity subscriber / lifecycle hook files — these cause implicit side effects on DB writes
that surprise new developers. Document each subscriber: which entity it watches, which event
(insert/update/delete) triggers it, and what side effect it produces.
- Read exception filter files — list all filters and their execution order (global → controller → method)
- Identify the process model: unified HTTP+worker, or separate processes?
2f. Dependencies
- For each outbound HTTP client: classify as sync (blocks request path) or async (fire-and-forget / background)
- Assign criticality using this heuristic:
- HIGH — called in the main request path with no fallback; failure breaks the core user flow
- MEDIUM — failure degrades a feature but the core flow still completes
- LOW — optional enrichment; service continues normally if this dependency is unavailable
- Note mitigation per dependency: timeout, retry, circuit breaker, fallback, or none
2g. Environment Variables
- Read all config/environment definition files
- Mark each variable: Required (Y/N), has default (Y/N), sensitive (Y/N)
- Flag variables that are feature flags (ENABLE_, DISABLE_) separately
2h. Infrastructure
- Docker: build stages, base image, entrypoint
- Compose / k8s: port mappings, restart policy, volume mounts
- Migration strategy: auto-run on startup? Manual? Note prod risks.
Phase 3: Generate Each File
Generate a docs/ directory with the following files. All diagrams must use Mermaid syntax.
Never use DTO class names as response schemas — always expand to actual JSON field names and types.
docs/overview.md
- One-paragraph service summary
- Responsibility / domain boundary table (In Scope / Out of Scope)
- Tech stack table (Language, Framework, Database, Cache, Message Broker, API Style)
- Explicit statement of process model (HTTP-only, HTTP+consumer, worker-only)
- Team ownership placeholder (team name, Slack channel)
- Links to all other docs in this format:
docs/architecture.md
- Component diagram in Mermaid showing: all modules, DB, cache, message broker, external HTTP deps, webhook sources
- Key flow sequence diagrams — at minimum: the primary create/write flow, and the most complex async flow
- Module list — every application module with its controllers, services, and repositories
- Entity subscribers / lifecycle hooks section — for each subscriber: entity watched, trigger event
(insert/update/delete), side effect produced. Label this section clearly as these are non-obvious
implicit behaviors.
- Exception filter stack — all global exception filters in execution order
- Design decisions narrative with references to ADRs (only if ADR mode was requested)
- Integration points table
docs/api.md
-
Every endpoint grouped by resource/controller: method, path, auth guard, request schema, response schema, error codes
-
Request schema: actual JSON field names and types, not DTO class names
-
Response schema: actual JSON including the response envelope wrapper. Expand nested objects
at least 2 levels deep. Show enum values for status fields.
-
Response envelope: document the exact wrapper applied by the global interceptor, e.g.:
{ "status_code": 200, "message": "...", "data": {}, "error": null }
-
Webhook endpoints: include the full inbound payload schema from the provider DTO
-
Error response shape: show the actual error envelope with all field names
-
Do not omit endpoints that seem internal or administrative — document them all
-
If gRPC: list RPCs and proto message shapes
-
If GraphQL: queries, mutations, subscriptions
docs/events.md
If no event system was detected, write: "This service does not publish or consume events." and
describe what was checked (no Kafka config, no queue consumers, etc.). Still generate the file.
Otherwise:
- Published events: exact routing key string (not env var name), exchange, payload schema, trigger condition
- If online and offline/partner channels use different event prefixes, document both explicitly
- Consumed events: queue name, exchange, handler class, what the handler does
- Internal events (EventEmitter, in-process): event name, emitter location, subscriber/listener
AFTER_TRANSACTION_COMMIT note: if this pattern is used, explain it prevents publishing events
for rolled-back DB transactions
- Idempotency note: state at-least-once delivery guarantee and what consumers must handle
- DLQ behavior if configured
- Mermaid event flow diagram
docs/database.md
- ER diagram in Mermaid with all tables and FK relations
- For every table: every column with type, nullable, default, unique/indexed flags
- Enum values: for every status/type column, list every possible value
- Self-referential / parent relationships: explain the business meaning
- JSON columns: list which fields they typically contain and their purpose
- Indexes table per table: column(s), index type, purpose
- Migration strategy: how to run, generate, revert; warn about irreversible migrations
docs/runbook.md
- Step-by-step local setup (clone → install → env → migrate → start)
- Test commands (unit, e2e, coverage, watch)
- CLI / management commands with description
- DB migration commands with warnings for destructive reversal
- Common diagnostic SQL queries for known failure modes
- Re-trigger / recovery API calls with example curl commands
- Restart commands for Docker and k8s
- Log locations and useful log filter patterns
docs/deployment.md
- Infrastructure requirements table
- Docker build and run commands
- Environment variables table: Variable | Required | Default | Sensitive | Description
- Feature flags table (ENABLE_* / DISABLE_* vars): Variable | Default | What it controls | Safe to enable in prod?
- Step-by-step deploy checklist:
- Verify migrations are safe to run
- Deploy new image
- Check
/health endpoint
- Check error monitoring (Sentry/equivalent)
- Check alert channel (Slack/equivalent)
- Smoke test critical path
- Auto-migration warning: if
DB_MIGRATE=true auto-runs on startup, call this out explicitly
with the prod risk (migration runs before health check passes; irreversible migrations are dangerous)
- CI/CD pipeline description
- Rollback procedure for both app and database
docs/troubleshooting.md
- Known failure modes with: symptom, likely cause, diagnostic checklist, fix/recovery steps
- Include SQL queries for each DB-level diagnosis
- Include curl commands for recovery API calls
- On-call escalation path
docs/dependencies.md
- Internal services table: Service | Env Var | Call Type (sync/async) | Criticality (HIGH/MEDIUM/LOW) | Mitigation
- External APIs table: Service | Purpose | Auth mechanism | Criticality | Feature flag (if any)
- Infrastructure table: Dependency | Purpose | Config
- Key packages table: Package | Version | Purpose — grouped by: Core, DB/Cache, Messaging, Auth, Monitoring
- Dependency diagram in Mermaid
- Risk summary: one row per HIGH-criticality dependency — what breaks if it goes down, and the mitigation
Phase 4: Generate ADRs
Only run this phase if the user explicitly requested ADRs. Otherwise stop after Phase 3.
Under docs/adr/ create:
ADR numbering and file naming
docs/adr/001-record-architecture-decisions.md — always first; the meta ADR about using ADRs
- Then one ADR per substantive design decision found in the codebase, numbered sequentially:
002-, 003-, etc.
- Do not pad with trivial ADRs — only write one if there is real evidence of a decision in the code.
Decisions to look for
Check the code for evidence of each. Write an ADR only if evidence is found:
- Event-driven vs synchronous architecture for downstream notifications
- Database engine choice and ORM choice
- Message broker choice
- API versioning strategy
- Auth mechanism (JWT, API key, OAuth, service key pattern)
- Caching strategy (what is cached, TTL, invalidation)
- Process model (unified HTTP+worker vs separate processes)
- Error tracking and alerting approach
- Data modeling strategy (JSON snapshot columns, soft deletes, audit fields)
- Feature flags for third-party integrations
- Language and framework choice
ADR format
# ADR-NNN: [Title]
**Status**: Accepted | Proposed | Deprecated
**Date**: YYYY-MM-DD
## Context
Why was a decision needed? What forces were at play?
## Decision
What was decided?
## Alternatives Considered
What else was evaluated and why was it rejected?
## Consequences
Positive and negative trade-offs. Operational implications.
Output Rules
- Use Mermaid for all diagrams
- Never use DTO class names as response schemas — expand to actual JSON field names and types
- Always show enum values for any field with a constrained value set
- Mark unknown or unverifiable fields with
<!-- TODO: verify -->
- Never invent values — if uncertain, use a placeholder and mark it
- Keep docs machine-readable: consistent headings, fenced code blocks, no smart quotes
- For nested response objects: expand at least 2 levels deep inline; use a sub-section for deeply nested structures
- Do not omit endpoints that seem internal or administrative — document them all
- If a component (events, cache, etc.) is not found, still generate the file with a "not applicable" note