A self-hosted web app for the Kling AI API — full image & video generation studio
Chat-style interface for text-to-image, text-to-video, image-to-video, and multi-element "Omni" generations — with projects, asset groups, credit tracking, and automatic archival to Google Cloud Storage.
Next.js React Convex Tailwind CSS TypeScript Vitest
AI Gen Studio — Omni video generation with element references and a results gallery
- 🖼️ Image generation — Kling Image (v2/v3), Omni Image, restyle, single-reference, and elements modes
- 🎥 Video generation — text-to-video, image-to-video, multi-image-to-video, and Omni Video with element references, first/end frame support, and motion control
- 🧩 Elements system — reusable characters & objects referenced with
@mentionsyntax in prompts, including custom element creation with Gemini-powered auto-describe - 📁 Projects & asset groups — organize generations per project, send results to shared asset groups
- 🕘 History — filterable gallery/list views, favorites, re-edit any past prompt with its media
- 💳 Cost tracking — pre-generation cost estimates, per-user/per-project credit dashboards, live account credit badge
- 🛡️ Admin panel — user allowlist, roles (RBAC), project management, usage reports
- 🔐 Auth — Google OAuth and email/password sign-in, gated by an admin-managed allowlist
| Layer | Technology |
|---|---|
| Frontend | Next.js 16 (App Router), React 19, Tailwind CSS 4, Radix UI, Lexical editor |
| Backend | Convex — database, server functions, HTTP endpoints, crons |
| Auth | @convex-dev/auth (Google + Password providers) |
| Generation API | Kling AI (JWT-signed requests, webhook callbacks) |
| Storage | Google Cloud Storage (generated results + user uploads) |
| AI utilities | Google Gemini (element auto-describe) |
| Testing | Vitest + Testing Library |
Browser ── Next.js (Vercel) ── Convex queries/mutations
│
├── actions → Kling AI API (JWT auth)
│ Kling → /api/kling-webhook (Convex HTTP action)
│
└── actions → Google Cloud Storage
(download results, signed upload URLs)
- A generation form submits a task via a Convex action, which builds the model-specific request and calls Kling with a short-lived JWT.
- A server-side queue caps concurrent Kling slots (
KLING_CONCURRENCY). - Kling calls back to the Convex HTTP endpoint
/api/kling-webhookwhen a task finishes. - A Convex action downloads the result media into GCS so URLs never expire, then updates the task, chat message, and credit ledger.
- Node.js 20+
- A Convex account
- Kling AI API access key & secret
- A GCP project with a Cloud Storage bucket and a service account with
Storage Object Adminon it - Google OAuth client (for Google sign-in)
- Optional: a Gemini API key for element auto-describe
npm install
cp .env.example .env.local
Fill in .env.local (see comments in .env.example). Server-side secrets must also be set on the Convex deployment:
npx convex env set AUTH_GOOGLE_ID <...> npx convex env set AUTH_GOOGLE_SECRET <...> npx convex env set KLING_ACCESS_KEY <...> npx convex env set KLING_SECRET_KEY <...> npx convex env set GCS_BUCKET_NAME <...> npx convex env set GCS_SERVICE_ACCOUNT_KEY "$(base64 -i service-account.json)" npx convex env set GEMINI_API_KEY <...>
⚠️ Never commit.env.local,.env.production.local, or any*service-account*.jsonfile — they are gitignored on purpose.
-
Google OAuth: add
https://<your-deployment>.convex.site/api/auth/callback/googleas an authorized redirect URI. -
Kling webhook: point the callback URL at
https://<your-deployment>.convex.site/api/kling-webhook. -
GCS CORS: allow your app origins to
PUTuploads (see cors.json for the shape, replace the origins with your own):gcloud storage buckets update gs://<bucket> --cors-file=cors.json
npm run dev:all # Convex backend + Next.js frontend together (dev.sh)or in two terminals:
npx convex dev # backend npm run dev # frontend at http://localhost:3000
The first signed-in user must be allowlisted/promoted to admin directly in the Convex dashboard (users table); after that, user management happens in the in-app Admin panel.
| Command | Purpose |
|---|---|
npm run dev |
Next.js dev server |
npm run dev:backend |
Convex dev server |
npm run dev:all |
Both, via dev.sh (dev.bat on Windows) |
npm run build |
Production build |
npm run test |
Vitest in watch mode |
npm run test:run |
Run test suite once |
npm run lint |
ESLint |
Standalone Kling API smoke tests live in scripts/ (they read KLING_ACCESS_KEY / KLING_SECRET_KEY from the environment).
src/app/ Next.js routes (login, app shell, admin, project/asset-group slugs)
src/components/ UI — generation forms, history, editor, admin, ui primitives
src/hooks/ Generation hooks suite, uploads, polling
src/contexts/ Panel & upload React contexts
convex/ Backend — schema, auth, tasks, queue, webhooks, GCS, admin, RBAC
convex/kling/ Kling API client & per-model request builders
convex/gcs/ GCS download/upload actions
kling_ai_documentation*/ Kling API reference docs used during development
_bmad-output/ Planning & implementation artifacts (story-driven development log)
The frontend deploys to Vercel; the backend deploys with npx convex deploy (wired into the Vercel build via CONVEX_DEPLOY_KEY). Set the same environment variables on the production Convex deployment as in step 2.
Private project — no license granted.