This document describes how to configure a Directus instance to work with Agenda Timer. You need a Directus project (self-hosted or Directus Cloud) with admin access.
Agenda Timer uses Directus WebSockets for real-time sync between participants. Add the following environment variable to your Directus instance:
WEBSOCKETS_ENABLED=true
On Directus Cloud, this is enabled by default. For self-hosted, set it in your .env or environment configuration.
Create two collections with an enforcer_ prefix. Both use UUID primary keys.
| Field | Type | Default | Notes |
|---|---|---|---|
id |
UUID (PK) | Auto-generated | Also serves as the room code for joining |
name |
String | — | Optional meeting name (set to "Untitled Meeting" if omitted) |
passcode |
String | — | Bcrypt hash of the room passcode |
admin_token |
String | — | Bcrypt hash of the admin token |
status |
String | active |
Dropdown: active, ended |
current_item |
UUID, nullable | null |
M2O relation to enforcer_items |
timer_state |
String | stopped |
Dropdown: stopped, running, paused |
timer_started_at |
Timestamp, nullable | null |
When the current timer run began |
timer_elapsed_before_pause |
Integer | 0 |
Milliseconds accumulated before the current run |
date_created |
Timestamp | Auto | System field |
date_updated |
Timestamp | Auto | System field |
| Field | Type | Default | Notes |
|---|---|---|---|
id |
UUID (PK) | Auto-generated | |
room |
UUID | — | M2O relation to enforcer_rooms (required) |
title |
String | — | Plain text agenda item title (required) |
duration_minutes |
Integer | 5 |
Allocated time in minutes |
bonus_minutes |
Integer | 0 |
Admin-added extra time |
sort |
Integer | — | Manual ordering (sequential per room) |
date_created |
Timestamp | Auto | System field |
date_updated |
Timestamp | Auto | System field |
| From | Field | To | Type | On Delete |
|---|---|---|---|---|
enforcer_items |
room |
enforcer_rooms |
M2O | CASCADE |
enforcer_rooms |
current_item |
enforcer_items |
M2O | SET NULL |
Optionally add an O2M alias field items on enforcer_rooms pointing back to enforcer_items for convenience in the Directus admin UI.
The app requires two Directus roles, each with a dedicated user and static access token.
- Purpose: Used server-side by Netlify Functions for all write operations
- Permissions: Full CRUD on both
enforcer_roomsandenforcer_items - User: Create a Directus user (e.g.
admin@enforcer.local) assigned to this role - Token: Generate a static access token for this user. Store it as the
DIRECTUS_ADMIN_TOKENenvironment variable.
This token is never exposed to the browser. It is only used in Netlify Functions.
- Purpose: Used client-side in the browser for read-only access and WebSocket subscriptions
- Permissions: See table below
- User: Create a Directus user (e.g.
participant@enforcer.local) assigned to this role - Token: Generate a static access token for this user. Store it as both
DIRECTUS_PARTICIPANT_TOKENandVITE_DIRECTUS_PARTICIPANT_TOKENenvironment variables.
This token is bundled into the frontend build and visible to anyone using the app. That's fine because it only grants read access with sensitive fields excluded.
| Collection | Action | Scope |
|---|---|---|
enforcer_rooms |
Read | All fields except passcode and admin_token |
enforcer_items |
Read | All fields |
No create, update, or delete permissions. All mutations go through Netlify Functions using the admin token.
Set these in your deployment environment (Netlify, Vercel, etc.) and in a local .env file for development. See .env.example for the template.
| Variable | Used By | Purpose |
|---|---|---|
DIRECTUS_URL |
Netlify Functions | Base URL of your Directus instance |
DIRECTUS_ADMIN_TOKEN |
Netlify Functions | Static token for the admin role user |
DIRECTUS_PARTICIPANT_TOKEN |
Netlify Functions | Static token for the participant role user (currently unused server-side but kept for reference) |
VITE_DIRECTUS_URL |
Vue frontend (build-time) | Base URL of your Directus instance |
VITE_DIRECTUS_PARTICIPANT_TOKEN |
Vue frontend (build-time) | Static token for the participant role user |
The VITE_ prefixed variables are embedded into the frontend bundle at build time by Vite.
- Enable WebSockets (
WEBSOCKETS_ENABLED=true) - Create
enforcer_roomscollection with all fields and defaults listed above - Create
enforcer_itemscollection with all fields and defaults listed above - Set up M2O relations between the two collections
- Create the Admin role with full CRUD on both collections
- Create the Participant role with read-only access (excluding
passcodeandadmin_tokenon rooms) - Create a user for each role and generate static access tokens
- Set all five environment variables in your deployment and local
.env