Appearance
Subscriptions (admin panel)
File: prototype/admin-panel/Subscriptions.dc.html (127 KB) · Status: 🔴 Findings logged, prompts not yet sent · Last reviewed: 2026-07-19 (full file fetched and grepped directly from the Claude Designs project)
Eight tabs: Plans, Add-ons, Promotions, Subscribers, Custom deals, Insights, Approvals, Audit. Token discipline is genuinely strong here (764 var(--token) references counted, only 2 hardcoded hex values found and both are var(--danger-soft,#fee2e2)-style fallbacks, not raw usage; 0 native <select> elements).
Finding 1 — No accessibility support in a keyboard-dense operator screen
Severity: blocker for an internal operator tool at this density
Full-file check: 1 aria-* attribute, 0 role= attributes, 0 keyboard handlers (onKeyDown/onKeyPress/tabIndex) across the entire 127 KB file. This screen has 8 tabs, multiple modals, a custom dropdown (dsSelect), tables, and bulk-action bars — none of it is confirmed keyboard-operable.
Design-fixable — copy-paste prompt for Claude Designs
markdown
In prototype/admin-panel/Subscriptions.dc.html, add real keyboard and screen-reader support before this goes
further:
1. Every tab in the tab bar needs role="tab" / role="tablist" / role="tabpanel" and arrow-key navigation
between tabs, not just click handlers.
2. The dsSelect dropdown (used throughout this screen) needs a keyboard path: Enter/Space to open, Arrow
Up/Down to move selection, Enter to confirm, Escape to close, and it needs to be focusable (tabIndex) with
a visible focus ring using the --focus-ring token.
3. Every icon-only button (e.g. bulk action icons, row action icons) needs an aria-label describing what it
does, not just a tooltip.
4. Modals need role="dialog", aria-modal="true", and focus should move into the modal on open and return to
the trigger element on close.
5. Data tables need proper semantic markup (or explicit role="table"/"row"/"cell" if not using native table
elements) so row content is announced correctly.
Do not change any visual styling, spacing, or tokens. This is purely about adding the missing interaction and
semantic layer on top of the existing visual design.Finding 2 — Organization/franchise/seat-based billing is not modeled
Severity: major (real gap, but a data-model question — see architecture note below)
Confirmed: PLANRANK={free:0,pro:1,business:2} covers individual/business plans. Custom deals exist with DSCOPE={org:['Organization',...], workspace:[...]} and explicit copy: "Enterprise is quote-based. Pricing is set per deal in Custom deals; the entitlements here are the default template." Per-seat pricing exists only as one add-on's pricing unit (unit:'/ seat / mo'), not a licensing model. A full-file search for "franchise" and "family plan" returned zero occurrences of either.
So today: "Enterprise" means "go negotiate a manual custom deal." There is no self-serve seat management, department-level sub-billing, or multi-location franchise rollup modeled anywhere.
Architecture-gated — not a Claude Designs prompt yet (tracked as QRS-043)
This needs a new Organization entity above the existing Workspace (see CONTRACTS.md §2's Account → Workspace(tenant) → Member(role) model) with a type (enterprise / franchise / community / NGO / family) and seat/member management, decided during core architecture planning. Once that data model is decided, a design-fixable prompt can ask Claude Designs to design the actual seat-management and org-admin UI against it. Sending "please design organization billing" to Claude Designs today would just produce more UI without a real entity behind it, which is how the current Custom Deals tab ended up being a manual-only escape hatch instead of a real feature.
Finding 3 — In-house billing engine modeled instead of a payment-provider integration
Severity: major (architecture decision, not a screen defect)
The screen models proration, dunning states (past_due, grace), refunds, and custom pricing as if this will all be custom Postgres + Edge Function logic. Building this in-house (rather than on a PSP like Razorpay or Stripe Billing as the system-of-record for money) is a significant reliability and compliance risk for a platform of this scale.
Architecture-gated — not a Claude Designs prompt (tracked as QRS-044)
This is a backend/vendor decision to make during core architecture planning, not something to send back to Claude Designs. Once decided, the entitlement-state UI (Plans, Subscribers tabs) mostly stays as designed since entitlement state belongs in Postgres regardless of which PSP handles the money; only the money-handling surfaces (refund flows, proration display, dunning detail) would need a follow-up design pass to match the chosen provider's actual capabilities.
Confirmed compliant (do not re-flag)
- Token discipline: 764
var(--token)references, only fallback-pattern hex values, 0 raw hardcoded colors. - No native
<select>anywhere. - Sidebar nav (11
<a href>links) is consistent with the shared admin shell used by Templates. - The one em-dash-looking character found is a data placeholder (
'—'for "no value" in a table cell), not prose copy — not a real violation of the no-em-dash rule.