EP-020: Infrastructure & DevOps — Phase 1 Hardening
Phase 1 hardening sprint, 2026-04. Branches in
hmp-shared-packages,hmp-infrastructure, andhmp-mobile-apps. Not yet pushed.
Infrastructure picked up several pieces in Phase 1 that don't fit cleanly into a single service epic: the service-account JWT mechanism (the foundation for all cross-service HTTP calls), the docker-compose change to enable event subscriptions, and the shared theme tokens / mobile branding components that the apps now consume.
C4a — Internal Service-Account JWT Mechanism
Branch: feat/service-account-jwt (in hmp-shared-packages,
hmp-reservation-service, hmp-infrastructure)
What was added
JwtAuthGuardin@hmp/authdistinguishes service-account tokens (scope: 'service',aud: 'hmp-internal') from user tokens. Service tokens gettenantId/propertyIdfrom headers; user tokens get them from claims.BaseServiceClientin@hmp/service-clientsauto-injectsAuthorization: Bearer <INTERNAL_SERVICE_TOKEN>and forwardsx-tenant-id,x-property-id,x-request-idfromAsyncLocalStorage.hmp-infrastructure/scripts/generate-service-token.sh— ops script for minting and rotating service-account tokens.- New environment variables:
JWT_AUDIENCE_INTERNAL,JWT_AUDIENCE_PUBLIC,INTERNAL_SERVICE_TOKEN. Documented inhmp-infrastructure/README.md.
Architecture documentation
Full spec in architecture/internal-service-auth.md.
This is the dependency for everything in EP-011's C4b migration and EP-006/EP-007's C4
migrations.
Tests
18 new tests on JwtAuthGuard (token type discrimination, header forwarding, expiry,
audience mismatch). All passing.
Open follow-ups
- HS256 → RS256 migration. Today HS256 means a leaked secret on any service can mint
tokens for any other. RS256 with per-service public keys is the target before production.
Tracked in
project_phase2-phase3-scope.md. - Per-service scopes. Today all service tokens carry
scope: 'service'. Phase 2 should introduceservice:reservation,service:property, etc., for finer-grained revocation. - Token storage. Demo uses static env value; staging/prod should pull from External Secrets Operator → AWS Secrets Manager.
C5 — Event Subscriptions (Compose Files)
Branch: feat/enable-event-flow (in hmp-infrastructure)
What was changed
docker-compose.staging-aws.yml and docker-compose.prod-aws.yml:
SKIP_EVENT_SUBSCRIPTIONS=false set on every backend service except api-gateway.
The flag's historical default is true (skip), which is correct for the gateway (proxy
only, never consumes events) but wrong for everything else in shared environments. Without
the change, the C5 dispatcher in hmp-analytics-service had nothing to subscribe to.
See EP-012 hardening notes for the full context.
Files touched
hmp-infrastructure/docker/docker-compose.staging-aws.ymlhmp-infrastructure/docker/docker-compose.prod-aws.yml
D5 — Shared Mobile Theme Tokens & Components
Branch: feat/mobile-keynova-branding (in hmp-mobile-apps)
What was added
A new shared package @hmp/shared-ui for the mobile monorepo, with:
theme.ts— colors (Midnight Sovereign palette), font sizes, font weights, spacing scale, Satoshi typography stackHeaderZone.tsx— KeyNova branded header used at the top of every screenKeyNovaLogo.tsx— placeholder logo (RN View + Text composition pending design handoff)BottomNav.tsx— shared bottom navigation primitive
The four mobile apps (HK, manager, F&B, guest) all import from @hmp/shared-ui instead of
having their own theme constants. 14 screens across the four apps consume the new tokens.
Files touched
hmp-mobile-apps/packages/shared-ui/(new package)hmp-mobile-apps/apps/housekeeping/src/screens/*(4 screens)hmp-mobile-apps/apps/manager/src/screens/*(4 screens)hmp-mobile-apps/apps/fnb/src/screens/*(3 screens)hmp-mobile-apps/apps/guest/src/screens/*(3 screens)
Open follow-ups
- Logo asset handoff. The
KeyNovaLogocomponent is a React Native View+Text composition pending the real PNG/SVG from the design team. - Satoshi font loading. All apps fall back to system fonts.
expo-fontintegration is deferred to the next mobile sprint.
Summary
| Story | Status before | Status after | Notes |
|---|---|---|---|
| US-020-002 (Service auth) | Not Started | Built | C4a: foundation in place |
| US-020-005 (Event bus) | Partial | Built | C5: dispatcher wired and subscribed |
| US-020-007 (Mobile theme) | Partial | Partial | D5: shared package shipped; logo + font pending |
| US-020-009 (Secrets management) | Partial | Partial | C4a uses static demo secret; ESO integration deferred |
Story-level status promotions: 2 (US-020-002 NS → Built; US-020-005 Partial → Built).