A working full-stack prototype for a technical-services / property-maintenance company. Customers self-register and raise a maintenance request, choosing the department (skill group) it belongs to; the department receives it; a dispatcher assigns a technician who actually holds that skill; the technician works it to completion. A technician can belong to many skill groups — one person, many jobs.
- Backend: Django 6 + Django REST Framework, JWT auth (SimpleJWT), Postgres (Neon in production, SQLite locally), drf-spectacular OpenAPI schema.
- Frontend: React 19 + TypeScript + Vite single-page app.
- Deploy: Render (two services) — see
render.yaml.
| Role | Does |
|---|---|
| Customer | Registers, raises requests, tracks status, comments, cancels/closes. |
| Dispatcher | Sees their departments' inbox; assigns/reassigns a skill-matched technician. |
| Technician | Works assigned jobs: start → hold/resume → complete; posts worklogs. |
| Manager | Operations dashboard + Django admin (departments, skills, users). |
The load-bearing rule lives in backend/apps/tickets/services.py: a technician
is only assignable to a request whose department is one of their skill groups
and they are available. It is enforced at the model layer and surfaced in
the assign UI (which only lists eligible technicians).
Option A — Docker (real Postgres):
docker compose up --build # API on http://localhost:8000
cd frontend && npm install && npm run dev # SPA on http://localhost:5173Option B — no Docker (SQLite):
cd backend
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements-dev.txt
python manage.py migrate && python manage.py seed
DEBUG=true python manage.py runserver # API on http://localhost:8000
cd ../frontend && npm install && npm run dev # SPA on http://localhost:5173Log in with a seeded demo user (password demo12345): customer, dispatcher,
tech.ahmed, manager. The login screen has one-click buttons for each.
render.yaml defines both services and wires them together. Three steps (only
the account owner can do them):
- Neon — create a Postgres database; copy the pooled connection string
(ending
?sslmode=require). - Render — New → Blueprint → point at this repo (both services created).
- In fixflow-api → Environment, paste the Neon string into
DATABASE_URL(it issync:false, never stored in the repo). Deploy.
SECRET_KEY is generated by Render; DEMO_MODE=true seeds the database on the
first build. The SPA's VITE_API_BASE_URL is wired to the API service
automatically.
cd backend && pytest # models, the skill-guard, permissions, API
cd frontend && npm run build # typecheck + production buildbackend/ Django project (config/) + apps/ (accounts, catalog, sla, tickets)
frontend/ Vite + React + TS SPA (src/pages/{customer,dispatch,tech,manage})
render.yaml docker-compose.yml
All data is synthetic. Built by Muhammad Saad. MIT licensed.