SliceFocus Architecture
SliceFocus Architecture
Scope
This document describes the current backend architecture for SliceFocus MVP deployment on GCP, including release flow and environment separation.
For application-level system design (layers, request flow, data design), see docs/system-design.md.
High-Level Design
flowchart LR
Dev["Developer"] --> GitHub["GitHub (main branch + Actions)"]
GitHub --> AR["Artifact Registry (container images)"]
GitHub --> CRDev["Cloud Run: slicefocus-backend-dev"]
GitHub --> CRTest["Cloud Run: slicefocus-backend-test"]
GitHub --> CRProd["Cloud Run: slicefocus-backend"]
User["Client"] --> DNS["DNS: api.slicefocus.com"]
DNS --> LB["External HTTPS Load Balancer"]
LB --> CRProd
CRDev --> Neon["Neon PostgreSQL"]
CRTest --> Neon
CRProd --> Neon
CRDev --> SM["Secret Manager"]
CRTest --> SM
CRProd --> SM
CRDev --> FCM["Firebase Cloud Messaging"]
CRTest --> FCM
CRProd --> FCM
Release Model
- Trunk-based development with
mainas the long-lived integration branch. - Push to
maintriggers automatic deploy todev. testandprodare promoted manually using the same image tag.- Promotion uses
SKIP_BUILD=trueto avoid rebuilding and keep artifact parity across environments.
Environment Matrix
| Environment | Spring Profile | Cloud Run Service | Exposure | Deploy Trigger | Workflow | Image Build | DB Secret Names | Primary URL |
| — | — | — | — | — | — | — | — | — |
| dev | dev | slicefocus-backend-dev | Public (current default) | Push to main or manual run | .github/workflows/deploy-dev.yml | Yes (SKIP_BUILD=false) | slicefocus-dev-db-url, slicefocus-dev-db-user, slicefocus-dev-db-pass | Cloud Run URL |
| test | test | slicefocus-backend-test | Public (current default) | Manual promotion | .github/workflows/deploy-test.yml | No (SKIP_BUILD=true) | slicefocus-test-db-url, slicefocus-test-db-user, slicefocus-test-db-pass | Cloud Run URL |
| prod | prod | slicefocus-backend | Private by default (ALLOW_UNAUTHENTICATED=false) | Manual promotion | .github/workflows/deploy-prod.yml | No (SKIP_BUILD=true) | slicefocus-prod-db-url, slicefocus-prod-db-user, slicefocus-prod-db-pass | https://api.slicefocus.com |
Firebase Secrets per Environment
| Environment | Firebase Credentials Secret | Enabled Flag |
| — | — | — |
| dev | slicefocus-dev-firebase-credentials | SLICEFOCUS_FIREBASE_ENABLED set by deploy.sh based on secret existence |
| test | slicefocus-test-firebase-credentials | Same |
| prod | slicefocus-prod-firebase-credentials | Same |
Firebase is opt-in per environment: if the credentials secret does not exist in Secret Manager, deploy.sh sets SLICEFOCUS_FIREBASE_ENABLED=false and push notifications are silently disabled. No deploy failure occurs.
APNS Secrets per Environment
| Environment | APNS Key Secret | Enabled Flag |
| — | — | — |
| dev | slicefocus-dev-apns-key | SLICEFOCUS_APNS_ENABLED set by deploy.sh based on secret existence |
| test | slicefocus-test-apns-key | Same |
| prod | slicefocus-prod-apns-key | Same |
APNS follows the same opt-in pattern as Firebase. Used for Live Activity content-state updates — the widget computes phases locally from session config, Cloud Tasks triggers re-renders at phase boundaries (see ADR-037, ADR-038).
Cloud Tasks Configuration
| Property | Purpose |
| — | — |
| SLICEFOCUS_CLOUD_TASKS_ENABLED | Feature toggle (true/false) |
| GOOGLE_CLOUD_PROJECT | GCP project ID |
| CLOUD_TASKS_LOCATION | Queue location (e.g., europe-west3) |
| CLOUD_TASKS_QUEUE | Queue name (phase-transitions) |
| CLOUD_RUN_SERVICE_URL | Webhook target URL + OIDC audience |
| CLOUD_TASKS_SA_EMAIL | Service account for OIDC token signing |
Cloud Tasks uses the REST API directly (no gRPC client library) with Application Default Credentials. Queue phase-transitions is created in europe-west3. Cloud Run SA has roles/cloudtasks.enqueuer; Cloud Tasks SA has roles/run.invoker.
Keep-Alive (Dev/Test)
Cloud Scheduler pings /actuator/health every 4 minutes on dev and test environments to prevent Cloud Run and Neon cold starts. Prod uses MIN_INSTANCES=1.
Core Infrastructure Decisions
- Runtime is Cloud Run for low-ops deployment and managed scaling.
- Database is Neon PostgreSQL for MVP cost efficiency.
- Secrets are stored in GCP Secret Manager and injected during deploy.
- Push notifications use Firebase Admin SDK (FCM) for regular notifications and direct APNS HTTP/2 for Live Activity updates. Cloud Tasks schedules APNS pushes at Pomodoro phase boundaries (ADR-038). Firebase credentials are stored in Secret Manager and injected as
FIREBASE_CREDENTIALS_JSONat deploy time. APNS key is stored similarly asAPNS_PRIVATE_KEY_BASE64. Both are opt-in per environment. - HTTPS custom domain for prod is provided via External HTTPS Load Balancer.
- CI/CD uses GitHub Actions with Workload Identity Federation (OIDC), not static service account keys.
Security Posture
- Production service is configured private-by-default.
- Production access is intended via authorized identities (
roles/run.invoker) or a future explicit public API policy. - Dev and test are currently public for faster iteration and can be hardened later if needed.
- Firebase service account credentials are stored in Secret Manager (one secret per environment), never in source control or GitHub Secrets. The Cloud Run runtime service account is granted
roles/secretmanager.secretAccessoron the Firebase secret bydeploy.sh.
Key Config Inputs
- GitHub repository variables:
GCP_PROJECT_IDGCP_REGION(defaulteurope-west3)GCP_ARTIFACT_REPO(defaultslicefocus-repo)CLOUD_RUN_SERVICE_DEVCLOUD_RUN_SERVICE_TESTCLOUD_RUN_SERVICE_PRODPROD_ALLOW_UNAUTHENTICATED
- GitHub repository secrets:
GCP_WORKLOAD_IDENTITY_PROVIDERGCP_DEPLOY_SERVICE_ACCOUNT
- GCP Secret Manager secrets (per environment, managed outside CI):
slicefocus-{env}-firebase-credentials— Firebase service account JSON for FCMslicefocus-{env}-apns-key— Apple Developer private key (.p8) for APNS Live Activity updates
- Cloud Run environment variables (set by
deploy.sh):SPRING_PROFILES_ACTIVE— Spring profile for the target environmentSLICEFOCUS_FIREBASE_ENABLED—true/falsebased on Firebase secret existenceFIREBASE_CREDENTIALS_JSON— injected from Secret Manager (only when secret exists)SLICEFOCUS_APNS_ENABLED—true/falsebased on APNS key secret existenceAPNS_PRIVATE_KEY_BASE64— injected from Secret Manager (only when secret exists)APNS_KEY_ID,APNS_TEAM_ID— Apple Developer identifiers for APNS JWT auth
Related Documents
- Application architecture (API, domain, persistence, security):
docs/system-design.md - Architecture Decision Records:
adr/