# Render Secrets — Configuration Checklist This document lists every environment variable that must be set in the Render dashboard for `hasarui-api` and `hasarui-worker`. Most are declared `sync: false` in `render.yaml`, which means Render keeps the key empty until you set it manually (so they never get committed to git). After applying `render.yaml` via **Blueprints -> New Blueprint** in the dashboard, go to each service -> **Environment** and populate: --- ## 1. JWT / auth | Key | Service(s) | How to set | |--------------------|-----------------|---------------------------------------------------| | `JWT_SECRET_KEY` | api, worker | Auto-generated by Render; worker pulls from api. | | `API_KEYS` | api, worker | Comma-separated tenant keys, e.g. `client1_xxx,client2_yyy`. | | `ADMIN_EMAIL` | api | First admin user email. | | `ADMIN_PASSWORD` | api | First admin password (rotate after first login). | ## 2. S3 (model weights + uploaded images) Use any S3-compatible provider. Recommended for pilot: **Cloudflare R2** (zero egress) or **Backblaze B2** (~$0.005/GB). | Key | Example value | Notes | |----------------------|--------------------------------------------------------|-----------------------------------------| | `S3_ENDPOINT` | `https://.r2.cloudflarestorage.com` | Empty for plain AWS S3. | | `S3_REGION` | `auto` (R2) / `eu-central-1` (AWS) / `eu-central-003` (B2) | Match the bucket. | | `S3_ACCESS_KEY` | (provider IAM access key id) | Use a *scoped* key, not root. | | `S3_SECRET_KEY` | (provider IAM secret) | Treat as max-sensitive. | | `S3_BUCKET` | `hasarui-inspections-prod` | Stores uploaded images & artefacts. | | `S3_PUBLIC_ENDPOINT` | `https://cdn.hasarui.com` or signed-URL base | Used to build URLs returned to clients. | ### Model bundle bucket (can be the same bucket, different prefix) | Key | Example | Notes | |--------------------|----------------------------------------|----------------------------------------| | `MODEL_S3_BUCKET` | `hasarui-models` | Bucket containing model weights. | | `MODEL_S3_PREFIX` | `models/full_20260515_044630` | Already set in render.yaml. | ### Uploading the model bundle (one-time) From a machine with the snapshot dir on disk: ```bash aws s3 sync \ services/ml/runs/bundles/full_20260515_044630/_SNAPSHOT_FOR_BUILD/ \ s3://hasarui-models/models/full_20260515_044630/ \ --endpoint-url https://.r2.cloudflarestorage.com ``` After upload, redeploy `hasarui-api` once; the entrypoint will pull the three `.pt` files into `/app/models/` on boot (~30 s on first boot). ## 3. CORS | Key | Example | |----------------------|------------------------------------------------------------------------| | `CORS_ORIGINS` | `https://hasarui.vercel.app,https://app.hasarui.com,tauri://localhost` | | `CORS_ORIGIN_REGEX` | `^https://([a-z0-9-]+\.)*hasarui\.com$` | For the desktop (Tauri) app include `tauri://localhost` and `http://tauri.localhost`. For Expo dev clients include `http://localhost:8081`. ## 4. Observability (optional but strongly recommended) | Key | Where to get it | |-----------------|--------------------------------------------------| | `SENTRY_DSN` | Sentry project settings -> Client Keys (DSN). | ## 5. Deploy hooks (set in GitHub repo secrets, NOT Render) After creating the services, copy each one's **Deploy Hook URL** from Render -> Service -> Settings -> Deploy Hook, and add to GitHub: | GitHub secret name | Value | |--------------------------------|------------------------------------| | `RENDER_DEPLOY_HOOK_API` | Deploy hook URL for `hasarui-api`. | | `RENDER_DEPLOY_HOOK_WORKER` | Deploy hook URL for `hasarui-worker`. | --- ## Cost reference (May 2026) | Component | Plan | Monthly | |-----------------------------|-----------|---------| | `hasarui-api` (web) | starter | $7 | | `hasarui-api` (web) | standard | $25 | | `hasarui-worker` | starter | $7 | | `hasarui-redis` | starter | $10 | | `hasarui-db` (Postgres) | starter | $7 | | **Total (starter)** | | **~$31** | | **Total (standard web)** | | **~$49** | Add S3 (R2: ~$0.015/GB stored, $0 egress) and Sentry developer free tier. --- ## Operational notes - **Cold start**: starter plans do NOT spin down. Stay on starter minimum even when traffic is low — free tier spins down after 15 min and the first inference would cost ~45 s of cold boot (uvicorn + model load). - **Memory**: the warmed pipeline holds ~700 MB of weights in RAM. Starter (512 MB) will OOM. Bump `hasarui-api` and `hasarui-worker` to **standard ($25)** before doing real inference. - **Filesystem is ephemeral**: every deploy and every restart wipes `/app/models`. That is why we re-fetch from S3 in `scripts/entrypoint.sh`. Boot time: ~30 s for the 3 weight files. - **One worker concurrency**: keep `--concurrency=1` until you upgrade plans — two parallel inferences on a 0.5 CPU plan starve each other. - **Secrets rotation**: rotate `S3_ACCESS_KEY` / `JWT_SECRET_KEY` every 90 days. JWT rotation invalidates active sessions — schedule during a maintenance window.