Appearance
Database Schema
The database is PostgreSQL 16, accessed via Prisma 5. All model definitions live in packages/database/prisma/models/.
Core entities
User
Global user account, managed by better-auth. One user can belong to multiple tenants.
| Field | Type | Description |
|---|---|---|
id | String | CUID primary key |
email | String | Unique email address |
name | String | Display name |
emailVerified | Boolean | Whether email has been verified |
image | String? | Avatar URL |
lastLoginAt | DateTime? | Last login timestamp |
createdAt | DateTime | Account creation time |
Tenant
A workspace that contains users, projects, invoices, and time entries.
| Field | Type | Description |
|---|---|---|
id | String | CUID primary key |
name | String | Workspace display name |
logo | String? | Logo URL |
theme | String | UI theme colour (default: blue) |
features | Json? | Feature flag configuration (FeatureSettings) |
emailSettings | Json? | IMAP email sync configuration |
counts | Json? | Cached aggregate counts |
The features JSON follows this shape:
typescript
type FeatureSettings = {
projects?: boolean // default: true
vehicles?: boolean // default: true
zones?: boolean // requires projects
tasks?: boolean // requires projects
invoices?: boolean // requires projects
hoursOverview?: boolean // default: true
emailSync?: boolean // default: true
punchClock?: boolean // default: false
approvalWorkflow?: boolean // default: true
}TenantUser
A user's identity within a specific tenant. Each user gets a separate TenantUser record per tenant they belong to.
| Field | Type | Description |
|---|---|---|
id | String | CUID primary key |
tenantId | String | FK to Tenant |
userId | String | FK to User |
name | String | Display name within this tenant |
archived | Boolean | Soft-delete flag |
vehicleId | String? | Assigned vehicle |
automations | Json? | Per-user automation configuration |
Entry
A logged time entry.
| Field | Type | Description |
|---|---|---|
id | String | CUID primary key |
tenantId | String | FK to Tenant |
tenantUserId | String | FK to TenantUser (who logged it) |
projectId | String? | FK to Project (optional) |
taskId | String? | FK to Task (optional) |
start | DateTime | Start time |
end | DateTime | End time |
duration | Int | Duration in minutes |
pauseMinutes | Int | Break time deducted in minutes |
comment | String? | Admin-visible comment |
userComment | String? | Worker's own comment |
approved | Boolean | Whether entry is approved |
rejected | Boolean | Whether entry was rejected |
archived | Boolean | Soft-delete flag |
Invoice
An invoice document uploaded by a worker or received via email sync.
| Field | Type | Description |
|---|---|---|
id | String | CUID primary key |
tenantId | String | FK to Tenant |
name | String | Invoice display name |
type | String? | Invoice type/category |
status | String | Processing status (default: nouveau) |
link | String? | File URL (presigned or permanent) |
amountHt | Float? | Amount excluding VAT |
amountTva | Float? | VAT amount |
amountTtc | Float? | Total amount including VAT |
number | String? | Invoice number |
date | DateTime? | Invoice date |
datePaid | DateTime? | Date the invoice was paid |
description | String? | Description of work |
comment | String? | Admin comment |
ocrContent | String? | Raw OCR-extracted text |
checked | Boolean | Reviewed by admin |
approved | Boolean | Approved for payment |
markedAsPaid | Boolean | Marked as paid |
archived | Boolean | Soft-delete flag |
Project
A project or cost centre that time entries and invoices can be attributed to.
| Field | Type | Description |
|---|---|---|
id | String | CUID primary key |
tenantId | String | FK to Tenant |
name | String | Project name |
zone | Int? | Zone number for grouping |
responsibleId | String? | FK to TenantUser (project manager) |
start | DateTime? | Project start date |
end | DateTime? | Project end date |
archived | Boolean | Soft-delete flag |
TaskList / Task
Task lists group tasks; projects reference a task list. Workers select tasks when logging time.
| Model | Key fields |
|---|---|
TaskList | id, tenantId, name, archived |
Task | id, taskListId, name, order |
Vehicle
A vehicle that can be assigned to a user for fuel/maintenance invoice tracking.
| Field | Type | Description |
|---|---|---|
id | String | CUID primary key |
tenantId | String | FK to Tenant |
name | String | Vehicle name/plate |
archived | Boolean | Soft-delete flag |
ApiKey
An API key scoped to a tenant, used for programmatic access.
| Field | Type | Description |
|---|---|---|
id | String | CUID primary key |
tenantId | String | FK to Tenant |
name | String | Human-readable label |
keyHash | String | SHA-256 hash of the key |
keyPrefix | String | First 8 characters for display |
revoked | Boolean | Whether the key is revoked |
expiresAt | DateTime? | Expiry date (null = never) |
lastUsedAt | DateTime? | Last usage timestamp |
Webhook / WebhookDelivery
Outbound webhook subscriptions and their delivery history.
| Field | Type | Description |
|---|---|---|
id | String | CUID primary key |
tenantId | String | FK to Tenant |
url | String | Destination URL |
secret | String? | HMAC signing secret |
events | String[] | List of subscribed event names |
active | Boolean | Whether the webhook is active |
Database extensions
pg_trgm— Trigram index extension for full-text search.searchVectorcolumns onEntry,Invoice,Project, andTenantUserare populated automatically.