Include Loyalty/Communication/Sports Center backends and registry updates alongside production nginx and compose wiring. Co-authored-by: Cursor <cursoragent@cursor.com>
4.8 KiB
4.8 KiB
Service Template
How to design a new independent service under backend/services/<name>/.
Use when the capability is shared across domains or requires sole database ownership (patterns: Loyalty ADR-011, Communication ADR-012).
For a slice inside an existing service, use module-template.md instead.
Architecture
- Deployable FastAPI app with package layout per service-architecture.md and coding-standards.md.
- Layering:
API → Services → Repositories → Models. - Database-per-service (ADR-001).
- Outbox-ready events (ADR-006).
- No imports of other services’ models/repos.
- Frontend remains a separate client (ADR-002).
backend/services/<name>/
app/
api/v1/
core/ # config, database, security, logging
models/
schemas/
services/
repositories/
providers/ # adapters if this service owns providers
events/
permissions/
middlewares/
validators/
tests/
alembic/
Dockerfile.dev
requirements.txt
README.md
Ownership
| Owns | Must not own |
|---|---|
| Its database schema and migrations | Other services’ tables |
Its permission tree {service}.* |
Foreign domain aggregates |
| Its public API + publish events | UI business rules |
| Provider adapters for its channel/domain | Direct calls into other DBs |
Document boundaries in module-boundaries.md when introducing a platform service.
Dependencies
| Kind | Rule |
|---|---|
| Core | Entitlement / tenant identity as required |
| Other services | HTTP + events only |
| Providers | Behind protocols; register in provider-registry.md |
| shared-lib | Envelope, JWT helpers, exceptions only |
| AI | Optional contract; core flows work without AI |
Public APIs
- Versioned under
/api/v1 - Documented in service README and eventually api-reference.md / services-contracts.md
- Auth: JWT + tenant header pattern used by sibling services
- Stable error codes via shared exceptions
- See api-template.md
Private APIs
- Internal-only routes (if any) require internal service token or network isolation
- Never expose admin debug endpoints without auth in non-dev profiles
- Do not publish private routes in public contracts
Events
- Publish domain events for state changes other services may need
- Prefer outbox in the same transaction as writes
- Naming and payload rules: event-template.md
- Catalog: event-catalog.md
Database Ownership
| Field | Value |
|---|---|
| Database name | <name>_db |
| Migrations | Alembic in this service only |
| Cross-DB FK | Forbidden |
| Tenant column | Required on business tables |
Reference: database-architecture.md, database-schema.md.
Configuration
- All settings via env / settings class — no hardcoded secrets or brand
- Document keys in
.env.exampleand service README when the phase wires runtime - Feature flags / entitlement keys documented
Permissions
- Prefix:
{service}.* - Map routes to permission checks
- Document tree in module registry and phase doc
Tenant Awareness
- Middleware / deps resolve
tenant_id - Repositories always filter by tenant for tenant-owned rows
- Isolation tests mandatory
- See multi-tenant-architecture.md
Monitoring
- Structured logging via service logging setup
- Operational stats endpoints when the domain requires them (see Communication monitoring pattern)
- Align with deployment/monitoring.md
Health Checks
| Endpoint | Purpose |
|---|---|
GET /health |
Liveness (and basic dependency signal as appropriate) |
Optional GET /capabilities |
Feature/channel discovery for platform services |
Register health URL in service-manifest.yaml.
Registration Checklist
- service-manifest.yaml
- module-registry.md
- ADR if platform ownership decision
- Phase doc + handover
- Compose/port docs when runtime is in scope
- Tests per testing-template.md