Skip to content

docs: ADR-0004 cohost role for competition co-management#351

Open
zacjones93 wants to merge 5 commits intomainfrom
docs/adr-0004-cohost-role
Open

docs: ADR-0004 cohost role for competition co-management#351
zacjones93 wants to merge 5 commits intomainfrom
docs/adr-0004-cohost-role

Conversation

@zacjones93
Copy link
Copy Markdown
Contributor

@zacjones93 zacjones93 commented Mar 19, 2026

Summary

  • Adds ADR-0004 proposing a new cohost system role on the competition_event team
  • Allows cross-gym partners to co-manage a single competition without full organizing team access
  • Defines per-cohost configurable permissions (revenue, settings, pricing) with sensible defaults

Details

This ADR proposes Option A: cohost role on the competition_event team over Option B (organizing team) because:

  • Cohost access is inherently per-competition, not per-gym
  • Reuses existing team membership + metadata patterns
  • Clean role hierarchy: organizing team (admin/owner) > competition team (cohost) > competition team (volunteer)

Includes a detailed 7-phase implementation plan covering schema changes, auth gates, route guards, sidebar, dashboard, invite flow, and session data.

Test plan

  • Review ADR content for completeness and accuracy
  • Verify implementation plan covers all affected routes
  • Confirm patterns align with existing codebase conventions

🤖 Generated with Claude Code


Summary by cubic

Adds ADR-0004 proposing a new per-competition cohost role so cross‑gym partners can manage a single event without full organizing team access. Clarifies auth, route guards, invite flow, and that cohosts enter from the public competition page.

  • New Features

    • Per-competition cohost on the competition_event team with configurable permissions (revenue, settings, pricing) and safe defaults; sidebar hides gated items.
    • Auth: compute isCohost/cohostPermissions in parent beforeLoad context; parent organizer route bypasses entitlement only for IDs starting with comp_ and defers to child guard; organizer dashboard remains organizer‑only.
    • Entry point: show a "Manage Competition" link on /compete/$slug to reach /compete/organizer/$competitionId for cohosts (and admins/owners).
    • Server functions: add requireCompetitionManagePermission to accept organizing or competition team paths (with optional cohost permission); documents migration across ~22 server-fn files (~179 call sites).
    • Invite flow: separate cohost invites and token acceptance via getCohostInviteFn and acceptCohostInviteFn; canonical metadata in src/db/schemas/cohost.ts.
  • Dependencies

    • No new packages, env vars, or migrations.

Written for commit 2c84268. Summary will update on new commits.

Summary by CodeRabbit

  • Documentation
    • Added an Architecture Decision Record proposing a new per-competition “cohost” role with configurable permissions (revenue, settings, pricing, coupons), route access rules, sidebar/dashboard visibility and a dedicated invite/accept flow.
    • Updated the ADR index to include the new proposed decision and adjusted formatting of the records list.

Proposes a new `cohost` system role on the competition_event team to
allow cross-gym partners to co-manage a single competition without
granting full organizing team access.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 19, 2026

Walkthrough

Adds a proposed ADR introducing a per-competition "cohost" system role, detailing schema additions, auth gating, route-level access rules, navigation/dashboard visibility, and a token-based cohost invite/accept flow; also updates the ADR index to include the new document.

Changes

Cohort / File(s) Summary
New ADR
apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md
Adds a proposed Architecture Decision Record defining a COHOST system role, CohostMembershipMetadata JSON permissions (canViewRevenue, canEditSettings, canManagePricing, inviteNotes), loader propagation (isCohost, cohostPermissions), route access rules (blocking edit/danger-zone, conditional revenue/settings/pricing/coupons), sidebar/dashboard visibility rules, and a token-based invite/accept flow with server-side invite/accept/list/update/remove/check functions.
ADR Index
apps/wodsmith-start/docs/decisions/README.md
Updates ADR index to include the new ADR entry (0004-...) marked proposed with date 2026-03-19; minor newline formatting adjustment.

