Easy-to-manage touch screens
무료 오픈소스 터치스크린으로 USB 설정 가이드, 드래그‑드롭 편집기, 로컬 제어를 제공하며 Home Assistant용으로 제작되었습니다
기억에 남도록 설계된 FinCards
FinCards — Designed to be remembered. Undangan digital yang terasa seperti film pendek. Rancang dulu sampai puas, bayar saat mau diterbitkan, sebar link-nya lewat WhatsApp.
라이프스타일TypeScript · JavaScriptGitHub @hafidz-A온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Multi-tenant SaaS undangan pernikahan digital. Beberapa template cinematic, banyak pasangan — tiap pasangan punya URL slug, akun pemilik, dashboard editor, dan database RSVP / Gift / Tamu sendiri. Model bisnis: self-serve, bayar sekali (couple daftar → pilih template → edit preview gratis → bayar via Midtrans untuk terbit).
fincards.land/ ← marketing
fincards.land/signup · /login ← akun pemilik (Supabase Auth)
fincards.land/onboarding ← pilih template + slug + data → buat draft
fincards.land/[template]/[slug] ← undangan publik (mis. /lovebirds/adi-rani)
fincards.land/[template]/[slug]/dashboard ← editor + data (khusus pemilik)
fincards.land/[template]/[slug]/checkin ← check-in QR/manual (buku tamu, Premium)
fincards.land/admin ← konsol operator (allowlist email)
| Layer | Tech |
|---|---|
| Framework | Next.js 14 (App Router) + React 18 + TypeScript |
| UI | CSS Modules + CSS variables (tanpa Tailwind/UI library) |
| Animasi | motion 12 + GSAP 3.15 + lenis; Solary + three.js |
| Backend | Supabase (Postgres + Storage + RLS) |
| Auth | Supabase Auth (email+password, verifikasi email, reset password, MFA TOTP opsional) |
| Payments | Midtrans (Snap redirect + notification webhook) |
| Resend | |
| Hosting | Vercel |
Arsitektur multi-template dijelaskan lengkap di tutorial-multi.md. Konteks arsitektur untuk sesi Claude: CLAUDE.md.
npm install
supabase/schema.sql (base), lalu semua file di
supabase/migrations/ berurutan sesuai tanggal. (Base saja tidak cukup — kolom seperti
owner_user_id, is_paid, gateway_* (payment), kolom *_enc, tabel guests/attendances/template_plans/
refund_requests semuanya datang dari migration.)invitation-media ada + public (dibuat oleh schema.sql).template_plans (atau lewat /admin → Templates → Plans).Sign up di resend.com → API Keys → Create. Opsional untuk dev: kalau
RESEND_API_KEY kosong, sendAdminEmail mengembalikan false tanpa melempar error — email tidak
terkirim, sisanya tetap jalan.
.env.localBuat file .env.local di root project. Tidak ada file contoh yang di-commit — sengaja, supaya
tidak ada berkas berbau env di repo sama sekali (.gitignore memblokir semua .env*). Daftar
lengkapnya ada di bawah:
# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://xxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
SUPABASE_SERVICE_ROLE_KEY=eyJ... # server-only
# App
NEXT_PUBLIC_SITE_URL=http://localhost:3000 # production: https://www.fincards.land
# Enkripsi data-at-rest (WAJIB — tanpa ini RSVP/gift/tamu tak bisa didekripsi)
APP_ENCRYPTION_KEY=... # 32-byte hex, untuk config PII + RSVP/gift
GUESTS_ENCRYPTION_KEY=... # 32-byte hex, untuk tabel guests + token RSVP
# Pembayaran (Midtrans)
MIDTRANS_SERVER_KEY=... # Dashboard → Settings → Access Keys
MIDTRANS_IS_PRODUCTION=false # 'true' = API production, selain itu sandbox
# Konsol admin — email yang boleh buka /admin (pisahkan koma)
[email protected]
# Email (Resend)
RESEND_API_KEY=re_...
[email protected]
Generate kunci hex cepat: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
npm run dev
Ini jalur utama — Anda tidak perlu melakukan apa-apa untuk onboarding biasa:
Untuk kasus khusus (giveaway, testing, bantu customer non-teknis), pakai salah satu:
node scripts/create-invitation.mjs budi-sari pass123aman `
--bride="Sari Wulandari" --groom="Budi Hartono" `
--date=2026-08-20T16:00 --venue="Hotel Grand Hyatt, Jakarta" `
[email protected] --plan=premium `
--template=lovebirds --full
Script ini membuat akun Supabase Auth (email + password) lalu insert invitation dengan
owner_user_id ke akun itu. Flag --full = seed 14 section penuh (Lovebirds); tanpa --full = 6
section starter./admin → Invitations → New (buat comp invitation dari konsol).Edit semua teks & foto (upload ke Supabase Storage), reorder section (drag-drop), atur palette/ornament/ musik/meta, kelola tamu (import CSV, kirim link WhatsApp), lihat RSVP/Gift + export CSV, buku tamu + QR check-in (Premium), reset password sendiri via /forgot-password, kelola akun & data di /profile.
PUT /api/invitation/<slug>/config:
401/403 = sesi login habis (login ulang); 409 = ada tab lain menyimpan (banner reload muncul); 500 =
cek log server / Vercel.invitation-media masih ada +
public, quota Storage belum penuh.invitations.email./refund; Anda putuskan di /admin → Payments
→ Refund requests (operator yang memutuskan, bukan otomatis). Takedown cepat: /admin set
suspended_at (sembunyikan halaman dari semua orang).-- Semua undangan
select slug, template_id, plan, is_paid, is_published, expires_at, created_at
from invitations order by created_at desc;
-- RSVP / gift / tamu per undangan (kolom PII terenkripsi di DB — angka agregat aman dilihat)
select i.slug,
count(distinct r.id) as rsvp, count(distinct g.id) as gifts, count(distinct gu.id) as guests
from invitations i
left join rsvps r on r.invitation_id = i.id
left join gift_confirmations g on g.invitation_id = i.id
left join guests gu on gu.invitation_id = i.id
group by i.slug order by rsvp desc;
Sebagian besar tugas monitoring/revenue kini ada di /admin (Invitations, Payments & revenue, Activity). Cek quota service di dashboard masing-masing (Supabase Usage, Resend, Vercel, Midtrans).
Harga tidak di-hardcode — tersimpan di tabel template_plans per template, diedit lewat /admin →
Templates → Plans. Plan: basic / premium; Premium membuka buku tamu (ledger kehadiran + QR
check-in). duration_days NULL = seumur hidup, N = aktif N hari lalu perlu diperpanjang.
wedding-saas-next/
├── src/
│ ├── app/
│ │ ├── page.tsx · layout.tsx ← marketing
│ │ ├── signup · login · verify-signup · forgot-password · reset-password
│ │ ├── onboarding · profile · terms · privacy · refund
│ │ ├── [template]/[slug]/ ← undangan publik + phone-frame
│ │ │ ├── page.tsx · InvitationView.tsx
│ │ │ ├── checkin/ ← QR / manual check-in
│ │ │ └── dashboard/ ← editor + tab RSVP/Gifts/Guests/BukuTamu/Tutorial + PaymentGate
│ │ ├── admin/ ← konsol operator
│ │ └── api/ ← rsvp, gift, guestbook, checkin, upload, auth/*, payment/midtrans/webhook, invitation/[slug]/{config,publish,meta,music,theme}
│ ├── all-templates/<id>/ ← lovebirds, solary (sections/config/Shell)
│ ├── config/ ← templateIndex.js, templateCatalog.js
│ ├── editor/ ← block editor (schemas, fields, EditorRoot)
│ ├── lib/ ← supabase, auth, crypto, guests, payments, admin, i18n, email, security …
│ └── components/ · hooks/ · styles/ · utils/
├── scripts/ ← create-invitation, seed-full-config, capture, diag-*, backfill/encrypt
└── supabase/ ← schema.sql (base) + migrations/ (30+ .sql)
.env.local, termasuk kunci enkripsi & Midtrans).NEXT_PUBLIC_SITE_URL ke URL production (penting untuk OG tag, link reset, dan redirect finish
Midtrans Snap).https://www.fincards.land/api/payment/midtrans/webhook.npm run typecheck # tsc --noEmit
npm run test # vitest (unit + integrasi)
npm run test:e2e # Playwright
npm run test:all # typecheck + unit + e2e
npm run check:tokens # guardrail design token
npm run verify:security # enkripsi PII at-rest + RLS anon = 0 baris
Kontrak cakupan: TEST-MATRIX.md · laporan: TEST-REPORT.md · bug produk nyata: BUG-LEDGER.md.