Meridian Field Services: instructional example, not project evidence
What: a managed PaaS runs the four services; cloud primitives hand the team undifferentiated plumbing; Kubernetes adds an orchestration team the project does not have. Why considered: four services, one team, pilot scale; nothing scales heterogeneously. Who & how: E. Sandoval with the delivery lead, walked against the container view July 17 (hosting decision[1]).
Re-decision triggers, stated: ten or more services, per-service scaling profiles diverging, or a second team needing isolated deploys; none fire at pilot. Secrets: the platform secret store per the config law; machine credentials per the machine-identity rows[2]; nothing in code.
§1 chose a class of platform. A class cannot be assessed, so this section names the actual one, and is the project's infrastructure register: the single place the concrete facts live, which every other artifact cites rather than keeping a second copy that drifts. The architecture owns the LOGICAL boundaries (boundaries[6]); this realizes them.
Three trust zones inside ca-central-1, shaded by the highest data class each holds. Fallback text: the public internet is untrusted and holds no Meridian data at rest. The PUBLIC EDGE (public subnets) contains AWS WAF and the application load balancer, the only internet-reachable construct, listening on 443 only and terminating TLS 1.3 with a 1.2 floor; RESTRICTED data transits it but nothing rests there. The APPLICATION TIER (private subnets, no public addresses) runs the four Fargate services: dispatch-api, dispatch-board, telematics-adapter, and notification-worker. The DATA TIER (private subnets, reachable only from the application tier) holds the meridian-ops RDS PostgreSQL 16.3 Multi-AZ instance and the dispatch-events SQS queue, both encrypted at rest with a customer-managed KMS key. PB-1 is realized as the load balancer's webhook listener; PB-2 as the single provider-gateway egress path. The node and edge tables below carry the full detail.
| Node · hostname | Runs on | Callers authenticate with | Encryption (transit · rest) | Highest class held |
|---|---|---|---|---|
| alb-dispatch | Application Load Balancer · public subnets · AWS WAF in front | n/a (terminates TLS; 443 only) | TLS 1.3 (1.2 floor) · nothing at rest | RESTRICTED transits |
| dispatch-api api.meridianfield.example |
ECS Fargate · application tier · 1 vCPU / 2 GB | Meridian SSO, OIDC code + PKCE (SR-001[11]); the webhook route instead verifies HMAC-SHA256 (SR-021[11]) | TLS 1.3 · no local persistence | CONFIDENTIAL in flight |
| dispatch-board dispatch.meridianfield.example |
ECS Fargate · application tier · 1 vCPU / 2 GB | Meridian SSO with MFA (passkey), required for operations-manager (identity model[2]) | TLS 1.3 · holds nothing | n/a (serves the browser application) |
| telematics-adapter | ECS Fargate · application tier · 0.5 vCPU / 1 GB · fixed 1 | No ingress listener: queue-fed, reachable from nothing | TLS 1.3 to queue and RDS · none local | RESTRICTED: raw positions |
| notification-worker | ECS Fargate · application tier · 0.5 vCPU / 1 GB | No ingress listener: queue-fed; egresses with the vendor API key from Secrets Manager (SR-027[11]) | TLS 1.3 · none local | CONFIDENTIAL |
| meridian-ops | RDS PostgreSQL 16.3 · Multi-AZ · data tier | IAM task roles only; no human credential path | TLS 1.3 · KMS customer-managed key | RESTRICTED: the positions table |
| dispatch-events | Amazon SQS · data tier · VPC endpoint | IAM task roles only | TLS 1.3 · KMS customer-managed key | RESTRICTED |
| Edge | Payload (the actual fields) | Class | Protocol · auth · encryption |
|---|---|---|---|
| vendor → alb-dispatch (PB-1) |
Position.vehicle_id, lat, lon, observed_at | RESTRICTED | HTTPS 443 · HMAC-SHA256 over the raw body + timestamp header, 300s replay window, verified before parsing (SR-021[11]; webhook signature[8]) · TLS 1.3 |
| alb → dispatch-api | the same payload, in-VPC | RESTRICTED | HTTP 8080 · security-group restricted (only the load balancer's group reaches the tier) · TLS terminated at the edge, re-encrypted to the task |
| dispatch-api → dispatch-events | position.observed: the raw position | RESTRICTED | HTTPS 443 to the SQS VPC endpoint · IAM task role · TLS 1.3 |
| telematics-adapter → meridian-ops | the normalized position; purged at 30 days (retention[10]) | RESTRICTED | PostgreSQL 5432 · IAM task role · TLS 1.3 |
| dispatch-api → dispatch-events | assignment.created: assignment_id, technician_id | CONFIDENTIAL | HTTPS 443 · IAM task role · TLS 1.3 |
| notification-worker → gateway (INT-2) |
the technician's own assignment | CONFIDENTIAL | HTTPS 443 via NAT · vendor API key from Secrets Manager (SR-027[11]) · TLS 1.3 |
| dispatch-api → model provider (PB-2, INT-4) |
anonymized ranking codes ONLY: no identity, no coordinates | INTERNAL | HTTPS 443 via the provider gateway · provider key from Secrets Manager (SR-014[11]) · TLS 1.3 |
Why PB-2 carries INTERNAL and not RESTRICTED: the anonymization happens before the crossing, so no personal data is ever presented to the provider (sensitive data paths[12]). This is a placement property, not a promise.
The cold-read test: a reviewer should be able to answer the only question that matters, where does RESTRICTED data rest and move?, from this section alone: it enters at the load balancer's webhook listener under HMAC verification, transits dispatch-api and the queue, is normalized by the adapter, rests in the positions table under a customer-managed KMS key, is hard-purged at 30 days, and never crosses PB-2 and never leaves ca-central-1. Backups go to ca-west-1 (Calgary), a second Canadian region, so isolation and residency hold together (§6).
Each environment states what it PROVES; every unclosed parity gap has a named owner. Console changes are drift by definition.
| Environment | Proves | Data source | Parity note | Owner · cost tag |
|---|---|---|---|---|
| dev | Isolated iteration | Synthetic (seeding[3]) | Shared platform tier: gap accepted; no load claims made from dev | Delivery lead · dev |
| staging | Production-shaped end-to-end behavior | Masked (seeding[3]) | Database one tier below production sizing, the named gap, owner E. Sandoval; limits the absolute-ceiling claim (environment[4]) | E. Sandoval · staging |
| production | Real scale, real users | Real | n/a | E. Sandoval · prod |
IaC law: all three reproducible from the infrastructure repository; drift check nightly with alerting to the platform channel.
Realization: four service images (API, board, adapter, worker) built once and promoted by reference (pipeline stages[5]). Runtime limits per class: API and board 1 vCPU / 2 GB; adapter and worker 0.5 vCPU / 1 GB, from the pilot frame (scale frame[6]). Only-if-earned: the platform owns scheduling, restarts, and networking; the project sits well under every orchestration trigger from §1, stated plainly.
Every number is a citation: the frame lives in the NFR catalog and architecture; this section states only the HOW.
| Service class | Policy | Cites |
|---|---|---|
| API · board | Autoscale on request concurrency, 1 to 3 instances (pilot headroom) | scalability rows[7] · scale frame[6] |
| Adapter | Single-instance by design: ordered feed reconciliation; scales vertically only | INT-1 design[6] |
| Worker | Autoscale on queue depth, 1 to 2 instances | scale frame[6] |
Load shedding: the API contract's rate limits (limits[8]). The fivefold breakpoint margin is the perf artifact's finding, cited (PS-3 results[4]), re-derived nowhere.
Objectives are cited; actuals are drilled. A number without a drill is paper.
| Data class | RPO | RTO | Mechanism | Last drill · actual |
|---|---|---|---|---|
| Assignment records | zero | 4 h | Continuous replication + point-in-time restore | Sep 9, 2026 · RTA 2 h 40 m vs 4 h (restore check[9]) |
| Jobs & configuration | 24 h | 4 h | Same restore path | Sep 9, 2026 · same drill |
| Positions | Irrelevant by design: the 30-day purge (retention[10]) outruns any restore need; stated so the absence is a claim | n/a | ||
Objectives cite NFR-A3[7]. Backups: encrypted, platform-isolated from the primary region; retention follows the classification rules[10]. Drill cadence: quarterly, timed, including application verification; the next objective-versus-actual gap escalates to the sponsor.
| Question | Owner | Answer by | Blocks |
|---|---|---|---|
| Does the staging database tier close to production sizing before the hub-six breakpoint re-run (the named parity gap's revisit, open questions[4])? | E. Sandoval | Sep 30, 2026 | The absolute-ceiling claim only |