Recipicity¶
Production¶
Domain: recipicity.com
Stack: app-recipicity-production (5 services)
Stack file: /opt/swarm/stacks/recipicity-production/stack.recipicity-production.yml
| Service | Image | Replicas | Port |
|---|---|---|---|
| frontend | recipicity-production-frontend | 2 | 80 |
| api | recipicity-production-api | 2 | 3000 |
| admin | recipicity-production-admin | 1 | 80 |
| scheduler | recipicity-production-api | 1 | -- |
| images | nginx:stable-alpine | 1 | 80 |
Tech stack: Next.js (frontend), Node.js/Express (API), PostgreSQL, Redis, Prisma ORM
Routes:
recipicity.com-> frontendrecipicity.com/api-> apirecipicity.com/admin-> admin (stripprefix)
Payment integration: Paddle (webhook route mounted before express.json() for raw body signature verification). Credentials encrypted with AES-256-GCM, key from Docker secret.
Build Script Required
Always use the build script on apps-dev1. Never run docker build manually -- the frontend requires --build-arg REACT_APP_API_URL=https://recipicity.com/api.
ssh john@192.168.51.40
cd /opt/development/recipicity/prod
./build.sh all --deploy # Build, push, deploy everything
./build.sh frontend --deploy # Frontend only
./build.sh api --deploy # API only
./build.sh admin --deploy # Admin only
The build script uses digest-pinned deploys -- it captures the SHA256 digest from each docker push and passes it to docker service update, eliminating stale image cache issues.
Staging¶
Domain: staging.recipicity.com
Stack: app-recipicity-staging (4 services) + app-recipicity-staging-admin (1 service)
Stack file: /opt/swarm/stacks/app-recipicity/stack.recipicity.yml
| Service | Image | Replicas | Port |
|---|---|---|---|
| frontend | recipicity-staging-frontend | 2 | 3000 |
| api | recipicity-staging-api | 2 | 3000 |
| scheduler | recipicity-staging-api | 1 | -- |
| images | nginx:stable-alpine | 1 | 80 |
| admin (separate stack) | recipicity-staging-admin | 1 | 80 |
Tech stack: Next.js 16.1.6 (frontend), React 19.2.3, Node.js/Express (API), PostgreSQL, Tailwind CSS v4
Key architecture decisions:
- Zero UUIDs in URLs -- recipes at
/{username}/{slug} - BFF auth pattern with httpOnly cookies
- CSS masonry via
column-count(SSR-safe, zero JS) - Native fetch (no axios) --
server-client.tsfor SSR,client.tsfor browser - Internal API:
http://app-recipicity-staging_api:3000/api(direct service mesh)
Build:
ssh john@192.168.51.40
cd /opt/development/recipicity/staging
./build.sh all --deploy # Build, push, and deploy (digest-pinned)
Staging-Specific Notes¶
- Frontend needs
data_netnetwork for SSR API calls (direct service mesh, not through Traefik) - Internal API URL set via
INTERNAL_API_URLenvironment variable - Memory: 512MB limit / 256MB reservation (higher than production due to SSR)
AI Integration¶
Provider-agnostic AI client supporting both Anthropic (Claude) and OpenAI. Provider is auto-detected from model name (e.g., claude-* routes to Anthropic). Configurable via admin panel.
AI Features¶
| Feature | Description |
|---|---|
| Recipe Generation | AI generates complete recipes from user prompts |
| Recipe Import (URL) | Schema.org parsing + AI enrichment (description, tags) |
| Recipe Import (Image) | Vision model extracts recipe from photos |
| Recipe Import (Text) | AI structures pasted recipe text |
| Conversational Recipes | Chat-based recipe creation and modification |
Recipe Import Pipeline¶
- Fetch and parse -- Downloads page, extracts Schema.org JSON-LD or microdata
- Schema.org extraction -- Parses structured recipe data (ingredients, steps, times)
- AI enrichment -- Generates factual description, suggests tags
- Unit normalization -- Standardizes ingredient units (cups->cup, tablespoons->tbsp, pounds->lb)
- Drink detection -- Heuristic analysis classifies recipe as food or drink
- Save as draft -- User reviews before publishing
All AI calls are logged to the ai_generation_logs table with provider, model, token usage, and cost.
Copyright Policy
Recipe imports never copy copyrightable content (personal stories, creative descriptions, images). Only factual data is extracted: ingredient lists, cooking steps, times, servings. AI generates original descriptions. Source URL is always attributed.
Payment System (Paddle)¶
- Webhook route mounted BEFORE
express.json()middleware (needs raw body for signature verification) - Credentials stored encrypted in SiteConfig DB table (AES-256-GCM)
- Encryption key from Docker secret:
recipicity_staging_encryption_key - Paddle SDK v1.10: uses
paddle.transactions.create()(not checkouts)