Legal
Overview
Q Lighting Co., Ltd. takes the security of Project Work and the data entrusted to it seriously. This document describes the security measures, architectural controls, and operational practices in place to protect the Platform and its users.
Project Work is a multi-tenant SaaS platform handling sensitive project documents and client approval records for design and construction firms. Security is a core requirement of the product, not an afterthought.
01
Project Work does not store passwords. All authentication is handled via OAuth 2.0 through Google or Microsoft (Azure Entra ID). Credentials are managed entirely by those providers and are never transmitted to or stored by the Platform.
At sign-in, the Platform receives a verified identity token from Google or Microsoft. The token includes the user's email address and a stable, provider-issued unique identifier (OAuth sub). The Platform stores the OAuth provider name and sub to uniquely identify each account, independent of email changes.
Sessions are managed using JSON Web Tokens (JWT) via Auth.js. Tokens are signed with a strong secret key and are not stored server-side. JWTs are rotated on each authentication event.
Client sessions are checked every 60 seconds to detect if a client account has been promoted to staff status, ensuring that access rights are updated promptly without requiring re-authentication.
Upon successful authentication, the backend determines the user's account type (tenant staff, client, or super administrator) and routes them to the correct workspace. Users do not select their role at sign-in. This prevents role spoofing at the entry point.
02
Each company ("tenant") using the Platform operates in a fully isolated workspace. Data belonging to one tenant is never visible to or accessible by another tenant.
The tenant identity of every authenticated staff session is derived exclusively from the authenticated session on the server side. APIs do not accept or trust a tenant identifier supplied in a request body, query string, or header. This prevents cross-tenant attacks via request manipulation.
Tenant isolation is enforced at the database layer using PostgreSQL Row-Level Security policies. Every tenant-scoped table carries a non-nullable tenant_id column. RLS policies verify that the session's tenant context matches each row before any read or write operation is permitted.
A session-level variable (app.tenant_id) is set at the start of every database transaction for staff operations. The database enforces isolation even if application-level checks were somehow bypassed.
For client sessions, RLS policies verify project-level access through the project_client_access table rather than by tenant ID, reflecting the fact that clients may access projects across multiple tenants from a single account.
All 16 tenant-scoped tables have both ENABLE ROW LEVEL SECURITY and FORCE ROW LEVEL SECURITY set, ensuring policies apply even to the table owner role.
PDF revision files are stored on the server filesystem under a path structure that uses database-assigned UUIDs only:
/tenants/{tenant_id}/projects/{project_id}/revisions/{revision_id}.pdf
No user-supplied names or labels appear in file paths. The application enforces that the path prefix matches the authenticated tenant before any file is read or written, preventing path traversal attacks and cross-tenant file access.
03
Within each tenant workspace, access to sensitive operations is controlled by a configurable role and permission system. Roles include Tenant Administrator, Team Head, and Designer. Each role has a defined set of permitted actions, and these are enforced server-side on every API request.
The permission set is tenant-configurable (e.g. whether Team Heads may release revisions to clients), but the Tenant Administrator role always retains full access and the permission grid itself can only be modified by a Tenant Administrator.
Clients can only access projects they have been explicitly invited to. Access is tracked in the project_client_access table and enforced at both application and database levels. A client who is removed or whose access is revoked immediately loses access to that project.
Clients can only see revisions that have been formally released to them. Internal revisions (in WORKING, INTERNAL_REVIEW, or INTERNAL_APPROVED status) and internal staff comments are never visible to client sessions.
The Super Administrator area is a separate, elevated access level reserved for Q Lighting Co., Ltd. platform operators. Super administrators are stored in a separate table (super_admins) and operate outside the tenant system. Super admin routes are protected by separate middleware and session checks.
04
Project invitations to clients can be issued via three methods: email invitation, shareable link, or access code.
05
Every action taken by a client — viewing a revision, leaving a comment, approving, or rejecting — is recorded in the client_actions table. This table is designed to be append-only:
client_actions are prevented by database triggers that raise an exception regardless of the requesting role.This design ensures that approval and rejection records are tamper-evident and can be relied upon as a permanent record of client decisions.
Revision status transitions are enforced by a database trigger. A revision can only advance through defined stages (e.g. WORKING → INTERNAL_REVIEW → INTERNAL_APPROVED → RELEASED_TO_CLIENT). Skipping stages or reversing to an earlier status is rejected at the database level, independent of application logic.
When a client e-signature is collected on approval, the signature image and associated metadata (client ID, revision ID, timestamp) are stored permanently. These records form part of the audit trail for finalized revisions.
06
All communication between users and the Platform is encrypted using HTTPS/TLS. The Platform is served exclusively over HTTPS, enforced by the Traefik reverse proxy. Unencrypted HTTP requests are redirected to HTTPS.
Email notifications are delivered via an SMTP relay (Brevo) using TLS-secured connections.
07
PDF revision files are stored on an encrypted-at-rest filesystem on the Platform's hosting infrastructure (Hetzner Cloud). Database data is stored in PostgreSQL on the same infrastructure.
Sensitive tokens (invitation links, access codes) are stored only as cryptographic hashes — the cleartext value is never written to persistent storage.
08
The Platform is hosted on Hetzner Cloud infrastructure. The application runs as a containerised service managed by Docker Swarm. Traffic is routed and terminated by Traefik, which handles TLS certificate provisioning and renewal.
Production secrets (database credentials, OAuth keys, SMTP credentials, session signing keys) are managed as Docker Swarm secrets or environment variables and are never committed to source control. The application's repository contains only example variable names, not values.
New versions of the application are deployed using immutable Docker image tags based on the Git commit hash. Deployments update the running service image without in-place modification of running containers.
The reminder cron endpoint (/api/cron/reminders) is protected by a shared secret passed in a request header (CRON_SECRET). Requests without the correct secret are rejected before any processing occurs.
09
Application errors and performance issues are monitored using Sentry, covering client-side, server-side, and edge runtime errors. Error reports may contain stack traces and contextual information. Sentry is configured to capture exceptions and to help diagnose production issues promptly.
Personal data included in error payloads is subject to Sentry's data processing terms. We configure Sentry to minimise the capture of unnecessary personal data.
10
Staff-only data (internal review comments, workflow notes) is stored in a dedicated table (internal_comments) that is completely separate from client-facing action records. Database RLS policies and application-layer access controls both enforce that client sessions can never read internal comments, regardless of how the request is constructed.
11
The Platform uses the following third-party services, each of which may process limited data:
| Service | Purpose |
|---|---|
| Google OAuth | Authentication for users with Google accounts |
| Microsoft OAuth | Authentication for users with Microsoft accounts |
| Brevo | Transactional email delivery |
| Sentry | Error monitoring and performance tracking |
| Hetzner Cloud | Infrastructure hosting |
No third-party advertising networks, behavioural analytics, or data brokers are used.
12
If you discover a security vulnerability in Project Work, please report it responsibly to us before public disclosure. We are committed to investigating all reported issues promptly and to communicating our findings and remediation timeline.
To report a vulnerability, contact us at:
Email: project@quill-shop.com
Subject: Security Vulnerability Report — Project Work
Please include a description of the issue, steps to reproduce, and the potential impact. We ask that you:
We treat all responsible disclosures with seriousness and appreciate the effort of the security research community in helping keep the Platform safe.
13
For security-related enquiries, please contact: