Files
TimeTracker/docs/deploy/RENDER.md
T
Dries Peeters 5a89d5f5df fix(security): treat DEMO_MODE account as a standard user, not admin
Create the auto-provisioned demo user with legacy role "user" and the RBAC
user role so public demos cannot reach settings or the PDF layout editor.
On startup, downgrade an existing demo user that still has admin or
super_admin roles left over from older releases.

Document behavior in docs/deploy/RENDER.md and README.md.
2026-04-24 21:13:25 +02:00

84 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Deploy TimeTracker on Render
This guide explains how to host TimeTracker as a Web Service on [Render](https://render.com) with optional **demo mode** (single user, credentials shown on the login page).
The Blueprint uses the **pre-built Docker image** from GitHub Container Registry (`ghcr.io/drytrix/timetracker:latest`), i.e. the same image built by your GitHub Actions (cd-release / cd-development). No Python or npm build runs on Render.
## Prerequisites
- A [Render](https://render.com) account
- This repository connected to your GitHub (or GitLab) account
- Docker image published to GHCR (e.g. by pushing to `main` or creating a release so the CD workflow builds and pushes the image)
## Deploy with the Blueprint
1. In the Render Dashboard, click **New****Blueprint**.
2. Connect your Git provider and select the TimeTracker repository.
3. Render will detect the `render.yaml` in the repository root.
4. Review the blueprint: it creates one **PostgreSQL** database and one **Web Service** that pulls `ghcr.io/drytrix/timetracker:latest`.
5. Click **Apply** to create the database and deploy the app.
To deploy a new version, push to `main` or create a release so GitHub Actions builds and pushes a new image, then in Render trigger a **Manual Deploy** (or use a deploy hook) to pull the updated image.
### Automatic demo deploy via release workflow
If you host a demo site on Render, the release workflow can automatically trigger a redeploy when a new container is published. Configure:
1. In Render: open your demo Web Service → **Settings****Deploy Hook** and copy the deploy hook URL.
2. In GitHub: add an **organization secret** named `TimeTrackerDemoRender` with the deploy hook URL as the value. Grant your TimeTracker repository access to this secret (Organization Settings → Secrets and variables → Actions → Repository access).
3. On each release (push to `main`, tag, or manual dispatch), after the Docker image is built and pushed, the workflow sends a POST request to the deploy hook. Render will pull the new image and redeploy your demo site.
If the secret is not set, the workflow skips the deploy trigger and the release completes normally.
## Environment variables
The blueprint sets:
- **FLASK_ENV**: `production`
- **FLASK_APP**: `app:create_app()` (used for `flask db upgrade` in the pre-deploy step)
- **SECRET_KEY**: Auto-generated by Render (recommended; you can override in the Dashboard)
- **DATABASE_URL**: Filled automatically from the linked PostgreSQL database
- **AUTH_METHOD**: `local` (username/password login)
- **REDIS_ENABLED**: `false` (rate limiting uses in-memory storage; no Redis required for demo)
## Demo mode (single-user demo)
To run a **demo** instance where only one user can log in and the credentials are shown on the login page:
1. In the Render Dashboard, open your **timetracker** web service.
2. Go to **Environment** and add (or uncomment in `render.yaml` and redeploy):
- **DEMO_MODE**: `true`
- **DEMO_USERNAME**: `demo` (or any username you want)
- **DEMO_PASSWORD**: Set a strong password (use a **Secret** so it is not visible in the dashboard to others)
3. Redeploy the service.
In demo mode:
- Only the user with **DEMO_USERNAME** can log in.
- The login page shows the demo username and password.
- Self-registration and admin user creation are disabled; OIDC cannot create new users.
- The demo user is created automatically on first run if it does not exist.
- The demo account has the standard **user** role only (not an administrator), so settings, PDF layout editing, and similar admin routes are unavailable on the demo login.
**Security:** Use a strong **DEMO_PASSWORD** for any public demo. Do not use `DEMO_MODE=true` for production multi-user deployments.
**Upgrading older demos:** If your database was created before this change and the demo user still has admin access, redeploying a current image runs a one-time adjustment on startup: the demo user is moved to the **user** role and `admin` / `super_admin` RBAC roles are removed. If you disabled `DEMO_MODE` and need a real administrator, create one via CLI or temporarily disable demo mode and use `ADMIN_USERNAMES` as documented in the main README.
## Optional: Run without the Blueprint
If you prefer to create the database and web service manually:
1. Create a **PostgreSQL** database and note the **Internal Database URL** (or **External** if your app runs elsewhere).
2. Create a **Web Service** and choose **Deploy an existing image from a registry**.
- **Image URL**: `ghcr.io/drytrix/timetracker:latest`
- **Docker Command**: `gunicorn --bind 0.0.0.0:$PORT --worker-class eventlet --workers 1 --timeout 120 "app:create_app()"`
- **Pre-deploy Command**: `flask db upgrade`
- If the image is private, add GHCR registry credentials in Render (Settings → Registry).
3. In **Environment**, set **FLASK_APP** to `app:create_app()`, **DATABASE_URL** to the Postgres URL, **SECRET_KEY**, and any demo-mode variables as above.
## Troubleshooting
- **Migrations**: The pre-deploy command runs `flask db upgrade`. If it fails, check that **FLASK_APP** is set to `app:create_app()` and that **DATABASE_URL** is set and reachable from Render.
- **Image**: The Blueprint uses the pre-built image `ghcr.io/drytrix/timetracker:latest`. Ensure that image exists (trigger a build by pushing to `main` or running the release workflow). If the image is private, add GitHub Container Registry credentials in Render Dashboard → Settings → Registry.
- **Database URL**: Renders PostgreSQL URL is usually in `postgres://` form; the app uses `postgresql+psycopg2`. If you see connection errors, try setting **DATABASE_URL** to the same URL with the scheme changed to `postgresql://` (Render may also provide a direct URL in the database dashboard).