Sequence Diagram(s)

sequenceDiagram
  participant Organizer
  participant Server
  participant EmailService
  participant Invitee
  participant Database
  participant ParentRoute
  Organizer->>Server: POST /invite-cohost (competitionId, email, permissions)
  Server->>Database: create cohost_invite(record with token)
  Server->>EmailService: send invite email (token)
  EmailService-->>Invitee: deliver invite link
  Invitee->>Server: GET /accept-invite?token=...
  Server->>Database: validate token -> create cohost membership (SYSTEM_ROLES_ENUM.COHOST + metadata)
  Server-->>Invitee: redirect to app / confirmation
  ParentRoute->>Server: loader check cohost membership (competitionId, userId)
  Server->>Database: fetch membership -> respond {isCohost, cohostPermissions}
  ParentRoute-->>Client: provide isCohost & cohostPermissions for child route guards
Loading

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

🐰 I hopped to write a cohost plan, so neat and spry,
I left tiny tokens for friends to try,
Permissions tucked in a JSON nest,
Sidebars updated, dashboards dressed,
Together we manage—two rabbits, one sky.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title accurately and concisely describes the main change: adding ADR-0004 documentation for a new cohost role system for competition co-management.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/adr-0004-cohost-role
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md (1)

67-68: Pick one canonical schema file location for cohost metadata.

Using “volunteers.ts (or new cohost.ts)” leaves implementation ambiguous and can cause drift across contributors. Prefer one target file path in the ADR.

Also applies to: 222-223

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md`
around lines 67 - 68, Choose one canonical schema file for cohost metadata
(either volunteers.ts or create a new cohost.ts) and update the ADR to reference
that single filename; replace the ambiguous “volunteers.ts (or new cohost.ts)”
text at the cited locations with the chosen filename and update the code block
header to match, and ensure any later references in the document (e.g., the
mentions at the other noted lines) are made consistent with the chosen schema
file name so contributors have one clear target.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md`:
- Around line 202-208: The decision doc omitted the invite acceptance flow for
cohost tokens—add a route/function to retrieve and accept cohost invites (e.g.,
getCohostInviteFn and an accept-token handler for cohost tokens) and update the
“Affected Paths Summary” and verification checklist to include the invite-token
retrieval + acceptance lifecycle; specifically list getCohostInviteFn (or
equivalent invite-token GET) and the accept-token POST flow, ensure permission
checks mirror existing invite-token handlers, and document tests/verification
steps for token validation, email link handling, and post-accept membership
state.
- Around line 105-110: The ADR currently returns isCohost and cohostPermissions
from the parent route loader but child routes rely on accessing them via context
in beforeLoad guards; since beforeLoad runs before loaders, move the role
context into the parent route's beforeLoad instead of the loader: compute
isCohost (using session and competition.competitionTeamId) and cohostPermissions
(via getCohostPermissions(session, competition.competitionTeamId)) inside the
parent beforeLoad and return them on the context object so child beforeLoad
guards can read context.isCohost and context.cohostPermissions; keep the loader
responsible for fetching competition data only.

---

Nitpick comments:
In
`@apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md`:
- Around line 67-68: Choose one canonical schema file for cohost metadata
(either volunteers.ts or create a new cohost.ts) and update the ADR to reference
that single filename; replace the ambiguous “volunteers.ts (or new cohost.ts)”
text at the cited locations with the chosen filename and update the code block
header to match, and ensure any later references in the document (e.g., the
mentions at the other noted lines) are made consistent with the chosen schema
file name so contributors have one clear target.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d9c6eb4c-02df-427d-9c91-db5b6e7986e4

📥 Commits

Reviewing files that changed from the base of the PR and between e89f4e1 and 9958c94.

📒 Files selected for processing (2)
  • apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md
  • apps/wodsmith-start/docs/decisions/README.md

