Phase 7 — Teams Surfaces & Wireframes
Status: Discovery / Design companion Source PRD: phase-7-teams-prd.mdLast updated: 2026-07-12 Owner: Josh Lockhart
This document is the surface inventory and low-fidelity wireframe set for every screen, panel, modal, and email that the Teams V1 (and V1.1 shape-only) work introduces or modifies. It is the bridge between the PRD's prose (§7 deep specs, §8 V1.1 sketches) and the Claude Design / Vue implementation work.
It is intentionally tool-agnostic (ASCII boxes, not Figma) so it can be reviewed inside a PR, pasted into a Claude Design prompt, or printed on a wall.
0. How to read this doc
- NEW = surface does not exist in master today; create from scratch.
- MODIFIED = surface exists; this work touches it.
- EMBEDDED = sub-component / banner / strip that lives inside another surface.
- EMAIL / NOTIFICATION = transactional or lifecycle artifact (no in-app screen).
Each entry has: purpose · personas · trigger · scope (V1 / V1.1 / V1.2) · file targets · wireframe.
Wireframes are mobile-first (390px). A ─┐ tablet/desktop: annotation marks where the layout reflows. All copy is illustrative; final copy ships under the brand-voice filter (see tightening-brand-voice).
The data-boundary contract (PRD §6) governs every admin-visible element. Anywhere a wireframe shows admin-only data, assume the §6 redaction rules already apply.
1. Surface map at a glance
1.1 New surfaces (V1)
| # | Surface | Personas | Where |
|---|---|---|---|
| N1 | Pricing page — Teams tier | Anonymous, admin | marketing_landing/index.html + new /pricing/teams panel |
| N2 | In-app Teams upgrade banner | Community admin | Top of any community admin sees |
| N3 | Team creation / plan selector — /teams/new | Team Owner | New view |
| N4 | Clerk Billing checkout (external) | Team Owner | Stripe-hosted; we return to step N5 |
| N5 | Team provisioning success → invite empty state | Team Owner | New view (lands inside Team Settings) |
| N6 | Convert existing community → Team flow | Community admin | New modal off Community Settings |
| N7 | Team Settings shell (tabbed) | Owner, Admin | New view |
| N7a | Team Settings · Billing tab | Owner | Subtab |
| N7b | Team Settings · Members tab | Owner, Admin | Subtab |
| N7c | Team Settings · Sub-Communities tab | Owner, Admin | Subtab |
| N7d | Team Settings · Invites tab | Owner, Admin | Subtab |
| N7e | Team Settings · Privacy panel preview | Owner, Admin | Subtab (read-only reflection of N18) |
| N8 | Invite-member modal (link + email) | Owner, Admin | Modal off N7d |
| N9 | Create-sub-community modal | Owner, Admin | Modal off N7c |
| N10 | Archive-sub-community confirm | Owner, Admin | Modal off N7c |
| N11 | Public join landing — /join-team/{code} | Invitee (anon or signed-in) | New view |
| N12 | Sub-Community Browser (self-select) | New team member | New view, first session after invite accept |
| N13 | Team Home — dashboard with sub-community switcher | Member, Admin | New view |
| N14 | Sub-Community switcher (sidebar/top-bar) | Member | Embedded nav |
| N15 | Team-wide Collective Progress card | Member | Embedded in N13 |
| N16 | Collective Goal detail view | Member, Admin | New view |
| N17 | Collective Goal opt-in modal | Member | Modal off any personal goal |
| N18 | Privacy contract panel — "What [Team] can see" | Member | New view, off member settings |
| N19 | Team Leaderboard view (scope × period toggles) | Member | New view |
| N20 | Leaderboard opt-out toggle | Member | Embedded in member settings |
| N21 | Monday Recap (in-app card) | Member | Notification + in-app card |
| N22 | Trial-ending / past-due / grace banner | Owner | Embedded at top of Team chrome |
| N23 | Team email — invite | Invitee | TeamInviteMailer |
| N24 | Team email — trial ending in 3d / payment failed | Owner | TrialEndingSoonJob, billing emails |
| N25 | Team email — welcome / upgraded / downgraded | Owner, members | TeamUpgradedJob, TeamDowngradedJob |
| N26 | Seat-cap blocker modal | Owner, Admin, member-being-invited | Modal off invite flow |
1.2 New surfaces (V1.1+ shape-only)
| # | Surface | V | Where |
|---|---|---|---|
| N27 | Bulk CSV invite | V1.1 | Subtab N7d extension |
| N28 | Team Admin Dashboard (analytics) | V1.1 | New top-level admin view |
| N29 | Custom Badges admin | V1.1 | Inside N7c sub-community settings |
| N30 | Manager View (grid of all members) | V1.1 | New top-level admin view |
| N31 | Accountability Pair auto-match — opt-in card | V1.1 | Embedded in N13 |
| N32 | Sub-community-scoped invite link (lead-shared) | V1.1 | Modal off sub-community settings |
| N33 | Per-team brand customization (color, logo) | V1.2 | Subtab inside N7 |
| N34 | Slack / MS Teams integration config | V1.2 | Subtab inside N7 |
| N35 | External Coach role management | V1.2 | Extension to N7b |
1.3 Modified existing surfaces
| # | Existing surface | What changes |
|---|---|---|
| M1 | Community feed (CommunityView.vue and equivalents) | If community.team_id set, gains team chrome: sub-community switcher (N14), Collective Progress card (N15), Team Leaderboard CTA |
| M2 | Community Settings | "Upgrade to Teams" entry → opens N6; existing private community owners get the conversion flow |
| M3 | Marketing landing (marketing_landing/index.html) | New "Teams" nav item; new Teams pricing panel (N1) |
| M4 | App side-nav / root tab bar | "Teams" group appears in nav when user has ≥1 TeamMembership; team switcher if ≥2 |
| M5 | User settings → Privacy | New row linking to N18 ("What your teams can see") |
| M6 | User profile (own) | "Member of [Team A], [Team B]"; "Previously a member of [Team C]" |
| M7 | Personal Goal detail (GoalView.vue) | New "Contributing to: [Collective Goal]" row + opt-in/opt-out from N17 |
| M8 | Personal Goal create flow | At create-time, if user is in a Team with active matching collective goal, surface opt-in (no auto-link) |
| M9 | Notifications inbox | New categories: team_invite, team_billing, monday_recap, collective_goal_milestone |
| M10 | Onboarding (post-signup) | Net-new step inserted only when signup arrived via team invite: lands on N11 → N12 instead of personal-goal seed flow |
| M11 | Admin Dashboard (admin_dashboard/) | New top-level "Teams" view: list of Teams, MRR, churn, seat utilization (internal Objectuve admins only) |
| M12 | Mailer base layout | Team emails carry team logo / brand color (V1.2); V1 they reuse Objectuve chrome |
| M13 | GraphQL Apollo cache shapes | Existing Community queries gain optional team {…} field; UI components read it to decide whether to render team chrome |
| M14 | Feature flag registry (featureFlags.ts + PostHog) | Adds teams_enabled, teams_billing_v1, teams_collective_goals, teams_leaderboards, teams_bulk_invite |
2. NEW surfaces — wireframes
N1 · Pricing page — Teams tier
Purpose: Public-facing pricing surface; primary acquisition lever for the coach + corporate-wellness ICPs. Personas: Anonymous visitor, signed-in community admin. Trigger: Marketing nav /pricing → Teams panel; or in-app Upgrade to Teams CTA. Scope: V1 (panel launched at GA; teams_enabled retired 2026-07-08 — PR #1498, OBJ-1096 — no flag gate remains). File targets: marketing_landing/index.html (Teams panel); link from in-app upgrade banner (N2).
┌──────────────────────────────────────────────────────────────┐
│ Objectuve Product Mission Pricing Sign in [Sign up] │
├──────────────────────────────────────────────────────────────┤
│ │
│ Pricing │
│ ┌────────────┐ ┌────────────┐ ┌────────────────────┐ │
│ │ Personal │ │ Supporter │ │ TEAMS │ │
│ │ Free │ │ $3/mo │ │ $7 / user / mo │ │
│ │ Forever │ │ Cosmetic │ │ or $70 / yr │ │
│ │ │ │ perks │ │ (save ~17%) │ │
│ │ │ │ │ │ │ │
│ │ • Goals │ │ • Themes │ │ Everything in │ │
│ │ • Habits │ │ • Badges │ │ Personal, plus: │ │
│ │ • Coach │ │ • Aura │ │ • Private team │ │
│ │ • Streaks │ │ │ │ • Sub-communities │ │
│ │ │ │ │ │ • Collective goals │ │
│ │ [Get app] │ │ [Become] │ │ • Leaderboards │ │
│ │ │ │ │ │ • Coach role │ │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ [Start free trial] │ │
│ └────────────┘ └────────────┘ └────────────────────┘ │
│ │
│ What's a team? │
│ For coaching cohorts, wellness teams, and school groups. │
│ One owner pays; up to 200 members; private by default. │
│ │
│ Compared to: Slack ($7.25), Asana ($10.99) │
│ │
│ ▸ Member privacy contract ▸ FAQ ▸ Talk to a human │
└──────────────────────────────────────────────────────────────┘N2 · In-app Teams upgrade banner
Purpose: Convert existing private-community admins. Personas: Community admin (private community ≥3 members). Trigger: Any time a community admin opens their community (no flag gate — teams_enabled retired at GA, PR #1498). Scope: V1. File targets: New <TeamsUpgradeBanner.vue> injected at top of community feed when community.team_id is null and user is admin.
┌──────────────────────────────────────────────────────────────┐
│ ✨ Make this a Team — collective goals, leaderboards, │
│ and seats your members can share. 14-day free trial. │
│ [Learn more] [×] │
└──────────────────────────────────────────────────────────────┘Dismissal persists per (admin_user_id, community_id). Re-surfaces after 30 days.
N3 · Team creation / plan selector — /teams/new
Purpose: Capture intent → Stripe checkout. Personas: Team Owner. Trigger: N1 CTA, N2 CTA, or direct nav. Scope: V1. File targets: ionic_frontend/src/views/teams/CreateTeamView.vue.
┌──────────────────────────────────────────────────────────────┐
│ ← Back Step 1 of 2 · Team setup │
├──────────────────────────────────────────────────────────────┤
│ │
│ Start your team │
│ You'll get a 14-day free trial. No card needed today. │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Team name │ │
│ │ ┌───────────────────────────────────────────────────┐ │ │
│ │ │ e.g. Habit Lab │ │ │
│ │ └───────────────────────────────────────────────────┘ │ │
│ │ This becomes your default sub-community name too. │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ Billing │
│ ┌────────────────────┐ ┌────────────────────────────┐ │
│ │ ○ Monthly │ │ ● Annual (save ~17%) │ │
│ │ $7 / user / mo │ │ $70 / user / yr │ │
│ └────────────────────┘ └────────────────────────────┘ │
│ │
│ Seats │
│ [ − ] 5 seats [ + ] $35 / mo after trial │
│ (You're seat 1 of 5. Add or remove anytime.) │
│ │
│ [ Start 14-day trial → ] │
│ │
│ By starting, you agree to Objectuve's terms. Your team's │
│ members will never have their personal data shown to you. │
└──────────────────────────────────────────────────────────────┘N4 · Clerk Billing checkout (Stripe-hosted)
Out-of-app — Stripe Checkout UI. No wireframe needed. Return URL hits Teams::ProvisionTeam interaction (PRD §7.1).
N5 · Team provisioning success → invite empty state
Purpose: First moment of value — owner sees their team is real, gets pushed to invite. Personas: Team Owner. Trigger: Webhook checkout.session.completed → redirect. Scope: V1. File targets: Lands directly on TeamSettingsView.vue (N7) with Invites tab (N7d) selected and a one-time celebration strip.
┌──────────────────────────────────────────────────────────────┐
│ ✓ Habit Lab is live. 14-day trial — no card needed yet. │
├──────────────────────────────────────────────────────────────┤
│ Settings ▾ [Billing][Members][Communities][Invites][Privacy]│
├──────────────────────────────────────────────────────────────┤
│ │
│ Invite your team │
│ │
│ ╭──────────────────────────────────────────────────────╮ │
│ │ 🔗 Share your team link │ │
│ │ https://app.objectuve.com/join-team/h7k2-9xp4-… │ │
│ │ [Copy] [QR] │ │
│ ╰──────────────────────────────────────────────────────╯ │
│ │
│ Or send by email │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ devon@example.com, priya@… │ │
│ │ │ │
│ └──────────────────────────────────────────────────────┘ │
│ [ Add a personal note ▾ ] │
│ [ Send invites (2) ] │
│ │
│ No one's joined yet. We'll show you here as soon as they │
│ do. │
└──────────────────────────────────────────────────────────────┘N6 · Convert existing community → Team
Purpose: Preserve existing private community when owner upgrades. Personas: Community admin. Trigger: N2 banner CTA inside an existing private community. Scope: V1. File targets: Modal <UpgradeCommunityToTeamModal.vue> mounted from Community Settings.
┌──────────────────────────────────────────────┐
│ Upgrade [Community name] to a Team │
├──────────────────────────────────────────────┤
│ What stays the same │
│ • All 8 members keep their access │
│ • Your community feed is preserved │
│ • Posts, goals, encouragements — all intact │
│ │
│ What you'll unlock │
│ • Collective goals across the team │
│ • Weekly leaderboards │
│ • Multiple sub-communities (optional) │
│ • Member seat management │
│ │
│ Pricing │
│ $7 × 8 seats = $56/mo ($70/yr/seat option) │
│ 14-day free trial. No card needed today. │
│ │
│ [ Cancel ] [ Continue to plan → ] │
└──────────────────────────────────────────────┘N7 · Team Settings shell (tabbed)
Purpose: All admin operations live here. Personas: Owner (full), Admin (no Billing tab). Trigger: Side-nav Settings icon inside Team Home. Scope: V1. File targets: TeamSettingsView.vue with <router-view>-style tab switching.
┌──────────────────────────────────────────────────────────────┐
│ ← Habit Lab │
│ Team settings │
├──────────────────────────────────────────────────────────────┤
│ [Billing] [Members] [Communities] [Invites] [Privacy] │
│ │
│ ↓ tab content renders here │
│ │
└──────────────────────────────────────────────────────────────┘(Owner sees all 5 tabs; Admin sees 4 — Billing hidden.)
N7a · Team Settings · Billing
┌──────────────────────────────────────────────────────────────┐
│ Plan │
│ ╭──────────────────────────────────────────────────────────╮ │
│ │ Annual · $70 / user / yr │ │
│ │ 8 seats · $560 / yr · Renews 2027-08-12 │ │
│ │ [ Switch to monthly ] [ Change seats ] │ │
│ ╰──────────────────────────────────────────────────────────╯ │
│ │
│ Billing owner │
│ Maya Okonkwo (you) [ Transfer ownership → ] │
│ │
│ Payment method │
│ Visa •••• 4242 [ Update via Stripe → ] │
│ │
│ Invoices │
│ • 2026-08-12 · $560.00 · Paid [Download PDF] │
│ • 2026-05-12 · $35.00 · Paid [Download PDF] │
│ │
│ Danger zone │
│ [ Cancel subscription ] │
└──────────────────────────────────────────────────────────────┘N7b · Team Settings · Members
┌──────────────────────────────────────────────────────────────┐
│ Members (8 of 8 seats) [ Add seats + ] │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 🔍 Search Filter ▾ Role Sub-community Status │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ ● Maya O. (you) Owner Joined 4/12 Active today ⋮ │
│ ● Devon S. Member Joined 5/03 Active 2d ago ⋮ │
│ ● Priya R. Lead* Joined 4/14 Active today ⋮ │
│ ● Marcus T. Lead* Joined 4/19 Active 4d ago ⋮ │
│ ○ Jules K. Member Joined 5/01 Inactive 9d ⋮ │
│ … │
│ │
│ * Lead = admin of one sub-community (not team-wide) │
│ │
│ Pending invites (2) │
│ • alex@example.com Sent 5d ago [Resend][Revoke][Copy] │
│ • amir@example.com Sent 1d ago [Resend][Revoke][Copy] │
└──────────────────────────────────────────────────────────────┘Row ⋮ menu: Change role · Remove from team · View team activity (no personal data). Selecting "View team activity" opens a read-only panel scoped per §6.
N7c · Team Settings · Sub-Communities
┌──────────────────────────────────────────────────────────────┐
│ Sub-communities (5 of 10) [ + New ] │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ #welcome Default · 47 members · 23 check-ins / wk │ │
│ │ Lobby for team-wide announcements ⋮ │ │
│ ├──────────────────────────────────────────────────────────┤ │
│ │ 🌅 Morning Movers · 18 members · 142 check-ins / wk │ │
│ │ Lead: Priya R. ⋮ │ │
│ ├──────────────────────────────────────────────────────────┤ │
│ │ 📚 Deep Work Pod · 12 members · 88 check-ins / wk │ │
│ │ Lead: Marcus T. ⋮ │ │
│ ├──────────────────────────────────────────────────────────┤ │
│ │ 🥗 Quiet Plate · 9 members · request-to-join · ⋮ │ │
│ ├──────────────────────────────────────────────────────────┤ │
│ │ 🧗 Weekend Warriors · 14 members · 31 check-ins / wk │ │
│ │ Lead: Jules K. ⋮ │ │
│ └──────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘⋮ menu: Edit · Set as default · Archive · Open feed.
N7d · Team Settings · Invites
Mirrors N5 (link + email composer) plus an active-invites table (same as N7b pending section). Bulk CSV (V1.1) appears as an extra panel:
┌──────────────────────────────────────────────────────────────┐
│ Bulk invite (V1.1) │
│ Drop a CSV with `email`, `team_role`, `communities` │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Drop file or [Browse] │ │
│ └──────────────────────────────────────────────────────────┘ │
│ Preview: 24 valid · 1 malformed · [Assign all to ▾] │
│ [ Send invites ] │
└──────────────────────────────────────────────────────────────┘N7e · Team Settings · Privacy panel preview
┌──────────────────────────────────────────────────────────────┐
│ What members see about what you (admin) can see │
│ This is the privacy panel every member can open. Read it. │
│ ─────────────────────────────────────────────────────────── │
│ You CAN see │
│ • Team-tagged goals and contributions │
│ • Challenge participation │
│ • Leaderboard points earned in the team │
│ • Last-active date (day only) │
│ │
│ You CANNOT see (ever) │
│ • Personal goals outside the team │
│ • Mood logs · Journal · Coach conversations │
│ • Lifetime XP / streaks │
│ • Friend graph · IP / device │
│ │
│ [ Open the member-facing version → ] │
└──────────────────────────────────────────────────────────────┘N8 · Invite-member modal (link + email)
Lifted out of N5 / N7d when triggered from anywhere else (e.g., empty-state CTA in N13).
┌──────────────────────────────────────────────┐
│ Invite to Habit Lab │
├──────────────────────────────────────────────┤
│ ◉ Team link (any sub-community) │
│ ○ Specific sub-community(s) [Pick ▾] │
│ │
│ https://app.objectuve.com/join-team/h7k2… │
│ [Copy] [QR] │
│ │
│ ── or email ── │
│ ┌──────────────────────────────────────────┐ │
│ │ name@example.com │ │
│ └──────────────────────────────────────────┘ │
│ Pre-join: ☐ Morning Movers ☐ Deep Work Pod │
│ │
│ [ Cancel ] [ Send → ] │
└──────────────────────────────────────────────┘N9 · Create sub-community modal
┌──────────────────────────────────────────────┐
│ New sub-community │
├──────────────────────────────────────────────┤
│ Icon [emoji picker — 🌅] │
│ Name ┌────────────────────────────────────┐ │
│ │ Morning Movers │ │
│ └────────────────────────────────────┘ │
│ Short description (1 line) │
│ ┌──────────────────────────────────────────┐ │
│ │ 5am club. Daily check-ins. │ │
│ └──────────────────────────────────────────┘ │
│ Join policy │
│ ◉ Open to all team members │
│ ○ Request to join (lead approves) │
│ Lead [pick member ▾] │
│ ☐ Make this the default sub-community │
│ │
│ [ Cancel ] [ Create ] │
└──────────────────────────────────────────────┘N10 · Archive sub-community confirm
┌──────────────────────────────────────────────┐
│ Archive “Quiet Plate”? │
├──────────────────────────────────────────────┤
│ 9 members will lose access immediately and │
│ get a one-time notification. │
│ │
│ Posts and collective goals will be readable │
│ for 30 days, then archived. │
│ │
│ You can un-archive within 30 days from the │
│ Sub-Communities tab. │
│ │
│ [ Cancel ] [ Archive ] │
└──────────────────────────────────────────────┘N11 · Public join landing — /join-team/{code}
Purpose: Decode invite, route through auth, hand off to N12. Personas: Anonymous or signed-in invitee. Trigger: Invite link click. Scope: V1. File targets: JoinTeamView.vue.
┌──────────────────────────────────────────────────────────────┐
│ │
│ 🌱 You're invited to │
│ Habit Lab │
│ │
│ Coached by Maya Okonkwo · 47 members │
│ │
│ Maya is inviting you to a private team on Objectuve. │
│ You'll choose which rooms (sub-communities) to join next. │
│ │
│ [ Continue ] │
│ │
│ ▸ What can Maya see about me? │
│ │
│ New here? You'll create a free Objectuve account first. │
└──────────────────────────────────────────────────────────────┘Signed-out → Continue routes through Clerk sign-up → returns here → N12. Signed-in → Continue → N12. Invite invalid/expired/at-cap → shows N26.
N12 · Sub-Community Browser (self-select)
Purpose: The biggest UX moment for multi-community Teams (PRD §7.2). Already deeply specified by phase-7-teams-claude-design-prompt.md — the wireframe below is the structural skeleton. Personas: New team member, first session only (or surfaced again via "Join more rooms" CTA). Trigger: Invite acceptance, only when team.communities.count > 1 AND not all are gated. Scope: V1. File targets: SubCommunityBrowser.vue.
┌──────────────────────────────────────────────────────────────┐
│ Step 2 of 2 · Almost there │
│ │
│ 🌱 Habit Lab │
│ Coached by Maya Okonkwo · 47 members │
│ You're in. Pick the rooms that match what you're working │
│ on — you can join more anytime. │
│ │
│ ╭──────────────────────────────────────────────────────╮ │
│ │ #welcome · Default │ │
│ │ Team-wide intros and Maya's weekly nudges. │ │
│ │ 47 members ✓ You're already in │ │
│ ╰──────────────────────────────────────────────────────╯ │
│ │
│ ╭───────────────────────╮ ╭───────────────────────╮ │
│ │ 🌅 Morning Movers │ │ 📚 Deep Work Pod │ │
│ │ 18 members · Priya │ │ 12 members · Marcus │ │
│ │ Daily 5am check-ins │ │ Two 90-min blocks/day │ │
│ │ [ Join ] │ │ [ Join ] │ │
│ ╰───────────────────────╯ ╰───────────────────────╯ │
│ ╭───────────────────────╮ ╭───────────────────────╮ │
│ │ 🥗 Quiet Plate │ │ 🧗 Weekend Warriors │ │
│ │ 9 members · Sam │ │ 14 members · Jules │ │
│ │ Slow food habits │ │ Saturday long-form │ │
│ │ [ Request to join ] │ │ [ Join ] │ │
│ ╰───────────────────────╯ ╰───────────────────────╯ │
│ │
│ ╭──────────────────────────────────────────────────────╮ │
│ │ 🔒 Maya can see your team activity — check-ins, │ │
│ │ collective contributions, leaderboard points. She │ │
│ │ cannot see your personal goals, mood, or Coach. Ever.│ │
│ │ ▸ How this works│ │
│ ╰──────────────────────────────────────────────────────╯ │
│ │
│ [ Join Habit Lab + 2 rooms ] │
│ Skip for now (default only) │
│ I'm not Devon → switch account │
└──────────────────────────────────────────────────────────────┘When team.communities.count == 1, skip this screen entirely — auto-join default and land on N13.
N13 · Team Home — dashboard
Purpose: Member's daily landing once they're inside a Team. Personas: Member, Admin. Trigger: Tab-bar Teams → pick team; or default landing for team-only members. Scope: V1. File targets: TeamHomeView.vue.
┌──────────────────────────────────────────────────────────────┐
│ ☰ Habit Lab ▾ 🔔 👤 │
├──────────────────────────────────────────────────────────────┤
│ Sub-community: [ #welcome ▾ ] │
│ (Switcher lists rooms you've joined + "Browse all rooms") │
├──────────────────────────────────────────────────────────────┤
│ ╭──────────────────────────────────────────────────────────╮ │
│ │ 🎯 Team goal · 1000 check-ins by Aug 31 │ │
│ │ ▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░ 642 / 1000 │ │
│ │ You're contributing 47. [ Add another goal → ] │ │
│ ╰──────────────────────────────────────────────────────────╯ │
│ │
│ Today │
│ • You logged "Ran 5km" · 2h ago +5 team pts │
│ • Priya completed "Read 30 min" · 4h ago │
│ • Marcus posted in #welcome · 6h ago │
│ │
│ This week │
│ [ 📊 Leaderboard ] [ 🏆 Challenges ] [ 👥 Members ] │
│ │
│ ╭──────────────────────────────────────────────────────────╮ │
│ │ Monday recap │ │
│ │ Last week you logged 18 check-ins. That's #3 on the team │ │
│ │ — and #1 in consistency. │ │
│ ╰──────────────────────────────────────────────────────────╯ │
└──────────────────────────────────────────────────────────────┘Trial / past-due / grace banner (N22) sits above the header strip when active.
N14 · Sub-Community switcher
Purpose: Pivot between rooms the member belongs to. Trigger: Tap Sub-community: ▾ in N13 chrome. Scope: V1. Hidden when team.communities.count == 1 or member belongs to exactly one room.
┌──────────────────────────────────────────────┐
│ Switch room │
├──────────────────────────────────────────────┤
│ ● #welcome 47 members │
│ ○ 🌅 Morning Movers 18 members │
│ ○ 🧗 Weekend Warriors 14 members │
│ ── │
│ + Browse all rooms │
└──────────────────────────────────────────────┘N15 · Collective Progress card
Purpose: Always-visible progress on the active collective goal in the current scope (team-wide on N13; sub-community-scoped on M1 community feed). Embedded in: N13, M1.
╭────────────────────────────────────────────────╮
│ 🎯 Team goal · 1000 check-ins by Aug 31 │
│ ▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░ 642 / 1000 │
│ You're contributing 47. [ Opt in / out ] │
╰────────────────────────────────────────────────╯If member hasn't opted in, primary CTA is "Contribute" → N17.
N16 · Collective Goal detail view
Personas: Member (own contribution + aggregate), Admin (aggregate + per-contributor counts). Scope: V1. File targets: CollectiveGoalDetailView.vue.
┌──────────────────────────────────────────────────────────────┐
│ ← Team goals │
│ │
│ 🎯 1000 check-ins by Aug 31 │
│ Scope: [Team-wide] · Created by Maya · 18 days left │
│ │
│ ▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░ 642 / 1000 │
│ │
│ ╭──────────────────────────────────────────────────────╮ │
│ │ You're contributing your goal: │ │
│ │ "Daily run" — 47 check-ins counted toward team │ │
│ │ [ Pause contribution ] │ │
│ ╰──────────────────────────────────────────────────────╯ │
│ │
│ Contributors (admin view) (members: see counts only) │
│ • Priya R. 142 │
│ • Devon S. 98 │
│ • Maya O. 76 │
│ • Anonymous member · 47 │
│ • Marcus T. 42 │
│ … │
│ │
│ 🔒 Your personal goal details are not visible to admins. │
└──────────────────────────────────────────────────────────────┘N17 · Collective Goal opt-in modal
Trigger: Tap "Contribute" on N15, or banner on N13, or opt-in row on personal goal (M7).
┌──────────────────────────────────────────────┐
│ Contribute "Daily run" to the team? │
├──────────────────────────────────────────────┤
│ Your check-ins on Daily run will count │
│ toward Habit Lab's 1000 check-ins goal. │
│ │
│ You can opt out anytime. Your personal goal │
│ details — title, notes, history — stay │
│ private. Only the count is exposed. │
│ │
│ Show me as ◉ Devon S. · ○ Anonymous member │
│ │
│ [ Cancel ] [ Opt in ] │
└──────────────────────────────────────────────┘N18 · Privacy contract panel — "What [Team] can see"
Personas: Member. Trigger: Settings → Privacy → "What [Team] can see"; also linked from N12 "How this works", from M7, from N17. Scope: V1. File targets: TeamPrivacyContractView.vue.
┌──────────────────────────────────────────────────────────────┐
│ ← What Habit Lab can see │
│ │
│ Maya (Team Owner) and Habit Lab admins CAN see │
│ • Goals you've tagged to Habit Lab or contributed to a team │
│ goal │
│ • Challenges you've joined and how you did │
│ • Leaderboard points you earned in Habit Lab │
│ • Your last-active day (not time) │
│ • The sub-communities you've joined │
│ │
│ They CANNOT see, ever │
│ • Any personal goal outside Habit Lab │
│ • Mood logs · Journal entries · Coach conversations │
│ • Lifetime XP, streaks, or check-in totals │
│ • Other teams you're part of │
│ • Your friends or allies graph │
│ • Your IP, device, or location │
│ │
│ Exported reports │
│ When Maya exports a CSV, it includes your display name, │
│ join date, last-active day, and team-scoped points only. │
│ No email. No personal goal titles. │
│ │
│ When you leave │
│ Your team contributions stay attributed as "Former member." │
│ Your personal account is untouched. │
│ │
│ [ Leave Habit Lab ] │
└──────────────────────────────────────────────────────────────┘N19 · Team Leaderboard view
Personas: Member. Scope: V1. File targets: TeamLeaderboardView.vue.
┌──────────────────────────────────────────────────────────────┐
│ ← Leaderboard │
│ │
│ Scope: [ Team-wide ▾ ] (or pick a sub-community) │
│ Period: ( Weekly ) ( Monthly ) ( All-time ) │
│ │
│ Mon 8/05 — Sun 8/11 │
│ │
│ 1 🥇 Priya R. 186 pts ↑ │
│ 2 🥈 Devon S. 142 pts ↑ │
│ 3 🥉 You 98 pts ↑ │
│ 4 Maya O. 76 pts → │
│ 5 Marcus T. 42 pts ↓ │
│ 6 Anonymous member 38 pts │
│ … │
│ │
│ Your week │
│ 18 check-ins · 2 milestones · 4 posts · 6 encouragements │
│ │
│ ▸ How points work ▸ Opt out of the board │
└──────────────────────────────────────────────────────────────┘For single-community teams, scope toggle is hidden.
N20 · Leaderboard opt-out toggle
Embedded in member settings → Privacy:
☐ Show me on Habit Lab's leaderboard
When off, you still earn points but appear as
"Anonymous member" on the board.N21 · Monday Recap (in-app card + push)
Trigger: WeeklyRecapJob Cron, Monday 9am team-timezone. Scope: V1. Push copy: "Habit Lab · last week's recap is ready." (one push max per week per team per member; counts against the §9 1-push/day cap)
╭──────────────────────────────────────────────╮
│ Monday recap · Habit Lab │
│ Last week you logged 18 check-ins. That's │
│ #3 on the team — and #1 in consistency. │
│ Team hit 642 / 1000 toward the August goal. │
│ [ See recap → ] │
╰──────────────────────────────────────────────╯N22 · Trial-ending / past-due / grace banner
Embedded above the Team chrome on every team screen for the owner.
─── Trial ending in 3 days ─────────────────────────────────────
Add a payment method to keep your team's leaderboards and
collective goals. [ Add card → ]
────────────────────────────────────────────────────────────────States: trial_ending_3d · past_due · grace_readonly. Each has tailored copy from PRD §7.1.
N23 · Team email — invite (TeamInviteMailer.team_invite_email)
Subject: Maya invited you to Habit Lab on Objectuve
Hi —
Maya Okonkwo invited you to join "Habit Lab", a private
accountability team for productivity coaching.
It's a small team — 47 members. You'd pick which rooms
to join after accepting.
[ Accept invite ]
If you don't recognize Maya, you can safely ignore this
email. The link expires in 14 days.N24 · Team email — trial ending / payment failed
Variants for T-3d, payment_failed_d0, payment_failed_d3, payment_failed_d6, grace_d7, downgraded_d14. Plain-text-friendly; one primary CTA per email; never alarmist.
N25 · Team email — welcome / upgraded / downgraded
TeamUpgradedJob: short welcome to owner + 14-day trial framing. Conversion-from-community: member-facing note ("Nothing changed for you — just new tools your admin can use.") Downgrade: TeamDowngradedJob to owner with 1-click resubscribe (30-day window).
N26 · Seat-cap blocker modal
┌──────────────────────────────────────────────┐
│ This team is full │
├──────────────────────────────────────────────┤
│ Habit Lab is at its 8-seat limit. │
│ │
│ Ask Maya to add a seat or remove a member, │
│ then try this link again. │
│ │
│ [ OK ] │
└──────────────────────────────────────────────┘Owner-side variant when adding seats above subscription:
12 members · 10 seats — add 2 seats to continue.
[ Add 2 seats (+$14/mo) ] [ Remove members ]3. V1.1+ shape-only wireframes
N27 · Bulk CSV invite
Already shown inside N7d. V1.1 only. PRD §8.9.
N28 · Team Admin Dashboard (analytics)
Scope: V1.1. PRD §8.2. Strictly aggregate per §6.
┌──────────────────────────────────────────────────────────────┐
│ Habit Lab · Dashboard │
├──────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Active 7d │ │ Active 30d │ │ Avg streak │ │
│ │ 31 / 47 │ │ 42 / 47 │ │ 4.6 days │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ Goal completion rate (team-scoped) │
│ ▓▓▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░ 58% │
│ │
│ Health flags (members inactive 7+ days) │
│ • Jules K. 9 days (last activity day shown) │
│ • Sam P. 11 days │
│ │
│ Sub-community activity │
│ • Morning Movers · 142 check-ins / wk · ▲ │
│ • Deep Work Pod · 88 check-ins / wk · ▼ │
│ • Quiet Plate · 32 check-ins / wk · → │
│ • Weekend Warriors · 31 check-ins / wk · → │
│ │
│ [ Export CSV (team-scoped) ] │
└──────────────────────────────────────────────────────────────┘No mood data (Open Question #4 → No, per PRD).
N29 · Custom Badges admin
Lives inside sub-community settings. Defines name, emoji, trigger (manual or rule-based on team challenge participation).
N30 · Manager View (grid)
Scope: V1.1. PRD §8.4.
Members (47) [ Filter ▾ ] [ CSV → ] │
┌────────────────────────────────────────────────────────────┐│
│ Name Goals Team-goal contrib Streak Last active ││
├────────────────────────────────────────────────────────────┤│
│ Priya R. 3 142 12d today ││
│ Devon S. 2 98 4d 2d ago ││
│ Marcus T. 4 42 6d 4d ago ││
│ Jules K. 1 0 0d 9d ago ⚠ ││
│ … ││
└────────────────────────────────────────────────────────────┘│Sort, filter, no personal goal titles, no mood.
N31 · Accountability pair card
Embedded in N13 (V1.1).
╭──────────────────────────────────────────────╮
│ 🤝 Accountability pair │
│ This week you're paired with Marcus T. │
│ Both of you have "Daily reading" goals. │
│ [ Send encouragement ] [ Skip this week ] │
╰──────────────────────────────────────────────╯N32 · Sub-community-scoped invite link
Same shape as N8 but generated by a sub-community Lead, pre-checks just their room. V1.1. PRD §8.10.
N33 · Per-team brand customization
Subtab in N7. V1.2.
Brand color [HSL picker — contrast-validated]
Team logo [Upload — 200x200 min, square crop]
Welcome msg [textarea — shows on N11]N34 · Slack / MS Teams integration config
Subtab in N7. V1.2. Picks workspace, channel, events to forward (defaults: weekly digest + collective goal hits only).
N35 · External Coach role extension
Subtab in N7b. V1.2. "Add external coach (read-only) — free addon, 1 per team."
4. MODIFIED existing surfaces — diff sketches
For each, the wireframe shows only the delta vs. master.
M1 · Community feed (sub-community variant)
When community.team_id set:
┌──────────────────────────────────────────────────────────────┐
│ ☰ Habit Lab ▾ Sub-community: [ Morning Movers ▾ ] │
├──────────────────────────────────────────────────────────────┤
│ ╭──── 🎯 Sub-community goal · 200 5am check-ins ────────╮ │ ← NEW (N15)
│ │ ▓▓▓▓▓▓▓▓▓░░░░░░░░░░░ 88 / 200 │ │
│ ╰──────────────────────────────────────────────────────╯ │
│ │
│ Feed posts (existing — unchanged structure) │
│ • Priya: "Up at 4:47, ran 6km" ❤️ 🔥 │
│ • Marcus: "Block 1 done" │
│ … │
│ │
│ [ Quick post ] [ Encourage Priya → ] │
└──────────────────────────────────────────────────────────────┘For non-team communities, surface is unchanged.
M2 · Community Settings — "Upgrade to Teams"
Existing settings gain one new row:
─────────────────────────────────────────────
Upgrade
This is a free private community. Convert to
a Team to unlock collective goals, leader-
boards, and seats.
[ Upgrade to Teams ] ← opens N6
─────────────────────────────────────────────M3 · Marketing landing — Teams pricing
marketing_landing/index.html adds:
Teamsnav entry → anchor to pricing panel- N1 pricing card
- "Teams" feature section (collective goals + leaderboards + coach role) above the existing Personal-only sections
- Schema.org
Productmarkup for SEO (delegate to seo-specialist before merge)
M4 · App side-nav
☰ Menu
─────────────
🏠 Home
🎯 Goals
🤝 Communities
─── Teams ─── ← NEW section appears only when user has ≥1 TeamMembership
• Habit Lab
• Acme Wellness
+ Browse / Create
─────────────
⚙️ SettingsFor users with no team, the section is absent.
M5 · User settings → Privacy
Adds one row per Team:
─────────────────────────────────────────────
What your teams can see
• Habit Lab ▸ ← opens N18
• Acme Wellness ▸
─────────────────────────────────────────────M6 · User profile (own)
Adds a "Teams" strip:
Teams
• Member of Habit Lab · since 4/12/2026
• Previously a member of Reading Club (left 1/2026)Only visible to the user themselves.
M7 · Personal Goal detail
Existing goal screen adds:
─────────────────────────────────────────────
Team contribution
This goal counts toward "1000 check-ins" in
Habit Lab. [ Pause / Resume ]
─────────────────────────────────────────────If not opted in, row offers [ Contribute to a team goal → ] opening N17.
M8 · Personal Goal create
After "Goal name" / "Target" fields, add:
─────────────────────────────────────────────
☐ Also contribute this goal to Habit Lab's
"1000 check-ins by Aug 31"
(Only the count is shared. Your personal
notes and history stay private.)
─────────────────────────────────────────────Only renders when a team-wide collective goal exists with matching metric.
M9 · Notifications inbox
Adds categories team_invite, team_billing, monday_recap, collective_goal_milestone. Per §9, max 1 push per member per day total across all categories.
M10 · Onboarding (post-signup, team-invite arrival)
Existing personal-onboarding flow has a branch:
[ post-signup ]
│
├── arrived via team invite cookie? → N11 → N12 → N13
│
└── normal sign-up → existing personal-goal seed flowThe personal-goal seed flow becomes accessible later from the goal create screen for team-only members.
M11 · Admin Dashboard (internal Objectuve admins)
New top-level view in admin_dashboard/:
Teams (internal)
- List: name, owner, plan, seat utilization, MRR contribution, status
- Filters: status (trialing / active / past_due / grace / canceled)
- Per-team detail: subscription history, webhook log, member churnNo member-level data is exposed (we eat our own privacy dog food).
M12 · Mailer base layout
V1: emails reuse Objectuve chrome (no per-team brand). V1.2: Team logo + accent color injected from N33 settings.
M13 · GraphQL Apollo cache shapes
type CommunityType {
id, name, slug, private,
team: TeamType # NEW (nullable)
isDefaultForTeam: Boolean! # NEW
…
}
type TeamType {
id, name, slug,
subscription: TeamSubscriptionType,
membership: TeamMembershipType, # current user's membership
communities: [CommunityType!]!,
…
}All UI components branch on community.team being non-null to render team chrome (M1).
M14 · Feature flag registry
Per PRD §11 + CLAUDE.md gotcha:
| Flag | Type | Registry | PostHog |
|---|---|---|---|
teams_enabled | boolean | retired at GA 2026-07-08 (PR #1498, OBJ-1096) — removed from featureFlags.ts | archived, project 368400 |
teams_billing_v1 | boolean | ↑ | ↑ |
teams_collective_goals | boolean | ↑ | ↑ |
teams_leaderboards | boolean | ↑ | ↑ |
teams_bulk_invite | boolean | ↑ | ↑ |
CI posthog-flag-drift enforces parity.
5. Dual-context user model — personal account × team seat
A single user can be a personal Objectuve user, a member of one or more Teams, an admin of a Team, and still be all of those at once. This section defines how the surfaces compose for that dual-context user, because the answer determines the §6 data-boundary enforcement contract on every modified surface.
5.1 Principle — one identity, one Coach, one Hall, scope-aware overlays
The user has one Objectuve account. Team membership is a lens applied to existing personal surfaces — not a parallel app, not a context switcher modal. This is the calm path: it preserves the lifetime narrative (streaks, badges, XP, Coach memory) that drives retention, and avoids forcing the user to decide which "mode" they're in before they act.
Operationally:
| Concept | Scope | Notes |
|---|---|---|
| Account / identity / avatar / display name | One (personal) | V1.2 may add per-team display name override (Open Q below) |
| Coach (assistant) | Personal only — never sees team activity | Hard §6 rule; coach conversation history is in the "cannot see ever" list |
| Achievement Hall | One, lifetime; team-earned badges filterable | Custom team badges (N29, V1.1) sit in same Hall with a "Habit Lab" filter chip |
| Streaks | Personal, lifetime — admin cannot see | Team leaderboard points (§7.4) are a separate scoring system, period-scoped |
| XP (lifetime) | Personal — invisible to team admins | Team leaderboard points are visible inside their scope only |
| Goals | Personal, optionally tagged for team contribution | Opt-in per goal (N17); admins see only counts of contributing events, never the goal |
| Mood log / Journal | Personal only — never team-visible | Hard §6 rule; surfaced explicitly in N18 |
| Notifications inbox | One, categorized | Per-team mute and per-category mute available in settings |
| Settings | One, with a per-team subsection | Privacy contract (N18) and notification overrides per team |
| Profile (own view) | One, with a "Teams" strip | M6 extension |
| Profile (team-admin view of a member) | Team-scoped slice | Strictly §6 columns; no personal goals, mood, streaks |
| Data export (user-requested GDPR export) | All personal + team-scoped contributions | Distinct from team admin CSV export, which is team-scoped only |
5.2 Surface-by-surface diff for dual-context user
5.2.1 Home dashboard (M-dashboard, new diff)
Today's personal Home shows: today's goals, streak, mood prompt, Coach card, recent badges. For a dual-context user, the Home does not split into tabs — it composes:
┌──────────────────────────────────────────────────────────────┐
│ Home │
├──────────────────────────────────────────────────────────────┤
│ Today │
│ • Daily run [✓ Check in] │
│ • Read 30 min [✓ Check in] │
│ │
│ ╭──── Your streak — 12 days ────────────────────╮ │
│ │ 🔥 Keep it going. Mood: how are you today? ▸ │ │
│ ╰─────────────────────────────────────────────╯ │
│ │
│ ╭──── Coach ──────────────────────────────────╮ │
│ │ "Want to plan tomorrow's two big rocks?" ▸│ │
│ ╰────────────────────────────────────────────╯ │
│ │
│ ─── Your teams ─────────────────────────────── ← NEW strip │
│ ╭───────────────────────╮ ╭───────────────────────╮ │
│ │ Habit Lab │ │ Acme Wellness │ │
│ │ 🎯 642 / 1000 · #3 │ │ 🎯 88 / 200 · #7 │ │
│ │ Last check-in: today │ │ Last check-in: 2d ago │ │
│ │ [ Open → ] │ │ [ Open → ] │ │
│ ╰───────────────────────╯ ╰───────────────────────╯ │
│ + Browse teams │
│ │
│ Recent badges (lifetime) │
│ 🏃 7-day streak · 🥇 Habit Lab — First Contributor · … │
└──────────────────────────────────────────────────────────────┘Key points:
- The personal modules lead. Teams strip lives below, not above.
- Each team card surfaces the active collective goal + the user's rank in that team's current period (no rank-change push — only on-open per §9).
- "Recent badges" interleaves personal + team-custom badges (N29) chronologically; a small "Habit Lab" pill tags team-earned ones.
- For a user with zero teams, the strip is absent. For a user with 5+ teams, the strip caps at 2 with a "Browse teams" overflow.
5.2.2 Goals tab (M7 expanded)
Personal Goal list shows every personal goal. Goals that contribute to a team collective goal get a discreet pill:
┌──────────────────────────────────────────────┐
│ Your goals [ + New ] │
├──────────────────────────────────────────────┤
│ ● Daily run │
│ ▓▓▓▓▓░░░ 47 / 90 check-ins │
│ [Habit Lab · contributing] │
│ │
│ ● Read 30 min │
│ ▓▓▓▓▓▓▓▓░ 68 / 90 │
│ │
│ ● Meditation │
│ ▓▓░░░░░░░ 15 / 90 │
│ [Acme Wellness · contributing] │
└──────────────────────────────────────────────┘The pill is informational only. Tapping a goal opens the existing detail view; the "Team contribution" row from M7 manages opt-out.
A goal can contribute to at most one collective goal at a time in V1 (Open Q below for whether to allow multi-team contributions of the same goal). The pill makes the binding visible at-a-glance so the user never wonders "what's seeing this?"
5.2.3 Achievement Hall (new diff, M-hall)
The existing Hall is lifetime-scoped. Extending for teams:
┌──────────────────────────────────────────────────────────────┐
│ Achievement Hall │
├──────────────────────────────────────────────────────────────┤
│ Filter: ( All ) ( Personal ) ( Habit Lab ) ( Acme Wellness ) │
│ │
│ Earned │
│ 🥇 First Streak · Common · Personal · 4/12/2026 │
│ 🥈 Goal Crusher · Rare · Personal · 4/20/2026 │
│ ✨ First Contributor · Custom · Habit Lab · 5/03/2026 │
│ … │
│ │
│ In progress │
│ ⚙️ 30-day streak · 12 / 30 (Personal) │
│ ⚙️ Pod regular · 14 / 20 check-ins (Habit Lab — Deep Work) │
└──────────────────────────────────────────────────────────────┘- Custom team badges (PRD §8.1 / N29) live in the same Hall — same visual treatment, with a team-source tag.
- "Personal" is the default filter; team filters appear only when the user has earned at least one badge in that team.
- Admins do NOT see a member's Hall (§6: no lifetime data exposure). Admin-view of a member shows team-scoped custom badges only.
- When a user leaves a team, their custom-badge earnings stay in their Hall, tagged "(former member)" — same anonymization model as collective-goal contributions.
5.2.4 Coach (no change — strictly personal)
Coach is the loudest §6 rule and it deserves an explicit statement in the doc, not just a one-line bullet:
Coach has zero awareness of any Team the user belongs to. Coach memory, prompt context, conversation history, and recommendation surface are scoped to the personal account. A user who joins Habit Lab does not see Coach references to Habit Lab; an admin in Habit Lab cannot see anything Coach said. Coach is the user's private thinking partner; Teams is their accountability surface. The two never cross.
UI implication: no Coach card on N13 (Team Home), no Coach surface on N19 (Leaderboard), no Coach prompts referencing team activity even when the user is clearly active in a team. If we want a team-aware nudge ("Your team is at 642/1000 — want help planning?"), it ships as a team-scoped in-app card on N13, not as a Coach turn.
5.2.5 Profile (M6 expanded)
Own profile view — full transparency:
┌──────────────────────────────────────────────┐
│ Devon S. │
│ Joined 4/02/2026 · 12-day streak │
│ │
│ Teams │
│ • Habit Lab — member since 5/03 · 3 rooms │
│ • Acme Wellness — member since 5/18 · 1 room │
│ • Previously: Reading Club (left 1/2026) │
│ │
│ Personal stats (only you can see) │
│ 4,182 lifetime XP · 47 goal events · │
│ 18 badges earned │
│ │
│ ▸ Privacy: what your teams can see │
└──────────────────────────────────────────────┘Team-admin view of the same user (surfaced from N7b "View team activity"):
┌──────────────────────────────────────────────┐
│ Devon S. · Member of Habit Lab │
│ Joined 5/03 · Active today · 3 rooms │
│ │
│ Team-scoped activity │
│ • 47 team-tagged events │
│ • 142 leaderboard points this week │
│ • Contributing to: "1000 check-ins" goal │
│ │
│ Custom team badges │
│ ✨ First Contributor │
│ │
│ 🔒 Personal goals, mood, journal, Coach, │
│ lifetime stats — not visible. │
└──────────────────────────────────────────────┘The "what you can't see" footer is not legalese — it's the trust artifact, identical principle to N18 but rendered for the admin.
5.2.6 Settings (M5 expanded)
The Settings tree gains a "Your teams" branch:
Settings
├── Account
├── Profile
├── Notifications
│ ├── Personal
│ ├── Habit Lab ← per-team mute / digest preferences
│ └── Acme Wellness
├── Privacy
│ ├── Personal (existing — friends, public profile, etc.)
│ └── Teams
│ ├── What Habit Lab can see ← N18
│ ├── What Acme Wellness can see ← N18
│ └── Leave a team
├── Appearance
└── Data & exportData & export is unchanged — the user's GDPR data export includes everything personal + their team-scoped contributions. This is distinct from the admin CSV export (N28) which is team-scoped only and excludes personal data by §6.
5.2.7 Notifications inbox (M9 expanded)
One inbox, multi-source, categorized — never split into "personal" and "team" tabs:
┌──────────────────────────────────────────────┐
│ Inbox │
│ ( All ) ( Personal ) ( Habit Lab ) ( Acme ) │
├──────────────────────────────────────────────┤
│ Today │
│ 🏆 Devon · You earned the 30-day streak │
│ 📣 Habit Lab · Monday recap — see N21 │
│ 🤝 Priya encouraged your check-in │
│ │
│ Earlier │
│ 💌 Acme Wellness · Trial ends in 3 days │
│ … │
└──────────────────────────────────────────────┘Per §9, total push notifications across all sources are bounded at 1/day; the user does not pay an attention tax for joining more teams.
5.2.8 App nav (M4 expanded)
Mobile bottom-tab bar stays as-is — 5 personal tabs (Home, Goals, Communities, Coach, Profile). Teams do not get a top-level tab. Instead:
- The Communities tab gains a "Teams" section at the top listing teams the user belongs to (Habit Lab, Acme Wellness), above the existing public/free community list.
- Tapping a team navigates to N13 (Team Home). Back navigates to Communities, not to a separate "Teams root" — there is no separate root.
┌────────────────────────────────────────┐
│ Communities │
├────────────────────────────────────────┤
│ Your teams │
│ ● Habit Lab 47 members → │
│ ● Acme Wellness 32 members → │
│ │
│ Your communities (free / public) │
│ ○ Reading Club → │
│ ○ Trail Runners → │
│ │
│ + Browse / Create │
└────────────────────────────────────────┘This preserves the "one app" mental model and avoids a Teams tab competing visually with Coach.
5.2.9 Onboarding split (M10 refined for dual-context arrivals)
Two arrival paths converge into one user state:
Path A — personal-first user joins a team later.
- User has 30 days of personal goals, mood, badges.
- Receives invite link → N11 → N12 (if multi-community) → lands on N13.
- No personal data is touched. Coach memory persists. Streaks persist.
- Goals tab gains team pills as the user opts in to contribute (N17).
- Settings gains the new team subsection. Notifications inbox gains the team category.
Path B — invite-first user (signed up via team invite).
- Clicks invite link, no Objectuve account → Clerk signup → returns to N11 → N12 → N13.
- Personal onboarding is deferred, not skipped. First time the user taps Home (N5-personal), they see an "It looks like you're brand new — want to set up a personal goal?" card. Optional. Skippable forever.
- Coach is initialized on first conversation, with no team context (§6).
- If the user leaves the team and was Path B, their account survives as a normal personal account. No "team-only" account type exists.
5.2.10 Leaving a team — what stays, what goes
When a dual-context user leaves a team:
- Personal everything (account, goals, mood, journal, Coach, streaks, lifetime XP, lifetime badges including team-custom badges earned, friends, allies, public profile) is untouched.
- Their team-scoped contributions become "Former member" entries on collective goals and leaderboards.
- The team card disappears from Home, Communities, Settings, Notifications inbox filters.
- The team is listed on the user's own Profile under "Previously a member of …" — visible only to them.
- The privacy contract panel (N18) for that team is archived (read-only) and accessible from settings → Data & export for one year, then purged.
5.3 Edge cases worth naming
- User is admin of Team A and member of Team B. They see admin tooling in A's chrome only; B looks like a normal member experience. Single nav, two surfaces, no "switch role" affordance — role is implicit in which team you're inside.
- User is the billing owner of a team they never use for personal goal-tracking. (Common for coaches.) The "Your teams" Home strip still surfaces — but their Coach, streak, Hall stay personal. Coaches who don't track personal goals will see a sparse personal Home and a rich team chrome; that's correct.
- User in 5+ teams. Home strip caps at 2 most-recent-active; Communities tab shows all. Notifications inbox filters become a
▾overflow at >4 sources. No artificial limit on team count. - User in two teams that both have a collective goal of "1000 check-ins." Their "Daily run" goal can contribute to one at a time (V1) — pill makes the binding explicit. Switching requires opting out then in. (Open Q: should V1.1 allow contributing to multiple? Probably yes, but counts only once per scope per event — needs a dedup rule.)
- User is on Supporter tier ($3/mo) AND in a paid team. Supporter cosmetics (themes, aura) apply across all surfaces including team chrome (because identity is one). Team Owner billing is independent.
- Admin tries to use Coach to ask about their team. Coach says something like: "I don't see your team's activity — that's by design. Want help thinking about how to run a team check-in?" Coach can talk about coaching practice in general; it just cannot read team data.
- User mutes a team. Mute means: no push notifications from that team. The team still shows on Home strip and Communities tab; the user is opting out of attention, not membership. (Distinct from leaving.)
- GDPR / data deletion request from a team member. Personal data is purged; their team-scoped contributions persist as "Former member" (anonymized) so the team's historical metrics stay coherent. The user's Privacy panel says this verbatim.
5.4 New / modified surface IDs introduced by this section
Additive only — no existing wireframes are invalidated.
| ID | Surface | Type |
|---|---|---|
| M15 | Home dashboard — "Your teams" strip | Modified |
| M16 | Goals list — team-contribution pill | Modified |
| M17 | Achievement Hall — team filter + custom-badge integration | Modified |
| M18 | Coach — §6 affirmation (no UI change; documented constraint) | Constraint |
| M19 | Profile — own view "Teams" strip + admin-scoped member view | Modified |
| M20 | Settings tree — "Your teams" branch | Modified |
| M21 | Notifications inbox — multi-source filter chips | Modified |
| M22 | Communities tab — "Your teams" pinned section | Modified |
| M23 | Personal onboarding card for Path B users | New (low-weight) |
| M24 | Leaving-a-team archive of N18 in Data & export | New (V1.2 polish) |
These slot into §4 of this doc when the team formally signs off on the dual-context model. Until then they live here.
5.5 Open questions for the dual-context model
- Per-team display name override. Should a user be able to present as "Dr. Devon Sun" in Habit Lab and "Devon" in Acme Wellness? Recommendation: defer to V1.2. Single display name + avatar in V1.
- Coach team-awareness toggle. Some users may want Coach to know they have a team. Strict reading of §6 says no. Recommendation: keep no in V1; revisit at SOC 2 phase with an explicit opt-in.
- Multi-team contribution of a single personal goal. V1 = one-at-a-time. V1.1 likely = many-to-many with per-scope dedup.
- Team-custom-badge weighting in lifetime XP. Should custom team badges (N29) award lifetime XP that admins cannot see? Recommendation: yes — same XP rules as personal badges. Admins see only the badge earned within team scope, never the XP total.
- Mute-vs-leave UX. Mute is one tap from any team notification (per §9). Should there also be a "snooze 30d" middle option? Recommendation: defer; mute + leave covers V1.
- Team-card recency rule for Home strip cap. "Most-recent-active" by last check-in date in that team. Tie-break: largest collective-goal delta. Confirm with product.
- Path B users who never set up a personal goal. How long before the personal-onboarding card stops showing? Recommendation: stop after 60 days of no interaction; surface again on next streak-eligible team check-in.
5.6 Mapping to PRD §6 (data boundary) — the dual-context safety check
The data-boundary contract is unchanged, but the dual-context view sharpens what each row means at the render layer:
| §6 rule | Personal surface | Team surface | Risk if violated |
|---|---|---|---|
| Personal goals invisible to admins | Goals tab shows all | Member-view (N7b) shows team-tagged only | High — kills the trust artifact |
| Mood / journal invisible | Personal modules on Home | Not rendered at all in team chrome | High |
| Coach invisible | Coach card on Home + Coach tab | Not rendered at all in team chrome | High |
| Lifetime XP / streaks invisible | Profile (own) shows | Member-view (admin) shows period-scoped only | Medium |
| Last-active truncated to day | Personal profile shows real time | Member-view shows day only | Low |
Every modified surface in §5.2 has been audited against this table. The single biggest risk vector is the Home dashboard composition: any widget that pulls team data into a personal-surface position must be reviewed for accidental cross-leak. We commit to a TeamScopedView Vue mixin (analog of the Rails TeamAccessPolicy from §5 of the PRD) that all team-data widgets must use; rendering a team widget without it should fail a Vitest contract test.
6. Coverage check vs. PRD §7
| PRD subsection | Wireframe IDs |
|---|---|
| §7.1 Billing & Subscriptions | N3, N4, N5, N7a, N22, N23, N24, N25 |
| §7.2 Team Invites & Sub-Community Self-Select | N5, N6, N7b, N7c, N7d, N8, N9, N10, N11, N12, N13, N14, N26, M2, M10 |
| §7.3 Team Goals (Collective Progress) | N13, N15, N16, N17, N18, M7, M8 |
| §7.4 Team Leaderboards | N13, N19, N20, N21 |
| §6 Data Boundary | N7e, N16 (admin slice), N18 (member-facing) |
| §8.1 Custom Badges | N29 |
| §8.2 Team Admin Dashboard | N28 |
| §8.3 Accountability Pair | N31 |
| §8.4 Manager View | N30 |
| §8.5 Priority Support | (no UI surface — routing only) |
| §8.7 Slack / MS Teams | N34 |
| §8.8 Brand customization | N33 |
| §8.9 Bulk CSV Invite | N27 |
| §8.10 Sub-Community-Scoped Invite Link | N32 |
| External Coach role (Open Q #13) | N35 |
Every V1 MVP feature in PRD §7 maps to at least one wireframe; every V1.1+ shape-only feature has at least a sketch.
7. Open design questions surfaced by this exercise
These complement PRD §12 but are scoped to UI:
- Sub-community switcher placement — top-bar dropdown (current sketch) vs. left-rail sidebar on desktop. Decide before N13 build.
- Default-community badging — is "Default" pill enough, or do we tag it
Lobbyinstead? Tested in design prompt for N12; revisit after Maya-cohort review. - Monday Recap rendering — inbox card only, or also banner on N13? Default: both, with banner dismissable.
- Privacy-panel link weight on N12 — currently a footnote strip; trust research may justify promoting it.
- Team switcher (M4) ordering — alphabetical vs. last-active. Default: last-active descending.
- Empty leaderboard state for 2-member teams — copy is in §7.4; visual treatment (illustration vs. text-only) TBD.
- Multi-team push grouping — when a member is in 2+ teams, do Monday Recaps combine into one push or stay separate? Default: separate (clearer attribution), capped by §9 1/day rule.
- Admin "join sub-community to moderate" affordance — PRD §6 says no silent observation; UI needs to show admins this is a member-visible action. Sketch needed.
8. Sequencing (mirrors PRD §Appendix C, UI lens)
| Sprint | Wireframes that must ship | Behind |
|---|---|---|
| 1 | (data model only — no UI) | — |
| 2 | N3, N4, N5, N7a, N22, N23, N25 | teams_billing_v1 |
| 3 | N7, N7b, N7c, N7d, N7e, N8, N9, N10, N11, N12, N13, N14, N26, M1, M2, M4, M5, M6, M10, M13 | teams_enabled (retired at GA, PR #1498 — no flag gate today) |
| 4 | N19, N20, N21, M9 | teams_leaderboards |
| 5 | N15, N16, N17, N18, M7, M8 | teams_collective_goals |
| 6 | (closed beta — bug-fix only) | — |
| 7 | N28, N29, N27 | teams_bulk_invite |
| 8 | N30, N31, N32 | — |
| 9 | (priority support; no UI) | — |
| 10 | M3 (pricing page live), all flags retired | — |
9. Next steps for designers
- Validate N12 against the existing
phase-7-teams-claude-design-prompt.md— they should match. - Build Figma boards (or Claude Design artifacts) for the top 5 surfaces in order: N12 → N13 → N19 → N7c → N16. Those carry the multi-sub-community story end-to-end.
- Run a flow walkthrough with one beta-cohort admin (Maya analog) before Sprint 3 kicks off.
- Confirm the data-boundary copy on N18 with legal/PBC counsel.
End of surfaces & wireframes doc.