Skip to content

kbrudnowski/WedApp

Repository files navigation

Wedapp — Wedding Guest Photo Uploader

Guests scan a QR code, type their name, and upload photos, videos, or voice messages. Files go straight to a Google Drive folder you own; metadata lands in Cloudflare D1. Runs entirely on Cloudflare's free tier.

Features

  • Upload page: photos (≤ 25 MB), videos (≤ 50 MB), voice notes (≤ 3 min), written messages.
  • Offline-resilient queue — blobs persist in IndexedDB across tab closes, browser restarts, and long disconnects; auto-resumes when the connection returns.
  • Shared gallery with infinite scroll, kind filters, 30-second live refresh, and a lightbox with download/share (Web Share API on mobile, <a download> fallback on desktop).
  • Admin page for hiding or deleting entries; deletion removes the file from Drive too.
  • Per-table QR codes (?table=7 auto-tags uploads).
  • Gallery thumbnails served by Google's CDN — zero Worker traffic per image load.

Cost

Everything fits in free tiers for a typical one-day event.

Free tier
Cloudflare Pages + Functions 100k req/day
Cloudflare D1 5 GB, 25M reads/day
Google Drive 15 GB

Configuration

Edit public/config.js before deploying:

export const WEDDING = {
  names:     { pl: "Anna i Jan", en: "Anna & Jan" },
  eventDate: { pl: "12.09.2026", en: "Sep 12, 2026" },
  lead:      { pl: "Podziel się zdjęciem…", en: "Drop in photos…" },
  themeColor: "#6d7c3d",
};

config.example.js has annotated placeholders to copy from.

Setup

1. Install

npm install

2. Google Cloud (one time)

  1. console.cloud.google.com → new project → enable Google Drive API.
  2. OAuth consent screen → External → scope: drive.filePublish app (stays in Production so tokens don't expire after 7 days).
  3. Credentials → Create OAuth client ID → Desktop app → download JSON as oauth-client.json (git-ignored).
  4. Create a Drive folder for uploads; copy its ID from the URL.

3. Get a refresh token

npm run auth

Browser opens, you approve, terminal prints the refresh token.

4. Cloudflare

npx wrangler login
npx wrangler d1 create wedding-photos   # paste the returned database_id into wrangler.toml
npm run db:init

Set secrets:

npx wrangler pages secret put GOOGLE_CLIENT_ID
npx wrangler pages secret put GOOGLE_CLIENT_SECRET
npx wrangler pages secret put GOOGLE_REFRESH_TOKEN
npx wrangler pages secret put DRIVE_FOLDER_ID
npx wrangler pages secret put ADMIN_TOKEN       # any random 32-char string

5. Run locally

npm run db:init:local
npm run dev

Open http://localhost:8788.

6. Deploy

npm run deploy

7. QR codes

node scripts/make-qr.mjs https://your-app.pages.dev         # one general QR
node scripts/make-qr.mjs https://your-app.pages.dev 1 10   # + one per table

Output lands in qr-output/ as PNG and SVG. Use SVG for print.

Admin

/admin.html?token=<ADMIN_TOKEN> — hide entries from the gallery or delete them (and the Drive file) permanently.

Notes

Drive files are granted anyone with link: reader so Google's CDN can serve gallery thumbnails. "Hide" removes an entry from the feed but does not revoke the Drive link — use Delete to fully remove content.

The admin token travels in the query string and will appear in browser history and server logs. The backend also accepts an x-admin-token header if you want to avoid that.

Tests

Playwright e2e suite covering upload, offline queue, gallery, lightbox, and download. No Cloudflare credentials needed — API calls are mocked.

npx playwright install chromium   # one-time
npm test
npm run test:ui                   # opens the UI runner

Specs live in tests/e2e/. Failing runs keep a trace at test-results/<name>/trace.zip.

License

MIT

About

Wedding guest photo/video/voice uploader — Cloudflare Pages + D1 + Google Drive, offline-resilient queue

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors