Production-like REST API backend for multi-workspace task management (a simplified Jira/Linear-style backend). Built as a portfolio project with clean Laravel conventions, RBAC, audit trail, test coverage, Docker-first setup and OpenAPI.
- Multi-workspace model (Workspace → Projects → Tasks)
- Tasks with filtering, sorting, pagination and bulk update
- Labels (CRUD) + many-to-many labels on tasks (attach/detach)
- Comments (CRUD) with author/admin rules
- Invitations (create, accept/decline by token) with
declined_at - Role-based access control:
owner / admin / member / viewer - Activity log (domain events → persisted audit log)
- OpenAPI/Swagger docs
- PHP 8.3
- Laravel 11
- PostgreSQL 16
- Redis 7
- Docker (nginx + php-fpm)
- Laravel Sanctum
- PHPUnit Feature Tests
- L5 Swagger (swagger-php attributes)
- GitHub Actions CI
sudo docker compose up -d --build
sudo docker compose exec -T app php artisan migrate --force
sudo docker compose exec -T app php artisan l5-swagger:generateOpen:
- API base URL:
http://localhost:8080/api/v1 - Swagger UI:
http://localhost:8080/api/docs - OpenAPI JSON:
http://localhost:8080/docs?api-docs.json
- Controllers: orchestration (authz, request → service → resource)
- Form Requests: validation + auth where appropriate
- Policies + WorkspaceRoleResolver: RBAC and isolation by workspace
- API Resources: consistent JSON shape
- Services:
WorkspaceRoleResolver— resolves role in a workspaceTaskIndexQuery— query builder for tasks index filters/sort/pagination
- Activity Log pipeline:
ActivityOccurred→ listener/job →activity_logs
Auth:
POST /api/v1/auth/registerPOST /api/v1/auth/loginGET /api/v1/auth/mePOST /api/v1/auth/logout
Workspaces:
GET /api/v1/workspacesPOST /api/v1/workspacesGET /api/v1/workspaces/{workspace}PATCH /api/v1/workspaces/{workspace}DELETE /api/v1/workspaces/{workspace}
Projects:
GET /api/v1/workspaces/{workspace}/projectsPOST /api/v1/workspaces/{workspace}/projectsGET /api/v1/workspaces/{workspace}/projects/{project}PATCH /api/v1/workspaces/{workspace}/projects/{project}DELETE /api/v1/workspaces/{workspace}/projects/{project}
Tasks:
GET /api/v1/workspaces/{workspace}/projects/{project}/tasks- filters:
status,priority,assignee_id,due_date(alias),due_from,due_to - sorting:
sort=id,-id,priority,... - pagination:
per_page
- filters:
POST /api/v1/workspaces/{workspace}/projects/{project}/tasksPATCH /api/v1/workspaces/{workspace}/tasks/{task}DELETE /api/v1/workspaces/{workspace}/tasks/{task}PATCH /api/v1/workspaces/{workspace}/tasks/bulk
Comments:
GET /api/v1/workspaces/{workspace}/tasks/{task}/commentsPOST /api/v1/workspaces/{workspace}/tasks/{task}/commentsPATCH /api/v1/workspaces/{workspace}/comments/{comment}DELETE /api/v1/workspaces/{workspace}/comments/{comment}
Labels:
GET /api/v1/workspaces/{workspace}/labelsPOST /api/v1/workspaces/{workspace}/labelsPATCH /api/v1/workspaces/{workspace}/labels/{label}DELETE /api/v1/workspaces/{workspace}/labels/{label}POST /api/v1/workspaces/{workspace}/tasks/{task}/labels(attach)DELETE /api/v1/workspaces/{workspace}/tasks/{task}/labels/{label}(detach)
Invitations:
GET /api/v1/workspaces/{workspace}/invitationsPOST /api/v1/workspaces/{workspace}/invitationsDELETE /api/v1/workspaces/{workspace}/invitations/{invitation}POST /api/v1/invitations/{token}/acceptPOST /api/v1/invitations/{token}/decline
Activity Log:
GET /api/v1/workspaces/{workspace}/activityGET /api/v1/activity?workspace_id=...
- Owner: full control (including workspace delete)
- Admin: manage workspace settings, projects, members, invitations, bulk actions
- Member: work on tasks (create/update/delete), comments
- Viewer: read-only access
workspaces1—Nprojectsprojects1—Ntaskstasks1—Ncommentsworkspaces1—NlabelstasksN—Mlabelsvialabel_taskworkspaces1—Nworkspace_membersworkspaces1—Ninvitationsworkspaces1—Nactivity_logs
sudo docker compose exec -T app php artisan test./vendor/bin/pint --testGitHub Actions pipeline runs:
- Pint (
pint --test) - DB migrations
- Feature tests (
php artisan test)
- Export OpenAPI schemas for response bodies (full DTO-level schemas)
- Add seeders for demo workspace/project/tasks
- Add additional task filters (e.g. full-text search)
- Add rate limiting and request IDs for tracing
