Members book desks and meeting rooms for time slots. Admins manage inventory, approve or reject bookings, block maintenance windows, and the API prevents double-booking under concurrent requests.
Built with an enterprise-style layered architecture: feature modules, repository/service/controller separation, Zod validation, httpOnly cookie JWT auth with refresh rotation + reuse detection, MongoDB transactions, and Docker Compose one-command bring-up.
| Layer | Stack |
|---|---|
| Backend | Node.js · Express · TypeScript · Mongoose |
| Frontend | React · Vite · TypeScript · Axios · Tailwind CSS |
| Database | MongoDB 7 (replica set — required for transactions) |
| Docs | Swagger UI · Postman collection |
| Use | Name |
|---|---|
| Product / UI | DeskFlow |
| GitHub repo | deskflow |
| npm packages | deskflow-backend, deskflow-frontend |
| Docker Compose project | deskflow |
| Docker containers | deskflow-mongo, deskflow-backend, deskflow-frontend |
| Docker images | deskflow-backend, deskflow-frontend |
| MongoDB database | deskflow |
| Docker volume | deskflow_mongo_data |
https://github.com/azadrajsingh/deskflow
git clone https://github.com/azadrajsingh/deskflow.git
cd deskflowPrerequisites: Docker Desktop (or Docker Engine + Compose v2).
# From the repo root
docker compose up --buildFirst boot initializes the MongoDB replica set and runs the seed (admin user + sample spaces). Wait until deskflow-backend logs Listening on port 5000.
| Service | URL |
|---|---|
| Frontend | http://localhost:3000 |
| Backend API | http://localhost:5001 |
| Health check | http://localhost:5001/api/health |
| Swagger docs | http://localhost:5001/api/docs |
| MongoDB (host) | localhost:27018 (replica set rs0) |
Note: The API container listens on port
5000; the host maps it to 5001 (Windows often reserves 5000). The frontend at:3000proxies/apito the backend container, so the UI works without calling:5001directly. Usehttp://localhost:5001for Swagger and Postman.
Stop:
docker compose downReset database (wipes all data):
docker compose down -vOptional: copy .env.example to .env at the repo root to override JWT secrets and seed admin credentials for Docker Compose.
| Role | Password | |
|---|---|---|
| Admin | admin@cowork.com |
Admin@12345 |
Members self-register from the UI or POST /api/auth/register.
Sample spaces (Hot Desk A1, Conference Room North, …) are created on first seed.
- List spaces (desks / meeting rooms) with capacity, type, amenities
- Search by name or type
- Filter by type, min capacity, and date availability
- Space detail + availability timeline for a chosen date
- Pagination on the space list
- Register / login with httpOnly cookie JWT + refresh rotation + reuse detection
- Book a space for a date + start/end time
- Overlap blocked for pending/approved bookings (transaction-safe)
- View own bookings (
pending/approved/rejected/cancelled) - Cancel own future pending or approved bookings
- CRUD spaces
- Maintenance windows (space unavailable for a range)
- View all bookings filtered by status / date / space
- Approve or reject pending bookings
- Approving one booking auto-rejects overlapping pending bookings
- Role-based auth (
member/admin) - Rate limiting on login & register
- Centralized error middleware + consistent JSON error shape
- Input validation on all write endpoints
- Indexes for search / filter / date-range queries
- Notification stub (console) on booking status change
- Docker Compose + Swagger + Postman
| Tool | Location |
|---|---|
| Swagger UI | http://localhost:5001/api/docs (Docker) · http://localhost:5000/api/docs (local dev) |
| OpenAPI JSON | /api/docs.json |
| Postman | Import postman/deskflow-api.postman_collection.json |
Postman setup:
- Set collection variable
baseUrltohttp://localhost:5001/api(Docker) orhttp://localhost:5000/api(local). - Run Auth → Login (Admin) — cookies and CSRF are handled automatically.
- Call protected endpoints; the pre-request script adds
X-CSRF-Tokenon mutating requests.
| Area | Endpoints |
|---|---|
| Auth | POST /api/auth/register · login · refresh · logout · GET /api/auth/me |
| Spaces | GET /api/spaces · GET /api/spaces/:id · GET /api/spaces/:id/availability · admin CRUD |
| Bookings | POST /api/bookings · GET /api/bookings/me · admin list / approve / reject · cancel |
| Maintenance | admin GET/POST/DELETE /api/maintenance |
Consistent error shape:
{
"success": false,
"message": "Conflict",
"errors": [],
"statusCode": 409
}Use this when you want hot-reload on backend and frontend.
- Node.js 18+ (20 LTS recommended)
- MongoDB 7 running as a replica set (transactions fail without it)
docker run -d --name deskflow-mongo -p 27017:27017 mongo:7 --replSet rs0 --bind_ip_all
docker exec deskflow-mongo mongosh --eval "rs.initiate({_id:'rs0',members:[{_id:0,host:'127.0.0.1:27017'}]})"cd backend
cp .env.example .env
npm install
npm run seed
npm run devcd frontend
npm install
npm run devVite proxies /api → http://localhost:5000, so you do not need VITE_API_URL for local dev.
| File | Purpose |
|---|---|
.env.example |
Docker Compose overrides (optional) |
backend/.env.example |
Local backend development |
frontend/.env.example |
Production frontend API URL (VITE_API_URL) |
| Variable | Description | Example (local) |
|---|---|---|
NODE_ENV |
development / production |
development |
PORT |
API port | 5000 |
MONGODB_URI |
Mongo connection string (include replicaSet=rs0) |
mongodb://127.0.0.1:27017/deskflow?replicaSet=rs0 |
JWT_ACCESS_SECRET |
Access token signing secret (≥32 chars) | change in production |
JWT_REFRESH_SECRET |
Refresh token signing secret | change in production |
ACCESS_TOKEN_TTL |
Short-lived access token | 15m |
REFRESH_TOKEN_TTL |
Refresh token lifetime | 7d |
COOKIE_SECURE |
Secure flag on auth cookies (set true behind HTTPS) |
false |
COOKIE_SAME_SITE |
SameSite policy (strict / lax / none) |
lax |
CORS_ORIGIN |
Allowed origins (comma-separated) | http://localhost:5173,http://localhost:3000 |
SEED_ADMIN_EMAIL |
Seeded admin email | admin@cowork.com |
SEED_ADMIN_PASSWORD |
Seeded admin password | Admin@12345 |
Docker Compose sets MONGODB_URI=mongodb://mongo:27017/deskflow?replicaSet=rs0 internally.
deskflow/
├── docker-compose.yml
├── .env.example
├── README.md
├── TESTING.md ← verify every requirement step-by-step
├── PROJECT_GUIDE.md ← architecture / concurrency deep-dive
├── postman/
├── backend/
│ ├── Dockerfile
│ └── src/
│ ├── app.ts / server.ts
│ ├── config/ # env, swagger
│ ├── database/
│ ├── modules/ # auth · users · spaces · bookings · maintenance
│ └── shared/ # errors, middleware, notifications
└── frontend/
├── Dockerfile
└── src/
├── api/ # Axios + cookie session + CSRF + refresh
├── features/ # spaces · auth · bookings · admin
└── components/
| Location | Command | Description |
|---|---|---|
| root | docker compose up --build |
Full stack (mongo + API + UI) |
| backend | npm run dev |
Watch mode API |
| backend | npm run seed |
Admin + sample spaces |
| backend | npm run build / npm start |
Production |
| backend | npm run lint |
Typecheck |
| frontend | npm run dev |
Vite dev server |
| frontend | npm run build |
Production bundle |
Step-by-step UI, API, and concurrency checks: TESTING.md
- Concurrency: booking create/approve run inside MongoDB multi-document transactions with per-space write locking; overlap =
existing.startAt < newEnd && existing.endAt > newStartforpending/approved. - Auth: short-lived access JWT in httpOnly cookies; refresh tokens hashed (SHA-256) in DB, rotated on use, with family-based reuse detection; CSRF double-submit for mutating requests.
- SOLID: thin controllers, business rules in services, persistence in repositories.
More detail: PROJECT_GUIDE.md
| Item | Location |
|---|---|
| README | This file |
.env.example |
Root, backend/, frontend/ |
docker-compose.yml |
Repo root — docker compose up --build |
| Swagger | /api/docs when API is running |
| Postman | postman/deskflow-api.postman_collection.json |
MIT