尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗A community gallery of AI-built templates plus a browser editor for remixing them. See PLAN.md for the architecture, data model and phase checklist.
Status: Phases 1 (Foundation) and 2 (Gallery) complete: auth, profiles, landing page, uploads with licenses and rights confirmation, sandboxed previews, source browser, likes, saves, follows, filters, reports, DMCA form, admin review queue, and 29 starter templates.
Step-by-step setup, updating, and the launch checklist: docs/DEPLOYMENT.md.
Next.js 16 (App Router, Cache Components) · TypeScript strict · Tailwind CSS 4 · Supabase (Postgres, Auth, Storage) · Drizzle ORM · Upstash rate limiting · Vitest + PGlite · GitHub Actions · Vercel.
Requirements: Node 22+ and pnpm 10 (corepack enable installs pnpm).
pnpm install
cp .env.example .env.local # then fill in the values, see below
pnpm db:migrate # create tables
pnpm storage:setup # create storage buckets
pnpm seed # load the 29 starter templates
pnpm dev # http://localhost:3000
The app starts without any keys: the landing page and legal pages work, sign-in shows a "not set up" message and the waitlist says it isn't open yet. Add the Supabase keys to turn those on.
Preview origin locally: http://localhost:3000 is the app and http://127.0.0.1:3000 acts as the separate preview domain. They're different sites to the browser, so isolation works the same way it will in production.
Everything is listed with instructions in .env.example. Only NEXT_PUBLIC_* values reach the browser. AI and payment keys are server-only and CI fails the build if one shows up in the client bundle.
| Variable | Needed for | Where to get it |
|---|---|---|
NEXT_PUBLIC_APP_URL | Links, metadata | Your domain, e.g. https://remaxx.ai |
NEXT_PUBLIC_PREVIEW_ORIGIN | Sandboxed previews | Your second domain, e.g. https://remaxxusercontent.com |
NEXT_PUBLIC_SUPABASE_URL | Auth, storage | Supabase → Project Settings → API Keys |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY | Auth in the browser | Same page (publishable / anon key) |
SUPABASE_SECRET_KEY | Storage admin (server) | Same page (secret / service_role key) |
DATABASE_URL | Everything with data | Supabase → Connect → connection string |
UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN | Shared rate limits | Upstash console (optional until launch) |
OPENAI_API_KEY | Moderation, vibe search | platform.openai.com (optional; without it uploads are marked unchecked and search matches words only) |
ANTHROPIC_API_KEY | Claude in the editor | console.anthropic.com → API Keys (optional; Claude models show "not set up" without it) |
GOOGLE_GENERATIVE_AI_API_KEY | Gemini in the editor | aistudio.google.com → Get API key (optional) |
DEEPSEEK_API_KEY | DeepSeek in the editor | platform.deepseek.com → API keys (optional) |
AI_ACCESS | Who can use AI features | admins (default) or signed-in. Plans are only sold to people who can use AI |
STRIPE_SECRET_KEY | Selling plans | Stripe → Developers → API keys. Test key (sk_test_...) until launch |
STRIPE_WEBHOOK_SECRET | Credits after payment | Stripe → Developers → Webhooks → endpoint → Signing secret (whsec_...) |
STRIPE_ALLOW_LIVE | Real charges | Leave unset. Live keys are refused unless this is |
.env.local.http://localhost:3000/auth/callback and https://<your-domain>/auth/callback to Redirect URLs.
Auth → Emails → Templates: paste the two templates in docs/email-templates.md so sign-in links work in any browser and include a typeable code.NEXT_PUBLIC_AUTH_PROVIDERS (e.g. google,microsoft,apple); their buttons stay hidden until you do.pnpm db:migrate and pnpm storage:setup. No terminal access to your database? Run pnpm db:setup-sql, paste the output into Supabase → SQL Editor and click Run; it does the same thing and is safe to run twice.pnpm seed, or pnpm seed:sql and paste the output into the SQL Editor.pnpm db:make-admin <your-handle>.| Command | What it does |
|---|---|
pnpm dev | Dev server |
pnpm build / pnpm start | Production build / serve it |
pnpm lint | ESLint (no any without an explicit, commented disable) |
pnpm typecheck | Generates route types, then tsc --noEmit (strict) |
pnpm test | Unit and integration tests. Integration tests run real SQL against an in-process Postgres (PGlite); no database needed |
pnpm db:migrate | Applies new files in db/migrations to DATABASE_URL |
pnpm db:make-admin <handle> [--revoke] | Grants or removes the admin role |
pnpm storage:setup | Creates or updates the storage buckets in config/limits.ts |
pnpm seed / pnpm seed:sql | Loads the starter templates into DATABASE_URL, or prints the SQL to paste. Safe to run again |
pnpm db:setup-sql | Prints all migrations plus storage buckets as one SQL script for the Supabase SQL Editor |
pnpm check:bundle | After a build, fails if a secret-looking value is in the browser bundle |
pnpm verify | Everything CI runs, in order |
app/ Routes (landing, explore, project pages, upload, profiles, saved, admin, legal, preview origin)
components/ UI kit, layout, gallery cards, project page pieces, landing visuals
config/ Site settings, legal versions, licenses and remix rules, tools/categories/styles, limits
lib/ auth, db, licensing (remix rules, credit chain), projects, upload (validate, scan), moderation, seed, security
db/migrations/ Plain SQL migrations, the source of truth for the schema
scripts/ migrate, seed, make-admin, storage setup, setup SQL, bundle secret scan
seed/ Starter template files and their catalog (titles, licenses, tags)
tests/ unit/ and integration/ (PGlite)
No browser access to tables. Every table has row level security on with no policies and no grants to the browser roles. The server talks to Postgres directly and checks permissions with the tested helpers in lib/auth/permissions.ts.
Sessions are verified. getClaims() validates the Supabase JWT on every request; nothing trusts an unverified cookie.
Untrusted code never runs on the server. Project previews are served as plain files from a separate domain with a sandbox CSP, and only ever run in the visitor's browser. The app domain refuses to be framed.
Rate limits on every write endpoint (Upstash when configured, in-memory otherwise).
Uploads are untrusted. Every file is checked by path, type, size and content (magic bytes, valid UTF-8), and scanned for leaked secrets (rejected) and malware or phishing patterns (held for admin review). Text and the cover image go through OpenAI moderation when a key is set.
Licenses are enforced. Every upload needs a license and a rights confirmation, recorded per project. Remixes can only use licenses every ancestor allows (config/licenses.ts, tested in tests/unit/licensing.test.ts).
blobs.storage_key.<preview origin>/v/<version id>/<path> inside a sandboxed iframe. Only published projects are served there.project_search: a plain-language look and feel description, the text search matches against (title, description, category, tool, style and topic tags, look and feel), and an embedding of that text (text-embedding-3-small, pgvector).seed/vibes.ts). For uploads, lib/search/hints.ts reads the CSS/HTML for clues (dark background, frosted glass, hard shadows, serif type...) and a small model turns code + clues into two or three sentences. With no AI key, the clues alone become the description.lib/search/rank.ts blends vibe similarity (55%), word coverage (40%) and a small popularity nudge (5%). The same function produces the "why it matched" chips. Everyday words map onto filters: "glassmorphism" counts as Glassy, "admin" as Dashboard./admin.lib/search/rank.ts; tests/unit/search-rank.test.ts pins the expected top result for real queries over the starter templates./admin (admins only). Admins can dismiss a report, remove a project, or approve held uploads.lib/projects/remix.ts): same files (no bytes copied, blobs are shared by hash), credit to every ancestor, and the most permissive license the chain allows. Drafts only count as remixes once they're published./edit/<id>) has a chat panel (text, voice through the browser's speech recognition, reference images, model picker) and a workspace with a live preview and a CodeMirror code view.lib/editor/bundle.ts) and posted to a blank runner page on the preview origin (<preview origin>/run), which runs under the same sandbox as published previews. Unsaved edits show instantly; nothing runs on the app origin.lib/ai/pipeline.ts): sign-in and AI_ACCESS, model set up, per-minute rate limit, per-person daily cap, site-wide daily budget, one request at a time, prompt moderation, then the model call with a timeout. Every attempt is logged in ai_messages with tokens and estimated cost.lib/ai/edit-protocol.ts): SEARCH/REPLACE edits or whole-file writes. The answer is parsed and applied to a copy of the files, path-checked (no escaping the project, no touching images), and shown as a per-file diff. Nothing is saved until the person applies it.lib/projects/versions.ts). Undo restores the previous version as a new one, so nothing is lost. Saves are rejected if the draft changed in another tab, and a draft can only reuse files from its own history./api/explain) writes a plain-English tour of a version and caches it, so each template is explained once and then free to read for everyone./create, lib/projects/new-project.ts) starts a private draft from one of the original starters in lib/projects/starters.ts (blank page, landing page, portfolio, link page, small app). If the person describes what they want, the description waits in the editor's chat; nothing is sent (or charged) until they press Send. Creating shares the remix rate limit and the 50-draft cap./edit/<id>/publish, lib/projects/publish.ts) turns a draft into a gallery template. It runs the same checks as an upload (secret scanner, moderation of the text and cover), only offers licenses the whole credit chain allows (a CC BY-SA ancestor keeps every remix CC BY-SA; Personal Use stays Personal Use), records the person's rights confirmation, and keeps the "Remixed from" credit, which can't be removed. Flagged remixes are held for review.config/plans.ts has the plans (price, monthly credits, model tier, rate limits), the markup (2.5×), what a credit is worth ($0.01) and the free prompts (2). Change a plan's price by editing it and bumping its priceVersion; Stripe prices can't be edited, so a new version makes a new price.credit_ledger (updates and deletes are refused by the database). credit_accounts.balance is kept in the same transaction and can never go below zero. Every row has a unique idempotency key, so retried webhooks and requests can't apply twice.lib/ai/pipeline.ts → lib/billing/credits.ts): the editor shows an estimate first. The server holds up to the maximum the request could cost, calls the model, then charges the actual cost (never more than the hold) and releases the rest. Failures, timeouts and unusable answers are refunded in full. With no credits left, requests stop (a free prompt is used instead if one is left, on Starter-tier models).AI_ACCESS). With AI_ACCESS=admins, only admins see working plan buttons, so you can test checkout without anyone paying for something they can't use./admin shows credits charged this month against estimated provider cost, and lets admins add or remove credits by handle (recorded in the ledger with a note).sk_test_...) into STRIPE_SECRET_KEY on Vercel.https://<your app domain>/api/stripe/webhook, events checkout.session.completed, customer.subscription.created, customer.subscription.updated, customer.subscription.deleted, invoice.paid. Copy its Signing secret (whsec_...) into STRIPE_WEBHOOK_SECRET./api/health: payments should say ok: test mode./pricing, pick a plan and pay with card 4242 4242 4242 4242, any future date, any CVC. /billing should show the plan and its credits within a few seconds.Going live later means a live key plus STRIPE_ALLOW_LIVE=true, a live-mode webhook, and AI_ACCESS=signed-in. Don't do it before the Terms and Privacy pages have had a lawyer's review.
instrumentation.ts, instrumentation-client.ts): server errors through Next's onRequestError, browser errors through the SDK. Collection is locked down (sentryDataCollection() in lib/monitoring/scrub.ts: no cookies, bodies, AI prompts, database values or stack-frame variables), and every report also passes scrubSentryEvent. No session replays. Source maps aren't uploaded yet; add withSentryConfig and a SENTRY_AUTH_TOKEN when readable stack traces are worth it.lib/monitoring/analytics.ts): page views plus six events (project_created, remix_started, ai_prompt_sent, ai_change_applied, published, checkout_started). Memory-only persistence (no cookies, no consent banner needed), no person profiles, no recordings, Do Not Track respected, URLs scrubbed. Events never carry typed text. Add one by extending AnalyticsEvent and calling track().MODELS in config/models.ts: a stable id, the label people see, the provider, the provider's apiModel name, whether it reads images (vision), its plan tier, and its price per million input/output tokens.lib/ai/providers.ts (request shape, response parsing, error mapping), its key in lib/env.ts and lib/ai/server.ts, an entry in PROVIDERS in config/models.ts, and a test in tests/unit/ai-providers.test.ts.apiModel and redeploy. The model's id stays the same, so history and usage stay linked.trueNEXT_PUBLIC_SENTRY_DSN | Error reports (optional) | sentry.io → Project → Settings → Client Keys (DSN). Off when unset |
NEXT_PUBLIC_POSTHOG_KEY, NEXT_PUBLIC_POSTHOG_HOST | Product analytics (optional) | posthog.com → Project settings → Project API key. Off when unset |
VIBE_DESCRIBE_MODEL | Style descriptions | Optional; defaults to gpt-5-mini |
config/limits.ts (AI_LIMITS). Admins see today's AI usage and spend on /admin.