3.4 KiB
Photobooth Control Service API
The control service is a lightweight sidecar responsible for provisioning vsftpd accounts. Laravel talks to it via REST whenever an Event Admin enables, rotates, or disables the Photobooth feature.
Authentication
- Scheme: Bearer token.
- Header:
Authorization: Bearer ${PHOTOBOOTH_CONTROL_TOKEN}. - Timeout: Configurable via
PHOTOBOOTH_CONTROL_TIMEOUT(default 5 s). - Token generation:
openssl rand -hex 32(orphp -r "echo bin2hex(random_bytes(32)), "); store in.env/Dokploy secrets asPHOTOBOOTH_CONTROL_TOKEN.
Endpoints
| Method & Path | Description |
|---|---|
POST /users |
Create a new FTP account for an event. |
POST /users/{username}/rotate |
Rotate credentials / extend expiry for an existing user. |
DELETE /users/{username} |
Remove an FTP account (called when an event disables Photobooth or expires). |
POST /config |
Optionally push global config changes (port, rate-limit, expiry grace) to the control service. |
POST /users
{
"username": "pbA12345",
"password": "F4P9K2QX",
"path": "tenant-slug/123",
"rate_limit_per_minute": 20,
"expires_at": "2025-06-15T22:59:59Z",
"ftp_port": 2121,
"allowed_ip_ranges": ["1.2.3.4/32"],
"metadata": {
"event_id": 123,
"tenant_id": 5
}
}
Response: 201 Created with { "ok": true }. On failure return 4xx/5xx JSON with error.code + message.
Implementation tips:
- Ensure the system user or virtual user’s home directory is set to the provided
path(prefixed with the shared Photobooth root). - Apply the rate limit token-bucket before writing to disk (or integrate with HAProxy).
- Store
expires_atand automatically disable the account when reached (in addition to Laravel’s scheduled cleanup).
Reference implementation (current stack): photobooth-ftp builds from docker/photobooth-control, starts pure-ftpd and a Node-based control API on port 8080. Healthcheck: GET /health on 8080 (wired in docker-compose.dokploy.yml). Rate-limit/expiry enforcement inside the FTP tier is still to be implemented.
POST /users/{username}/rotate
{
"password": "K9M4T6QZ",
"rate_limit_per_minute": 20,
"expires_at": "2025-06-16T22:59:59Z"
}
- Rotate the password atomically and respond with
{ "ok": true }. - If username does not exist return
404with a descriptive message so Laravel can re-provision.
DELETE /users/{username}
No request body. Delete or disable the FTP account, removing access to the assigned directory.
POST /config
Optional hook used when SuperAdmins change defaults:
{
"ftp_port": 2121,
"rate_limit_per_minute": 20,
"expiry_grace_days": 1
}
Use this to reload vsftpd or adjust proxy rules without redeploying the control service.
Error Contract
Return JSON structured as:
{
"error": {
"code": "user_exists",
"message": "Username already provisioned",
"context": { "username": "pbA12345" }
}
}
Laravel treats any non-2xx as fatal and logs the payload (sans password). Prefer descriptive code values: user_exists, user_not_found, rate_limit_violation, invalid_payload, etc.
Observability
- Emit structured logs for every create/rotate/delete with event + tenant IDs.
- Expose
/healthso Laravel (or uptime monitors) can verify connectivity. - Consider metrics (e.g., Prometheus) for active accounts, rotations, and failures.