- Move isCohost/cohostPermissions from loader to beforeLoad context
  (child beforeLoad runs before parent loaders in TanStack Router)
- Add cohost invite acceptance flow (getCohostInviteFn, acceptCohostInviteFn,
  acceptance route)
- Use canonical src/db/schemas/cohost.ts for metadata interface
- Add 7 verification checklist items for acceptance + context propagation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md">

<violation number="1" location="apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md:103">
P1: Opening `$competitionId` to cohosts is not enough by itself; many organizer actions still enforce organizing-team permissions, so cohosts would reach pages they cannot actually use.</violation>

<violation number="2" location="apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md:136">
P2: The guard example uses `context.isCohost`, but child routes only receive parent loader data via `parentMatchPromise`/`getRouteApi` in this router setup.</violation>

<violation number="3" location="apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md:188">
P1: The dashboard plan misses the current `organizingTeams.length === 0` path, so cohost-only users would still land on the empty state instead of seeing their cohosted competitions.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

- Add Phase 3b: server function authorization with new
  requireCompetitionManagePermission helper that accepts both
  organizing team (admin/owner) and competition team (cohost) paths
- Document all 22 server-fn files (~179 call sites) needing migration
- Fix dashboard plan for cohost-only users who have no organizing teams
- Add 5 verification checklist items for server fn auth + dashboard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md">

<violation number="1" location="apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md:238">
P2: File count inconsistency: the header says "26 files" but only 22 are listed, and other parts of the document (consequences, summary table) correctly say "22 files". Update the count to match the actual list.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

2. For actions gated by configurable cohost permissions (pricing, settings, revenue), pass the relevant `cohostPermission` key
3. Update incrementally — start with the most common server functions (competition detail, divisions, events, registrations, volunteers, results) and expand

**Files requiring server function auth updates** (26 files, ~179 call sites):
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: File count inconsistency: the header says "26 files" but only 22 are listed, and other parts of the document (consequences, summary table) correctly say "22 files". Update the count to match the actual list.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md, line 238:

<comment>File count inconsistency: the header says "26 files" but only 22 are listed, and other parts of the document (consequences, summary table) correctly say "22 files". Update the count to match the actual list.</comment>

<file context>
@@ -175,6 +176,89 @@ if (context.isCohost && !context.cohostPermissions?.canViewRevenue) {
+2. For actions gated by configurable cohost permissions (pricing, settings, revenue), pass the relevant `cohostPermission` key
+3. Update incrementally — start with the most common server functions (competition detail, divisions, events, registrations, volunteers, results) and expand
+
+**Files requiring server function auth updates** (26 files, ~179 call sites):
+- `src/server-fns/competition-detail-fns.ts`
+- `src/server-fns/competition-divisions-fns.ts`
</file context>
Suggested change
**Files requiring server function auth updates** (26 files, ~179 call sites):
**Files requiring server function auth updates** (22 files, ~179 call sites):
Fix with Cubic

…hboard

- Remove dashboard changes (Phase 5) — /compete/organizer/ stays organizer-only
- Parent route skips entitlement for $competitionId routes (same pattern as
  onboard bypass), defers auth to child beforeLoad
- Add Phase 5: cohost entry point via "Manage Competition" link on public
  competition page (/compete/$slug)
- Remove hasCohostMembershipsFn (no longer needed)
- Dashboard cohost section deferred to future enhancement

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md">

<violation number="1" location="apps/wodsmith-start/docs/decisions/0004-add-cohost-role-for-competition-co-management.md:145">
P2: This path-based bypass is too broad: it would also skip the `HOST_COMPETITIONS` gate for organizer dashboard routes like `/compete/organizer/new` and `/compete/organizer/series`, not just competition-detail pages.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

The regex /^\/compete\/organizer\/[^/]+/ was too broad — it matched
dashboard routes like /new and /series. Competition IDs always start
with "comp_" (e.g., comp_01HXYZ), so check the prefix instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant