diff --git a/README.md b/README.md
index 666407e..9743d01 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,86 @@
IMFestival SMS Dashboard
-### What is this repository?
+A web-based SMS notification system for managing festival attendees and delivering workshop reminders via [Clickatell](https://www.clickatell.com/).
-This repository holds the SMS notification system for IMFestival, featuring a web dashboard along with containerization files (`Dockerfile` and `docker-compose.yml`) for easy deployment.
+
-## How to use the dashboard
-The dashboard will allow the upload of a CSV file that contains the user's name, email, workshop name and times.
+## Architecture
-You can use the dashboard to schedule messages for delivery to selected users at specific times. Message content can be configured directly within the dashboard and supports the placeholders {name} for the recipient's name, {workshop} for the workshop name, and {workshop_time} for the workshop time.
+Three Docker services work together:
-## Considerations
-The character limit needs to check against the longest workshop name to ensure the limit isn't misrespresented.
+| Service | Tech | Role |
+|---------|------|------|
+| `db` | MariaDB 11 | Persistent storage for attendees, templates, schedules, and delivery logs |
+| `web` | PHP 8.3 + Apache | Dashboard UI and REST API |
+| `worker` | Python 3 + Flask | SMS dispatch service; polls for due scheduled rules every 60 s |
-### Python Dependencies
-- numpy
-- dateutil
-- pandas
+## Features
+
+- **CSV import** — upload an attendee export from splash; the importer auto-detects common column names for first name, last name, email, and mobile number
+- **Workshop sessions** — attendees are linked to named sessions with a start time, enabling per-workshop targeting
+- **SMS templates** — reusable message bodies (≤ 160 chars) with `{name}`, `{workshop}`, and `{workshop_time}` placeholders
+- **Scheduled texts** — rules fire relative to a workshop start time (e.g. *30 minutes before*) or at a specific datetime
+- **Send now** — dispatch immediately to all attendees or a single workshop group
+- **Delivery log** — per-recipient status tracking (`sent` / `failed`)
+- **Sandbox mode** — tag sends as tests so they are excluded from sent stats or cost calculations without disabling the API
+- **Admin panel** — configure the Clickatell API key, cost-per-SMS, and sender ID through the UI
+
+## Getting started
+
+### Prerequisites
+
+- Docker and Docker Compose
+
+### 1. Create a `.env` file
+
+Create a `.env` file in the project root. All three services read from it.
+
+```env
+# MariaDB
+MYSQL_ROOT_PASSWORD=changeme
+MYSQL_DATABASE=imf_sms
+MYSQL_USER=imf_user
+MYSQL_PASSWORD=changeme
+MYSQL_HOST=db
+
+# Optional — defaults to Europe/London
+TZ=Europe/London
+```
+
+### 2. Start the stack
+
+```bash
+docker compose up --build
+```
+
+The dashboard will be available at **http://localhost:8000**.
+
+### 3. Configure Clickatell
+
+Open **Admin** in the dashboard and enter your Clickatell API key. You can also set a cost-per-SMS and a default sender ID here.
+
+### 4. Import attendees
+
+Go to **Attendees** and upload a CSV export from your event management tool. The required columns are `first_name` (or `First Name`), `last_name`, and `mobile_number` (or `Custom: Mobile number`). `email` and workshop session columns are optional but recommended.
+
+## CSV column mapping
+
+The importer accepts comma- or tab-separated files and recognises these column names (case-insensitive):
+
+| Field | Accepted column names |
+|-------|-----------------------|
+| First name | `first name`, `first_name`, `firstname`, `first` |
+| Last name | `last name`, `last_name`, `lastname`, `last` |
+| Mobile | `custom: mobile number`, `mobile_number`, `mobile number`, `mobile`, `phone`, `telephone`, `cell` |
+| Email | `email` |
+| Workshop | `custom: please pick one workshop…` (and similar variants) |
+
+## SMS placeholders
+
+| Placeholder | Replaced with |
+|-------------|---------------|
+| `{name}` | Recipient's first name |
+| `{workshop}` | Workshop name |
+| `{workshop_time}` | Workshop start time |
+
+The character counter in the template editor calculates length against the longest possible substitution so the 160-character limit is never misrepresented.