Skip to main content

EP-020: Infrastructure & DevOps — Phase 1 Hardening

Phase 1 hardening sprint, 2026-04. Branches in hmp-shared-packages, hmp-infrastructure, and hmp-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​

  • JwtAuthGuard in @hmp/auth distinguishes service-account tokens (scope: 'service', aud: 'hmp-internal') from user tokens. Service tokens get tenantId/propertyId from headers; user tokens get them from claims.
  • BaseServiceClient in @hmp/service-clients auto-injects Authorization: Bearer <INTERNAL_SERVICE_TOKEN> and forwards x-tenant-id, x-property-id, x-request-id from AsyncLocalStorage.
  • 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 in hmp-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 introduce service: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.yml
  • hmp-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 stack
  • HeaderZone.tsx — KeyNova branded header used at the top of every screen
  • KeyNovaLogo.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 KeyNovaLogo component 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-font integration is deferred to the next mobile sprint.

Summary​

StoryStatus beforeStatus afterNotes
US-020-002 (Service auth)Not StartedBuiltC4a: foundation in place
US-020-005 (Event bus)PartialBuiltC5: dispatcher wired and subscribed
US-020-007 (Mobile theme)PartialPartialD5: shared package shipped; logo + font pending
US-020-009 (Secrets management)PartialPartialC4a uses static demo secret; ESO integration deferred

Story-level status promotions: 2 (US-020-002 NS → Built; US-020-005 Partial → Built).