Skip to content

Profile, Settings & Onboarding — reconciliation brief for Claude Designs ​

Architecture references are stale; the SCREEN spec is current (2026-08-08)

Read profiles as users + workspaces (principal vs business tenant), profiles.business_domain_id as workspaces.industry_key (stable TEXT key), and profiles.subscription_tier as platform_plans resolved through feature_grants — the tier column and user_subscriptions/subscription_tiers were dropped from Dev 2026-08-08.

⚠ The Business tab needs a behavioural change, not a rename. Industry/archetype is write-once to the subject — the live PillSelect that let a merchant change it freely is a defect. It becomes a read-only row with a "contact support to change" affordance, backed by a DB trigger plus an admin-only RPC that writes an audit row. A read-only input is not the control; the trigger is. See ADR-0020 · user ecosystem.

The prototype already has prototype/onboarding/Onboarding.dc.html, prototype/mobile-console/Profile.dc.html, and a desktop ui_kits/merchant-console-v2/profile.html. This brief exists because those screens were designed without the real profiles schema in front of them, and a codebase sweep (2026-07-19, for ADR-0006 / ADR-0001) found both missing fields and live bugs where the UI collects a value the backend silently drops.

How to use

Paste the fenced block below into Claude Designs with the PDPR and Screen Coverage Mandate. It uses the exact profiles column names — do not rename them. Field names here are the contract; the labels in quotes are the human-facing text.

Ground truth

Every field below is a real column on public.profiles (baseline 20260710134136_…:1328) or a real Edge-Function action (manage-profile, manage-settings, manage-account, validate-user-input). Do not invent fields, and do not add a business_name or display_name column — brand_name is the business name and full_name is the person's name (ADR-0001 D3).

Global rules for this module (apply the PDPR too) ​

markdown
# PROFILE, SETTINGS & ONBOARDING — RECONCILIATION BRIEF FOR CLAUDE DESIGNS

You are UPDATING three existing screens to match the real backend, not inventing a new module:
- prototype/onboarding/Onboarding.dc.html
- prototype/mobile-console/Profile.dc.html  (and desktop ui_kits/merchant-console-v2/profile.html / modules.jsx)
- the Settings surface (add one if the console lacks a dedicated Settings screen; it exists in the app today)

Use the EXACT field names below (they are real database columns). The quoted text is the human label.

=====================================================================
PART 0 — THE REAL FIELD SET (public.profiles) — use these names verbatim
=====================================================================

Identity / person:
- full_name (text) — label "Full Name" in onboarding, "Owner Name" in Profile. The individual/owner.
- email (text) — from auth; shown read-only in Profile header; changed only via Settings > Security.
- mobile_number (text, 10 digits) — a country_code selector may sit beside it in the UI, but note there is NO
  country_code column; if you keep the selector, treat it as display-only OR store it inside mobile_number.
- avatar_url / avatar_path (image) — uploaded via manage-profile action:'upload_avatar'.

Business / brand:
- brand_name (text) — label "Brand Name". THIS IS THE BUSINESS NAME. Do not add business_name.
- business_domain_id (integer → business_domains) — label "Business Industry". Options come from the
  business_domains table (id, name, slug, description). Selecting one also sets business_type to the domain slug.
- gstin (varchar 15, GSTIN-format CHECK) — label "GSTIN". India tax id, optional.
- country (varchar, NOT NULL, default 'India') · state (text) · city (text) · pin_code (text, 6 digits)
- business_hours (jsonb) — per-day { open, close, is_closed } for monday..sunday.
- social_media_links (jsonb) — keys: whatsapp, instagram, facebook, youtube, twitter, linkedin, telegram,
  google_business.
- planned_holidays_ooo (jsonb array) — items { title, startDate, endDate }.
- slug (varchar) — the public URL handle (qrsetu.com/<slug>), chosen at onboarding, validated for uniqueness.

Preferences / account (Settings):
- default_currency (text, default 'INR') — options INR/USD/EUR/GBP.
- language (varchar, CHECK en/mr/hi) — options English / मराठी / हिंदी.
- show_ads (boolean, default true) — whether ad placements show for this account.
- subscription_tier (read-only here; managed by billing) — show as a badge, link to plan/billing.

Do NOT surface in these screens (they are not user-editable identity): role, permissions, is_demo_account,
status, is_published, version, template_id, name (the generic public-page name), reminder_* fields,
tier_expires_at, attributes.

=====================================================================
PART 1 — ONBOARDING (update Onboarding.dc.html)
=====================================================================

