No description
  • TypeScript 96.6%
  • Dockerfile 1.9%
  • CSS 0.7%
  • JavaScript 0.4%
  • Shell 0.4%
Find a file
2026-06-18 17:07:36 +02:00
app push 2026-06-18 17:07:36 +02:00
components push 2026-06-18 17:07:36 +02:00
config push 2026-06-18 17:07:36 +02:00
lib Initial commit 2026-06-10 18:43:56 +02:00
prisma Initial commit 2026-06-10 18:43:56 +02:00
public Initial commit 2026-06-10 18:43:56 +02:00
services Initial commit 2026-06-10 18:43:56 +02:00
.env.example Initial commit 2026-06-10 18:43:56 +02:00
.gitignore Initial commit 2026-06-10 18:43:56 +02:00
ai.md Initial commit 2026-06-10 18:43:56 +02:00
docker-compose.yml Initial commit 2026-06-10 18:43:56 +02:00
docker-entrypoint.sh Initial commit 2026-06-10 18:43:56 +02:00
Dockerfile Initial commit 2026-06-10 18:43:56 +02:00
next-env.d.ts Initial commit 2026-06-10 18:43:56 +02:00
next.config.js Initial commit 2026-06-10 18:43:56 +02:00
package-lock.json Initial commit 2026-06-10 18:43:56 +02:00
package.json Initial commit 2026-06-10 18:43:56 +02:00
postcss.config.js Initial commit 2026-06-10 18:43:56 +02:00
README.md Initial commit 2026-06-10 18:43:56 +02:00
start.md Initial commit 2026-06-10 18:43:56 +02:00
tailwind.config.ts push 2026-06-18 17:07:36 +02:00
tsconfig.json Initial commit 2026-06-10 18:43:56 +02:00

AI Photo Style Generator (MVP)

Upload a photo, pick a style, pay via Stripe, get an AI-generated version back via Nano Banana Pro (Gemini image generation).

Stack

  • Next.js 15 (App Router) + TypeScript + Tailwind
  • PostgreSQL + Prisma
  • MinIO (S3-compatible storage)
  • Stripe Checkout + Webhooks
  • Google Gemini API (Nano Banana Pro) for image generation
  • Docker Compose

Setup

  1. Copy .env.example to .env and fill in:

    • STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET - from your Stripe test dashboard.
    • GEMINI_API_KEY - from Google AI Studio.
    • NEXT_PUBLIC_BASE_URL - public URL of the app (used for Stripe redirect URLs).
    • MINIO_PUBLIC_ENDPOINT - URL where the browser can reach MinIO (e.g. http://localhost:9000 for local dev, or your domain in production).
    • Adjust MINIO_ACCESS_KEY / MINIO_SECRET_KEY if you don't want the defaults.
  2. Run everything:

docker compose up -d --build

The app runs migrations automatically on startup (docker-entrypoint.sh).

  1. Open http://localhost:3000

Stripe webhook (local testing)

Use the Stripe CLI to forward events to your local instance:

stripe listen --forward-to localhost:3000/api/stripe/webhook

Copy the printed whsec_... value into STRIPE_WEBHOOK_SECRET in .env.

Local development (without Docker)

Requires a local Postgres and MinIO (or point .env at remote instances).

npm install
npm run prisma:migrate:dev
npm run dev

Flow

  1. / - landing page, CTA to /generate.
  2. /generate - upload photo, pick one of 5 styles, optional prompt -> POST /api/upload (validates file, stores in MinIO, creates Generation row with status pending) -> POST /api/checkout (creates Stripe Checkout Session, Payment row) -> redirect to Stripe.
  3. After payment, Stripe redirects to /processing?generationId=... and sends checkout.session.completed to /api/stripe/webhook, which marks the payment as paid and triggers services/imageGeneration.ts (status: pending -> processing -> completed/failed).
  4. /processing polls GET /api/generations/:id every ~2.5s, redirects to /result/:id once completed.
  5. /result/:id shows the generated image(s) with signed download links and a "Generate Another" button.

Notes / limitations (MVP)

  • No user accounts - generations are addressed by UUID only.
  • Rate limiting (lib/rateLimit.ts) is in-memory, per-instance only - fine for a single container, won't work correctly if you scale app to >1 replica.
  • Image generation runs in the webhook handler without awaiting (fire and forget) so Stripe gets a fast response. If the container restarts mid- generation, that generation stays processing forever - acceptable for MVP, would need a real job queue for production.
  • Original uploads and results are not auto-deleted (the 24h/30-day retention mentioned in the spec would need a cron/cleanup job).