A policy sign-off tracker for HR and compliance teams. Users create policies with deadlines and optional document attachments. All registered users are required to acknowledge each policy, and managers can see exactly who has signed and who hasn't.
Live: policysignoff.justinsovine.com
- Create policies with a title, description, due date, and optional PDF/Word attachment
- All users sign off on every policy - no assignment or invitation step
- Dashboard shows each policy's status: signed, pending, or overdue
- Policy detail shows a full sign-off summary: who signed, when, and who's still outstanding
- Files are stored in S3-compatible object storage (MinIO); uploads go directly from the browser to the object store via presigned URLs
Three separate frontend clients consume the same Laravel API, demonstrating the same product built three different ways:
| Client | Stack | URL |
|---|---|---|
client/ |
React (TypeScript) + Vite + React Router | policysignoff.justinsovine.com |
api/ |
Laravel 12 + Sanctum + MinIO | policysignoff-api.justinsovine.com |
Auth is cookie-based via Laravel Sanctum (no tokens, no localStorage). The API is fully documented in docs/api-spec.md.
Prerequisites: Docker and Docker Compose.
# Start all services (API, MySQL, MinIO, React dev server)
docker compose up -d
# First run: migrate, seed, create the MinIO bucket
docker compose exec api php artisan migrate --seed
docker compose exec minio mc alias set local http://localhost:9000 minioadmin minioadmin
docker compose exec minio mc mb local/policysignoff| Service | URL |
|---|---|
| React client | http://localhost:3001 |
| API | http://localhost:8000 |
| MinIO console | http://localhost:9001 (minioadmin / minioadmin) |
Default seed credentials: jane@example.com / password (and alice@example.com, bob@example.com, etc.
A Postman collection is in postman/ covering all endpoints with Sanctum cookie auth pre-wired. Import the collection, run "Auth / 1. CSRF Cookie" then "Auth / 2. Login", and the rest of the requests are ready to use. Requires cookie handling enabled for localhost in Postman settings.
A curl-based smoke test also covers all 16 API endpoints including the full file upload/download roundtrip:
./test-api.sh
# or as a specific user:
./test-api.sh jane@example.com passwordThe app runs on a Linode VPS behind host-level NGINX. SSL is terminated upstream; NGINX proxies to Docker containers on port 80. To deploy:
./deploy.shThe script pulls the latest code, rebuilds images, restarts containers, and runs migrations. See docs/deployment.md for one-time VPS setup (NGINX config, Cloudflare DNS, MinIO bucket).
docs/api-spec.md- API routes, data model, response shapes, auth and file upload patternsdocs/mockups/- Static HTML+Tailwind mockups with all UI statesdocs/roadmap.md- Ideas for continuing to grow the projectdocs/deployment.md- One-time VPS setup instructions