Template
Varianceboard
A multi-tenant budget-versus-actual reporting app for finance and FP&A teams. Users upload spend exports as CSV, map the columns, and get a live dashboard of budget, spend, variance and utilization by category, department and period, which they can share with teammates through role-based invites.
Budget vs actual dashboard · App · Small tools and apps · full-stack app (auth + DB)
A mock-up of the homepage, drawn from this design’s layout, palette and typefaces. A build follows the full prompt below.
Start from this templateRead the build prompt
Typefaces
Schibsted Grotesk is a newspaper grotesk with a true black weight for the stark headlines, and the Plex pair keeps the editorial-meets-terminal finance tone.
- Schibsted GroteskHeadings: display 800-900 at -0.025em, 60px
- IBM Plex SansBody: body 16px
- IBM Plex MonoFigures and code: eyebrows and tabular figures
Who it is for
- Finance and FP&A teams
- Operations leads sharing spend views
- Founders building internal reporting
- Analysts tired of rebuilding quarterly spreadsheets
Layout
- Black top bar: pulse-line logo tile + wordmark left; 'How it works' and 'FAQ' links, outlined 'Log in' and white 'Sign up' right
- Full-width monochrome office photo hero with dark overlay: monospace uppercase eyebrow in a bordered tag, big bold headline, paragraph, white square CTA button
- 'How it works' four numbered steps on white
- FAQ accordion with hairline dividers
- Black rounded CTA banner with a white button
- Footer with copyright, a Docs link and a tagline
- App: onboarding wizard, dashboard, import with column mapping, analytics, exports, members/invites, docs page
Palette
stark, serious, efficient, editorial, confident. A black-and-white finance tool that respects your time.
- background
#ffffff - ink/primary
#0b0b0b - primary foreground
#fcfcfc - secondary/muted
#f2f2f2 - border
#dedede - over-budget red
#dc2626 - under-budget green
#15803d
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text on background | 19.68:1 | 4.5:1 |
| Aa | label on black primary button | 19.18:1 | 4.5:1 |
| Aa | neutral/muted text on muted surface | 4.76:1 | 4.5:1 |
| Aa | over-budget text | 4.83:1 | 4.5:1 |
| Aa | under-budget text | 5.02:1 | 4.5:1 |
| Aa | white hero text on 60% black overlay (worst case over white) | 5.74:1 | 4.5:1 |
| input border on background | 3.23:1 | 3:1 | |
| focus ring on background | 19.68:1 | 3:1 | |
| inverted focus ring on black blocks | 19.68:1 | 3:1 |
As vibld’s tokens
The palette on the fifteen colour tokens vibld styles a project with, each text colour on the fill it is read on. Marked tokens are solved from the palette, because no swatch held that role at 4.5:1.
- background
- card
- muted
- primary
- secondary
- accent
- destructive *
Type scale
- Display
- Schibsted Grotesk Black 60px, -1.5px tracking; H2 36px black
- Body
- IBM Plex Sans 16px; eyebrows and figures in IBM Plex Mono uppercase
A strong grotesk display, a neutral Plex body and mono labels give an editorial-meets-terminal finance tone.
Spacing and imagery
1100px container, square-cornered buttons, 6px radius elsewhere, hairline dividers, large section padding; the monochrome hero is full-bleed.
Desaturated black-and-white office photography behind a dark overlay; no color illustrations; charts inside the app.
Components
- Black top bar with outlined and solid auth buttons
- Photo hero with mono eyebrow tag
- Numbered how-it-works steps
- FAQ accordion
- Black CTA banner
- KPI cards (budgeted, spent, variance, utilization)
- Breakdown tables by category/department/period
- Trend line chart budget vs actual
- Variance by department bar chart
- Top over/underspend rankings
- CSV import with column mapping
- Onboarding wizard
- Members and invite links
- Export menu (raw/rolled up)
Interactions
- Upload CSV; the mapper guesses columns and the user confirms
- Seed sample data in one click
- Filter by period, department and category
- Accordion expand/collapse
- Create an expiring invite link bound to an email
- Role-restricted actions hidden or disabled
- Download raw or rolled-up CSV
- Three-step onboarding flow
Data
Organization{id, name, fiscal_year_start, currency}Membership{org_id, user_id, role admin|member}Invite{id, org_id, email, token_hash, role, expires_at, accepted_at}BudgetEntry{id, org_id, period (month), department, category, budget_amount, actual_amount, source, import_id, created_by}Import{id, org_id, file_name, mapping jsonb, row_count, status, created_by, created_at}
Build prompt
The baseline every prompt in the catalog assumes, then this design’s own ten sections, from goal to guardrails.
The baseline
### How to use these prompts Paste a template's build prompt into your coding agent as the first message. Each prompt names its own stack, tokens and acceptance criteria; the rules below apply to all of them and can be prepended once per project. ### Engineering baseline - TypeScript strict mode, no `any`, small typed components, feature folders, and one source of truth for design tokens (CSS variables consumed by Tailwind). - Validate every input with a shared zod schema on the client and again on the server or edge function. Never trust client-side checks alone. - Show loading, empty and error states for every async view. Surface errors in plain language with a retry, and log details to the console in development only. - Keep secrets out of the bundle. Only publishable keys (for example a Supabase anon key) belong in client code; service-role keys, API keys and webhooks live in server or edge-function environment variables. ### Data and auth baseline (full-stack templates) - Enable Row Level Security on every table before inserting data. Default-deny, then add owner-scoped policies (`auth.uid() = user_id`) and explicit role checks for admin views. - Store roles in a separate table checked by a security-definer function, never in a user-editable profile field. - Upload files to private storage buckets with size and MIME limits, and serve them through signed URLs. - Rate-limit public endpoints (forms, auth, AI calls) and add a honeypot field or captcha to anonymous forms. - Take payments through a hosted checkout and verify webhooks by signature. Never handle raw card data. ### Accessibility and UX baseline - Target WCAG 2.2 AA: 4.5:1 contrast for normal text and 3:1 for large text, input borders, focus rings and meaningful icons or chart lines. Every palette in this catalog lists its verified pairs; re-check with a contrast tool after any colour change. - Keep body text at 16px or larger with 1.5 line height, nothing below 12px, no light weights under 24px, and uppercase only for short labels. - Give every interactive element a visible focus ring, full keyboard support, semantic landmarks, labelled form fields, and alt text on meaningful images. - Respect `prefers-reduced-motion` for every animation. Give drag-and-drop and carousels keyboard and button alternatives. - Build mobile-first and test at 375px, 768px and 1280px. ### Content guardrails - Use original copy, fictional sample data and placeholder or licensed imagery. Do not reuse another product's name, logo, screenshots or marketing text. - Label demo testimonials and metrics as samples. Collect the minimum personal data the feature needs.
### Goal Build **Varianceboard**, a budget-vs-actual reporting workspace for finance teams. Users upload the CSV exports they already have, map the columns once, and get a live, shareable dashboard of budget, spend, variance and utilization by department, category and period. Teammates join through secure invites with admin or member roles. ### Stack React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Radix: Accordion, Tabs, Select, Dialog, Table) and lucide-react. Use TanStack Query and Table, Recharts, react-hook-form + zod, Papa Parse (in a web worker) and date-fns. Supabase provides: - Auth: email and Google. - Postgres for orgs, memberships, invites, imports and entries. - Edge Functions: `create-invite` and `accept-invite` (hashed tokens, 7-day expiry, email-bound) and `import-commit` (server-side validation and a bulk insert in a transaction). ### Pages & layout 1. **Landing**: - Black top bar: logo tile and wordmark; How it works, FAQ, an outlined Log in and a white Sign up. - Full-bleed black-and-white office photo with a dark overlay: a bordered mono uppercase eyebrow, a heavy two-line headline, a paragraph and a square white CTA. - "How it works" in four numbered steps, a FAQ accordion, a black rounded CTA banner and a footer. 2. **Onboarding** (3 steps): workspace name and fiscal settings, import or seed sample data, invite teammates. 3. **Dashboard**: KPI row (budgeted, spent, variance, utilization %), filters, and tabs for Category, Department and Period tables. 4. **Analytics**: budget vs actual trend, variance by department, top five over and under. 5. **Import**: upload, auto-guessed column mapping, preview with row errors, then commit. 6. **Exports**: raw entries or roll-ups. 7. **Members**: roles and pending invites. 8. **Docs**: a public page explaining roles, import format and exports. ### Design system - Tokens: `--background: #ffffff`, `--foreground: #0b0b0b`, `--primary: #0b0b0b`, `--primary-foreground: #fcfcfc`, `--muted: #f2f2f2`, `--border: #dedede` (decorative hairlines), `--input-border: #8f8f8f`, `--ring: #0b0b0b`. - Semantic colors: over `#dc2626`, under `#15803d`, neutral `#6b6b6b`. - Fonts: Schibsted Grotesk (display, 800-900, -0.025em), IBM Plex Sans (body 16px) and IBM Plex Mono (eyebrows, figures, tabular). Scale 12/14/16/20/28/36/60; body line-height 1.6; mono uppercase only for short eyebrows (0.08em tracking). - Spacing on a 4px base; sections 96px tall. - Radius: 0 on primary buttons, 6px on cards and inputs. - Shadows: none; hairlines and black blocks instead. - Motion: 150ms, accordion 200ms. ### Components & interactions AuthButtons, PhotoHero, StepList, FaqAccordion, CtaBanner, OnboardingStepper, KpiCard (variance sign and color plus a text label), BreakdownTable (sortable, totals row, empty state), TrendChart, VarianceBars, RankList, ColumnMapper (guessed mappings highlighted, required fields marked, unmapped error), ImportPreview (first 50 rows, error count, commit disabled until valid), ExportMenu, InviteDialog (copy link, expiry shown), MemberTable (role select for admins only), ErrorBoundary with retry. ### Data & state Tables: `organizations`, `memberships(org_id, user_id, role)`, `invites(org_id, email, token_hash, role, expires_at, accepted_at)`, `imports(id, org_id, mapping jsonb, row_count, status, created_by)`, `budget_entries(org_id, period date, department, category, budget_cents, actual_cents, import_id, created_by)`. Variance and utilization are computed in SQL views. The active org lives in the URL (`/o/:orgId`). Seed fictional sample data. ### Accessibility Hero text sits on a 60% black overlay, which keeps white text at 5.7:1 even over the brightest part of the photo. Variance shows a sign and label, never color alone. The accordion follows the Radix keyboard model. The column mapper uses labelled selects, and errors are listed and linked. Tables have captions. Focus rings: 2px black with offset, which stays visible on the black blocks when inverted to white. Verified contrast: body: #0b0b0b on #ffffff = 19.7:1; muted: #6b6b6b on #f2f2f2 = 4.8:1; hero on overlay: #ffffff on #666666 = 5.7:1. ### Security RLS: members read their org's data; members insert and edit their own entries; admins manage members, invites and all entries. Check membership through a security-definer function. Invite tokens are random, stored hashed, single-use, bound to an email and expire after 7 days. `import-commit` rechecks role, file size (up to 10 MB) and a zod row schema, rejects formula-leading cells, and writes within a transaction. Keep only the anon key in the client. Exports neutralize CSV injection. ### Performance & SEO Parse CSVs in a web worker and paginate tables on the server. Index `(org_id, period, department, category)`. Lazy-load analytics. Give the landing and docs pages meta/OG tags; noindex workspaces. ### Guardrails - Write fresh copy; don't imply direct integrations with named finance tools unless you build them. - Use fictional sample data only. - Keep components small and typed; no `any`. Show import errors row by row. - Done when: (1) a messy CSV can be mapped, validated and committed; (2) KPIs and views reconcile to the raw totals; (3) invites expire and work only for the named email; (4) members cannot manage roles; (5) raw and rolled-up exports download correctly.