Spec: Backoffice Project Usage Visibility
Spec: Backoffice Project Usage Visibility
User Input
$linear:linear https://linear.app/devpunks/issue/IP-138/build-harness-intelligence-backoffice-for-project-usage-visibility https://linear.app/devpunks/issue/IP-143/harness-reports-are-triaged-in-backoffice-and-linked-to-github https://linear.app/devpunks/issue/IP-142/backoffice-shows-project-usage-adoption-dashboards https://linear.app/devpunks/issue/IP-141/backoffice-uses-authenticated-operator-identity https://linear.app/devpunks/issue/IP-140/cli-submits-happy-path-project-usage-events https://linear.app/devpunks/issue/IP-139/api-persists-project-usage-aggregates-and-observed-repositories
$delivery-phase lets go
Initial Situation
M4 implemented product telemetry and CLI-backed report submission. The database already has project_usage, observed_repository, cli_usage_event, and harness_report tables. The API can ingest telemetry and reports, and the CLI emits only the locked happy-path product events.
The missing M4.5 capability is the internal operational surface: maintainers still cannot inspect project adoption, map repositories into a project usage aggregate, or triage reports without reading raw database rows.
Issue
Harness maintainers need a first-party internal backoffice that answers adoption and support questions at the product level. OTel is not the right surface because it describes runtime behavior, not project usage. Linear is not the right default destination for reports because report follow-up is closer to implementation and tooling work.
Solution
Add a separate apps/backoffice Next.js app backed by typed API read/update contracts in packages/contract and Effect handlers in apps/api. The API exposes project usage summaries, project usage details, repository mapping, report status updates, and GitHub follow-up linking. The app presents project-level adoption and report triage while treating operator identity as audit/contact context only.
Child Coverage
| Child | Required outcome | Covered by |
|---|---|---|
| IP-139 | API persists and exposes ProjectUsage aggregates with 1:n observed repositories. | DB-backed read model and repository mapping endpoint. |
| IP-140 | CLI submits only happy-path usage events with filterable source/noise metadata. | Existing IP-105 event taxonomy plus dashboard filters for counted sources. |
| IP-141 | Better Auth operator identity is canonical; git identity is fallback/context only. | Better Auth bearer/device auth and operator-only UI presentation. |
| IP-142 | Backoffice shows project usage list/detail dashboards and manual repository mapping. | apps/backoffice list, detail, and mapping controls. |
| IP-143 | CLI-submitted reports are triaged in backoffice and linked to GitHub issue/PR follow-up. | Report list/detail controls, status transitions, and GitHub URL updates. |
Non-Goals
- No developer ranking, scoring, comparison, or KPI dashboards.
- No OTel dashboard embedded as the product adoption UI.
- No new product events beyond the five locked v1 happy-path events.
- No automatic GitHub issue creation without explicit credentials/config.
- No consumer-repo business logic inside
apps/cli. - No public web or customer-facing backoffice surface.
Acceptance Criteria
apps/backofficeexists as a separate internal app, not insideapps/web.- Root Turborepo scripts delegate backoffice development/build/typecheck through package tasks.
- Better Auth bearer/device authorization supports canonical operator identity for CLI/API/backoffice sessions.
- Git identity remains stored and displayed only as observed metadata/fallback context.
packages/contractexposes typed backoffice project usage and report triage endpoints.apps/apiexposes authenticated backoffice read/update handlers backed by Postgres when database persistence is enabled.- Project usage list shows project name/id, repository count, counted event count, open report count, latest CLI version, latest baseline/channel/version, and last activity.
- Project usage detail shows mapped observed repositories, recent happy-path events, and recent/open reports.
- Backoffice can ignore local/test/debug/CI events in adoption counts.
- Backoffice can map an observed repository into an existing project usage aggregate.
- Backoffice report triage supports at least
new,triaged,accepted,wontfix, andresolved. - Backoffice can link a report to a GitHub issue or pull request URL.
- Project dashboards surface open/recent reports without merging reports into happy-path product stats.
- UI shows operator/developer information only as audit/contact fields such as initialized by, last updated by, and report submitted by.
Constraints
- Use
ProjectUsageas the aggregate. Do not collapse project usage into repository identity. apps/apiowns backend/control-plane reads and writes.apps/backofficeconsumes the API.packages/contractis the shared typed boundary for API/backoffice contract.- Product telemetry remains separate from OTel.
- Portless local URLs remain the docs/env baseline.
- Root scripts must delegate through Turborepo package tasks.
- Backoffice is internal/private.
apps/webstays parked public surface.
Technical Notes
- Existing telemetry/report stores derive stable project and repository ids from explicit
projectUsageIdor safe repository remote identity. - Current database persistence keeps reports and usage events nullable when no repository/project identity exists. Backoffice should surface linked data where present and not manufacture project usage from report titles.
- Backoffice read APIs can return a purpose-built read model instead of exposing raw Drizzle rows.
- Local token-based development remains usable as an explicit development escape hatch.
Validation Plan
- Contract schema tests for backoffice summary/detail/report update payloads.
- API tests for project usage summary/detail, source filtering, repository mapping, and report status/GitHub updates.
- Backoffice typecheck and build.
- Browser smoke for the backoffice dashboard at the local dev URL.
- Root
bun run check-typesand targeted package tests.
Decision Log
| Decision | Rationale |
|---|---|
| Create one parent-scoped spec for IP-138 through IP-143 | The child stories form one dependency graph and one product capability. |
| Keep reports separate from adoption events | Reports are friction/support evidence, not happy-path usage stats. |
| Use GitHub URL linking before automatic issue creation | It satisfies v1 follow-up without requiring GitHub credentials in the backoffice. |
| Keep Better Auth bearer/device auth as the identity flow | Local development can keep token auth while production can use authenticated operator sessions. |
Open Questions
| # | Question | Affects | Owner | Status |
|---|---|---|---|---|
| 1 | Which exact production auth host and cookie-domain env values are canonical? | Deployment docs | Delivery | Non-blocking; deployment-specific values live outside the spec. |