Emails were rendered and sent inline in the LiveKit webhook, so a
slow SMTP server blocked the request and a transient failure lost
the email. Delivery now runs in a worker, with retries and backoff.
The task is generic (template, subject, recipients, context,
language) so other emails can reuse it. The subject is translated
in the worker, and dates are formatted per owner before queuing,
so the arguments stay JSON-serializable.
Without Celery, the task still runs synchronously. Success now
means "queued", not "delivered".
The development stacks now run Garage instead of MinIO which is
deprecated.
Garage is a bit stricter than MinIO:
- key IDs and secrets must be at least 8 and 16 characters long
- requests must be signed for its region, so every development env now sets
AWS_S3_REGION_NAME=local;
- cross-origin requests are denied unless the bucket CORS rules allow
them, so a one-shot aws-cli container allows the frontend origin to
upload files straight to the bucket.