Home

boring / v2

publicBoring-Software-Inc/v2
Overview Code History Branches Pull requestsIssuesInsights Campfire Docs
main
HomeOverview Code PRsIssues

feat(web): onboarding — user ↔ installation ↔ active repo (§10)

4 months ago

c3c7bd7
Authored
grim7/12/2026, 1:05:21 PM
Tripwire becomes an app with accounts: sign-in gets a session, onboarding gets a
repo, and every dashboard surface scopes to the user's ONE active repo. The repo
dropdown on /rules and /workflows is gone.

- schema (migration 0002): user_installations(user_id, forge, installation_id)
  UNIQUE on (forge, installation_id) — an installation belongs to exactly one
  user; user.active_repo_id FK → repos.id. all granted repos stay synced, only
  the active one scopes the dashboard (no switcher, MVP).
- onboardingServices: linkUserInstallation / listUserRepos / getActiveRepo /
  setActiveRepo / getOnboardingState, with an integration test locking the
  ownership + must-be-yours invariants.
- Setup URL callback /onboarding/setup links the installation to the SIGNED-IN
  user; the install `state` HMAC-binds that user (CSRF). /onboarding narrows:
  one granted repo auto-selects, more than one shows a picker.
- gate: getSessionInfo gains `onboarded`; __root beforeLoad redirects a signed-in
  not-onboarded user to /onboarding, mirroring the /login redirect.
- scoping: listActivityFeed / getHomeStats / listPendingItems take a repoFullName,
  resolved per session by a getActiveRepo helper (open-dev falls back to the first
  installed repo; a fresh repo yields honest zeros). replaced the /rules +
  /workflows dropdowns with the active repo; deleted the dead listRepoOptions.
- documented GITHUB_APP_SLUG + the Setup URL in .env.example. spec §4/§10 updated.

honest ledger: this scopes dashboard LISTS but does NOT authorize a run fetched
directly by id — any signed-in session can still load any run by id. cross-user
run authorization stays open (DECISIONS + spec §10).

Checks: typecheck all, biome, boundaries, 204 tests, migration applied.

Parent62c52d0

32 files changed
  • .env.example+4−0
  • DECISIONS.md+46−0
  • all-summaries.md+18−0
  • apps/web/src/components/onboarding/onboarding-page.tsx+180−0
  • apps/web/src/components/rules/rules-page.tsx+30−39
  • apps/web/src/components/workflows/workflows-page.tsx+8−21
  • apps/web/src/lib/activity.functions.ts+6−2
  • apps/web/src/lib/auth.functions.ts+22
−8
  • apps/web/src/lib/moderation-queue.functions.ts+9−3
  • apps/web/src/lib/moderation.functions.ts+20−6
  • apps/web/src/lib/onboarding.functions.ts+106−0
  • apps/web/src/lib/onboarding.query.ts+34−0
  • apps/web/src/lib/rules.functions.ts+0−16
  • apps/web/src/lib/rules.query.ts+0−9
  • apps/web/src/lib/server/active-repo.ts+34−0
  • apps/web/src/lib/server/install-state.ts+44−0
  • apps/web/src/routes/__root.tsx+12−4
  • apps/web/src/routes/onboarding.setup.tsx+33−0
  • apps/web/src/routes/onboarding.tsx+18−0
  • apps/worker/src/moderation.integration.test.ts+5−5
  • packages/db/drizzle/0002_nosy_steel_serpent.sql+12−0
  • packages/db/drizzle/meta/0002_snapshot.json+1560−0
  • packages/db/drizzle/meta/_journal.json+7−0
  • packages/db/src/index.ts+2−0
  • packages/db/src/schema/auth.ts+35−0
  • packages/db/src/services/activity.integration.test.ts+15−11
  • packages/db/src/services/events.ts+5−1
  • packages/db/src/services/insights.ts+22−10
  • packages/db/src/services/moderation.ts+9−3
  • packages/db/src/services/onboarding.integration.test.ts+121−0
  • packages/db/src/services/onboarding.ts+141−0
  • spec.md+40−9