A reality-check tool that benchmarks your life against real global data — income percentile, purchasing power, youth unemployment, and resilience — instead of against Instagram. No data is stored; every report is generated on the fly and never persisted.
npm install
cp .env.example .env.local # optional — only needed if you change NEXT_PUBLIC_SITE_URL
npm run devOpen http://localhost:3000.
| Command | What it does |
|---|---|
npm run dev |
Start the local dev server with hot reload |
npm run build |
Production build |
npm run start |
Run the production build locally |
npm run lint |
Run ESLint |
npm run type-check |
Run the TypeScript compiler with no emit |
src/
├── app/
│ ├── page.tsx # Main page: form <-> report state machine
│ ├── layout.tsx # Root layout, fonts, metadata
│ ├── globals.css # Tailwind entrypoint + a11y defaults
│ └── api/generate-report/
│ └── route.ts # POST endpoint: validates input, runs the engine
│
├── components/
│ ├── Header.tsx, Footer.tsx
│ ├── InputForm.tsx # Composes the field groups below
│ ├── form/
│ │ ├── Field.tsx # Shared label/input wrapper + shared classes
│ │ ├── defaults.ts # Default form values
│ │ ├── PersonalDetailsFields.tsx
│ │ ├── LifeSituationFields.tsx
│ │ ├── EmploymentFields.tsx
│ │ └── HealthFields.tsx
│ ├── ReportView.tsx # Composes the report sections below
│ ├── ScoreCard.tsx
│ ├── PrivilegeCard.tsx
│ ├── ReframeBox.tsx
│ ├── WinBox.tsx
│ ├── ContextPanel.tsx
│ └── icon-map.ts # Maps serializable icon keys -> lucide components
│
├── lib/ # Pure logic — no React, no HTTP. Unit-testable in isolation.
│ ├── data.ts # Benchmark data: countries, cities, currencies, percentiles
│ ├── validation.ts # zod schema — the security boundary for all user input
│ ├── scoring.ts # Percentile + resilience math
│ ├── privileges.ts # "Hidden privileges" list generation
│ ├── insights.ts # Reframe paragraph + actionable win copy
│ └── engine.ts # generateReport() — orchestrates everything above
│
└── types/index.ts # Shared types used across lib/, components/, and the API route
lib/has zero UI or framework dependencies. Every function inlib/takes plain data in and returns plain data out, so the scoring logic can be tested, audited, or reused (e.g. in a CLI or a different frontend) without touching React.- The scoring engine runs server-side, behind
/api/generate-report. The client never sees the benchmark data or formulas directly — it just POSTs form values and gets back a finished report. This means you can tweak scoring logic without shipping it to the browser, and it closes off the obvious "edit the JS in devtools to inflate my score" path. - All input is re-validated on the server with
zodinlib/validation.ts, regardless of what the client already checked. Never trust a request just because it came from your own form. - Components are split by responsibility, not by file size for its
own sake: each form field group and each report section is its own
file, so a change to (say) the health slider only touches
HealthFields.tsx.
- Security headers (CSP, X-Frame-Options, etc.) are set in
next.config.js. - The API route applies a simple in-memory rate limit (20 requests/minute per IP). This resets on server restart and does not share state across multiple server instances — fine for a single small deployment, but if you deploy to a multi-instance/serverless platform at scale, swap it for a shared store (Vercel KV, Upstash Redis, etc.).
- Free-text fields (city) are length-capped and restricted to letter/space/ punctuation characters via regex, both to keep garbage out of the generated report text and as defense-in-depth against injection.
- No personal data is persisted anywhere — each request is stateless.
All country/city/currency figures live in src/lib/data.ts. To add a new
country, add an entry to COUNTRY_DATA and, if you have a currency that
isn't yet in CURRENCY_TO_USD, add it there too — the form's currency
dropdown is generated automatically from that table.
This is a standard Next.js 14 App Router project — it deploys as-is to
Vercel, Netlify, or any Node.js host that supports Next.js. Set
NEXT_PUBLIC_SITE_URL in your hosting provider's environment variables to
your production domain before going live (used for Open Graph metadata).
All rights reserved. This repository is source-visible but not open-source: no license is granted to use, copy, modify, or distribute this code without explicit written permission from the owner.