feat: switch from MySQL to SQLite for zero-dependency deployment

- Rewrite db.php to use SQLite via PDO (no external DB server needed)
- Rewrite schema.sql for SQLite (AUTOINCREMENT, CHECK constraints,
  triggers for updated_at, ON CONFLICT instead of ON DUPLICATE KEY)
- Fix config.php upsert to use ON CONFLICT syntax
- Fix index.php: tag filter via json_each, vote upsert via ON CONFLICT,
  and fix protocol create route (was returning 405 for POST /api/protocols)
- Fix yaml.php seed import: replace invalid false callbacks with fn() => null,
  fix yaml_parse pos argument (-1 -> 0)
- Update Dockerfile: drop pdo_mysql/mysqli (pdo_sqlite is built in)
- Update CloudronManifest.json: remove mysql addon, bump to v0.3.0
- Update README for SQLite deployment
This commit is contained in:
Protocolbot
2026-07-06 14:42:45 -06:00
parent 7379d0c540
commit 3386ac6542
8 changed files with 155 additions and 132 deletions
+29 -17
View File
@@ -17,6 +17,7 @@ Protocol Droid is a web application where communities can document, share, and r
- **Identity**: user accounts with optional SSO support
- **YAML import/export**: protocols are fully structured YAML — portable, git-diffable, human-readable
- **Whitelabel**: customize site name, tagline, and theme via `config.yaml`
- **Zero-dependency database**: SQLite — no external database server required
## Architecture
@@ -24,7 +25,7 @@ Protocol Droid is a web application where communities can document, share, and r
protocol-droid/
├── api/ PHP backend (REST API)
│ ├── index.php API router (all /api/* requests)
│ ├── db.php Database connection + helpers (MySQL/MariaDB)
│ ├── db.php Database connection + helpers (SQLite via PDO)
│ ├── auth.php Session-based authentication
│ ├── config.php Site configuration
│ └── yaml.php YAML import/export helpers
@@ -41,7 +42,8 @@ protocol-droid/
│ └── fishbowl-discussion.yaml
├── cloudron/ Cloudron deployment files
│ └── CloudronManifest.json
├── schema.sql MySQL database schema
├── data/ SQLite database (auto-created)
├── schema.sql SQLite database schema
├── config.yaml Whitelabel configuration
├── .htaccess Apache rewrite rules
└── README.md This file
@@ -49,19 +51,19 @@ protocol-droid/
## Stack
- **Backend**: PHP 8.x with PDO (MySQL/MariaDB)
- **Database**: MySQL/MariaDB (Cloudron-native)
- **Backend**: PHP 8.x with PDO (SQLite)
- **Database**: SQLite — file-based, no server required
- **Frontend**: Vanilla HTML/CSS/JS — no frameworks, no build step, no external dependencies
- **Data format**: YAML for portability, MySQL for runtime
- **Data format**: YAML for portability, SQLite for runtime
- **Auth**: Session-based with optional SSO
## Deployment
### On Cloudron
1. Create a LAMP app in Cloudron
1. Create a LAMP app in Cloudron (no MySQL addon needed)
2. Upload all files to the app's web root
3. The database schema auto-initializes on first API request
3. The database schema auto-initializes on first API request (creates `data/protocol_droid.db`)
4. Visit the site and register — the **first user to register becomes admin**
5. Optionally load seed protocols: sign in as admin and `POST /api/seed` (or use the API endpoint with curl: `curl -b cookies.txt -X POST https://your-site/api/seed`)
@@ -70,25 +72,34 @@ protocol-droid/
### On any LAMP server
1. Upload files to your web root (or a subdirectory like `/protocol-droid/`)
2. Create a MySQL database and user
3. Set environment variables (or edit `api/db.php`):
- `MYSQL_HOST`, `MYSQL_PORT`, `MYSQL_DATABASE`, `MYSQL_USER`, `MYSQL_PASSWORD`
4. Visit the site and register — first user becomes admin
2. Ensure the `data/` directory is writable by the web server
3. Visit the site and register — first user becomes admin
The SQLite database file is created automatically at `data/protocol_droid.db`. To use a custom path, set the `DATABASE_PATH` environment variable.
**Subdirectory deployment:** Protocol Droid works in a subdirectory (e.g. `example.com/protocol-droid/`). The root `index.php` auto-detects the base path from the server's script name. No configuration needed — just upload the files to the subdirectory and ensure `index.php` is served as the directory index (most LAMP setups do this by default with `DirectoryIndex index.php` or `.htaccess`).
### With Docker
```bash
# Build and run a single container (no separate database container needed)
docker build -t protocol-droid .
docker run -d --name pd-web -p 8080:80 \
-v pd_data:/var/www/html/data \
protocol-droid
```
The SQLite database lives in the `pd_data` volume. The `docker-compose.yml` included in the repo runs the same setup.
### Local development
```bash
# Start PHP built-in server
cd protocol-droid
php -S localhost:8000
# Or with a MySQL database:
MYSQL_HOST=localhost MYSQL_DATABASE=protocol_droid MYSQL_USER=root MYSQL_PASSWORD=secret php -S localhost:8000
```
The first registration creates the admin account. To load the 6 sample protocols (Round Robin Check-In, Consent Decision-Making, etc.):
The SQLite database is created automatically at `data/protocol_droid.db`. The first registration creates the admin account. To load the 6 sample protocols (Round Robin Check-In, Consent Decision-Making, etc.):
```bash
# After registering as admin:
@@ -112,14 +123,15 @@ curl -b cookies.txt -X DELETE http://localhost:8000/api/protocols/round-robin-ch
| `/api` | GET | API info | none |
| `/api/config` | GET | Site configuration | none |
| `/api/protocols` | GET | List public protocols | none |
| `/api/protocols/:slug` | GET | Get protocol | none |
| `/api/protocols` | POST | Create protocol | member |
| `/api/protocols/:slug` | GET | Get protocol | none |
| `/api/protocols/:slug` | PUT | Update protocol | author/admin |
| `/api/protocols/:slug` | DELETE | Delete protocol | author/admin |
| `/api/protocols/:slug/yaml` | GET | Export as YAML | none |
| `/api/protocols/:slug/votes` | GET | Get votes for protocol | none |
| `/api/collections` | GET | List collections | none |
| `/api/collections/:slug` | GET | Get collection | none |
| `/api/collections` | POST | Create collection | member |
| `/api/collections/:slug` | GET | Get collection | none |
| `/api/collections/:slug` | PUT | Update collection | author/admin |
| `/api/collections/:slug` | DELETE | Delete collection | author/admin |
| `/api/auth/register` | POST | Register | none |