Tymeslot
A coop-cloud recipe for deploying Tymeslot, a meeting scheduling and booking app.
- Category: Apps
- Status: 1, alpha
- Image:
luka1thb/tymeslot, 4, upstream - Healthcheck: Yes
- Backups: Yes
- Email: Yes
- Tests: No
- SSO: Yes
Basic usage
abra app new tymeslot --secretsabra app config <app-name>and at minimum setDOMAINand a realEMAIL_ADAPTERto use for signup and booking confirmationsabra app deploy <app-name>- Open
https://<your-domain>and sign up. The first account is created through the normal signup form; there is no separate admin bootstrap step.
Once you have your account, consider setting REGISTRATION_ENABLED=false if the instance is only for you or your team (though of course anyone with a booking link will be able to book in any case).
FAQ
The app keeps restarting right after a deploy
Swarm has no depends_on: condition: service_healthy, so on a cold start the app exits until the database accepts connections. A few restarts is expected; it settles on its own. If it does not, check the db service: docker service ps <stack>_db.
Nobody receives any email
The default EMAIL_ADAPTER is test, which silently discards everything, without erroring. Set a real adapter and enable the matching overlay, see "How to enable an optional integration" below.
If you enabled an overlay but never inserted its key, the deploy fails rather than starting without it: generate=false means abra creates nothing, and the compose files declare these secrets external: true, so Swarm has nothing to mount. abra app secret ls <app-name> shows what is missing.
How to enable an optional integration
Every integration follows the same four steps. For sending emails with Mailgun as an example:
-
Uncomment its block in your env file with
abra app config <app-name>. That means theCOMPOSE_FILEline, theSECRET_..._VERSIONline, and any plain settings:EMAIL_ADAPTER=mailgun COMPOSE_FILE="$COMPOSE_FILE:compose.mail.mailgun.yml" SECRET_MAILGUN_API_KEY_VERSION=v1 # generate=false MAILGUN_DOMAIN=mg.example.com -
Insert the key. The secret name is the lowercased variable name, and the version must match what you just set:
abra app secret insert <app-name> mailgun_api_key v1 '<your-mailgun-key>' -
Redeploy:
abra app deploy --force <app-name> -
Check it took:
abra app logs <app-name> app
Same shape for the others. compose.google.yml wants google_client_secret and google_state_secret, compose.stripe.yml wants three Stripe secrets, and so on. The overlay file lists exactly which, and .env.sample has the matching version lines next to each COMPOSE_FILE entry.
To rotate a value later, insert it under a new version (v2) and bump the SECRET_..._VERSION line to match, then redeploy.
How secrets work here
Tymeslot reads no *_FILE environment variables, both start-docker.sh and config/runtime.exs take their configuration straight from the environment. So this recipe mounts a small wrapper entrypoint that reads /run/secrets/* and exports each file as the matching variable before handing over to the upstream start script.
The mapping is the file name, uppercased. /run/secrets/smtp_password becomes SMTP_PASSWORD. If you add a compose overlay of your own, declare the secret with the lowercased name of the variable it feeds and it will be picked up with no other change.
abra app new --secrets generates the secrets it can invent for you, such as secret_key_base. Anything that comes from a third party is marked # generate=false in .env.sample, which means abra creates nothing at all and you insert it yourself. Since the compose files declare secrets external: true, enabling an overlay without inserting its secret makes the deploy fail. abra app secret ls <app-name> shows what is missing.
Two secrets you must not lose
DATA_ENCRYPTION_KEY encrypts stored calendar and video integration credentials at rest. Rotating or losing it makes every one of them undecryptable. It has to be valid base64 that decodes to at least 32 bytes, which is why .env.sample generates it with # length=48 charset=bytes encoding=base64 rather than a plain length.
ANALYTICS_SALT_SECRET, if you enable booking analytics, keys the cookie-less daily visitor fingerprint. Changing it re-hashes the same visitor and double-counts uniques.
Real-time calendar sync
WEBHOOK_BASE_URL defaults to https://${DOMAIN}, so Google and Microsoft push calendar changes to you and there is nothing to configure.
Providers run a validation handshake against that URL when a subscription is registered, so it only works on a host reachable from the public internet over HTTPS. If yours is not, set WEBHOOK_BASE_URL= empty in your env file, which the recipe respects. Sync then falls back to polling every 15 minutes, which works fine, just not in real time.
Serving under more than one hostname
If you set EXTRA_DOMAINS, also set WS_ALLOWED_ORIGINS to the full list of origins. Without it the LiveView websocket is refused on every hostname except DOMAIN, and the UI appears to load but never updates.
Using a managed database
Comment out the compose.db.postgres.yml line in your env file, uncomment compose.db.external.yml, and insert the connection string as a secret:
abra app secret insert <app-name> database_url v1 'postgres://user:pw@host:5432/tymeslot'
RDS, Neon and Supabase generally also want DATABASE_SSL=true.
--
For more, see docs.coopcloud.tech and the upstream Docker guide.