System architecture
Read this when you need a map of the running system before changing a service, a route, a frontend or the development environment.
This page describes the development environment on homelab-talos-dev, defined in
k8s/dev/base/. Production is deployed from a private repository and is not
documented here.
Components
| Component | Role | Defined in |
|---|---|---|
| Tadoku API | Serves every public HTTP operation and publishes typed jobs in the business transaction. | services/tadoku-api/, k8s/dev/base/services/tadoku-api.yaml |
| Tadoku worker | Executes registered jobs and composes feature operations. | services/tadoku-api/cmd/tadoku-worker/, k8s/dev/base/services/tadoku-worker.yaml |
| webv2 | Main site: logging, contests, leaderboards and content | frontend/apps/webv2/, k8s/dev/base/frontend-webv2/ |
| authv2 | Account app: login, registration, recovery and Settings through the identity API | frontend/apps/authv2/, k8s/dev/base/frontend-authv2/ |
| admin | Administration, moderation and CMS | frontend/apps/admin/, k8s/dev/base/frontend-admin/ |
| Ory Oathkeeper | Access proxy for API and operator routes; issues user and service JWTs | k8s/dev/base/oathkeeper/ |
| token-reflector | Publishes the Kubernetes service-account JWKS and returns exchanged service tokens | services/token-reflector/ |
| Flipt | Feature flags | k8s/dev/base/flipt/, feature-flags.contract.json |
| PostgreSQL | Tadoku API database in an operator-managed server | k8s/dev/base/data/postgres.yaml |
| Valkey | Caches and throttling counters; PostgreSQL stays the source of truth | k8s/dev/base/data/cache.yaml |
Each component runs in its own tdk-dev-* namespace. tdk-dev-routing
attaches the application routes to the platform Envoy Gateway.
Request paths
browser → ingress-nginx → Envoy → webv2 / authv2 / admin
→ Oathkeeper → Envoy → Tadoku API
- Browser API calls go to
/api/internal/<domain>/…on the main host. Oathkeeper checks the native session cookie with Tadoku API or accepts an anonymous request, replaces it with a signed JWT (id_tokenmutator) and forwards to Tadoku API. Tadoku API verifies that JWT against Oathkeeper's JWKS and rejects banned users before any operation runs. See Authorization. - Service calls use short-lived service JWTs from the Oathkeeper token exchange. Tadoku API uses them to reach Flipt. See Service-to-service authentication.
- Operator routes such as the Flipt UI on
flags.tadoku.dev.labrequire a native session, and Oathkeeper asks Tadoku API whether that user is an administrator. - Branch routing: Envoy sends each request to a developer's branch overlay when one is selected and healthy, and to the base otherwise. See Development environment.
Data
- Tadoku API owns the application schema. Its migrations live in
services/tadoku-api/migrations/and run as Argo CD sync hooks before the API starts. - PostgreSQL is the source of truth for leaderboards. Valkey holds sorted-set caches of the unfiltered leaderboards, each built from a board version that PostgreSQL triggers raise with every write. A read serves a cached board only when it was built from the current version, and rebuilds it otherwise, so a served board reflects every committed write. See Leaderboard freshness and worker health.
- Filtered requests, cache misses and cache errors read a leaderboard from
PostgreSQL; other requests read a page from Valkey. Contest boards and
official boards, yearly and global, each have one statement in
services/tadoku-api/sql/leaderboard/leaderboard.sqlthat decides who is on the board, with optional filters. It both rebuilds the cache and serves the PostgreSQL reads, so cached and filtered views list the same users. - A log counts on the official boards when its
eligible_official_leaderboardis set. Every request that attaches or detaches a live user's log, including a registration that drops a language, recomputes that flag in the same transaction from whether an official contest is still attached. Nothing recomputes stored flags in bulk: a stored flag is corrected only when its log's attachments next change. - Both paths order a board by score descending, then user ID descending, so
pages from either store line up: Valkey's sorted set does so for cached
pages, and
pageOfinservices/tadoku-api/features/leaderboard/leaderboard_service.gofor PostgreSQL rows.buildEntriesin the same file assigns competition ranks and tie flags for both. - Administrator and ban relationships are tenant-owned rows in the Tadoku API database; see Authorization.
- The former Keto database and namespace are retained without a service. Their removal requires a separate data-disposition decision; see Development base.
Where to go next
- Module design for deep modules and information hiding
- Tadoku API for the backend
- Frontend overview for the applications and design systems
- Development environment to run and verify a branch
- API reference for the public HTTP contract