Website submission untuk Indonesia Web3 Hackathon (#WhereBuildersBuild). Full Next.js (frontend + backend), database Google Sheets.
- Landing page, Prizes, Schedule, FAQ, Projects gallery
- Submit project: nama tim/project, track (checklist), contract address (auto-link ke BscScan sesuai network), problem statement, solution, project detail (markdown + diagram mermaid, ada tab Write/Preview), GitHub repo, video demo (YouTube auto-embed), info tim + sosmed, link tambahan (docs, sosmed project, dll)
- Edit submission real-time pakai edit code + email (kode di-hash SHA-256, tidak pernah disimpan plaintext)
- Tanpa credentials Google, otomatis pakai file lokal
.data/submissions.json(enak buat development)
npm install
npm run devBuka http://localhost:3000. Tanpa setup apa pun, data tersimpan di .data/submissions.json.
- Buat Google Sheet baru di sheets.new. Salin ID dari URL:
https://docs.google.com/spreadsheets/d/INI_SHEET_ID/edit - Buat Service Account:
- Buka console.cloud.google.com, buat project baru (gratis)
- Menu APIs & Services > Library → cari Google Sheets API → Enable
- Menu APIs & Services > Credentials → Create Credentials > Service Account → beri nama, klik Done
- Klik service account yang baru dibuat → tab Keys → Add Key > Create new key > JSON → file JSON terunduh
- Share Sheet ke Service Account:
- Buka file JSON, salin nilai
client_email(bentuknyaxxx@yyy.iam.gserviceaccount.com) - Di Google Sheet, klik Share, paste email itu, kasih akses Editor
- Buka file JSON, salin nilai
- Isi environment variables (salin
.env.examplejadi.env.local):
GOOGLE_SHEET_ID=isi_sheet_id
GOOGLE_SERVICE_ACCOUNT_EMAIL=xxx@yyy.iam.gserviceaccount.com
GOOGLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMII...\n-----END PRIVATE KEY-----\n"GOOGLE_PRIVATE_KEY diambil dari field private_key di file JSON (biarkan \n apa adanya, bungkus dengan tanda kutip).
Header kolom dibuat otomatis saat submission pertama masuk (tab submissions).
Wajib diisi sebelum peserta masuk. Fallback file lokal
.data/submissions.jsonhanya untuk development. Filesystem Vercel read-only, jadi kalau deploy tanpa tiga env var di atas, setiapPOST /api/submissionsgagal dengan500dan tidak ada submission yang tersimpan.
npm run check:sheetsMenguji berurutan: env var lengkap → format private key → autentikasi → akses dokumen → izin tulis. Uji tulis dilakukan dengan membuat tab sementara lalu menghapusnya lagi. Itu penting: Sheet yang ter-share sebagai Viewer lolos semua tes baca dan baru gagal saat peserta pertama menekan submit.
Tiap kegagalan menyebut penyebab dan cara perbaikannya. Jalankan juga setelah mengisi env
var di Vercel — tarik dulu nilainya ke lokal dengan vercel env pull .env.local.
GET /api/submissions/export mengembalikan CSV berisi seluruh submission, siap dibuka
di Excel atau Google Sheets (sudah ber-BOM UTF-8, jadi huruf beraksen tidak rusak).
Ekspor ini memuat email kontak tim, jadi endpoint-nya berproteksi token. Set env var:
EXPORT_TOKEN= # bikin dengan: openssl rand -hex 32Tanpa EXPORT_TOKEN, endpoint mati (gagal tertutup, bukan terbuka).
# cara aman: token di header
curl -H "Authorization: Bearer $EXPORT_TOKEN" \
https://situsmu.vercel.app/api/submissions/export -o submissions.csv
# cara praktis: token di query, bisa langsung diklik di browser
# (hindari kalau bisa — token ikut tercatat di log akses dan riwayat browser)
https://situsmu.vercel.app/api/submissions/export?token=ISI_TOKENKolom: id, createdAt, updatedAt, projectName, tagline, teamName, tracks,
network, contractAddress, contractExplorerUrl, githubUrl, demoVideoUrl,
demoUrl, problemStatement, solution, description, teamSize, teamMembers,
extraLinks, email, logoUrl. Kolom editCodeHash sengaja tidak ikut diekspor.
npx vercelTambahkan 3 env vars di atas lewat Vercel Dashboard > Project > Settings > Environment Variables, lalu redeploy. Selesai.
app/
page.tsx Landing
submit/ Form submission + layar sukses (edit code)
projects/ Gallery + filter track + search
projects/[id]/ Detail (markdown, mermaid, YouTube embed)
projects/[id]/edit/ Verifikasi edit code lalu form edit
prizes|schedule|faq/ Halaman info
api/submissions/ REST API (GET, POST, PUT, verify)
components/ Navbar, form, markdown editor/renderer, dll
lib/ db (Sheets + fallback lokal), types, validasi
- Edit code hanya ditampilkan sekali setelah submit, disimpan sebagai hash
- Email kontak tim tidak pernah dikirim ke client di endpoint publik
- Semua input divalidasi dan disanitasi di server
apps/web — situs publik (Next.js 14, port 3000)
apps/backoffice — panel organizer (Next.js 14, port 3001, khusus role admin)
packages/db — skema Drizzle + query layer + migrasi (Turso/libsql)
packages/auth — SIWE + session iron-session + RBAC (dipakai kedua app)
db/seed.sql — seed edisi hackathon (idempotent)
Perintah dari root: pnpm dev · pnpm build · pnpm test · pnpm typecheck · pnpm check (biome).
- Produksi:
indonesia-web3-hackathon— hanya kredensial Vercel Production. - Dev:
iw3h-dev— dipakai lokal & preview (lihat.env.exampletiap app). - Ubah skema: edit
packages/db/src/schema.ts→pnpm --filter @iw3h/db generate→pnpm --filter @iw3h/db migrate(env menentukan DB target). Jangan ubah DB langsung lewat shell.
Login = connect wallet + tanda tangan SIWE (modal Reown). Session di cookie httpOnly;
role (participant/judge/admin) selalu dibaca dari tabel users per request.
Bootstrap admin pertama (sekali saja):
turso db shell iw3h-dev "UPDATE users SET role='admin' WHERE address='0xALAMAT_KAMU'"
(Sign-in dulu di app supaya row user-nya ada; ulangi di DB produksi saat deploy.)