# 01 — Foundations and Decisions

**Parent:** [`docs/ROADMAP.md`](../ROADMAP.md) · [`00_MASTER_EXECUTION_PLAN.md`](./00_MASTER_EXECUTION_PLAN.md)

> Strategic decisions locked for execution. These should not be silently changed once
> downstream work starts — open an issue and discuss first.

---

## D-001 — Product Identity

**Decision:** Tracker dashboard is a **standalone first-party product** within `learning_ai_common_plat`,
not a feature of `platform-service`.

**Rationale:**

- Independent deployment cadence — UI iterations don't require platform-service redeploys
- Multi-product use case — same UI serves chronomind, notelett, flowmonk, etc. via `x-product-id` header
- Public-facing roadmap surface needs distinct domain (`tracker.bytelyst.com`)

**Implications:**

- Lives at `learning_ai_common_plat/dashboards/tracker-web` (not in a `services/` folder)
- Owns its own Dockerfile, docker-compose stanza, Caddy route
- Has its own `productId` (`tracker`) for self-hosted bug reports

---

## D-002 — Backend Strategy: Proxy via `platform-service`, No Standalone Backend

**Decision:** All tracker API calls proxy through `platform-service`. We do **not** create a
separate `tracker-service` repo.

**Rationale:**

- Reuses platform-service's auth (JWT, MFA, OAuth), Cosmos client, telemetry, observability
- Avoids second auth subsystem maintenance burden
- Tracker items are CRUD-shaped; no specialised compute needed
- Future: if tracker logic outgrows platform-service, extract then — not now

**Implications:**

- Tracker data lives in Cosmos under a `tracker` container, partition key `productId`
- Schema changes require platform-service PR + tracker-web PR coordinated
- Phase 3 agent API endpoints live in platform-service under `/api/agent/v1/*`

---

## D-003 — Auth Strategy: Reuse Platform JWT

**Decision:** Auth = same JWT issued by `platform-service` for all ByteLyst products.
Agent API keys are separate but minted by platform-service.

**Rationale:**

- Single sign-on across all dashboards (chronomind-web, tracker-web, devops-web, etc.)
- Centralised key rotation, MFA, OAuth provider config
- Agent keys join the same audit infrastructure

**Implications:**

- No bespoke auth in tracker-web — `@bytelyst/react-auth` adapter only
- API key UI proxies to platform-service `/api/keys/*` (built in Phase 3.1)

---

## D-004 — UI Strategy: `@bytelyst/ui` Primitives via Adapter

**Decision:** All UI components route through `src/components/ui/Primitives.tsx` adapter that
re-exports `@bytelyst/ui`. Direct `@bytelyst/ui` imports outside the adapter are forbidden
and enforced by the UI drift ratchet (Phase 1.D).

**Rationale:**

- Matches NoteLett, FlowMonk, ChronoMind, NomGap pattern — proven across 4+ products
- Lets us inject tracker-specific design-token theming at the adapter level
- Single insertion point for cross-cutting concerns (telemetry, error boundaries, accessibility tweaks)

**Implications:**

- Phase 2.1 is mandatory before Phase 6 theming work
- UI drift ratchet (Phase 1.D) must ship before any new UI code lands
- Components migrate in this order: auth + modals (UI5) → list/board/dashboard (UI6) → detail/comments/roadmap (UI7) → globals cleanup (UI8) — same order NoteLett used

---

## D-005 — Design Tokens: `--tk-*` Prefix

**Decision:** Tracker dashboard uses CSS custom properties under the `--tk-*` prefix, sourced
from `@bytelyst/design-tokens`.

**Rationale:**

- Each product gets its own token namespace (`--nl-*` NoteLett, `--fm-*` FlowMonk, `--cm-*` ChronoMind, `--tk-*` Tracker)
- Allows per-product theming without conflicts on shared components
- Hardcoded hex literals fail the UI drift ratchet — forces token usage

**Implications:**

- Token PRs go to `learning_ai_common_plat/packages/design-tokens`
- Hardcoded colors in tracker-web fail CI from Phase 1.D onward
- Dark mode (Phase 6.3) flips token values, not component code

---

## D-006 — Item Schema: Extensible Core + `metadata` Map

**Decision:** Item schema has a fixed core (title, description, status, priority, type, etc.)
plus an open-ended `metadata` map for product-specific and agent-supplied data.

**Rationale:**

- Core fields cover 95 % of cases for all products
- `metadata` lets CI agents stash `{ testRunId, commitSha, ciJobUrl }` without schema churn
- Custom fields (Phase 2.6) write into the same `metadata` map with admin-defined keys
- Avoids Jira-style schema explosion

**Implications:**

- Cosmos document shape: `{ ...coreFields, metadata: { ... } }`
- Indexing strategy: index core fields, leave `metadata` as catch-all
- Custom field UI is a thin layer reading/writing the same map

---

## D-007 — Status Workflow: Default + Custom Per Product

**Decision:** Default workflow is `open → in_progress → done → closed` plus terminal `wont_fix`.
Products can extend with additional statuses (e.g., `needs_review`, `blocked`, `in_qa`) defined
in their product config.

**Rationale:**

