v4.19 — Teams V1 Wiring Completion
Every enabled control a paying team owner or member can tap now does the real thing — and everything deliberately deferred to V1.1 reads as an honest "coming soon," never a dead button.
Summary
Teams V1 went GA on tag v4.0.3 (2026-07-15), but the OBJ-1817 audit found the pattern was systemic: several controls that shipped enabled fired nothing when tapped, and one headline feature — in-app collective-goal creation — had no UI surface at all despite its opt-in/contribution flow already being live. The trigger was OBJ-1808's seat-cap "Add seats" CTA advertising a specific charge and then silently no-op'ing; the audit found the same shape of gap in billing, collective goals, and sub-communities.
v4.19 closed every one of those gaps in four sequential phases on the integration branch gsd/v4.19-teams-v1-wiring. Phase 1 wired the seat-cap "Add seats" flow to Teams::AdjustTeamSeats and built a real grace-state resubscribe checkout path, closing OBJ-1808 findings #2 and #4 — plus a same-milestone follow-up (OBJ-1835) fixing an initial resubscribe defect that would have re-granted a free trial to a churned, previously-paying team. Phase 2 gave Teams::CreateCollectiveGoal its first UI caller: an in-app owner/admin creation flow. Phase 3 wired Teams::JoinSubCommunity/LeaveSubCommunity and active-room switching, closing the "owners can create rooms, but no member can join one" loop, and added the backend read query multi-room joiners needed to land on a real room picker instead of a bare dashboard. Phase 4, the final phase, wired the fresh-member "mark today done" CTA to a real destination and honestly gated all eight remaining V1.1-shaped stubs (notifications bell, points breakdown, team-picker chevron, sub-community filter, team-activity view, room edit, room feed, leaderboard scope switcher) so none of them render as an enabled dead control.
Every phase ran the full Multica crew chain (Desi → Codi → Riley → Roy → Vicki → Dori), with Orion coordinating phase-to-phase dispatch from the milestone's parent issue (OBJ-1827). Two deviations surfaced and were resolved without blocking the ship: the resubscribe trial-reset defect (fixed via OBJ-1835, run in parallel with Phase 2 rather than folded into Phase 4), and a Roy-flagged N+1 query on the Team Home page's room list (bundled into the Phase 3 PR per Josh's call and closed as OBJ-1851 in the same ship).
The work is complete and merged to master via promotion PR #1956 (OBJ-2012). See Outcomes below.
Goal
Finish wiring the Teams V1 surfaces that shipped to GA (
v4.0.3) but silently no-op. Every enabled control a paying team owner or member can tap should do the real thing — fire its mutation, navigate, or start checkout — and anything deliberately deferred to V1.1 should render as an honest "coming soon" placeholder, never an enabled dead button. Concretely: wire the seat-cap "Add seats" flow and a grace-state resubscribe path (billing); surface in-app collective-goal creation (a dark headline feature); wire sub-community join/leave/switch (a broken create-a-room-nobody-can-join loop); give the fresh-member CTA a real destination; and honestly gate the V1.1-shaped stubs.—
.planning/milestones/v4.19-teams-v1-wiring-ROADMAP.md
Scope — What Shipped
- Seat-cap "Add seats" wired —
TeamMembersTab.vue'sonAddSeatsnow firesADJUST_TEAM_SEATS_MUTATION(mirroringTeamBillingTab.handleSaveSeats's toast + refetch + close pattern) instead of closing the modal and doing nothing. - Grace-state resubscribe, end-to-end — a new
useTeamResubscribe.tscomposable starts a fresh Stripe checkout (not a portal session — the subscription is already canceled) from bothTeamHomeView's banner CTA andTeamSettingsView's billing tab. Ships with a same-milestone follow-up (OBJ-1835) so the resumed subscription bills immediately rather than granting a new 14-day trial. - In-app collective-goal creation —
useCreateCollectiveGoal.tswiresCREATE_COLLECTIVE_GOAL_MUTATION(backend + GraphQL constant existed with zero callers before this milestone) behindteams_collective_goals; new goals render inCollectiveProgressCard. Non-check_insmetrics are gated as coming-soon pending broader metric aggregation. - Sub-community join/leave/switch —
useSubCommunityMembership.tswiresJOIN_SUB_COMMUNITY_MUTATION/LEAVE_SUB_COMMUNITY_MUTATION;onBrowseAllmounts the previously-orphanedSubCommunityBrowser.vue;onSelectRoomsets the active room. - Post-accept multi-room onboarding — a new
TeamAccessPolicy-guarded backend read query letsAcceptTeamInvite→TeamHomeView?browse=1renderSubCommunityBrowserwith the team's real rooms instead of discarding the browse intent. - Fresh-member CTA wired —
TeamHomeView.onMarkTodayDoneroutes to/dashboard's real personal check-in surface (no team-scoped check-in path exists in V1, so this deliberately leaves team context rather than inventing one — documented inline). - All 8 remaining V1.1-shaped stubs honestly gated — notifications bell (OBJ-1819), points breakdown (OBJ-1820), team-picker chevron (OBJ-1821), sub-community filter (OBJ-1822), team-activity view (OBJ-1823), room edit (OBJ-1824, gate lifted — see below), room feed (OBJ-1825), leaderboard scope switcher (OBJ-1826) — each now renders a disabled affordance with a
ComingSoonPill/toast, never an enabled no-op. - N+1 query fix —
TEAM_HOME_QUERY.rooms[].isMemberbatch-loads membership instead of one query per room (OBJ-1851, bundled into Phase 3). - Docs —
docs/product/phase-7-teams.md,docs/architecture/graphql.md,docs/features/communities.md, and both CHANGELOGs updated per phase.
Phases
| Phase | Name | Status | PRs | Highlights |
|---|---|---|---|---|
| 1 | Billing dead-ends — seat-cap + grace resubscribe | Shipped | #1831, #1836 (follow-up) | Closes OBJ-1808 #2/#4; follow-up fixes resubscribe trial-reset to immediately-billed |
| 2 | In-app collective-goal creation | Shipped | #1833 | First UI caller for a mutation that existed since GA with zero callers |
| 3 | Sub-community join/leave/switch | Shipped | #1842 | Closes the create-a-room-nobody-can-join loop; N+1 fix (OBJ-1851) bundled per Josh's call |
| 4 | Fresh-member CTA + honest gating (final) | Shipped | #1848 | All 8 V1.1 stubs honestly gated; no enabled Teams control silently no-ops |
Key Decisions
- Resubscribe follow-up shipped standalone and in parallel, not folded into Phase 4 (Orion, confirmed by Josh) — the trial-reset fix is a backend billing-correctness change on a different surface from Phase 4's frontend gating; running it in parallel with Phase 2 got the revenue-leak risk closed sooner instead of waiting on the phase chain.
- N+1 query fix bundled into Phase 3's PR rather than a separate follow-up (Josh's explicit product call) — kept the fix shipping alongside the code that introduced the query shape, rather than opening a second review cycle for a fix Roy had already scoped.
- Fresh-member CTA leaves team context rather than inventing a team-scoped check-in (Codi, per the ROADMAP's own "wire it, or honestly gate it with a justification" instruction) — no team-scoped check-in surface exists in V1, so
onMarkTodayDoneroutes to the real personal-dashboard check-in instead of fabricating a team-specific equivalent that doesn't map to anything real. - All 8 gating targets tied to their V1.1 backlog ticket, not a generic "coming soon" — each disabled affordance references its own OBJ-18xx ticket, so the placeholder reads as an honest, trackable deferral rather than an unexplained dead end.
Requirements Coverage
6 / 6 requirements satisfied (per .planning/milestones/v4.19-teams-v1-wiring-MILESTONE-AUDIT.md — this milestone has no separate REQUIREMENTS.md; the ROADMAP's Definition of Done is the requirements source of record).
| Category | Count | Status |
|---|---|---|
| Billing dead-ends (Phase 1) | 1 | Satisfied |
| Collective-goal creation (Phase 2) | 1 | Satisfied |
| Sub-community join/leave/switch (Phase 3) | 1 | Satisfied |
| Fresh-member CTA + honest gating (Phase 4) | 1 | Satisfied |
| Native boundary respected | 1 | Satisfied |
| Docs updated per phase | 1 | Satisfied |
Full requirements list: v4.19-teams-v1-wiring-ROADMAP.md on GitHub.
Outcomes
In the codebase, every Teams V1 control that shipped enabled at GA now does the real thing: seat-cap upgrades fire the seat mutation, grace-state teams can resubscribe (and resume as immediately-billed, not a fresh trial), owners/admins can create collective goals in-app, members can browse/join/leave/switch sub-communities and multi-room joiners land on a real picker, and the fresh-member CTA performs a real check-in. Every remaining V1.1-shaped surface is an honest, ticket-linked "coming soon" rather than a silent dead end.
Merged to master via promotion PR #1956 (OBJ-2012). The features stay behind the existing teams_billing_v1/teams_collective_goals kill switches; teams_enabled itself was already retired at GA. Riding the next Wednesday release train is the one concrete step standing between this milestone's code being on master and paying Teams customers actually seeing it.
Tech Debt
- (Phase 3) Per-phase RSpec/Vitest coverage and the
TeamScopedViewcontract test were CI-gated at each PR's merge but not independently re-run as part of this close audit. - (Out of milestone scope) OBJ-1819–1826 — the 8 gated V1.1 stubs — remain honestly gated, not built. Deferred to the Teams V1.1 backlog project. Update: OBJ-1824 (sub-community room edit) shipped separately via PR #2207 — see docs/product/phase-7-teams.md and
docs/architecture/graphql/mutations.md'supdateSubCommunityentry. - (Out of milestone scope) OBJ-1811 (native App Store 3.1.1 billing boundary) is a separate, in-flight track; this milestone only confirmed it stayed respected, it didn't touch it.
Related Artifacts
- Roadmap: v4.19-teams-v1-wiring-ROADMAP.md
- Milestone Audit: v4.19-teams-v1-wiring-MILESTONE-AUDIT.md
- Phase PRs: #1831 · #1836 · #1833 · #1842 · #1848
- Source issue: OBJ-1817 (audit) · Milestone anchor: OBJ-1827 · Deferred backlog: OBJ-1819–1826 (Teams V1.1)
- Git tag: none yet — rides
masterpromotion, then the next weekly release train
Related Commits
d125c67— Phase 1 merge: seat-cap "Add seats" + grace resubscribe billing dead-ends5387ea4— Phase 1 follow-up merge: resubscribe resumes immediately-billed9cf49d9— Phase 2 merge: in-app collective-goal creationedcd01ea— Phase 3 merge: sub-community join/leave/switch (+ N+1 fix)f12bfdbf3— Phase 4 merge: fresh-member check-in CTA + honest gating of 8 V1.1 stubs
Last updated: 2026-08-08