# COMPONENT-STUDIO-SPEC.md â per-surface component config (for Code)
**FE:** `pure-components-admin.html` (live, fail-soft) + a `PureConfig.get(surface,key)` read that each component honors at mount. **Backend = Code.** Contract-first; admin-gated; audited; reversible.

## Table
```sql
create table if not exists public.pure_surface_configs (
  id uuid primary key default gen_random_uuid(),
  surface text not null,           -- '/pure-home', '/pure-ingest', ...
  component text not null,          -- 'table','uploader','statcard','modal','turnstile','form','ingest'
  enabled boolean not null default true,
  roles text[] not null default '{}',     -- hats that can see it: superadmin,tech,broker,agent,mls,assoc,tc,client
  modules jsonb not null default '{}',     -- {search:true,sort:true,...} per-component feature flags
  updated_by text, updated_at timestamptz default now(),
  unique(surface, component)
);
-- RLS: read = any authed staff hat; write = admin (pure_my_rank() >= admin) only.
```

## RPCs (SECURITY DEFINER, admin-gated, audited)
| RPC | Args | Returns / effect |
|---|---|---|
| `mcp_component_config_get` | `{surface?}` | `{configs:{ '<surface>':{ '<component>':{enabled,roles,modules} } }}` (all, or one surface) |
| `mcp_component_config_set` | `{surface, config}` | upsert every component row for that surface; audit each change |
| `mcp_component_config_reset` | `{surface}` | delete rows for surface â components fall back to defaults |

## FE read contract (already shipped, fail-soft)
Each component should, at mount, consult config and honor it:
```js
// pseudo â add to component mount:
var cfg = window.PureConfig ? PureConfig.get(surface, 'table') : null;
if (cfg && cfg.enabled === false) return;          // kill switch
if (cfg && !PureConfig.roleOk(cfg.roles)) return;  // role gate (current hat)
opts.modules = cfg ? cfg.modules : opts.modules;    // feature toggles (search/sort/â¦)
```
Ship a tiny `pure-config.js` (Lane A) that fetches `mcp_component_config_get` once, caches, and exposes `PureConfig.get/roleOk`. Until then components use their own defaults (no behavior change).

## Module vocab per component (FE source of truth)
- table: search, sort, select, bulk, pagination, export, columns
- uploader: browse, camera, paste, phone, ai-extract, multi, progress
- statcard: sparkline, delta, drill-in, accent
- modal: dialog, drawer, confirm, wizard
- turnstile: challenge, server-verify
- form: validation, inline-errors, autosave
- ingest: light, medium, heavy, phone-qr, dictate

## Wiring
- Mounts as the **Component Studio** tab in `pure-admin-console` (Studio & Admin). Add nav â `pure-components-admin.html`.
- Ties to `pure_components` registry (DESIGN-SYSTEM-SPEC) â same component keys.
- Governance: new surface/component auto-appears with defaults (enabled, all hats); admin narrows.

## Change log
- 2026-06-30 â Lane A: FE Studio live (fail-soft, localStorage); this hands the config table + 3 RPCs + `pure-config.js` read path to Code.
