CollabBoards is a Trello-style collaboration app with workspaces, boards, lists, cards, comments, and file attachments. Updates broadcast in real time over Socket.IO.
Shipped:
- email/password auth (JWT access + refresh tokens)
- workspaces with role-based members (OWNER / ADMIN / MEMBER)
- boards, lists, cards with inline edit + delete
- card metadata: assignee, labels, due date
- rich-text card descriptions (TipTap, sanitized on render)
- drag-and-drop card movement within and across lists
- file attachments per card (upload, download, delete)
- card comments and activity feed
- live updates over Socket.IO
- Backend: Node.js, Express, TypeScript, Prisma, PostgreSQL, Socket.IO, multer
- Frontend: React, TypeScript, Vite, Axios, Socket.IO client, @dnd-kit, TipTap, DOMPurify
- CI: install, lint, tests, backend build, frontend build
backend/: API, Prisma schema, seed, route + service + integration testsfrontend/: SPA — auth, workspaces, boards, DnD card moves, rich-text editor, attachments.github/workflows/ci.yml: repository CI gatesCHECKLIST.md: implementation ledgerREQUIREMENTS.md: product requirements
- Install packages:
npm install- Copy env examples:
copy backend.env.example backend\.env
copy frontend.env.example frontend\.env- Provide PostgreSQL in
backend/.envviaDATABASE_URL.
Optional Docker path if Docker exists on your machine:
docker run --name collabboards-postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_USER=postgres -e POSTGRES_DB=collabboards -p 5432:5432 -d postgres:16Then use:
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/collabboards- Apply committed migrations and seed demo data:
npx prisma migrate deploy --schema backend/prisma/schema.prisma
npm run prisma:seed --workspace backendSeed login after this step:
- email:
demo@collabboards.local - password:
demo12345
- Run backend and frontend:
npm run dev:backend
npm run dev:frontendDefaults:
- backend:
http://localhost:4000 - frontend:
http://localhost:5173 - frontend backend origin override:
VITE_BACKEND_URL=http://localhost:4000
| Variable | Purpose | Default |
|---|---|---|
PORT |
HTTP port | 4000 |
DATABASE_URL |
PostgreSQL connection string | required |
JWT_ACCESS_TOKEN_SECRET |
Access token signing secret | required |
JWT_REFRESH_TOKEN_SECRET |
Refresh token signing secret | required |
FRONTEND_URL |
CORS allowlist (optional) | http://localhost:5173 |
UPLOAD_DIR |
Where attachments are stored on disk | backend/uploads/ |
MAX_UPLOAD_BYTES |
Per-file upload limit | 10485760 (10 MB) |
On Railway, mount a volume at UPLOAD_DIR to persist attachments across deploys.
All routes live under /api.
Auth:
POST /api/auth/registerPOST /api/auth/loginPOST /api/auth/refreshPOST /api/auth/logout
Workspaces:
GET /api/workspacesPOST /api/workspacesGET /api/workspaces/:workspaceIdPATCH /api/workspaces/:workspaceIdDELETE /api/workspaces/:workspaceId
Boards:
GET /api/workspaces/:workspaceId/boardsPOST /api/workspaces/:workspaceId/boardsGET /api/boards/:idPATCH /api/boards/:idDELETE /api/boards/:id
Lists:
POST /api/boards/:boardId/listsGET /api/lists/:idPATCH /api/lists/:idDELETE /api/lists/:id
Cards:
POST /api/lists/:listId/cardsGET /api/cards/:idPATCH /api/cards/:idDELETE /api/cards/:id
Comments:
POST /api/cards/:cardId/commentsGET /api/cards/:cardId/commentsDELETE /api/comments/:id
Members:
GET /api/workspaces/:workspaceId/membersPOST /api/workspaces/:workspaceId/membersPATCH /api/workspaces/:workspaceId/members/:memberIdDELETE /api/workspaces/:workspaceId/members/:memberId
Attachments:
GET /api/cards/:cardId/attachmentsPOST /api/cards/:cardId/attachments(multipart, field namefile)GET /api/attachments/:id/downloadDELETE /api/attachments/:id
Card metadata in the contract:
assigneeIdlabelsdueDatedescription(HTML; sanitized at render time)position(used for ordering; PATCH withlistId + positionreorders the target list)
Socket.IO rooms:
workspace:{id}board:{id}
Client events:
join-workspaceleave-workspacejoin-boardleave-board
Server events:
board:createdboard:updatedboard:deletedlist:createdlist:updatedlist:deletedcard:createdcard:updatedcard:movedcard:deletedcomment:addedcomment:deletedattachment:addedattachment:deleted
Frontend joins relevant rooms on navigation and refetches board/card state on any event.
Repository:
npm install
npm run lint
npm test
npm run build --workspace backend
npm run build --workspace frontendnpm test --workspace backend includes a DB-backed integration suite that boots an embedded PostgreSQL instance, applies the committed Prisma migrations, and exercises the auth, workspace, board, list, card, comment, reorder, and cascade-delete flow end-to-end. Embedded PostgreSQL does not run on Windows; on Windows the integration suite is skipped and full coverage runs in CI on Linux.
Manual smoke with configured DB:
- backend
GET /api/health - auth register/login/refresh/logout
- workspace create/list
- board create/list/open
- list create
- card create/move
- comment create/list
Automated production-style smoke:
npm run smoke -- --backend-url https://your-backend.example.com --frontend-url https://your-frontend.example.comThis command:
- checks
GET /api/health - registers a disposable user, then exercises login, refresh, and logout
- creates and refetches workspace, board, list, card, and comment data over REST
- joins
workspace:{id}andboard:{id}Socket.IO rooms - verifies board/card refresh after
board:created,list:created,card:created,card:moved, andcomment:added - cleans up the disposable board, list, card, and comment data it created
Local production-style proof:
npm run build --workspace backend
npm run build --workspace frontend
npm run smoke:localsmoke:local starts a temporary embedded PostgreSQL instance, applies committed Prisma migrations, boots the backend from dist/, serves the built frontend with vite preview, and runs the same smoke flow against those local URLs.
Deployment note:
- Railway uses
npm run start:railway --workspace backend, which runsprisma migrate deploybeforenode dist/index.js.