Heimdall/state/map.yaml
2026-04-29 16:23:21 +01:00

102 lines
8.1 KiB
YAML

project:
name: Heimdall
status: active
phase: streampixels_migration
premise: >
Build Heimdall as one reusable GameCult auth authority service for OAuth,
linked identities, local sessions, grants, and capability claims without
mixing in app-domain audience or product data.
objective:
primary: >
Create a shared auth authority service that Repixelizer, StreamPixels, and
future GameCult-hosted experiments can consume.
current: >
Migrate StreamPixels viewer and creator OAuth onto Heimdall while keeping
StreamPixels-owned viewer profiles, creator memberships, connector
bindings, runtime state, and audience data local.
constraints:
- Heimdall owns auth/control-plane authority; app-domain data stays app-owned by default.
- Prefer a same-host Heimdall service on Yggdrasil over duplicated per-app provider stacks.
- Host apps verify signed claims locally for routine guarded routes.
- App profiles stay thin; the shared architecture note owns the main model.
- StreamPixels audience and creator data must not be absorbed into a shared auth store.
invariants:
- The map is canonical and slow-changing.
- Scratch is temporary and disposable.
- Evidence is durable and distilled; routine activity logs belong in git history and commit messages.
- Heimdall owns OAuth, local sessions, grants, entitlement refresh, capability evaluation, and audit surfaces.
- App-domain data stays with the host app unless there is a deliberate, source-grounded reason to share it.
- Host apps verify signed claims locally and keep resource ownership checks local.
- StreamPixels can reuse shared auth authority without centralizing streamer-audience data.
- Persistent state cruft is the same failure class as architecture cruft.
data_flow:
observe:
- task request
- shared architecture note
- app profile bindings
- current app/runtime seams in Repixelizer and StreamPixels
- Yggdrasil host topology and nginx/service shape
process:
- rehydrate from canonical state
- choose one bounded architecture or implementation slice
- keep auth authority and app-domain data boundaries explicit
- keep routine route auth local after claim verification
- record only belief-changing evidence
- commit or backtrack
cut:
- reject shared-data creep
- reject duplicated auth blobs per app
- reject per-request auth round-trip chatter
active_subgoals:
- Keep the shared architecture explicit and separate from app profiles.
- Preserve the default boundary that app-domain data remains app-owned.
- Align the plan to Heimdall as a Yggdrasil-hosted authority service.
- Verify the Discord and Patreon Repixelizer auth paths with real provider credentials, stable signing, persistent storage, and live browser callback verification.
- Wire StreamPixels through Heimdall for Twitch/YouTube viewer identity and managed creator-provider credentials without moving StreamPixels domain state into Heimdall.
accepted_design:
- `docs/architecture.md` is the canonical shared architecture note.
- `docs/service-contract.md` records the concrete HTTP/JWKS contract of the landed service slice.
- `docs/app-profiles/*.md` are thin app bindings, not duplicate brains.
- Heimdall owns provider OAuth, identity linking, signed local sessions, grants, entitlement refresh, capability evaluation, and audit events.
- Host apps own their domain data, runtime state, and product-specific resources.
- Host apps verify signed claims locally for routine route authorization.
- A shared Heimdall store, if it exists, should hold auth/control-plane truth only.
- Repixelizer is the first auth-blank hosted-app binding.
- StreamPixels is the migration case that proves shared authority must not imply audience-data centralization.
- The first service skeleton is a standalone TypeScript/Fastify app with Ed25519 JWT signing, JWKS discovery, signed OAuth `state`, and app-profile-driven shared capability evaluation.
- The first stateful slice adds durable auth/control-plane storage plus a real Discord callback path for Repixelizer.
- Repixelizer has consumed the Heimdall backend-callback flow in its hosted web layer; Heimdall no longer needs to wait on Repixelizer refactoring before live Discord launch work.
- Heimdall is deployed on Yggdrasil at `https://heimdall.gamecult.org` with nginx/TLS, Postgres storage, file-backed signing-key bootstrap, configured token custody, and passing public health/discovery/JWKS checks.
- Repixelizer is deployed on Yggdrasil at `https://repixelizer.gamecult.org` with `GC_ACCESS_MODE=heimdall`, `GC_ACCESS_ALLOWED_PROVIDERS=discord,patreon`, required access, queue protection enabled, app-owned Discord guild/role policy, and app-owned Patreon tier-title policy sent to Heimdall during backend-callback OAuth start.
- StreamPixels viewer and creator provider OAuth should start through Heimdall; StreamPixels redeems one-time completion codes, owns local profile/connector binding, and resolves current provider access tokens from Heimdall by app-authenticated managed-credential calls.
landed_baseline:
- Shared architecture extracted into its own repo and renamed to Heimdall.
- Repixelizer and StreamPixels app-profile notes created.
- Repo-local state, handoff, and compaction scaffolding created.
- Initial Heimdall service skeleton landed with discovery, JWKS, OAuth start/callback contract surfaces, and claim issuance scaffolding.
- Durable auth persistence landed for accounts, linked identities, sessions, grants, entitlement snapshots, and audit events.
- The first real provider slice landed for Discord callback exchange, identity resolution, entitlement evaluation, and session/claim issuance for Repixelizer.
- Signing-key persistence/bootstrap, managed token encryption at rest, and a local verifier seam landed for the first real consumer integration pass.
- Direct backend callback handoff landed as the preferred same-host app-consumer path, with browser completion-code exchange retained as fallback.
- Repixelizer's hosted web layer now creates Heimdall auth attempts, receives direct backend callbacks, verifies Heimdall Ed25519 access tokens locally, and adopts httpOnly local sessions.
- Heimdall now has generic Twitch and YouTube OAuth callback runtimes plus an app-authenticated managed-credential resolve endpoint for app-owned connector runtimes.
- StreamPixels now starts viewer and creator Twitch/YouTube OAuth through Heimdall, redeems Heimdall completion codes server-side, writes its own viewer sessions and creator connector bindings, and leaves provider refresh-token custody in Heimdall.
rejected_paths:
- name: per_app_auth_copy_paste
reason: duplicates the same provider/session sludge across every experiment
- name: per_request_auth_round_trip
reason: turns shared auth into a noisy bottleneck instead of local claim verification
- name: shared_user_data_swamp
reason: reusing auth mechanics does not justify centralizing app-domain audience or product data
current_status:
summary: Heimdall and StreamPixels are deployed on Yggdrasil for the StreamPixels auth migration slice. Heimdall has Twitch/YouTube provider credentials, the shared StreamPixels app secret, generic Twitch/YouTube identity and managed-credential custody runtimes, and a live fix for Twitch token responses that return scopes as arrays. StreamPixels delegates Twitch/YouTube OAuth to Heimdall, redeems one-time completion codes through its service, writes its own httpOnly viewer session, stores local profile/creator connector binding state, and asks Heimdall for current provider access tokens when runtime code needs them. The key boundary still holds: Heimdall owns provider OAuth and credential custody; StreamPixels owns viewer profiles, creator memberships, connector config, diagnostics, EventSub/live-chat runtime behavior, and audience data.
next_action: Complete real browser verification for StreamPixels viewer sign-in/link and creator Twitch/YouTube connector attach from `https://streampixels.gamecult.org/auth/connect`. If Twitch or YouTube fails, inspect Heimdall audit events and StreamPixels service logs first; do not move provider-specific app state into Heimdall while debugging.