- Default covers the simple case
- Some products (security-sensitive, regulated) need explicit `in_review` gates
- Custom-per-product avoids forcing all products onto a complex workflow

**Implications:**

- Phase 2.2 ships the custom-status mechanism
- Kanban columns (Phase 2.9) render based on the active product's workflow
- Workflow changes require admin permission

---

## D-008 — Visibility Model: Binary `internal` vs `public`

**Decision:** Items have a single `visibility` flag: `internal` or `public`. No fine-grained ACLs.

**Rationale:**

- Simpler mental model than Linear/Jira issue-level permissions
- Public roadmap shows only `public` items; team dashboard shows both
- Aligns with "public users + internal team" two-audience model

**Implications:**

- Toggling visibility audit-logged
- Comments on `public` items are also public (no per-comment visibility)
- Mention notifications respect visibility — `@external-user` on internal item silently drops

---

## D-009 — Agent API: Keyed, Versioned, Rate-Limited

**Decision:** Agent API lives at `/api/agent/v1/*`, authenticated via bearer API key. Versioned
URL prefix with 6-month backward compatibility on breaking changes.

**Rationale:**

- Bearer keys are simpler than OAuth for service-to-service
- Versioned URL prefix makes deprecation explicit
- 6-month window is enough for agents to migrate without forcing emergency upgrades

**Implications:**

- API key UI (Phase 3.1) is admin-only
- `Deprecation` + `Sunset` headers on v1 routes when v2 ships
- Rate limits enforced via valkey (Redis) sliding window

---

## D-010 — Webhook Strategy: Inbound + Outbound, Signed

**Decision:** Tracker accepts inbound webhooks from GitHub + Gitea (Phase 3.4) and emits
outbound webhooks for any registered target URL (Phase 3.5). Both directions HMAC-SHA256 signed.

**Rationale:**

- Inbound enables PR-status auto-sync without polling
- Outbound enables Slack notifications, custom alerting, mirroring to other systems
- Signing prevents replay attacks and spoofing

**Implications:**

- Per-product webhook secret stored in Cosmos (admin-rotatable)
- Delivery log + replay mechanism (Phase 3.4/3.5) for debugging
- Outbound retries on non-2xx with exponential backoff (5 retries over 24 h)

---

## D-011 — Test Strategy: Vitest + Playwright + axe-core

**Decision:** Three-layer test strategy:

1. **Vitest** for unit tests (`src/lib/`, pure functions, hooks)
2. **Playwright** for E2E against deployed Docker stack
3. **`@axe-core/playwright`** for automated WCAG 2.1 AA checks on every E2E run

**Rationale:**

- Matches NoteLett + FlowMonk pattern proven across 2 products
- Playwright deployed-stack catches integration bugs unit tests miss
- axe-core in CI prevents accessibility regressions before merge

**Implications:**

- Cosmos emulator smoke job runs in CI (catches partition-key bugs)
- Cleanup traps prevent test-data leakage between runs
- Port-conflict-proof config (random ports per run) allows parallel local runs

---

## D-012 — Docker Strategy: Standalone Next.js + `docker-prep.sh` Tarballs

**Decision:** Tracker-web ships as a standalone Next.js Docker image built with the
`docker-prep.sh` pattern (pack `@bytelyst/*` tarballs locally, ignore Gitea npm registry at build time).

**Rationale:**

- Corp network blocks public CDNs and sometimes Gitea registry — bundling tarballs is reliable
- Standalone output is ~80 % smaller than full `node_modules` image
- Matches NoteLett + FlowMonk + ChronoMind proven pattern

**Implications:**

- `docker-prep.sh` (Phase 1.C.1) must be adopted before Phase 1.C.8 verification
- `.docker-deps/` is in `.gitignore`; tarballs regenerated per build
- `NEXT_PUBLIC_*` baked at build time via Dockerfile `ARG` (Phase 1.C.3)

---

## D-013 — Deployment Topology: Single VM, Shared Caddy, Shared valkey

**Decision:** Tracker-web shares the existing single-VM topology with all other ByteLyst products.
Caddy routes by hostname (`tracker.bytelyst.com` → `tracker-web:3003`). valkey + Cosmos shared
across products.

**Rationale:**

- Cost-effective for current scale (< 1k users per product)
- Easier ops — one VM to monitor, one Caddy config, one Loki/Prometheus stack
- Can split later if any single product needs isolation

**Implications:**

- Resource contention is real (B-001 valkey impact cascaded across all products) — mitigations in Phase 1.A
- Per-product secrets isolated via env vars, not separate VMs
- Capacity planning needs swap (Phase 1.A.5) and CI runner concurrency caps (Phase 1.A.6)

---

## Open Decisions

These are not yet locked — discuss before Phase 3.

- **D-Open-001:** Should agent API keys be Cosmos-stored or KeyVault-stored? (Affects Phase 3.1)
- **D-Open-002:** Outbound webhook retry policy — give up after 24 h or escalate?
- **D-Open-003:** Auto-classification (Phase 3.7) — does the LLM call run synchronously on submit or async via a queue?
- **D-Open-004:** Cross-product routing (Phase 4.4) — does moving an item rewrite history or create a new item with link-back?
