close
Skip to content

himanshu748/FormOS

Repository files navigation

FormOS 🗔

A full-stack form builder with a retro operating-system soul — build forms on a Windows-95-flavored desktop, publish them, share a link + QR, and watch responses roll in.

Built for the ChaiCode "build a similar project" challenge on the exact restricted stack: Turborepo · Next.js · tRPC · Drizzle ORM · PostgreSQL · Scalar (OpenAPI).

All business logic is implemented as tRPC procedures — there are no REST endpoints for forms, submissions, views, or analytics. The only non-tRPC routes are the single tRPC HTTP handler and the OpenAPI/docs endpoints.


✨ Features

  • Form editor / canvas — create a form, add fields dynamically, edit labels, help text, placeholders, required state, and options, reorder fields (▲/▼), duplicate, delete, pick a window theme, Save draft and Publish. Includes a live interactive preview.
  • 8 field types — short text, long text, email, rating (stars), dropdown, multiple choice, checkbox, and date.
  • Public form/forms/[slug] renders the published schema, validates required fields (client and server), stores the response as JSON, and tracks views. Fully anonymous.
  • Sharing — one-click public link + a QR code for any published form.
  • Analytics dashboard — total views, total submissions, completion rate, average completion time, a paginated response table, and per-field breakdowns for rating / dropdown / multiple-choice / checkbox fields.
  • Retro OS UI — hand-built window chrome, beveled controls, group boxes, a taskbar with a live clock, retro scrollbars, and playful microcopy. Fully responsive down to mobile.
  • Scalar API docs/docs renders an OpenAPI 3.1 spec that is generated by introspecting the live tRPC router (so it can't drift from the procedures).
  • Loading / empty / error states everywhere.

🧱 Tech stack

Layer Choice
Monorepo Turborepo + pnpm workspaces
Frontend Next.js 15 (App Router) + React 19 + TypeScript
API tRPC v11 (procedures only — no REST business API)
Validation Zod (shared client + server)
ORM Drizzle ORM (postgres-js driver)
Database PostgreSQL 16
API docs Scalar over an introspected OpenAPI 3.1 document
Styling Hand-built retro CSS design system + Tailwind for responsive layout
Local DB Docker Compose

📁 Project structure

formos/
├─ apps/
│  └─ web/                 # Next.js app (UI + the only HTTP routes)
│     └─ src/
│        ├─ app/
│        │  ├─ page.tsx                 # Dashboard (retro desktop)
│        │  ├─ editor/[id]/             # Form editor
│        │  ├─ forms/[slug]/            # Public form (anonymous)
│        │  ├─ analytics/[id]/          # Analytics dashboard
│        │  ├─ docs/route.ts            # Scalar docs viewer
│        │  └─ api/
│        │     ├─ trpc/[trpc]/route.ts  # THE single tRPC endpoint
│        │     └─ openapi.json/route.ts # OpenAPI spec (for Scalar)
│        ├─ components/                 # dashboard, editor, runner, analytics…
│        ├─ lib/trpc/                   # tRPC React client + provider
│        └─ server/api.ts               # server-side tRPC caller (SSR)
├─ packages/
│  ├─ api/                # tRPC routers, context, Zod inputs, OpenAPI generator
│  ├─ db/                 # Drizzle schema, client, migrations, seed, field model
│  ├─ ui/                 # Retro OS component kit + retro.css
│  └─ config/             # Shared tsconfig presets
├─ docker-compose.yml     # Local PostgreSQL
├─ turbo.json
└─ pnpm-workspace.yaml

Request flow

React components ──(@trpc/react-query)──▶ POST/GET /api/trpc/<proc>
                                              │
                                   packages/api  appRouter (Zod-validated)
                                              │
                                   packages/db   Drizzle ──▶ PostgreSQL

/api/openapi.json introspects the same appRouter to produce the spec Scalar renders at /docs.


🚀 Quick start

Prerequisites: Node ≥ 20, pnpm ≥ 10, and Docker (for local PostgreSQL).

# 1. Install dependencies
pnpm install

# 2. Configure environment
cp .env.example .env
#   (DB defaults match docker-compose.yml. Set ADMIN_TOKEN to any passcode —
#    you'll enter it once to unlock the builder/analytics.)

# 3. Start PostgreSQL
docker compose up -d

# 4. Apply the schema + load demo data
pnpm db:migrate     # create the tables
pnpm db:seed        # 1 demo user, 3 forms, ~78 views, ~53 submissions

# 5. Run the app
pnpm dev

Open http://localhost:3000 🎉

First run without seeding? No problem — a demo operator and your first form are created on demand.


📜 Scripts

Command What it does
pnpm dev Run the web app in dev mode
pnpm build Production build of every package
pnpm typecheck Type-check all packages
pnpm lint ESLint across the repo
pnpm db:generate Generate a new SQL migration from the Drizzle schema
pnpm db:migrate Apply migrations to the database
pnpm db:push Push the schema directly (handy in dev)
pnpm db:seed Reset + seed demo data
pnpm db:studio Open Drizzle Studio

🗃️ Data model

  • demo_users — simplified auth: one demo operator owns the forms.
  • formstitle, description, unique slug, status (draft | published), accent, and an ordered fields array stored as JSONB.
  • form_views — one row per public view, with an anonymous session_id.
  • form_submissions — answers as JSONB keyed by field id, plus duration_ms (paired to a view via session_id for completion-time analytics).

The field model (packages/db/src/fields.ts) is the single source of truth — the same Zod schemas validate tRPC inputs, type the JSONB column, and drive the editor/renderer.


📖 API & docs

Every operation is a tRPC procedure under form.*, submission.*, view.*, analytics.*. Browse them at /docs (Scalar). The spec at /api/openapi.json documents how each procedure is reached over tRPC's HTTP transport:

  • QueriesGET /api/trpc/<procedure>?input=<url-encoded JSON>
  • MutationsPOST /api/trpc/<procedure> with the input as the JSON body

No duplicate REST API is generated — the doc is built by reading the real router + Zod inputs.


✅ Status & honest notes

What's been verified in this repo:

  • pnpm typecheck — ✅ passes (all 5 packages)
  • pnpm lint — ✅ passes
  • pnpm build — ✅ next build succeeds
  • pnpm db:generate — ✅ initial migration committed in packages/db/migrations
  • Runtime smoke test (no DB needed): /, /docs, and /api/openapi.json all return 200, and the OpenAPI generator emits all 13 procedures.

Notes:

  • Live PostgreSQL is exercised via the steps above on your machine (Docker). The repo ships the migration + seed so a clean machine reaches a working app with migrate → seed → dev.
  • Auth is simplified per the brief: a single demo operator owns the forms, and the builder + analytics are gated by a shared admin passcode (ADMIN_TOKEN, sent as the x-admin-token header; enter it once on the unlock screen). Public form-filling at /forms/[slug] stays anonymous. Swap in real per-user auth later if needed.
  • The Scalar viewer at /docs loads its bundle from a CDN at runtime; the OpenAPI JSON itself is served by the app.

🚀 Live demo

Hosted on Vercel (Next.js) + Supabase (PostgreSQL via the IPv4 transaction pooler). The builder & analytics are behind an admin passcode (ADMIN_TOKEN); public form-filling is open.

Built for the ChaiCode #ChaiForms challenge — a form builder on the restricted stack, built end-to-end (including the demo video) with Claude Opus 4.8.

🚢 Deploy

apps/web is a standard Next.js app and deploys cleanly to any Node host (e.g. Vercel) with a managed PostgreSQL DATABASE_URL, NEXT_PUBLIC_APP_URL, and ADMIN_TOKEN set. For a pnpm monorepo, set the Vercel Root Directory to apps/web and deploy from Git (Vercel includes the workspace automatically).

License

MIT — add a LICENSE file if you publish it.

About

Retro OS full-stack form builder with Next.js, tRPC, Drizzle, PostgreSQL, public forms, QR sharing, analytics, and Scalar docs.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors