NEONVIL & Confidential Luxury Client
A Case Study: A Zero-Trust Media Time Capsule Unlocked by the Diamond Itself
Business Outcome
A live, production-deployed mobile SPA that turns a physical diamond into a private, credentialless media time capsule — photos, videos, and journal entries bound to the stone, unlocked by scanning the QR on its certificate.
Credentialless Access
The QR on the diamond is the only key — no accounts, no passwords, no email. The physical object is the login.
Private by Default
Every photo and video stays private. Access is granted only while the owner is actively using the capsule, and expires on its own — nothing lives behind a permanent link.
Safe by Every Release
Every release ships the app and its security guarantees together — there is no window where new features run against stale rules.
Context & Challenges
Every diamond the brand sells is physically unique, but once it leaves the boutique there's no digital tether between the stone and the owner's story. The client wanted a time capsule the buyer unlocks by scanning the diamond's QR code — turning a one-off purchase into an ongoing emotional artefact (photos, videos, journal entries bound to the stone), with no accounts, no passwords, and no permanent URLs.
Four critical engineering challenges:
01
Credentialless, shareable access tied to a physical object: 32-byte session token minted on scan, 1-hour Firestore TTL, scheduled pub/sub purge — client never touches Firestore or Storage directly.
02
Private media without public URLs: signed URLs regenerated server-side on every read, with cross-verified qrCode metadata on delete — no permanent download tokens to leak.
03
Multipart ingestion on serverless with no Express middleware: Busboy streaming parser with MIME whitelist, 50 MB/file cap, 10-file batch limit, bumped memory and timeout on the upload function only.
04
Workshop chain-scanning with stale state: URL-vs-store mismatch detection plus a hard remount forces vendor iframes (Kiradam v360) to re-initialise cleanly between stones.
Project Goals
Mobile SPA
A React 19 + Vite app with a native-camera QR scanner, in-app photo/video capture, lazy media gallery, fullscreen viewer, and a story journal.
Cloud Functions Backend
A Node 20 Gen 2 function set for product, media, story, and scheduled cleanup — with Busboy streaming uploads and signed-URL delivery.
Zero-Trust Infra
Deny-all Firestore and Storage rules, per-IP rate limiting, and a GitHub Actions pipeline that deploys code and rules atomically.
Our Solution
Three layers with distinct responsibilities. The mobile SPA owns camera, scanner, and capture. The Cloud Functions backend mediates every read and write, issues ephemeral sessions and signed URLs. The rules-and-pipeline layer makes the zero-trust posture the default state, not a deployment checklist.
Mobile SPA
Native-camera QR scanning via getUserMedia + jsQR frame parsing
Diamond certificate view with embedded Kiradam v360 video
In-app photo/video capture and file-picker upload with progress
Lazy media gallery with fullscreen viewer and story journal drawer
Cloud Functions Backend
Busboy multipart parsing with MIME whitelist and size enforcement
Session tokens minted on scan, verified on every write call
Signed-URL generation for every media read, metadata-verified deletes
Scheduled pub/sub cleanup of expired sessions and per-IP rate limiting
Zero-Trust Infra
Deny-all Firestore and Storage rules — 100% of traffic flows through functions
Service accounts and secrets managed through GitHub Actions
Atomic deploys of hosting, functions, and rules on merge to main
PR preview channels for safe UX iteration on live data contracts
Effort Allocation
Frontend UI/UX & Polish (30%)
Security & Hardening (20%)
Backend / Business Logic (20%)
Infrastructure & CI/CD (10%)
Integrations (10%)
Requirements & Spec (10%)
Infrastructure & Technologies
React 19 + Vite
Chosen for a mobile-first SPA with sub-second cold boot on 4G — Vite HMR kept iteration fast through many UX polish cycles, and React 19 handled the camera-driven scanner UI without blocking the main thread.
Zustand (persist)
Chosen for cross-route state that survives page reloads without Redux boilerplate, and to cleanly swap product on chain-scan without prop-drilling through the scanner, gallery, and journal views.
jsQR
Chosen to decode QR codes from live canvas frames in pure JavaScript — avoided a native-app dependency, one camera permission, works on iOS Safari and Android Chrome.
Firebase Cloud Functions Gen 2
Chosen for pay-per-invocation scaling with no servers to patch — the v2 API also fixed CORS issues the v1 onCall had in this setup, while giving us streaming request bodies for multipart uploads.
Busboy
Chosen as the only practical multipart parser for Cloud Functions Gen 2 streams — enabled per-file MIME validation and size enforcement before bytes ever reached Storage.
Firestore + Scheduled Pub/Sub
Chosen to hold short-lived session tokens with TTL semantics — a 60-minute cron function purges expired rows, replacing a Redis TTL cache with zero extra infrastructure.
Signed URLs (Admin SDK)
Chosen to deliver private-by-default media with time-boxed access — no permanent download tokens to leak, and revocation is implicit (just stop reissuing).
GitHub Actions + firebase-tools
Chosen so hosting, functions, Firestore rules, and Storage rules deploy atomically — preventing the classic "new code, old rules" security gap on every release.
