# Service Layer Template

Standards for business logic services, commands, queries, policies, and specifications.

Enterprise default: phases deliver these layers for in-scope capabilities — CRUD-only services are insufficient ([definition-of-done.md](definition-of-done.md), [mandatory-phase-artifacts.md](mandatory-phase-artifacts.md)).

## Responsibility

Services:

- Own domain rules and orchestration
- Validate invariants (via validators / specifications)
- Apply policies (authorization, entitlement, domain policy objects)
- Expose **Commands** (state changes) and **Queries** (reads without write side-effects)
- Write audit records
- Write outbox/domain events in the **same transaction** as state changes
- Call other services only via HTTP clients / events — never via foreign repos
- Receive dependencies via explicit injection (constructor / factory / FastAPI deps)

Services must **not**:

- Depend on FastAPI `Request` / response objects
- Emit raw SQL bypassing repositories (except rare documented cases)
- Perform provider I/O without going through provider adapters owned by the service
- Mutate another aggregate’s invariants across boundaries without explicit domain rules
- Duplicate another service’s business logic ([boundary-rules.md](boundary-rules.md))

## Commands

| Rule | Detail |
| --- | --- |
| Location | `app/commands/` or clearly named command methods on services |
| Naming | Verb phrases (`CreateMember`, `FreezeMembership`) |
| Effect | Single use-case state change; emit audit + outbox as required |
| Idempotency | Document for retried operations |

## Queries

| Rule | Detail |
| --- | --- |
| Location | `app/queries/` or query services / read methods |
| Effect | Read-only; no accidental writes or event emission |
| Lists | Support pagination, filtering, sorting, searching as API requires |

## Specifications

| Rule | Detail |
| --- | --- |
| Location | `app/specifications/` |
| Purpose | Reusable query predicates and business specification objects |
| Use | Repositories/services compose specs instead of duplicating filter logic |

## Policies

| Rule | Detail |
| --- | --- |
| Location | `app/policies/` |
| Purpose | Authorization, entitlement, and domain policy decisions reusable across commands |
| Note | Route-level permission deps remain; policies encode richer domain rules |

## Conventions

| Topic | Rule |
| --- | --- |
| Location | `app/services/` (+ commands/queries/policies/specifications) |
| Naming | `{Capability}Service` |
| Dependencies | Repositories, validators, specs, policies, event publisher, provider protocols |
| DTOs | Accept/return schema objects or typed domain results — not ORM leakage to API |
| Errors | Raise shared/domain exceptions with stable codes |
| Idempotency | Document for retried operations (OTP, webhooks, messaging) |
| DI | Explicit wiring; no hidden service locators for domain logic |

## Transaction & Events

1. State change + outbox row in one transaction ([ADR-006](../architecture/adr/ADR-006.md)).
2. Event types follow [event-template.md](event-template.md).
3. Failures calling remote systems must not corrupt local invariants; use async patterns where required (Communication pattern).

## Audit

- Record actor, action, entity, tenant, timestamp for sensitive mutations.
- Prefer dedicated audit tables where the service already has them.

## Testing

Service / command / query / policy / specification tests cover business rules with DB or fakes — see [testing-template.md](testing-template.md).

## Related Documents

- [Repository Template](repository-template.md)
- [API Template](api-template.md)
- [Mandatory Phase Artifacts](mandatory-phase-artifacts.md)
- [Project Principles](../development/project-principles.md)
- [Service Architecture](../architecture/service-architecture.md)
- [Event-Driven Architecture](../architecture/event-driven-architecture.md)
