Full-stack demo: Node.js + TypeScript + GraphQL backend, PostgreSQL database, React + TypeScript frontend, JWT authentication, portfolio analytics, and basic fake-listing detection.
- Node.js 20+ (or 22+; project tested with current LTS)
- PostgreSQL (local Docker, managed instance, or Neon)
| Path | Description |
|---|---|
Backend/ |
GraphQL API, migrations, seed script |
Frontend/ |
Vite + React SPA |
cd Backend
cp .env.example .envEdit Backend/.env:
-
DATABASE_URL— PostgreSQL connection string.
Important: wrap the value in double quotes if it contains&(e.g. Neon query params), or variables may not load.DATABASE_URL="postgresql://USER:PASSWORD@HOST/dbname?sslmode=require" JWT_SECRET="at_least_8_characters_long" PORT=4000
-
JWT_SECRET— any random string ≥ 8 characters (required in production; dev defaults exist only whenNODE_ENVis notproduction).
Install dependencies and apply schema:
npm install
npm run migrate
npm run seedStart the API (default http://localhost:4000):
npm run devProduction-style run:
npm run build
npm startGraphQL endpoint: POST /graphql (GraphQL over HTTP JSON). Health check: GET /health.
npm run seed creates:
- 2 agencies, 3 agents (password for all seeded agents:
password123) - 20–30 properties per agent, mixed statuses
- View history (bulk insert) and 3 intentionally suspicious listings
- Auto scam-detection flags where rules match
Example login: alice@realadvisor.dev / password123.
cd Frontend
npm install
npm run devBy default Vite serves the app (e.g. http://localhost:5173) and proxies /graphql to http://127.0.0.1:4000.
Start the backend first, otherwise the proxy will log connection errors.
Optional: set VITE_API_PROXY_TARGET in Frontend/.env (see Frontend/.env.example) if the API runs elsewhere.
Build:
npm run build
npm run preview # optional: test production buildRequires Docker and Docker Compose v2.
From the repository root:
docker compose build
docker compose up -dThe backend container runs AUTO_MIGRATE migrations on each start (SQL uses IF NOT EXISTS, so this is safe). Load demo data once:
docker compose exec backend node dist/data-access/seed.jsThen open http://localhost:8080 — nginx serves the SPA and proxies /graphql to the backend. Postgres is published on localhost:5433 → container 5432 (avoids conflict with a local Postgres on 5432). Credentials: realadvisor / realadvisor, database realadvisor.
| Service | Role |
|---|---|
postgres |
PostgreSQL 16 |
backend |
API on port 4000 (internal to Compose) |
frontend |
nginx on 8080 → static files + GraphQL proxy |
Security: edit JWT_SECRET (and DB credentials) in docker-compose.yml before any public deployment.
Disable auto-migrate (optional): set AUTO_MIGRATE=0 on the backend service environment.
External database (e.g. Neon): remove or stop the postgres service, point backend.environment.DATABASE_URL at your URL (quoted if it contains &), and keep depends_on only where needed or start backend after the DB is reachable.
SOLUTION.md— schema rationale, architecture, scam detection, dashboard SQL, improvementsCODE_REVIEW.md— review of the challenge’s sampledashboardStatssnippet
See RealAdvisor_Technical_Challenge.md for the original specification.