Visual and information-architecture pass across every screen. No API call, payload, poll, permission rule or workflow mirror changes; forms still render from the live schema and the timeline's merge/grouping is unchanged (only the display order is reversible). Design language - Ground + white cards with one hairline and one radius; sentence-case headings; shared primitives in index.css (.card .pill .btn .avatar .live). - One inline icon set (components/Icon.jsx); no more filled navy/red tiles. - Read-side labels in api/display.js: roles and enum tokens humanized, customer initials/tones, money and date formatters. Nothing sent changes. Shell - 56px header with brand, global lead search (portfolio rows, "/" to focus) and identity chip with a human role label. - Sidebar rows carry icons and a clear active bar; AI roster at the foot, each opening its remit card. Login - Operator copy instead of retail copy; centred sign-in card with show/hide password; demo persona picker that fills the EMAIL only. Overview - "Who holds the work" as four quiet cards that warm only when owed. - Pipeline flow bar with every stage named beneath it; KPI strip in a card. - Action rows with chevron / view-only eye; expiry bands filter the table. Queues - Filter bar (search, product, channel, expiry band, stalled, hide closed) and sortable columns, all client-side on the fetched page. - Avatars, product/channel chips, stage chips for closed leads, tinted stalled rows, count inline with the title. Lead - Avatar + chips in the header; metrics card with the stage rail inside, and a branch node for Referred / Parked / Lost / Declined. - Timeline newest-first by default (toggle), the worker's face as the node, one footer row per entry, AI markdown rendered as bold. - "AI team on this lead" panel with per-agent step counts; PDF tags on docs. Forms & dialogs - Required marked with an asterisk + legend; "Select…" placeholder; dd Mon yyyy hint under date inputs; open activity form in a titled panel; one-line dialog footnotes. Fixes: horizontal overflow at 1024px, boxed "in N days" figure, raw tokens (sme_underwriter, verbal_call, Rsa), findings cut at "1.". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|---|---|---|
| public/brand | ||
| src | ||
| .env.example | ||
| .gitignore | ||
| CLAUDE.md | ||
| eslint.config.js | ||
| index.html | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| vite.config.js | ||
Zurich Kotak — Lead Desk
Operator console for the Zurich Kotak "Lead to Policy" demo. Leads arrive through three channels — direct, bancassurance and agency — and run one state machine to policy issuance. The agents do the work; a person appears at one queue.
Workflow config is seeded from sm2/custom-apps/zurich-kotak/ (org 84,
app 536, workflow zk_wf_lead). Design doc:
sm2/app-designs/zurich-kotak/design.html. Workflow spec PDF:
sm2/custom-apps/zurich-kotak/zurich-kotak-workflow.pdf.
Run it
npm install
npm run dev # http://localhost:5175
npm run build # → dist/
.env carries the API host for local dev only:
VITE_ZINO_API_URL=https://dev.getzino.in
Logins (all password ZurichKotak@2026, org 84):
| Role | Can do | |
|---|---|---|
sanjay.uw@zurichkotak.example |
SME Underwriter | Clear / Decline Referral — the only human decision |
meera.rm@zurichkotak.example |
Bancassurance RM | Submit a Partner Bank Lead |
arjun.posp@zurichkotak.example |
POSP / Broker | Submit a Partner Agent Lead |
kavya.csr@zurichkotak.example |
Direct / Call centre | Submit a Self-Serve Lead |
deepa.ops@zurichkotak.example |
Operations | Cross-channel visibility |
Sign in as Sanjay to land in Referred to Underwriting, which is where the demo happens.
How it talks to the platform
Everything goes through src/api/client.js:
POST /usr/login— auth.org_idmust be a string; a number returnscannot unmarshal number into Go struct field LoginRequest.org_id.POST /app/536/view/recordview— every queue is one record view (zk-rv-leads) filtered server-side oncurrent_state_name.POST /app/536/view/form-screensthenPOST /app/536/activity— forms are read from the live activity schema and submitted straight back.
Forms are not defined in this repo
Whatever /view/form-screens returns is what renders — labels, types, select
options, which fields are mandatory. Add a field to an activity in Studio,
redeploy, and it appears here with no frontend change. That is deliberate: the
workflow is the source of truth, and a hardcoded form would quietly diverge
from it.
Permissions are never enforced here
The console does not hide a button to stop someone using it. Every permission
decision is the workflow's, made server-side on each submission — the platform
refuses and this app reports what it said. Two refusals worth knowing:
/activity answers 403, /start answers 400, and both carry
permission denied.
The runtime-config contract
VITE_ZINO_API_URL is read at runtime from a config.js the server writes
when it places the build — never compiled in. One artifact is promoted between
environments unchanged, so a build-time URL would point every environment at
whichever backend happened to build it. requireConfigValue throws if it is
missing, so a production build with no config.js fails loudly rather than
calling the wrong backend.
vite.config.js uses base: './' and the router takes its basename from the
<base href> the server writes, so one build serves any mount path. Do not
reintroduce a build-time base.
This is also why the fonts and logo live under src/assets/ and not
public/. Vite rewrites bundled asset URLs to be relative; a public/ file
referenced as /fonts/… stays absolute and 404s under the /zurich-kotak/
mount path. The favicon is the one exception — it stays in public/brand/ and
is referenced relatively from index.html.
Deployment
Registered with frontgen by sm2/custom-apps/zurich-kotak/05_frontgen_project.sql
(slug zurich-kotak, repo_name zurich_kotak, org 84). A push to main builds
and serves at https://preview-dev.getzino.in/zurich-kotak/.
The webhook only fires on a new push — a push made before the frontgen project row existed matched no project and did nothing.
State of the build
| Piece | Status |
|---|---|
| Brand — Zurich Sans, palette, logo | done (kept from the original scaffold) |
| Sign-in against the real gateway | done |
| Runtime config, relative base, router | done |
Pipeline sidebar (mirrors tbl_wf_states) |
done |
| Queue lists | waiting on the zk-rv-leads record view |
| Lead file, activity forms, attribution panel | waiting on zk-dv-lead + form screens |