尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗Turns app screenshots into animated promo videos, rendered on a canvas in the browser. Next.js on Vercel, Supabase (auth + Postgres), Cloudflare R2 (files), Paddle (billing). Architecture, conventions and every dashboard setting live in CLAUDE.md; this file covers running it and operating it.
cp .env.example .env.local # fill in values (see comments in the file)
npm install
npm run dev # http://localhost:3000
npm run visual-regression # after any rendering change (see CLAUDE.md rule 6)
Free accounts can store 200 MB of files (screenshots, icons, music), Pro
accounts 5 GB (maxStorageBytes in src/lib/plan.ts). The limit is
enforced on the server when an upload is approved
(/api/storage/upload → public.reserve_storage, migration 0019), so it
can't be bypassed from the browser. Usage shows on /account, on
/projects and in the editor's slide rail. Deleting a project frees its
space immediately; files a project no longer uses (replaced screenshots,
deleted slides) are cleaned up an hour after they stop being used,
whenever the user's usage is recounted.
After running migration 0019 once, record files that already existed:
node --env-file=.env.local scripts/backfill-storage-usage.mjs.
Every Sunday at 03:17 UTC, .github/workflows/db-backup.yml:
Backs up production with pg_dump (scripts/backup/backup-db.mjs) to
the private R2 bucket nimina-backups, under weekly/<YYYY-MM-DD>/:
data.sql.gz: every row of every table in public and auth (users,
sign-in identities, projects, billing records, …);public-schema.sql.gz: our schema exactly as it was in production;supabase-schemas.sql.gz: Supabase's own auth/storage schemas,
used only by the restore check below;manifest.json: row count and content checksum of every table, taken
in the same database snapshot as the dump.It keeps the newest 8 backups and deletes older ones.
Proves the backup restores (scripts/backup/verify-backup.mjs). It
downloads the backup it just uploaded, runs the restore procedure below
into a throwaway Postgres 17, and compares every table's row count and
contents with the manifest. Any difference fails the run, and GitHub
emails the repo owner. The result is saved next to the backup as
verify.json. It also reports drift, meaning any difference between
production's schema and what supabase/migrations/ builds.
Run it on demand: GitHub → Actions → Database backup → Run workflow.
See what you have: node --env-file=.env.local scripts/backup/fetch-backup.mjs --list.
Not in the backup: uploaded files (they're in R2, not the database), and Supabase dashboard settings (auth providers, email templates, SMTP, URL configuration; see CLAUDE.md "Accounts & sign-in").
Restoring means loading the data into a new Supabase project and pointing
the app at it. You need the PostgreSQL 17 client tools (psql) and the
Supabase CLI.
node --env-file=.env.local scripts/backup/fetch-backup.mjs --date=2026-10-04 --out=./restore
Leave out --date to get the newest. You can also download the files
from Cloudflare (R2 → nimina-backups → weekly/<date>/).export NEW_DB_URL='postgresql://postgres.<new-ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres'
supabase link --project-ref <new-ref>
supabase db push
psql "$NEW_DB_URL" -v ON_ERROR_STOP=1 -c "do \$\$ declare t text; begin for t in select format('%I.%I', schemaname, tablename) from pg_tables where schemaname = 'public' loop execute 'truncate ' || t || ' cascade'; end loop; end \$\$;"
gunzip -c restore/data.sql.gz | PGOPTIONS='-c session_replication_role=replica' psql "$NEW_DB_URL" -v ON_ERROR_STOP=1 --quiet
ok:
node scripts/backup/check-restore.mjs --manifest=restore/manifest.json --db="$NEW_DB_URL"
NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY and
SUPABASE_SERVICE_ROLE_KEY to the new project's values, both in
Vercel and in .env.local, then redeploy.SUPABASE_DB_URL (GitHub secret) to the new project.The weekly check runs steps 3–6 against a stand-in project, so a green run means this exact procedure works on that week's data.
nimina-backups (private, no public
URL). Then create an API token with Object Read & Write limited to
that one bucket. Don't reuse the app's token: the app should never be
able to read the backups.db.<ref>.supabase.co host is IPv6-only,
and GitHub's runners can't reach it.SUPABASE_DB_URL (the session pooler string)R2_ACCOUNT_IDR2_BACKUP_ACCESS_KEY_IDR2_BACKUP_SECRET_ACCESS_KEYFree Supabase projects pause after 7 days without activity. A daily Vercel
Cron (vercel.json → /api/cron/keepalive) runs one real query. It needs
CRON_SECRET set in Vercel (any long random string); Vercel sends it
automatically, and the route refuses every other caller. The weekly backup
is a second, independent source of activity.