-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrender.yaml
More file actions
163 lines (161 loc) · 6.99 KB
/
Copy pathrender.yaml
File metadata and controls
163 lines (161 loc) · 6.99 KB
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# Render Blueprint for Approach Note
# https://render.com/docs/blueprint-spec
#
# This file describes the production deployment: a web service (Flask API)
# and a worker service (research_worker) that processes background jobs.
# The worker service is the one that holds the Apple Music catalog on a
# persistent disk; the catalog is downloaded by the chained
# `apple/refresh_catalog` job (see backend/integrations/apple_music/refresh.py).
#
# ---------------------------------------------------------------------------
# How to apply this for the first time
# ---------------------------------------------------------------------------
# If services already exist in your Render dashboard:
# 1. Service names below MUST match what's in the dashboard, OR
# 2. Use the "New > Blueprint" flow to convert (Render will offer to link
# the existing services).
#
# After linking the Blueprint, set every `sync: false` env var via the
# Render dashboard (these are secrets, not committed here). The values
# you should already have in your local backend/.env are the ones to copy.
#
# The persistent disk on the worker (100 GB) is the new piece for issue 162.
# Render plans: persistent disks require Standard or higher. The Apple
# catalog (parquet + DuckDB index) needs ~80 GB; 100 GB leaves headroom.
#
# ---------------------------------------------------------------------------
# Bootstrap the catalog after deploy
# ---------------------------------------------------------------------------
# 1. Confirm worker shows the disk at /data:
# render shell -s approachnote-research-worker (or web shell)
# df -h /data
# 2. Confirm Apple credentials are set on the worker:
# env | grep APPLE_
# 3. Open https://api.approachnote.com/admin/apple-music-catalog and click
# "Refresh catalog now". The chain runs:
# albums (~30 GB) → songs (~40 GB) → artists (~6 GB) → rebuild_index
# Watch the "Recent Refresh Activity" panel for status.
services:
# ===========================================================================
# Flask API
# ===========================================================================
- type: web
name: approachnote-api
runtime: python
plan: standard # adjust to match your current plan
region: ohio
rootDir: backend
buildCommand: pip install -r requirements.txt
startCommand: gunicorn -c gunicorn.conf.py app:app
healthCheckPath: /health
envVars:
- key: PYTHON_VERSION
value: 3.13.0
- key: DB_USE_POOLING
value: "true"
# --- secrets (set in dashboard) ---
- key: DATABASE_URL
sync: false
- key: JWT_SECRET_KEY
sync: false
- key: SPOTIFY_CLIENT_ID
sync: false
- key: SPOTIFY_CLIENT_SECRET
sync: false
- key: SENDGRID_API_KEY
sync: false
# PostHog product analytics for the public marketing pages. This is the
# public project key (phc_...) — same project as the iOS app, US Cloud.
# It's exposed in client JS by design; set it in the dashboard. The
# marketing snippet no-ops if it's unset. POSTHOG_HOST defaults to the
# US Cloud host in app.py, so it only needs setting for EU/self-hosted.
- key: POSTHOG_API_KEY
sync: false
# Apple Music Feed (also needed on the web side if any admin route
# needs to read credentials; if not, these can be worker-only).
- key: APPLE_MEDIA_ID
sync: false
- key: APPLE_KEY_ID
sync: false
- key: APPLE_TEAM_ID
sync: false
# Sign in with Apple — grant revocation on account deletion (App Store
# 5.1.1(v)). The /auth/* routes run on THIS web service, so the SIWA
# credentials live here (not on the worker). This uses a DIFFERENT Apple
# key than APPLE_KEY_ID above: a Sign-in-with-Apple key, not the
# MusicKit/Media key. Deliver the .p8 as a Render Secret File on this
# service and point APPLE_SIGNIN_PRIVATE_KEY_PATH at its mount path
# (e.g. /etc/secrets/AuthKey_XXXXXXXXXX.p8).
# APPLE_SIGNIN_TEAM_ID is optional — it falls back to APPLE_TEAM_ID above.
# APPLE_BUNDLE_IDS (comma-separated client_ids, already set in the
# dashboard for identity-token verification) is reused by the revoke flow.
- key: APPLE_SIGNIN_KEY_ID
sync: false
- key: APPLE_SIGNIN_PRIVATE_KEY_PATH
sync: false
# ===========================================================================
# Research worker — processes background jobs from research_jobs.
# Owns the Apple Music catalog disk.
# ===========================================================================
- type: worker
name: approachnote-research-worker
runtime: python
plan: standard # required for persistent disk
region: ohio # MUST match the web service's region
rootDir: backend
buildCommand: pip install -r requirements.txt
startCommand: python -m research_worker.run
disk:
name: apple-catalog
mountPath: /data
sizeGB: 100
envVars:
- key: PYTHON_VERSION
value: 3.13.0
- key: DB_USE_POOLING
value: "true"
- key: RESEARCH_WORKER_LOG_LEVEL
value: INFO
# Catalog lives on the persistent disk; both the parquet tree and the
# DuckDB index sit under /data so they survive restarts.
- key: APPLE_MUSIC_CATALOG_DIR
value: /data/apple_music_catalog
- key: APPLE_MUSIC_CATALOG_DB
value: /data/apple_music_catalog.duckdb
# MusicBrainz / Wikipedia HTTP caches live on the persistent disk too,
# so they survive deploys instead of being wiped with the ephemeral
# repo checkout (core/cache_utils.get_cache_root reads CACHE_ROOT).
# Worker-only: the web service has no /data mount and keeps its default
# ephemeral cache.
- key: CACHE_ROOT
value: /data/cache
# --- secrets (set in dashboard) ---
- key: DATABASE_URL
sync: false
# Apple Developer credentials for the Feed API (the .p8 private key
# is delivered as a Render Secret File; see APPLE_PRIVATE_KEY_PATH).
- key: APPLE_MEDIA_ID
sync: false
- key: APPLE_KEY_ID
sync: false
- key: APPLE_TEAM_ID
sync: false
- key: APPLE_PRIVATE_KEY_PATH
# Set this to the path Render mounts your secret file at, e.g.
# /etc/secrets/AuthKey_XXXXXXXXXX.p8
sync: false
- key: SPOTIFY_CLIENT_ID
sync: false
- key: SPOTIFY_CLIENT_SECRET
sync: false
# Commons imagery enrichment (commons source). ANTHROPIC_API_KEY powers
# the Claude vision rerank; without it the rerank is skipped and images
# are ranked on local signals only. FLICKR_API_KEY is optional (adds the
# Flickr Commons source). Face-detection ONNX models cache on the
# persistent disk so they survive deploys.
- key: ANTHROPIC_API_KEY
sync: false
- key: FLICKR_API_KEY
sync: false
- key: IMAGE_MODEL_DIR
value: /data/face_models