For a limited time, use our exclusive coupon code KWINGSMEDIA at checkout and enjoy a special 10% discount on all of our products and services across the entire Kwings Media store
Kwings Media Logo
KWINGS MEDIA
Back to Projects
Events & Weddings

Kwings Guest Book

A multi-tenant platform that runs a wedding’s entire guest side from one place: the couple builds their invitation page in an admin portal, sends every household its own private link, and sees invitation by invitation who opened it, how far they read and who is actually coming. Each wedding is its own tenant with its own owner, content, guest list and links, served from a shared public site.

Visit the live site
Loading live preview…

Live preview of guestbook.kwingsmedia.com

Overview

Three surfaces sit on one API: a server-rendered public invitation site, an admin portal where the couple builds the wedding and reads the analytics, and an Express + Knex API that is the only thing touching the database or object store.

Every invitation page is rendered per request, so a link can be revoked, an RSVP can appear instantly and a content edit can go live without a rebuild. There are two kinds of link — a personal one that names the household and pre-attributes its RSVP, and an open one that anyone can share, where the visitor names themselves and a guest row is created from the reply. Both are independently revocable, and un-revoking restores the same URL rather than minting a new one.

The page itself opens on an envelope gate and then hands off to a motion system: split-character headlines, directional reveals, clip-path curtain wipes over photography and scroll-scrubbed parallax — all of which switches off under prefers-reduced-motion.

What it does

Personal and open invitation links

A personal link names the household, carries its seat allowance and pre-attributes the RSVP; an open link is shareable anywhere and creates a guest row from whoever replies. Each has its own off switch that routes visitors to an expired page while leaving the guest row and RSVP history intact.

The invitation page

An envelope gate, hero, live countdown, love story, gallery, venue and schedule details, optional background music and the RSVP form — animated with anime.js and Lenis smooth scroll, and rendered in its resting state for visitors who prefer reduced motion.

Guest list and QR codes

The portal manages households, generates their links and QR codes, and tracks seat allowances and replies across the whole list.

A local wedding planner

A Sri Lankan wedding plan template — nekath, poruwa decorator, bridal dresser, hewisi drummers — phased from twelve months out to the week of and ordered by what actually blocks what. Every task and budget line is editable.

A demo that works before anything exists

A sample invitation renders from the site’s built-in content with no wedding of its own — which is exactly when a couple most needs to see what they are buying.

Engineering highlights

Content as one structured document

Everything beyond the couple, date and venue columns lives in a single jsonb document that the portal edits as a whole and the public site merges over built-in defaults — so a new wedding inherits a complete page and overrides only what it cares to, with no table per content type.

Engagement, not just opens

An open count proves the page was fetched, not that anyone reached the RSVP. The page reports scroll depth and labelled button presses as events, and the deepest point any visit reached is denormalised onto the guest row — so the couple sees “read to 90%, never pressed RSVP” without aggregating the event log on every load. Depth only counts once the envelope gate is dismissed, since the gate locks scroll.

Passwordless sign-in done carefully

Login codes and password resets share one table that stores only a bcrypt hash of the six-digit code, caps guessing attempts and marks a code consumed so it is single-use rather than valid until expiry. The API boots fine without SMTP configured — only those two endpoints answer 503.

Fail-fast configuration

Compose refuses to start without the database password, JWT secret and object-store keys rather than booting a half-configured API, and CORS is locked to the portal origin instead of reflecting whatever asks.

Three services behind one proxy

The public site, portal and API run as containers bound to loopback only, with the host nginx terminating TLS on three subdomains — so even the public tracking and RSVP endpoints sit behind the same proxy as everything else.