Skip to main content

Milestone 4: Onboarding and tenant settings

Purpose: New tenants complete the onboarding wizard; admins can edit org settings; feature flags are available for gating.

Exit state: Onboarding wizard (org → first inbox → invite optional → done); Settings → General (org name, slug, timezone, danger zone); feature flags DB and config loader.

Spec reference: §2.1 Tenant onboarding wizard, §2.9 Tenant settings, §2.9 Feature flags, §5.19 FeatureFlag, §5.21b FeatureFlagOverride, §6.2 Onboarding wizard, §6.10 Onboarding, settings/general.

Prerequisites: M03 (App shell). First inbox step in wizard can stub connection (M05) or link to connect flow.


4.1 Onboarding wizard

Tasks

  1. Wizard route and layout

    • /app/[slug]/onboarding: full-screen or prominent layout (no sidebar or minimal) so user focuses on steps.
    • Step indicator (e.g. 1/4, 2/4). Back / Next; persist current step (e.g. in tenant or session so refresh resumes).
  2. Step 1: Welcome / org confirm

    • Show tenant name and slug (editable or read-only from signup). User confirms or edits; validate slug unique and URL-safe.
    • On Next: update tenant name/slug if changed; move to step 2.
  3. Step 2: Connect first inbox

    • Option A: Embed connect-inbox flow (M05) — choose type (IMAP, Gmail, Microsoft), then OAuth or form, test connection, save. On success → step 3.
    • Option B (stub): "Connect your inbox" CTA that links to Settings → Inboxes → Add, or show placeholder "You can connect an inbox in Settings"; Skip or Next to step 3.
    • Spec: "Connect your first inbox" is required in wizard; recommend implementing minimal connect (at least one type) or explicit Skip for M04 and require inbox in M05.
  4. Step 3: Invite team (optional)

    • Form: add one or more emails with role (admin/agent/viewer). "Send invites" or "Skip".
    • If Skip: go to step 4. If Send: create invitation rows, send invite emails (Postmark template; M09 implements full invite flow); then step 4.
    • For M04, invite creation can be minimal (invitations table + send one email per invite); full accept flow in M09.
  5. Step 4: Done

    • Summary: org name, inbox count, invites sent. CTA "Go to inbox" or "Go to tickets".
    • On CTA: set tenants.onboarding_completed_at = now(); redirect to /app/[slug]/tickets.
  6. Persistence and redirect

    • If user exits mid-wizard, next visit to /app/[slug]/** (middleware M02) redirects back to /app/[slug]/onboarding until completed.
    • Store step in tenant (e.g. onboarding_step if added to schema) or in session so "Next" and "Back" and refresh work.

Acceptance criteria

CriterionStatus
New tenant (from M02 signup) lands on /app/[slug]/onboarding.
Steps 1–4 are visible and navigable (Back/Next); step 2 either connects inbox or skips; step 3 invites or skips.
Completing step 4 sets onboarding_completed_at and redirects to /app/[slug]/tickets.
If user leaves and returns before completing, middleware redirects to onboarding again.
After completion, visiting /app/[slug]/onboarding redirects to tickets (or show "Already completed" and link to tickets).

4.2 Settings → General

Tasks

  1. Settings layout

    • /app/[slug]/settings/layout.tsx: settings nav (General, Inboxes, Team, Billing, SLA, Snippets, Webhooks, API, SSO, Audit). Only General and optionally placeholders for others in M04.
    • Content area: render child route (General = form).
  2. General form

    • Fields: Organization name, Slug, Timezone (searchable select or combobox).
    • Validation: slug unique, URL-safe; name non-empty. Save via tRPC; update tenants row.
    • Success: toast or inline message. Slug change warning: "The previous URL will stop working; notify your team."
  3. Danger zone

    • Section: "Delete organization". Button opens confirmation (AlertDialog); require typing org name to confirm (Section 10.10). On confirm: delete tenant and related data (cascade or explicit); cancel Stripe if any; redirect to /no-workspace or /login. Defer full delete implementation to M10 if billing not yet integrated; document "blocked until M10" or implement soft delete only for M04.

Acceptance criteria

CriterionStatus
Admin can open Settings → General and edit org name, slug, timezone; save persists to DB.
Slug change shows warning; after save, new slug works and old slug 404s for app routes.
Danger zone visible; delete either implemented (with Stripe cancel when in M10) or documented as coming in M10.

4.3 Feature flags

Tasks

  1. Schema

    • feature_flag_globals (flag_key PK, enabled, description) — global defaults.
    • feature_flags (tenant_id, flag_key, enabled) — per-tenant overrides (unique tenant_id, flag_key).
  2. Config loader

    • getFeatureFlag(flagKey, tenantId) in apps/web/lib/get-feature-flag.ts: override for tenant else global else false. Server-only (uses getDb). Can be moved to packages/config later for worker/tRPC.
  3. Seed

    • Migration inserts new_ticket_ui = false. Settings → Feature flags UI lists known flags + per-tenant toggles (overrides).

Acceptance criteria

CriterionStatus
Config/loader returns correct value for a flag (global and, if overrides exist, tenant override).
tRPC or layout can read flag and conditionally show/hide or enable/disable a feature.✅ (server component + getFeatureFlag on tickets page)
At least one flag exists in DB and is read in code path (e.g. hide a placeholder section when flag off).✅ (new_ticket_ui in feature_flag_globals; tickets page shows beta line when on)

Milestone 4 sign-off

CriterionStatus
All tasks in 4.1–4.3 complete.
All acceptance criteria met.
New tenant completes onboarding; admin can edit General settings; feature flags usable in code.
E2E: Onboarding and Settings smoke tests (see INDEX — Testing strategy).
Ready for M05 (Inbox management).