PROJECT_01
Skilled ERP
ERP for payroll, employees, inventory and tools: a Flask JSON API with 216 endpoints and a React/Vite SPA, with real-time notifications over Socket.IO.
- TYPE
- Full Stack · Security
- STATUS
- IN PRODUCTION
- SCREENSHOTS
- 5
CONTEXT
Internal management system that brings payroll, employee records, inventory and tools together on a single platform, with strict control over what each of the 6 roles can see.
WHAT IT COVERS
- Employees: create, edit and deactivate, with employment, personal, medical and financial fields filtered by a per-role whitelist.
- Payroll: pre-payroll, deductions, extra deposits, loans with repayments and per-period adjustments.
- Hours: weekly reports, daily records, absences, vacation balance and RFID/QR clock-in.
- Inventory: products, warehouses and QR-labelled shelves, requests with approval flow and partial delivery, physical counts with automatic adjustment, and purchase orders.
- Tools: catalogue and physical units traceable by serial/QR, with assignments, maintenance, incidents and authorized write-off.
- PDF and Excel reports (receipts, certificates, per-project totals) sanitized against formula injection.
ARCHITECTURE
- JSON API in Flask 3 + SQLAlchemy 2 with 18 blueprints and 216 documented endpoints; migrations with Alembic.
- Production chain: Cloudflare Tunnel → Nginx → Gunicorn → Flask. The origin publishes no inbound ports.
- 4 gevent workers with real WebSockets; all shared state (rate limiting, lockout, anti-replay, events) lives in Redis.
- Files on Cloudflare R2: a public bucket for the catalogue and a private one for documents, with disk as fallback.
- Docker Compose for development: api, PostgreSQL, Redis and ClamAV, each with its own volume.
SECURITY AND CONCURRENCY
- Two-step login: the password returns a single-use token, and only with it can the TOTP code be requested; the 2FA secret is stored encrypted.
- JWT with refresh in an httpOnly cookie and automatic renewal; several in-flight requests share a single refresh.
- External images are checked against SSRF and by magic bytes, rewritten to WebP and scanned with ClamAV before being stored.
- Inventory movements lock the row with SELECT … FOR UPDATE, so two operations on the same stock cannot overwrite each other.
- Rate limiting and escalating account lockout with Flask-Limiter on Redis; security headers with Flask-Talisman.
OBSERVABILITY
- Every response goes through an after_request hook that increments counters in Redis and stores the detail of slow and failed requests.
- Systems panel with p50/p95/p99, traffic, active sessions, account lockouts, security events and an audit of orphan files on R2.
- 36 test modules with pytest.