# Architecture Principles

## Purpose

This document defines the permanent structural principles of the SMPP Gateway. It governs responsibility, dependency direction, state, validation, and safe extensibility.

## Layer Responsibilities

Each layer must own one coherent category of behavior:

- **Protocol:** wire representation, parsing, encoding, protocol validation, classification, and typed protocol results.
- **Routing:** pure mapping from an approved input category to a typed route.
- **Handler boundary:** pure mapping from a typed route to a typed handling result until a later approved boundary explicitly introduces effects.
- **Application:** orchestration of approved use cases and business capabilities.
- **Domain:** business rules, policies, entities, and domain state.
- **Persistence and infrastructure:** database, network, queue, provider, framework, and external-system concerns.

Business behavior must not leak into protocol, routing, or pure handler layers. Persistence behavior must not leak into pure layers.

## Dependency Direction

- Dependencies must point toward stable contracts and values.
- Pure layers must not depend on application services, domain services, framework facades, databases, queues, or external integrations.
- Infrastructure implements contracts owned by the appropriate inner boundary.
- Cross-layer data must use explicit typed objects rather than loosely structured arrays.
- Dependency cycles and hidden service location are prohibited.

## Protocol Layer

The protocol layer owns command identifiers, field limits, wire parsing, encoding, protocol models, validation, classification, response construction, and protocol failure categories.

It must be deterministic, immutable where practical, and side-effect free. It must not perform database access, tenant resolution, application routing, business processing, callbacks, queueing, or metrics emission.

## Routing Layer

The routing layer maps approved typed inputs to typed route results. It must be pure, deterministic, exhaustive for supported categories, and identity-preserving where pass-through behavior is required.

Routing does not select tenants, applications, providers, repositories, endpoints, or business workflows unless a separately approved architecture introduces a distinct non-pure boundary.

## Handler Layer

The pure handler boundary maps typed routes to typed handling results. It introduces no persistence, callback, event, queue, business mutation, or external communication.

Any future effectful processing must be introduced behind a newly approved contract outside the stable pure handler boundary.

## Persistence Boundaries

- Database access belongs only in approved repositories or persistence services.
- Tenant-owned data must always be explicitly tenant-scoped.
- Transaction ownership must be explicit.
- Network I/O must not occur inside database transactions unless an approved design explicitly requires and justifies it.
- Protocol objects must not acquire persistence responsibilities.

## Runtime Boundaries

- Runtime state transitions must be explicit and validated.
- Protected runtime components must not change unless the approved work targets them.
- Reads, writes, acknowledgements, retries, reconnects, and loops must be explicit and bounded.
- Hidden retries, reconnects, loops, and duplicate acknowledgements are prohibited.
- Failures must preserve established cleanup and state-transition policy.

## Business Logic Boundaries

Business policy belongs in domain or application components designed for that policy. Controllers, protocol codecs, routers, transport adapters, and persistence models must not become informal business-service containers.

## Immutability and Value Objects

- Protocol models, routing results, handling results, identifiers, money, and state snapshots should be immutable.
- Value objects must represent one valid concept and reject invalid construction.
- Mutable state must have an explicit owner and controlled transitions.
- Money must use integer representation, never floating point.

## Constructor Invariants

Public constructors and factories must prevent impossible states. Related fields must be validated together, including type, direction, length, range, status, sequence, classification, and identity relationships where applicable.

Readonly storage alone is not an invariant; construction must also be valid.

## Validation Philosophy

- Reuse authoritative validators, registries, calculators, and limits.
- Never duplicate protocol rules.
- Validate at the earliest trustworthy boundary.
- Reject malformed or ambiguous evidence conservatively.
- Do not normalize input in a way that hides invalid protocol state.
- Preserve raw binary data where interpretation is not explicitly approved.

## Error Handling Philosophy

- Use typed or fixed-category failures appropriate to the owning boundary.
- Preserve failure identity when pass-through behavior is required.
- Never convert a failure into success silently.
- Do not leak credentials, secrets, sensitive payloads, internal paths, or uncontrolled exception details.
- Cleanup must be deterministic and idempotent where required.

## State Transition Philosophy

State machines must enumerate legal states and transitions. Invalid transitions must fail explicitly without partial mutation. Side effects and state changes must occur in an approved order and be covered by production-path and failure-path tests.

## Future Extensibility

Architecture evolves by adding new boundaries rather than modifying stable ones whenever practical. New capabilities should compose existing immutable results and contracts. Stable protocol and runtime authorities must not absorb downstream business, persistence, tenancy, or operational responsibilities.
