File size: 5,995 Bytes
e327f0d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# 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://<accountid>.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://<accountid>.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.