Skip to content

Configuration ​

The API reads its settings from environment variables. Everything optional is off when unset.

VariablePurpose
DATABASE_URLPostgreSQL. Without it, data lives in memory and is lost on restart.
PORTListen port (default 3000).
PUBLIC_URLPublic https address of the API (calendar links, admin).
APP_URLAddress of the web app (invites, Apple sign-in redirect).
CORS_ORIGINAllowed web origin for the app.
TRUST_PROXY1 behind a reverse proxy.
METRICS_TOKENOptional 64-character lowercase hex secret for private monitoring.
RESEND_API_KEY, RESEND_FROMEmail (verification codes, invites).
GOOGLE_CLIENT_IDS, APPLE_CLIENT_IDSAccepted audiences for Google/Apple sign-in. Empty disables the provider.
S3_ENDPOINT, S3_REGION, S3_BUCKET, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEYPrivate EU bucket for photos and files.
ADMIN_SECRET_KEYEnables the admin dashboard.
ASSISTANT_PROVIDER, ASSISTANT_API_KEY, ASSISTANT_MODELServer-side assistant model (openai, anthropic or mistral).
VOICE_API_KEYSpeech in and out for plans with voice.
OPENAI_API_KEY, LIST_AI_*, ANTHROPIC_API_KEYOptional model for shopping-list categories.

The app reads EXPO_PUBLIC_API_URL and, for social sign-in, EXPO_PUBLIC_GOOGLE_{WEB,IOS,ANDROID}_CLIENT_ID and EXPO_PUBLIC_APPLE_SERVICE_ID.

Upload recovery ​

With PostgreSQL enabled, upload tickets survive API restarts. The signed PUT and initial completion window last 15 minutes. A successful completion can be retried for another 24 hours after that window and returns the same photo or file, provided it still exists and the caller retains access. Completion never recreates a deleted record.

The object sweeper removes expired unfinished uploads after a 24-hour grace period for in-flight PUT requests. Member erasure and family purging also invalidate their tickets and schedule unfinished objects for removal. Completed ticket receipts expire without deleting the saved media. Retried storage deletions use the existing orphan cleanup queue.

The app can capture photos, files and attachment messages into a separate local binary queue while offline, then resume when it has a connection. It stores at most 20 pending items and 100 MiB total. Web payloads use IndexedDB transactions; native payloads live in the app cache directory and are not backed up to iCloud or Google. Browser quota/eviction and operating-system cache purges can remove local bytes, and the OS does not guarantee background work. Queue data is cleared on sign-out or family/member revocation. If a saved completion receipt has expired, the user must discard the pending entry and select the file again; a completion that may have been sent is never restarted with a new ticket.

Fellesly: the family, in one place.