An AI-powered survey creation platform that guides you through a three-step workflow: define your survey configuration, generate a structured variable model, then produce a full question set—automatically. Powered by OpenRouter, the AI doesn't just generate questions; it evaluates them for quality, detects duplicates, checks readability, and auto-regenerates underperforming items. An integrated chat assistant lets you refine questions in plain language after generation.
Built for teams, the platform also supports user accounts, survey persistence with full version history, shareable links, and live multi-user collaboration over WebSockets.
- Three-step AI workflow — configure your survey, generate a structured variable model (dependent / driver / control), then stream-generate a validated question set
- Intelligent question evaluation — automatically scores questions for clarity, relevance, readability, duplicate similarity, and skip-logic correctness; auto-regenerates on failure
- AI chat assistant — refine, add, remove, reorder, or simplify questions through a natural-language chat interface
- Survey flow visualization — interactive node-graph view of your survey's branching logic, powered by React Flow
- Question types — Likert, Multiple Choice, Multi-Select, Yes/No, Open-Ended, and Rating scales, all with conditional branching
- PDF import — paste or upload a PDF and the AI extracts the survey configuration automatically
- Authentication — register/login with JWT-based sessions
- Survey persistence — save, edit, and manage surveys with
DRAFT/PUBLISHED/ARCHIVEDstatuses - Version history — every save creates a snapshot; restore any previous version at any time
- Sharing — generate shareable links with
VIEWorEDITpermissions and optional expiry - Real-time collaboration — live cursor tracking and survey sync over Socket.IO; authenticated users or guests can share a room
- Multilingual — full Arabic (RTL) and English support via i18next
| Technology | Role |
|---|---|
| React 18 & Vite | UI framework and build tool |
| Tailwind CSS v3 | Utility-first styling |
| React Router v6 | Client-side routing |
| @xyflow/react | Interactive survey flow graph |
| Socket.IO Client | Real-time collaboration |
| i18next | Multilingual support (EN / AR) |
| Lucide React | Icon set |
| Technology | Role |
|---|---|
| Node.js & Express.js | HTTP server |
| PostgreSQL & Prisma ORM | Relational data persistence |
| Socket.IO | WebSocket rooms and event broadcasting |
| JSON Web Tokens (JWT) | Authentication |
| bcrypt | Password hashing |
| pdf-parse | PDF text extraction |
| @xenova/transformers | Local embeddings for duplicate detection |
| OpenRouter API | LLM gateway (configurable model) |
- Node.js 20.6+
- PostgreSQL database (local or hosted, e.g. Supabase, Neon, Railway) — not needed for Docker
- An OpenRouter API key
npm run install:allcp server/.env.example server/.envEdit server/.env:
OPENROUTER_API_KEY=your_key_here
OPENROUTER_MODEL=moonshotai/kimi-k2.6:free
DATABASE_URL="postgresql://user:password@localhost:5432/dynamic_survey"
JWT_SECRET=a_long_random_secret_stringcd server && npm run db:migratenpm run devThis starts both the client (http://localhost:5173) and the API server (http://localhost:4000) concurrently. Vite proxies /api and /socket.io to the server in development.
The Docker setup is a development environment — PostgreSQL and pgAdmin are included as services, and your local server/, client/, and shared/ source folders are bind-mounted into the app container for hot reload (Vite dev server + node --watch). Database migrations run automatically on every container start.
cp .env.example .envEdit .env and fill in your values:
POSTGRES_PASSWORD=changeme
JWT_SECRET=a_long_random_secret_string
OPENROUTER_API_KEY=your_key_here
OPENROUTER_MODEL=moonshotai/kimi-k2.6:freedocker compose up --buildThat's it. Compose will:
- Pull and start a PostgreSQL 16 container
- Start a pgAdmin container for inspecting the database
- Build the app image and install dependencies (root, server, client)
- Wait for Postgres to pass its healthcheck
- Run
prisma migrate deployto apply any pending migrations - Start the Express server (with
--watch) on http://localhost:4000 and the Vite dev server on http://localhost:5173
Data is persisted in named Docker volumes (postgres_data, pgadmin_data) so it survives container restarts. Code changes on your host are picked up automatically — no rebuild needed unless you change a package.json.
docker compose updocker compose downTo also delete the database volume:
docker compose down -vPostgres is exposed on the host at localhost:5432 (configurable via POSTGRES_PORT), so you can connect with any DB client — pgAdmin, a VS Code database extension, DBeaver, psql, etc. — using the POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB values from your .env.
A pgAdmin instance is also included at http://localhost:5050 (login with PGADMIN_EMAIL / PGADMIN_PASSWORD, default admin@example.com / admin). Add a new server connection there using host postgres, port 5432, and your Postgres credentials.
| Variable | Required | Default | Description |
|---|---|---|---|
POSTGRES_USER |
No | survey |
PostgreSQL username |
POSTGRES_PASSWORD |
Yes | — | PostgreSQL password |
POSTGRES_DB |
No | survey_db |
PostgreSQL database name |
POSTGRES_PORT |
No | 5432 |
Host port mapped to Postgres (for DB clients) |
PGADMIN_EMAIL |
No | admin@example.com |
pgAdmin login email |
PGADMIN_PASSWORD |
No | admin |
pgAdmin login password |
PGADMIN_PORT |
No | 5050 |
Host port mapped to pgAdmin |
JWT_SECRET |
Yes | — | Secret used to sign and verify JWT tokens |
OPENROUTER_API_KEY |
Yes | — | OpenRouter API key |
OPENROUTER_MODEL |
No | (empty) | Model to use via OpenRouter |
PORT |
No | 4000 |
Host port mapped to the Express server |
CLIENT_PORT |
No | 5173 |
Host port mapped to the Vite dev server |
| Variable | Required | Default | Description |
|---|---|---|---|
OPENROUTER_API_KEY |
Yes | — | OpenRouter API key |
OPENROUTER_MODEL |
No | moonshotai/kimi-k2.6:free |
Model to use via OpenRouter |
DATABASE_URL |
Yes | — | PostgreSQL connection string |
JWT_SECRET |
Yes | — | Secret used to sign and verify JWT tokens |
| Method & Path | Description |
|---|---|
POST /api/auth/register |
Create a new user account |
POST /api/auth/login |
Authenticate and receive a JWT |
GET /api/auth/me |
Return the authenticated user |
| Method & Path | Description |
|---|---|
GET /api/surveys |
List all surveys for the authenticated user |
POST /api/surveys |
Create a new survey |
GET /api/surveys/:id |
Fetch a single survey |
PUT /api/surveys/:id |
Update survey metadata or content |
DELETE /api/surveys/:id |
Delete a survey |
GET /api/surveys/:id/versions |
List all saved versions |
POST /api/surveys/:id/versions |
Restore a version snapshot |
GET /api/surveys/:id/shares |
List active share links |
POST /api/surveys/:id/shares |
Create a share link (VIEW or EDIT, optional expiry) |
DELETE /api/surveys/:id/shares/:shareId |
Revoke a share link |
GET /api/surveys/:id/collaborators |
List collaborators |
GET /api/shared/:token |
Access a survey via a public share token |
| Method & Path | Description |
|---|---|
POST /api/generate-variable-model |
Generate a variable model (dependent / driver / control) |
POST /api/generate-questions |
Generate and evaluate questions — streams progress via SSE |
POST /api/evaluate-questions |
Evaluate an existing question set |
POST /api/chat |
Chat assistant for natural-language survey editing |
| Method & Path | Description |
|---|---|
GET /health |
Health check |