SECURITY
Walls you can explain to the union.
Scheduling data is workforce data — seniority lists, absences, discipline-adjacent decisions. GrievanceFree walls every plant’s data off behind controls you can inspect and explain. Below is exactly what we enforce, not a compliance slide.
DATA HANDLING
Isolation enforced by the database itself.
Your rosters and schedules live in encrypted, hosted PostgreSQL with row-level security: every query is scoped to your organization at the database layer, so tenant isolation doesn’t depend on application code getting it right. That’s a control you can point to in an audit, not a checkbox on a marketing page.
Sessions ride httpOnly cookies, tokens are verified against a pinned algorithm, and every database access is parameterized. The full list of enforced controls is below — each one maps to real code, not aspiration.
THE CONTROLS
What we actually enforce.
Tenant isolation at the database layer
Every organization is a separate tenant behind row-level security in PostgreSQL — every table, every query, scoped to your organization by the database itself, not just by application code. One plant can never read another’s data.
Encrypted, managed PostgreSQL
Data is encrypted in transit and at rest on managed database infrastructure, with organization-scoped filters enforced on every tenant query in addition to row-level security.
httpOnly session cookies
Sessions ride in httpOnly, SameSite cookies (marked Secure in production), so tokens aren’t reachable from page JavaScript and cross-site request forgery is blocked by default.
Hardened token verification
JWTs are verified with a pinned HS256 algorithm, real signature checks, expiry enforcement, and access-vs-refresh type validation — the classic “alg:none” and refresh-as-access bypasses are rejected.
Password & brute-force defenses
Passwords are hashed with bcrypt. Accounts lock after repeated failures, login errors are generic to prevent username enumeration, and timing is normalized against probing.
Injection-resistant data access
All database access uses parameterized queries, and database errors are sanitized before they reach the client so internals never leak in a response body.
Locked-down transport
CORS is restricted to exact known origins, security headers are set via Helmet, and API responses carry no-store cache-control so sensitive data isn’t cached by intermediaries.