QRSETU serves TWO audiences (locked product decision): businesses AND individuals. The current flow forces every
user to enter a brand name + industry, which is wrong for an individual. Add an account-type fork as Step 1.

Step 0/1 — "How will you use QRSETU?" : a two-choice selector — "For my business" or "For myself / personal".
This choice drives which later steps appear. (It maps to whether brand_name/business fields are collected; an
individual should never be forced to enter a brand_name.)

Then, in order:
1. "What should we call you?" — full_name (2+ chars, letters/spaces) + mobile_number (10 digits, with the
   country-code selector). BOTH audiences.
2. "Tell us about your brand" — brand_name (2+ chars). BUSINESS ONLY (skip for individuals).
3. "What's your industry?" — business_domain_id from business_domains. BUSINESS ONLY (skip for individuals).
4. "Where are you based?" — country (required), and optionally state / city / pin_code.
5. "Choose your unique URL" — slug (3–30 chars, ^[a-z0-9-]+$), auto-suggested from brand_name (business) or
   full_name (individual). Show live availability (there is a validate-user-input check for slug).
Finish — a celebratory completion screen; on finish, onboarding_completed becomes true.

Design the individual path as visibly shorter (Steps 2–3 removed), not the business path with fields greyed out.

=====================================================================
PART 2 — PROFILE (update Profile.dc.html + desktop)
=====================================================================

Keep the existing tabbed structure; make the fields match Part 0. For an INDIVIDUAL account, the Business Details
tab collapses to just location (no brand_name/industry/GSTIN/hours) — mirror the onboarding fork.

Tab "Basic Information" (editable): full_name (label "Owner Name" for business, "Your Name" for individual),
mobile_number. Header shows avatar, brand_name (business) or full_name (individual), the subscription_tier badge,
and email (read-only).

Tab "Business Details" (BUSINESS ONLY): brand_name, business_domain_id ("Business Industry"), gstin ("GSTIN"),
country, state, city, pin_code.

Tab "Business Hours" (BUSINESS ONLY): the business_hours per-day editor (open / close / is_closed per weekday),
plus the planned_holidays_ooo list (add/remove a holiday with title + date range).

Tab "Social Media" (BOTH): the eight social_media_links keys as labelled inputs (whatsapp, instagram, facebook,
youtube, twitter, linkedin, telegram, google_business).

Avatar upload with the standard image picker (crop optional), wired to the upload action.

=====================================================================
PART 3 — SETTINGS (create/align a Settings screen)
=====================================================================

Three sections, matching the app's real capabilities:

General: default_currency (INR/USD/EUR/GBP), language (English/मराठी/हिंदी), and a show_ads toggle
("Show partner offers and sponsored content"). These auto-save on change.

Security: change email, change password (current + new). Standard forms with validation states.

Danger Zone: delete account — a destructive, confirm-guarded action (soft-delete), with a plain-language
explanation of what happens to the user's public page and data.

=====================================================================
PART 4 — WHAT NOT TO INVENT (flag instead)
=====================================================================

1. Do not add a business_name or display_name field — brand_name and full_name already cover these.
2. Do not add a country_code column to the data model — it has none; keep the selector display-only or fold it
   into mobile_number, and flag the choice.
3. Do not add profile fields beyond Part 0 (no "bio", "website", "tagline", etc. unless told — they are not
   columns today). If a screen seems to need one, flag it as a proposed new column, do not silently design it.
4. Do not surface role / permissions / is_demo_account in the user Profile or Settings — those are
   platform/admin concerns (see ADR-0006), not user-editable identity.
5. The individual-vs-business fork is required, but the exact copy and where the choice is later changeable
   (Settings? not at all?) is open — design the fork and flag the "can they switch later?" question.

Why this shape ​

It reconciles the design to the schema that already exists rather than growing either side speculatively, and it encodes two locked decisions: the dual-audience fork (individuals aren't forced a business identity) and ADR-0001 D3 (business name = brand_name, member name = full_name, no new name column). The live data-loss bugs it exposes (slug / gstin / language / onboarding_completed silently dropped by Edge-Function allow-lists) are logged separately in the tracker — those are backend fixes (widen the allow-lists), not design fixes, and must land alongside this UI work or the new fields will look editable but won't persist.

After this ships in Claude Designs ​

Review the regenerated Onboarding / Profile / Settings screens the same way as every other screen: read the actual files, check field names against Part 0 and the fork against Parts 1–2, then log findings under design-system/screen-reviews/ and request revalidation.