Portfolio-grade reporting platform that demonstrates project-based backend experience with Node.js, TypeScript, Python, FastAPI, PostgreSQL, Redis, Docker, and React.
The application models a realistic internal sales operations workflow: authenticated users browse order and outlet data, request asynchronous CSV reports, track report status, and download completed exports.
React + TypeScript web app
|
Node.js + TypeScript API
Auth, RBAC boundary, REST endpoints, pagination, report job creation
|
PostgreSQL
Relational sales data, users, report metadata, export metadata
|
Redis Streams
Report job queue and short-lived job status cache
|
Python + FastAPI worker
Report aggregation, CSV export generation, job status updates
The Node.js API owns the user-facing contract. The Python service is intentionally focused on data processing and export generation.
- Frontend: Vite, React, TypeScript
- API: Node.js, NestJS, TypeScript, direct SQL with
pg - Worker: Python, FastAPI, asyncpg, Redis client
- Data: PostgreSQL, Redis Streams
- Runtime: Docker Compose
Direct SQL is used in the first pass so schema constraints, indexes, and reporting queries are visible. An ORM can be added later if it reduces maintenance cost.
Create a local env file. Secrets are intentionally not committed.
cp .env.example .envSet POSTGRES_PASSWORD, JWT_SECRET, and SEED_USER_PASSWORD in .env, then generate the matching seed hash:
SEED_USER_PASSWORD="<your-local-seed-password>" node scripts/hash-password.mjsPowerShell:
$env:SEED_USER_PASSWORD="<your-local-seed-password>"; node scripts/hash-password.mjsCopy the generated SEED_USER_PASSWORD_HASH=... line into .env. The helper escapes $ characters for Docker Compose.
Start the full stack:
docker compose up --buildOpen the frontend:
http://localhost:5173
Seeded credentials:
admin@example.com / value of SEED_USER_PASSWORD in .env
manager@example.com / value of SEED_USER_PASSWORD in .env
analyst@example.com / value of SEED_USER_PASSWORD in .env
Service URLs:
- Web:
http://localhost:5173 - API health:
http://localhost:3000/api/health - Worker health:
http://localhost:8000/health - PostgreSQL:
localhost:5432 - Redis:
localhost:6379
- Sign in with a seeded user.
- Review dashboard sales totals and report job status.
- Browse paginated orders and outlets with filters.
- Request a report from the Reports screen.
- The Node API inserts a report job and writes a Redis Stream event.
- The Python worker consumes the event, runs PostgreSQL aggregation queries, writes a CSV export, and marks the job completed.
- Download the completed CSV export from the Reports screen.
Login:
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d "{\"email\":\"manager@example.com\",\"password\":\"$SEED_USER_PASSWORD\"}"List orders:
curl "http://localhost:3000/api/orders?page=1&limit=25&status=fulfilled" \
-H "Authorization: Bearer <token>"Create report job:
curl -X POST http://localhost:3000/api/reports/jobs \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"reportType":"sales_summary","startDate":"2026-01-01","endDate":"2026-04-30","regionCode":"NE"}'After installing dependencies locally:
npm testWorker tests:
cd apps/worker
pip install -e ".[test]"
pytestThe first committed tests cover password hash verification in the API and CSV export formatting in the worker. Broader endpoint and workflow tests should be added as the vertical slice matures.
The default seed creates users, roles, regions, representatives, outlets, products, 240 orders, and order items. The schema includes indexes for order browsing, date-range reporting, report job lookup, and JSONB report parameters.
For larger local performance checks, run:
psql "$DATABASE_URL" -f infra/db/large-seed.sqlSales Reporting and Data Processing Platform | Node.js, TypeScript, Python, FastAPI, PostgreSQL, Redis, Docker
Built a production-style project with a Node.js API layer and Python worker service for asynchronous report generation. Implemented authentication, role-based report access, pagination, PostgreSQL indexing, Redis-backed job coordination, CSV exports, Dockerized local development, and focused tests.
Use this as project-based experience, not employment experience.