# render.yaml — Render Blueprint for arac-hasar-v2 # ---------------------------------------------------------------------- # FREE-TIER PROFILE (active by default in this file). # For paid pilot/staging blueprint, see scripts/deploy/render-paid.yaml # (kept as historical reference; legacy contents are inlined at the bottom # of this file as comments). # # Free-tier services (cost = $0): # - hasari-api Render Free web service (512 MB / 0.1 CPU, sleeps after # 15 min idle; cold start ~30 s on first request). # - hasari-worker Render Free does NOT officially support background # workers. Workaround: run Celery in SOLO mode INSIDE the # web container at boot (see scripts/entrypoint_free.sh). # In production code, the API will also accept # FORCE_SYNC_INFERENCE=1 so /analyze runs inline if the # worker is unreachable (graceful degrade). # - DB -> Supabase Free (external, NOT managed here). 500 MB, # pauses after 7 days idle. # - Redis -> Upstash Free (external, NOT managed here). 10K cmd/day. # - S3 -> Cloudflare R2 Free (external). 10 GB storage, 10 GB egress. # # ML model weights strategy for free tier: # We EMBED a quantized small model (yolo11s-seg ~20 MB) into the image # so cold-start does not need an S3 download (Render free has no disk # cache between restarts, and Upstash/R2 free bandwidth is precious). # Use Dockerfile.embedded with MODEL_VARIANT=small to keep the final # image well under Render's 10 GB free-tier image cap (target ~600 MB). # # IMPORTANT: secrets MUST be set in Render dashboard (sync: false). Never # commit them here. Use `JWT_SECRET_KEY: generateValue: true` so Render # auto-generates a 32-char secret on first deploy. # ---------------------------------------------------------------------- services: # =================================================================== # Web service — FastAPI (FREE plan) # =================================================================== - type: web name: hasari-api runtime: docker # repo: set this to your GitHub repo URL after first blueprint import, # e.g. https://github.com/erdoganpeker/arac-hasar-v2 # Render Dashboard "Connect Repo" UI also resolves this automatically. repo: https://github.com/erdoganpeker/arac-hasar-v2 branch: main rootDir: . # Dockerfile.embedded baked the 137 MB CarDD bundle into the image # (too big for Render free 10 GB image + slow rebuilds). We use the # slim Dockerfile and fetch weights from B2 at boot via entrypoint.sh. dockerfilePath: ./services/backend/Dockerfile dockerContext: ./services/backend plan: starter # 2 GB RAM, no sleep; required for ML pipeline (free 512 MB OOMs) region: frankfurt # closest free region to TR autoDeploy: false # gated by GH Actions deploy hook healthCheckPath: /health numInstances: 1 envVars: - key: PORT value: "8000" - key: ENVIRONMENT value: production - key: RUN_MIGRATIONS value: "1" - key: ML_DEVICE value: cpu - key: MODEL_DIR value: /app/models # Boot-time model fetch from B2: entrypoint.sh downloads .pt files # from s3://$MODEL_S3_BUCKET/$MODEL_S3_PREFIX/ into MODEL_DIR. - key: SKIP_MODEL_FETCH value: "0" - key: MODEL_S3_BUCKET value: hasari-inspections - key: MODEL_S3_PREFIX value: models # B2 path: hasari-inspections/models/{damage,parts,severity}_best.pt - key: FORCE_SYNC_INFERENCE value: "1" # free tier has no worker -> run inline - key: UVICORN_WORKERS value: "1" # 512 MB cannot hold 2 workers + model # ---- External services (set in dashboard, sync: false) ---- - key: DATABASE_URL # Supabase pooled URL (pgbouncer 6543) sync: false - key: REDIS_URL # Upstash rediss:// URL sync: false - key: JWT_SECRET_KEY generateValue: true # Render generates 32-char secret - key: API_KEYS sync: false # ---- S3 / Cloudflare R2 ---- - key: S3_ENDPOINT # https://.r2.cloudflarestorage.com sync: false - key: S3_REGION value: auto - key: S3_ACCESS_KEY sync: false - key: S3_SECRET_KEY sync: false - key: S3_BUCKET sync: false - key: S3_PUBLIC_ENDPOINT # https://pub-.r2.dev or custom sync: false # ---- CORS — pin to Vercel URL ---- - key: CORS_ORIGINS value: https://hasari.vercel.app - key: CORS_ORIGIN_REGEX value: ^https://hasari(-[a-z0-9]+)?\.vercel\.app$ # ---- Admin bootstrap (set once in dashboard) ---- - key: ADMIN_EMAIL sync: false - key: ADMIN_PASSWORD sync: false # ---- Optional observability ---- - key: SENTRY_DSN sync: false # =================================================================== # Worker — DISABLED on free tier (Render Free does not support workers). # We rely on FORCE_SYNC_INFERENCE=1 in the web service to run /analyze # synchronously. When upgrading to a paid plan, UNCOMMENT this block # and remove FORCE_SYNC_INFERENCE from the web service env. # =================================================================== # - type: worker # name: hasari-worker # runtime: docker # repo: https://github.com/REPLACE_ME/arac-hasar-v2 # branch: main # rootDir: . # dockerfilePath: ./services/backend/Dockerfile.embedded # dockerContext: . # dockerCommand: celery -A worker.celery_app worker --loglevel=info --concurrency=1 # plan: starter # workers require a paid plan # region: frankfurt # autoDeploy: false # numInstances: 1 # envVars: # - key: ENVIRONMENT # value: production # - key: RUN_MIGRATIONS # value: "0" # - key: ML_DEVICE # value: cpu # - key: MODEL_DIR # value: /app/models # - key: MODEL_VARIANT # value: small # - key: SKIP_MODEL_FETCH # value: "1" # - key: DATABASE_URL # sync: false # - key: REDIS_URL # sync: false # - key: JWT_SECRET_KEY # fromService: # type: web # name: hasari-api # envVarKey: JWT_SECRET_KEY # - key: S3_ENDPOINT # sync: false # - key: S3_REGION # value: auto # - key: S3_ACCESS_KEY # sync: false # - key: S3_SECRET_KEY # sync: false # - key: S3_BUCKET # sync: false # - key: SENTRY_DSN # sync: false # =================================================================== # NO managed databases / redis on free tier — see docs/DEPLOY_FREE.md # for Supabase + Upstash setup. The legacy paid blueprint (hasarui-db # Postgres + hasarui-redis Redis) is kept in git history under the # `services/databases` section of earlier revisions of this file. # ===================================================================