Platform Admin Service — Application Logic
Status: populated
Owner: TBD
Last updated: 2026-04-18
Companion: DOMAIN_MODEL · API_CONTRACTS
1. Use cases (commands)
| Use case | Command | Triggered by | Emits |
|---|
UpsertConfigUseCase | UpsertConfigCommand | Super Admin POST | platform_admin.config.updated.v1 |
ArchiveConfigUseCase | ArchiveConfigCommand | Super Admin DELETE | — |
CreateFlagUseCase | CreateFlagCommand | Super Admin POST | platform_admin.flag.created.v1 |
UpdateFlagUseCase | UpdateFlagCommand | Super Admin PATCH | platform_admin.flag.updated.v1 |
ArchiveFlagUseCase | ArchiveFlagCommand | Super Admin DELETE | platform_admin.flag.archived.v1 |
SetTenantFlagOverrideUseCase | SetTenantOverrideCommand | Super Admin POST | platform_admin.flag.updated.v1 |
RegisterHealthSourceUseCase | RegisterHealthSourceCommand | Service startup POST | platform_admin.health_source.registered.v1 |
2. Use cases (queries)
| Query | Returns | Cache |
|---|
GetConfigQuery | Single config KV | Redis 60 s |
ListConfigsQuery | Paginated config list | No cache |
GetConfigHistoryQuery | Change history (cursor-paginated) | No cache |
GetFlagQuery | Flag metadata | Redis 60 s |
ListFlagsQuery | All flags (optional tenant filter) | No cache |
EvaluateFlagQuery | { enabled: boolean, reason } | Redis 60 s (flag:{key}:eval:{tenantId}) |
BootstrapFlagsQuery | All non-archived flags + decisions for tenant | No cache (startup only) |
AggregateHealthQuery | { overall, services[] } | Redis 10 s |
3. Feature flag evaluation logic
Result cached at flag:{key}:eval:{tenantId} with 60 s TTL. Cache invalidated on flag mutation or override change.
4. Health aggregation flow
AggregateHealthQuery checks Redis cache (platform:health:aggregate, 10 s TTL).
- On cache miss: iterate registered
HealthSource records.
- For each source: check last
HealthCheckResult (within staleness_threshold).
- Derive
overall:
- All healthy →
healthy
- Any unhealthy →
unhealthy
- Any stale or degraded →
degraded
- Write result to Redis; return to caller.
Background HealthPollerJob polls each registered source every 15 s; stores result in HealthCheckResult; emits platform_admin.health_source.status_changed.v1 on transition.
5. Ports
| Port | Implementation |
|---|
ConfigRepository | DrizzleConfigRepository |
ConfigHistoryRepository | DrizzleConfigHistoryRepository |
FeatureFlagRepository | DrizzleFlagRepository |
HealthSourceRepository | DrizzleHealthSourceRepository |
EventPublisher | NatsOutboxEventPublisher |
CachePort | RedisCacheAdapter |
HealthProbeClient | HttpHealthProbeClient |
6. Error codes
| Code | HTTP | Meaning |
|---|
ADM_CONFIG_KEY_UNKNOWN | 400 | Key not in allow-list |
ADM_CONFIG_VALUE_INVALID | 400 | Value type mismatch for key schema |
ADM_FLAG_NOT_FOUND | 404 | Flag key does not exist |
ADM_FLAG_KEY_DUPLICATE | 409 | Create attempted on existing active key |
ADM_FLAG_ARCHIVED | 422 | Mutation attempted on archived flag |