# Atelier admin implementation contract

User requests a COMPLETE working staff Mini App per REDESIGN_BRIEF_ADMIN.md, matching02-atelier's charcoal/apricot identity. All brief features required. Persian only, RTL, Latin technical digits, Tehran dates, mobile360 first with useful desktop. Root owns admin-atelier/app.js, ui.js, style.css, index.html and customer/catalog/revenue UI. Delegated domain modules own specified files only. Preserve01-20.

## One world and API

Core owner owns shared/api.js ONLY for a minimal private store bridge and needed customer identity consistency; preserve29existing API tests. Export a backend-only `adminWorldTransaction(fn,{write=false,delay}={})` or equivalent; admin-core imports it, UI never does. Use existing abnabot.world.v1, WebLock, save-if-changed semantics and customer subscriptions/users/ledger/plans/categories. Do not create a second localStorage world.

Core owner creates shared/admin-core.js and shared/admin-api.js (+ typed d.ts and core tests). Public admin-api reexports core, admin-finance, admin-operations APIs using exactbriefnames/args/shapes. Core exports to private domain modules:

- `request(name, fn, options={})`: Promise, fn(w,actor) runs synchronously/transactionally after seeds/ticks. options.write or delay. Errors rollback mutation. Latency150-600ms, occasional2-3s. Actor from admin gate.
- `registerDomain(seed,tick)`: finance/ops call once at module load. request invokes all domain seed/tick functions on the same world.
- `fail(status,detail)`: detail string or {code,message,...}, throws status/detail envelope.
- `now(w)`, `iso(ms)`, `DAY`, `clone(value)`, `balance(w,userId,walletId)` shared helpers.
- `actor` parameter {id,full_name,username}; audited writes use it.

Canonical customer objects remain w.users, w.subscriptions, w.panels (live subscription state), w.ledger, w.categories, w.plans. Core adapters expose staff wire fields. Admin-only data lives under w.admin, common {version,variant,actor,...}. Finance owns w.admin.finance; operations owns w.admin.operations. Core exposes infrastructure under w.admin.infrastructure={panels:[],templates:[]} and categories add panel_id/template fields; coordinate if representation changes. Finance/ops register ticks; no timers inside backend, elapsed time processed on requests. UI polls only active jobs/safe mode. One module exports getDashboard/getRevenue/getPanelHealth/etc. Never expose raw secrets. Demo controls expose all required failures and fatal identities without editing code.

Setup operations use canonical categories/plans and w.admin.infrastructure plus finance data. Ask core for adapters if needed; do not guess existingcustomerfieldnames. Other modules may import helper exports from core. Direct edits to shared/api.js are core-owner only.

## Frontend module contract

Finance owns admin-atelier/finance.js. Operations owns admin-atelier/operations.js. Each exports `routes` object mapping route names to async `(c, params={}) => HTML` render functions, and `actions` object mapping data-action names to async `(c,id,element)=>...` functions. Prefix actions fin-/ops-. Use root's context:

- c.api (all public API exports), c.esc(value), c.icon(name,size=20), c.fmt(number), c.money(number), c.date(UTC_ISO) Tehran, c.technical(value) escaped <bdi>, c.badge(label,tone), c.notice(text,tone='info'), c.empty(title,body='',actions='')
- c.button(label,action,id='',kind='secondary',extra='') returns native button data-action/data-id; label accepts trustedHTML. c.link(label,route,id='',kind='secondary') navigates route with params.id. c.card(title,body,actions=''), c.facts([[label,trustedValueHTML],...]).
- c.go(route,params={}); c.refresh(quiet=false); c.notify(message,tone='success'); c.copy(value); c.error(error) Persian text.
- c.show({title,body,footer='',wide=false,onMount?}) native dialog. c.closeDialog(). c.confirm({title,body,onConfirm,danger=false,confirmLabel='تأیید'}) with proper financial explanation; native host confirmation when available, readable browser fallback. onConfirm awaited, inline errors, no accidental double writes.
- c.form({title,fields,values={},description='',submitLabel='ذخیره',danger=false,onSubmit,onChange?}): fields {name,label,type='text',required,min,max,step,pattern,options:[{value,label}],help,placeholder,section,rows}; checkbox returnsboolean, numberreturnsnumber ornullifempty, selectreturnsstring; callers convert numericIDs. password inputs never prefill secrets; help supportsset/maskedstate. onSubmit(values,formElement) awaited; throw {fields:{key:message},message?} forinlinevalidation. onChange(values,formElement) canupdateprojectionpanel; use description HTML for preview placeholder. Dialog remains on failed submit, success closes unlesscallbacknavigates/showsnext.
- c.onMount(fn) queue function after render; c.poll(fn,ms) installs route-scoped poll clearedwhenrender/replaced; callbacks may refresh(true). c.state is UI state only; no domain writes outsideAPI.

Design: same theme tokens as02, but admin uses task workspaces, dense inset rows, command-like detail pages, clear projected changes, inline process instruments. Root stylesheet styles .panel,.stack,.row,.between,.grid-2,.grid-3,.page-heading,.section-heading,.stat,.data-list,.data-row,.muted,.small,.technical,.btn,.primary,.secondary,.danger,.badge,.notice,.field,.form-grid,.segmented,.chips,.process-track,.process-fill,.metric,.metric-value,.empty,.action-row,.danger-zone and native dialog classes. Use these semantic classes; add feature-specific CSS via notes to root or scoped module style file only if agreed. No decorative fake metrics or category icons.

## QA

Use exactbrief sections eachowner. Write meaningful API tests for consequentialrules and crossentityeffects. Browser server http://127.0.0.1:8765; root session admin-review; domainagents unique admin-finance/admin-ops ifusingbrowser. CLI npx --yes --package @playwright/cli playwright-cli -s=NAME. Driver expressionfiles async(page)=>{...} with NO trailingsemicolon. Screenshots output/playwright/admin-*. Closeownbrowser. Eachowner reports APIexports, routes, testresult, any remaining gaps. Do not leave placeholders or silently trim brief scope.
