Files
interactive-story/render.yaml
T
parththakkar106andClaude Opus 5 bbcb07c6be Delete guest accounts left idle for five days
The app had no cleanup of any kind: in multi-user mode every first visit
mints a users row, so the demo has been accumulating one permanent account
per visitor along with everything they generated.

cleanup.py sweeps guests idle for AIDND_GUEST_RETENTION_DAYS (default 5),
once at startup and then every few hours. Startup is the load-bearing
trigger — the free tier sleeps after ~15 minutes, so a long timer rarely
gets to fire.

Idle is COALESCE(last_seen_at, created_at), not last_seen_at: _touch only
writes that column hourly, and a guest minted by /auth/me has it NULL until
its second request, so the simpler query would have deleted brand-new
visitors mid-session.

It's one Core DELETE rather than db.delete(user), which would SELECT every
adventure, action and memory into Python purely to delete them — the same
egress pattern as the 189x fix. Every FK from users down is ON DELETE
CASCADE, so the database does the whole graph and returns a count.

The filter requires is_guest AND email IS NULL, so registered users (who
upgrade in place) and local mode's implicit user are both out of reach, and
is_public is output-only so a guest can never own content another user can
see. Session cookies have no expiry and can outlive a swept row; that path
401s and the frontend's existing retry re-mints a session.

Guests are told: /auth/me serves guest_retention_days and the signup modal
states the window, sourced from the server so it can't drift from what is
enforced.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015CYEJKobJ2Re4Dv7qUoSA7
2026-08-15 20:14:12 +05:30

62 lines
2.4 KiB
YAML

# Render Blueprint — https://render.com/docs/blueprint-spec
#
# One web service: the multi-stage Dockerfile builds the React SPA and the
# FastAPI backend into a single image that serves both same-origin. Database
# is external Neon Postgres (set AIDND_DATABASE_URL in the dashboard); the
# free tier has no persistent disk, which is why the DB lives off-box.
#
# First deploy: create a Blueprint from this repo in the Render dashboard,
# then fill the `sync: false` secrets (Neon URL + demo key). Pushes to `main`
# auto-deploy thereafter.
services:
- type: web
name: ai-dnd
runtime: docker
dockerfilePath: ./Dockerfile
dockerContext: .
plan: free # sleeps after ~15 min idle; first wake takes ~30-60s
region: virginia # us-east, closest to the Neon us-east-1 database
healthCheckPath: /api/health
autoDeploy: true
envVars:
# Multi-user hardening on (guest sessions, per-user data, rate limits).
- key: AIDND_MULTI_USER
value: "1"
# Signs session cookies + encrypts stored API keys. Render generates a
# strong value once and keeps it stable across deploys (a regenerated
# secret would log out every user on each deploy).
- key: AIDND_SECRET_KEY
generateValue: true
# Neon Postgres connection string (pooled, sslmode=require). Secret —
# set it in the dashboard; never commit it.
- key: AIDND_DATABASE_URL
sync: false
# --- Shared demo key (optional): lets first-time visitors play without
# bringing their own API key. Set these in the dashboard to enable;
# leave unset to require BYOK. ---
- key: AIDND_DEMO_API_KEY
sync: false
- key: AIDND_DEMO_MODELS
sync: false
- key: AIDND_DEMO_TURNS_PER_DAY
value: "20"
# Comma-separated emails of trusted testers: unmetered demo turns, plus
# the AI Chat page (hidden from everyone else). Set in the dashboard;
# leave unset and nobody gets it. Registered accounts only.
- key: AIDND_POWER_USERS
sync: false
# Guest retention: one account is minted per first-time visitor, so idle
# ones are collected (with their adventures) to keep the free-tier
# Postgres from filling with abandoned demo data. Registered accounts are
# never touched. 0 would disable it.
- key: AIDND_GUEST_RETENTION_DAYS
value: "5"
# CORS is unset on purpose: the SPA is served same-origin by FastAPI.