--- type: SQLite Table title: employees description: The whitelist of employee emails allowed to log attendance, with a soft-delete active flag. resource: backend/src/db/index.ts tags: [data-model, sqlite] timestamp: 2026-08-12T00:00:00Z --- # employees The employee whitelist. A row here (with `active = 1`) is what lets a Google account log in as an employee — see [Auth flow](/docs/architecture/auth-flow.md). Admins are **not** rows in this table; they're resolved purely from the `ADMIN_EMAILS` env var. # Schema | Column | Type | Description | |---|---|---| | `id` | INTEGER PK | autoincrement | | `email` | TEXT | unique, lowercased on write | | `name` | TEXT | nullable; filled in from the Google profile on first login (`touchEmployeeName` in `backend/src/services/employees.ts`), only if still null | | `active` | INTEGER | 1 = can log in, 0 = soft-deleted | | `created_at` | TEXT | ISO 8601 UTC, set by SQLite default | # Behavior - **Add** (`addEmployee`): upsert by email. If a soft-deleted row exists for that email, it's reactivated (`active = 1`) rather than duplicated. - **Remove** (`deactivateEmployee`): sets `active = 0`. This is a **soft** delete by design — [attendance_events](./attendance-events.md) rows keep referencing the employee, so historical stats for a removed employee are still computable and re-adding the same email restores access without losing history. # Related - [attendance_events](./attendance-events.md) — `employee_id` references this table - [Employees API](/docs/api/admin-routes.md)