Service Architecture
Peak Gateway runs 7 Kotlin/Spring Boot microservices on Google Cloud Run.
Service Map
| Service | Local HTTP | Purpose | Key Dependencies |
|---|---|---|---|
| auth | 8181 | OAuth2 token issuance, JWK publishing, client admin | schema, security, rate-limiting, Spring Authorization Server |
| processing | 8182 | Core payment engine: sale, auth, capture, void, refund, subscriptions | transit-client, schema, security, notifications, rate-limiting, resilience |
| management | 8183 | Portal backend: merchants, users, SAML SSO, reports, audit, device commands | schema, security, notifications, rate-limiting |
| online-txn | 8184 | E-commerce: checkout sessions, hosted payments, webhooks, API keys | transit-client, schema, security, notifications, rate-limiting |
| merchant-onboarding | 8185 | CDE-scoped: TransIT credentials, NexGO XTMS device binding | transit-client, xtms-client, schema, security, Cloud KMS, resilience |
| status | 8186 | Health aggregator (no database, no Pub/Sub) | security only |
| card-present | 8187 | In-person acceptance boundary: terminal sale/auth, transaction sync, sync refund | processing, schema, security, notifications, rate-limiting |
Every service container listens on port 8080 in Cloud Run and Docker. The ports above are the local docker-compose.dev.yml host mappings.
Communication Flow
Auth ──JWK──> Public services validate OAuth tokens via JWK endpoint
Processing <──IAM── Management <──Firebase── Portal
Processing <──IAM── Online-Txn <──OAuth── Checkout/E-commerce
Processing <──IAM── Card-Present <──OAuth── Terminals / in-person flows
Merchant-Onboarding <──IAM── Management --> TransIT + XTMS
Status ──health──> All services
Two-tier security model:
- Public-facing (auth, management, online-txn, card-present, status): Firebase Auth + OAuth2 via JWK
- Internal-only (processing, merchant-onboarding): Cloud Run IAM only — no public access, no LB route
Shared Library Dependencies
| Service | security | schema | transit-client | xtms-client | notifications | rate-limiting | resilience |
|---|---|---|---|---|---|---|---|
| auth | ✓ | ✓ | ✓ | ||||
| processing | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| management | ✓ | ✓ | ✓ | ✓ | |||
| online-txn | ✓ | ✓ | ✓ | ✓ | ✓ | ||
| card-present | ✓ | ✓ | ✓ | ✓ | |||
| merchant-onboarding | ✓ | ✓ | ✓ | ✓ | ✓ | ||
| status | ✓ |
Tech Stack
| Layer | Technology |
|---|---|
| Language | Kotlin 2.2.2, Java 25 |
| Framework | Spring Boot 4.0.5, Spring Security 7.0 |
| Database | Cloud Spanner (PostgreSQL dialect) via SQLDelight 2.2.1 |
| Auth | OAuth2 (Spring Authorization Server) + Firebase Auth + SAML SSO |
| Messaging | Cloud Pub/Sub (email, SMS, transaction events) |
| External APIs | TSYS TransIT Multipass (payments), NexGO XTMS (devices) |
| Build | Bazel with rules_kotlin 2.2.2 |
| Deployment | GCP Cloud Run (us-east1) |
| Observability | Structured ECS logging, OpenTelemetry -> Cloud Trace |
Environments
| Environment | API Domain | Portal | Cloud Run Prefix |
|---|---|---|---|
| Production | api.peakgateway.co | portal.peakgateway.co | gateway-{service} |
| Staging | staging-api.peakgateway.co | staging-portal.peakgateway.co | gateway-{service}-staging |
Request Flow
- Client sends request with Bearer token (OAuth2 or Firebase ID token)
- Cloud Run routes to the target service
- Security filters validate the token via JWK endpoint (auth service)
- Controller checks
@RequireScope(API clients) or@RequireRole(portal users) - Service layer executes business logic
- Repository layer queries Cloud Spanner via SQLDelight/PGAdapter
- External calls to TransIT/XTMS if needed
- Response wrapped in
ApiResponse<T>envelope