IKHSAN
ENID Baca dalam Bahasa Indonesia

snapme

Public
Branch
master
Latest commit
130fdb828 October 2026

CHANGELOG.md

Open raw
Changelog

snapme is built in the milestone order of MILESTONES.md, one milestone per commit. Entries below follow the milestone, not a tag: 0.1.0 is the first released state and contains the whole of M0 to M10. The reasoning, measurements, and failed attempts behind each entry are in docs/DECISIONS.md.

Unreleased

Housekeeping after 0.1.0: the repository was audited for dead weight and reorganised, and snapme now carries its own mark. Nothing else in the flow changed.

Added

  • snapme's own mark, and the wordmark, favicon, and app icon built from it. The mark is a paper tile holding a fan of four photo prints; the favicon uses a single print, because four of them collapse into a colour patch at 16 px. public/brand/snapme-mark.svg is the source, src/app/icon.svg the small-size variant, and npm run brand:icons derives src/app/apple-icon.png and src/app/favicon.ico (16, 32, and 48 px) from both. The 15 KB create-next-app favicon, whose three frames were uncompressed bitmaps, is replaced by a 4.6 KB one with PNG payloads
  • sharp as a dev dependency: the only renderer scripts/render-brand-icons.mjs needs

Changed

  • Server-only modules moved from src/lib to src/server (the binding seam, db/, r2/, purge, rateLimit, tokens, expiry), so the client-boundary rule is a path, not a hand-kept list
  • tests/ now mirrors src/ (tests/app/api, tests/components, tests/features, tests/lib, tests/server, tests/security, tests/stores), with the miniflare harness and the route helpers in tests/support
  • Client network calls share one module, src/lib/http.ts (messageFrom, putToSignedUrl)
  • src/features/gallery/muatFotoGaleri.ts is loadGalleryPhotos.ts; the exported names follow it
  • Every module in src/components/ui imports cn from @/lib/utils, matching what shadcn add generates
  • The repository root now holds only the entry points and the tool configs: the four working documents (PRD, design system, architecture, milestones) moved to docs/ next to the decision log, r2-cors.json moved to infra/, and the Playwright specs moved from e2e/ to tests/e2e/ so there is one test root
  • tsconfig.tsbuildinfo is written into .next/cache/, so no TypeScript artifact lands in the repository root
  • Product components moved out of src/components/booth into the features that own them: the booth shell to src/features/booth, the camera picker to features/camera, the capture stage, shot tray, countdown and shutter to features/capture, the gesture HUD and toggle to features/gesture, the relay invite card to features/relay. src/components now holds only ui/ (the shadcn/ui primitives) and site/ (header and wordmark)
  • The result screen moved out of the editor: ResultView, the strip export, and the 4R print sheet now live in src/features/result, so src/features/editor is only the decorating step
  • GalleryPicker moved from src/components/site to src/features/gallery, next to the loader it uses; component tests followed their components into tests/features/<area>
  • The placement rule is written down in ARCHITECTURE.md §4 and in the repository conventions in .github/CONTRIBUTING.md, so the next milestone does not have to rediscover it
  • DESIGN-SYSTEM.md §8 now documents the mark, its files, and the rule that the raster icons are derived rather than drawn twice; §10.1 shows the mark in the top bar, and ARCHITECTURE.md §4 lists public/brand/ and the three icon files under src/app/
  • brag-output*/** is ignored by eslint.config.mjs and by git: a /brag run writes a Hyperframes composition (with a vendored gsap.min.js that fails the project's lint rules, exactly like the MediaPipe wasm) plus a rendered video, and neither belongs to npm run lint or to the repository

Removed

  • CreateStripPayload and CreateRelayPayload in src/lib/schemas.ts: type aliases nothing imported, while the routes take their types from the Zod schemas directly
  • The export keyword on 26 symbols that only their own module uses (StripLayout, CropRect, GESTURE_ACTIONS, BoothSettings, and the like), so the module surface matches what is really shared. src/components/ui keeps the exports the shadcn CLI writes, so shadcn add stays comparable with upstream
  • --color-pink-700: defined and documented but never used in any component. The palette and the contrast table in DESIGN-SYSTEM.md §2 no longer list it
  • Duplicated helpers: two copies of the canvas checksum (three, counting customize.spec.ts), the four-slot fill, the camera permission step in tests/e2e/gesture.spec.ts, and the request, rate-session, route-context, and bucket-clearing helpers in the route tests. The two bucket copies had already drifted: only one paginated

Backend dibongkar: snapme jadi client-only (18 Oktober 2026)

Keputusan pengguna: cabut seluruh backend Cloudflare (Workers/OpenNext, D1, KV, R2, wrangler) dari proyek ini. snapme kini aplikasi klien murni — booth kamera berjalan penuh secara lokal, tanpa unggahan ke mana pun dan tanpa env yang dibutuhkan build.

Removed

  • Seluruh sisi server: src/server/ (cloudflare.ts, db/, r2/, rateLimit.ts, expiry.ts, purge.ts, tokens.ts), src/app/api/cron/, worker.ts, open-next.config.ts, wrangler.jsonc, playwright.cf.config.ts, infra/, migrations/, scripts/cf-typegen.mjs, scripts/patch-opennext.mjs
  • Komponen dan modul yang hanya berguna di atas backend: RelayJoinView, RelayCompleteView, RelayCancel, relay/bootstrap.ts, StripOwnerActions, LiveStripVideo
  • Uji dan penopangnya: tests/support/, tests/app/api/, tests/server/, jalur e2e ber-binding (CLOUDFLARE_E2E) beserta helper pasangSidangBaru/undangEstafet
  • Dependensi @opennextjs/cloudflare, aws4fetch, wrangler, lighthouse; skrip npm cf:patch, preview, preview:e2e, deploy, cf-typegen, test:e2e:cf, perf:lcp
  • Berkas env .env.example dan .dev.vars.example, termasuk salinan lokalnya (.env.local, .dev.vars yang berisi kredensial R2) dari mesin pengembangan

Changed

  • Sembilan rute /api (strips, strips/[id], strips/[id]/complete, relays, relays/[id], relays/[id]/claim, relays/[id]/complete, relays/[id]/strip, events) menjadi stub yang menjawab 503 dengan pesan "belum tersedia" yang tetap, supaya klien menampilkan pesan itu, bukan galat jaringan atau 404
  • /s/[id] dan /r/[id] menjadi stub notFound() (selalu 404) dengan metadata noindex; header noindex dan no-referrer untuk /s/* dan /r/* tetap dipasang next.config.ts
  • CSP di next.config.ts tanpa satu pun host luar; postinstall kini hanya copy-mediapipe-wasm.mjs; src/lib/schemas.ts dipangkas ke ekspor yang masih dipakai klien
  • Dokumen kondisi-kini (README, ARCHITECTURE, PRD, CONTRIBUTING, SECURITY) ditulis ulang untuk kondisi client-only

Konsekuensi

  • Alur booth tidak berubah: welcome, layout, capture, gesture MediaPipe, customize, hasil, ekspor PNG/cetak, perekaman lokal Strip Hidup, dan sesi IndexedDB tetap berjalan seperti sebelumnya
  • Fitur bagikan/estafet tetap utuh di UI (dialog persetujuan, kartu bagikan, QR lokal) dan kini selalu menerima pesan "belum tersedia"; tidak ada gambar yang meninggalkan perangkat
  • Antrean analitik klien tetap ada dan diam-diam membuang batchnya selama rute peristiwa menjawab 503

0.1.0 - 2026-10-16

First release. The full v1 scope of PRD.md §5, deployed on Cloudflare Workers.

Added

M0 Fondasi (1988139)

  • Next.js App Router project with TypeScript, Tailwind v4, and shadcn/ui components restyled through the design tokens
  • Design tokens as the single source of color, radius, shadow, and font, plus the component gallery at /dev/ui
  • Vitest, Playwright, ESLint, and the wrangler toolchain wired into npm scripts

M1 Welcome dan kerangka booth (7a0872e)

  • Welcome page with one primary action, and the three feature panels where the Gesture Snap panel is the widest
  • Booth shell: stepper, three-column layout down to one column, and the main action pinned to the bottom on narrow screens
  • Layout picker for Strip 4, Strip 3, and Grid 2x2

M2 Kamera (880bc00)

  • Camera permission screen shown before the browser dialog, with the gallery picker as the fallback when permission is refused
  • Mirrored preview with a crop guide that matches the chosen layout, so the photo is stored as it looks on screen
  • Countdown capture from the shutter button or Space, single flash, shot tray with per-slot retakes, and camera selection when a device has more than one

M3 Gesture Snap (89a5aea, 40dc887)

  • Self-hosted MediaPipe wasm and gesture model, loaded only after camera permission and never on the Welcome route
  • Hold detection as pure functions with thresholds in one file, the capture state machine reduced from events, and the on-screen indicator with "Terdeteksi. Tahan..."
  • Gesture switch that is remembered on the device, Open_Palm to retake the last photo, and Thumb_Up to move on once every slot is filled
  • A network assertion that no request carrying image data leaves the capture step

M4 Hias strip (40dc887)

  • Konva strip canvas with 6 frames, 7 effects, and 12 stickers that can be dragged, rotated, scaled, and deleted
  • Short text line and date, keyboard controls for every decor item, and a list equivalent for screen readers so the canvas is not the only way to reach them

M5 Hasil dan cetak (771ea64)

  • PNG export at 600 x 1800 (2 x 6 inches at 300 dpi) without metadata, named snapme-YYYYMMDD-HHmm.png
  • 4R print sheet with two strips side by side and a cut line
  • Session persistence in IndexedDB, restored after a reload, with "Mulai dari awal" to clear it
  • Gallery picker for JPEG, PNG, WebP, and HEIC where the browser supports it

M6 Link strip dan QR (b4372be)

  • Consent dialog before the first upload, naming what is uploaded, who can see it, and when it is deleted
  • Direct browser upload to a private R2 bucket through presigned URLs, verified server side with bucket.head
  • Strip page at /s/{id}, noindex and no-referrer, with a delete token kept on the device
  • QR placed in the strip footer at 168 px, so it survives a 300 dpi print

M7 Strip Hidup (099d70a)

  • Ten 480 px frames captured during the last 1.5 seconds of each countdown, without delaying the still photo
  • Live preview that stops under prefers-reduced-motion and offers a play button
  • Clip export as WebM or MP4 following what the browser supports, with the button hidden when recording is unavailable

M8 Strip Estafet (292ca73)

  • Relay link at /r/{id} for two people on two devices: the creator fills the odd slots, the friend fills the rest, and the friend's preview carries a 35% shadow overlay of the creator's photos
  • Single claim enforced by a conditional database update, so a second visitor is told the relay is taken
  • Relay links expire in 48 hours and strips in 7 days; the creator can cancel and delete
  • After completion both sides get the strip page, and the creator sees "Menunggu teman" then "Selesai"

Changed

M9 Pengerasan (ee4ae8e)

  • Full CSP, Permissions-Policy, X-Content-Type-Options, and no-referrer rules on private pages
  • Rate limits: exact strip and relay quotas counted in the database, and an hourly analytics budget in KV
  • Analytics through a first-party endpoint, without cookies and without an identity column
  • Accessibility pass: axe on every page, keyboard-only completion of the whole flow, aria-live countdown, and status text beside every color-coded state
  • Cross-browser test projects for WebKit and Gecko

M10 Migrasi Cloudflare (1a2d64a)

  • Backend moved from the previous hosted stack to Cloudflare Workers with the OpenNext adapter, so the whole app, the API routes, and the daily purge job run as one Worker
  • Data in D1, files in a private R2 bucket, the analytics budget in KV, and scheduled cleanup through a Cron Trigger
  • Route tests run against real D1, R2, and KV bindings through wrangler getPlatformProxy
  • Welcome LCP measured in production at a 2.416 s median against the 2.5 s budget

Not in this release

Out of v1 scope on purpose, per PRD.md §5: accounts and a personal gallery, payment and print ordering, AI face filters or generated images, real-time shared booths, relays of more than two people, native apps and locked kiosk mode, and a template CMS.

bytes
12,696
lines
226
Type
md
Latest commit
28 October 2026