Skip to main content
vibld

Template

Spendgate

An expense claim and approval tool for startups and agencies. Employees submit claims with receipts, categories and cost centers; managers approve their team's claims; finance gives final sign-off in batches. The app adds spending analytics, an audit trail, CSV import/export and an AI assistant for spending questions.

Expense claim approval tool · App · Small tools and apps · full-stack app (auth + DB)

Who it is for

  • Startups replacing spreadsheet expense tracking
  • Finance teams needing audit trails
  • Managers approving team spend
  • Agencies tracking billable project costs

Layout

  1. Split sign-in screen: left light panel with blue receipt icon tile, bold product name, subtitle, outlined 'Continue with Google', 'or continue with email' divider, labeled email and password fields, full-width blue 'Sign In' button, sign-up link
  2. Right half: full-height photo of a team reviewing data, with a bold white headline and subcopy over a dark gradient (70% black) at the bottom
  3. App: sidebar layout with dashboard, my expenses, new expense form, approvals (manager), finance queue, analytics, audit log, AI assistant, settings (categories, cost centers, users/roles)

Palette

corporate, dependable, clear, efficient, neutral. A straightforward business tool that looks at home in any company.

  • background#f9fafb
  • card#ffffff
  • text#131720
  • primary blue#2463eb
  • muted surface#f1f5f9
  • border#e1e7ef
  • muted text#5f6e84

Every checked pair, measured again

SampleWhereRatioNeeds
Aabody text on background17.16:14.5:1
Aatext on card17.93:14.5:1
Aamuted text on background4.96:14.5:1
Aamuted text on muted surface4.73:14.5:1
Aawhite label on primary button5.17:14.5:1
Aawhite headline on photo gradient (worst case)8.45:14.5:1
Aaapproved status text5.02:14.5:1
Aarejected status text4.83:14.5:1
focus ring on card5.17:13:1
input border on card3.36:13: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

Display
System UI sans Bold 30px, -0.75px tracking (the system face is not on Google Fonts; a vibld project loads Inter)
Body
System UI 16px body; 12px uppercase divider label (the system face is not on Google Fonts; a vibld project loads Inter)

A default system stack keeps it neutral and fast, like a standard enterprise tool.

Spacing and imagery

50/50 split; 400px form column with 16px gaps; 44px inputs; 6-8px radius; the app uses a standard sidebar with card grids.

A business photo of a team reviewing data in the auth panel; a receipt icon tile; charts in analytics.

Components

  • Split auth layout with photo panel
  • Google sign-in button
  • Labeled email/password form
  • Expense submission form with receipt upload
  • Category and cost center selects
  • Status badges (draft, submitted, manager approved, approved, rejected, reimbursed)
  • Manager approval queue
  • Finance queue with batch actions
  • Spending analytics charts
  • Audit trail timeline
  • CSV import/export
  • AI assistant chat
  • Role management

Interactions

  • Save as draft, then submit
  • Upload a receipt image or PDF with preview
  • Manager approves or rejects with a comment
  • Finance batch-approves, rejects or marks reimbursed
  • Real-time status updates for the submitter
  • Filter analytics by category, cost center, status, period or merchant
  • Ask the AI about spending patterns
  • Import and export CSV

Data

  • Profile{id, name, role employee|manager|finance, manager_id?, cost_center_id?}
  • Expense{id, user_id, amount, currency, date, merchant, category_id, cost_center_id, description, receipt_path, status, submitted_at}
  • Approval{id, expense_id, step manager|finance, approver_id, decision, comment, decided_at}
  • Category{id, name}
  • CostCenter{id, name, code}
  • AuditLog{id, expense_id, actor_id, action, details jsonb, 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 **Spendgate**, a web app for submitting and approving expense claims at startups and agencies. Employees file claims with receipts; each claim goes through a manager, then finance; everyone can see the status at every step; and finance gets analytics, exports and a complete audit trail.

### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Radix: Table, Dialog, Select, Tabs, Checkbox) and lucide-react. Use react-hook-form + zod, TanStack Query and Table (with row selection for batch actions), Recharts, date-fns and Papa Parse. Supabase provides:
- Auth: Google and email.
- Postgres for expenses, approvals, categories, cost centers and the audit log.
- A private Storage bucket for receipts.
- Realtime for status changes.
- An Edge Function for the AI assistant, answering from read-only aggregate queries.

### Pages & layout
1. **Sign in**: a 50/50 split. The left side has an icon tile, product name, subtitle, a Google button, an "or continue with email" divider, labelled fields, a full-width blue button and a sign-up link. The right side is a full-height photo with a bottom gradient, a bold headline and one line of copy.
2. **Dashboard**: my totals by status, recent claims, and pending approvals for managers.
3. **New / edit expense**: amount and currency, date, merchant, category, cost center, description and receipt upload with preview; Save draft or Submit.
4. **My expenses**: a table with a status filter and a detail drawer with a timeline.
5. **Approvals** (manager): the team queue with approve and reject plus a comment.
6. **Finance**: all submitted and manager-approved claims with batch approve, reject and mark reimbursed.
7. **Analytics**: breakdowns by category, cost center, status, month and merchant.
8. **Audit log**, **Assistant**, **Settings** (categories, cost centers, users and roles).

### Design system
- Tokens: `--background: #f9fafb`, `--card: #ffffff`, `--foreground: #131720`, `--primary: #2463eb`, `--muted: #f1f5f9`, `--muted-fg: #5f6e84`, `--border: #e1e7ef` (decorative), `--input-border: #728eb4`, `--ring: #2463eb`.
- Status colors: draft slate, submitted blue, manager-approved indigo, approved green `#15803d`, rejected red `#dc2626`, reimbursed teal.
- Font: Inter (or the system stack). H1 30px bold at -0.025em, body 16px at line-height 1.5 (15px in dense tables), divider label 12px uppercase, figures tabular.
- Spacing on a 4px base; radius 6-8px; subtle card borders.
- Motion: 150ms, drawers 200ms.

### Components & interactions
AuthSplit, ExpenseForm (currency input, required receipt above a configurable amount, draft autosave, submit confirmation), ReceiptUpload (drag area, image/PDF preview, progress, type and size errors), StatusBadge (text and color), ExpenseTable (filters, empty state, pagination), ClaimTimeline, ApprovalQueue (keyboard shortcuts A/R with confirmation), BatchBar (selected count, disabled when nothing is selected), AnalyticsCharts (with tables), AuditList, CsvImportExport, AssistantPanel (suggestions, streaming, error).

### Data & state
Tables as in the data model, plus `user_roles`. Keep the status machine in the database: `draft → submitted → manager_approved → approved → reimbursed`, and `rejected` from either review step. A trigger enforces valid transitions and writes an `audit_log` row. Store amounts in minor units. Seed fictional data.

### Accessibility
Blue `#2463eb` on white passes for text and buttons. White text on the photo sits on a 70% black gradient, which holds 8.4:1 even over the brightest part of the image. The auth photo needs meaningful alt text or should be marked decorative. Form fields keep visible labels, and errors are announced. Batch checkboxes need row labels. Status is never color-only. Charts include data tables. Dialogs trap focus.
Verified contrast: body: #131720 on #f9fafb = 17.2:1; muted: #5f6e84 on #f9fafb = 5.0:1; white on primary: #ffffff on #2463eb = 5.2:1; photo text: #ffffff on #4d4d4d = 8.5:1.

### Security
RLS:
- Employees CRUD their own drafts and read their own claims.
- Managers read their direct reports' submitted claims and insert manager-step approvals.
- Finance reads everything and performs finance-step actions.
- Nobody updates `status` directly except through transition RPCs that check the role.
Keep receipts in a private bucket with signed URLs, a 10 MB limit and JPEG/PNG/PDF only. Validate with zod on the client and in RPCs and functions. The AI assistant uses the caller's JWT and returns aggregates only. Keep keys server-side. Neutralize CSV formula injection.

### Performance & SEO
Paginate on the server, compress images on the client before upload, index `(user_id, status)` and `(status, submitted_at)`, and lazy-load analytics and the assistant. The sign-in page gets a title and meta; noindex the app.

### Guardrails
- Write fresh copy; use royalty-free or generated imagery and fictional staff.
- Don't store card numbers or bank details.
- Keep components small and typed; no `any`. Show errors visibly.
- Done when: (1) a claim moves through both approval steps with a complete audit trail; (2) invalid transitions are rejected by the database; (3) submitters see status changes live; (4) finance batch actions work; (5) roles cannot see data outside their scope.

Open the builderAll templatesThis palette on its own