A bilingual SaaS platform for generating and managing digital wedding invitations. Clients pick from animated French and Arabic templates, personalise them through an admin dashboard, and share a private, self-expiring link with guests over WhatsApp — no login required on the guest side.
L'Élégance Digitale grew out of a simple gap: couples wanted a modern, animated wedding invitation to share on WhatsApp and Instagram, but existing options were either static PDFs or generic template sites with no personalisation or Arabic support. The platform lets an admin build a fully personalised invitation — photos, colours, couple names, venue, and wedding date — and hand the client a single private link that guests open with no account, no app, and no friction.
Ten animated templates are available across French and Arabic, with the Arabic layouts built RTL-first rather than mirrored after the fact — every component uses Tailwind's logical spacing utilities (ms-, me-, ps-, pe-) so text direction, alignment, and animation flow flip correctly with zero per-locale styling. next-intl handles the routing split between /fr and /ar and serves the translated copy for each.
The admin authenticates with JWT over bcrypt-hashed passwords, and the login endpoint always runs a dummy bcrypt comparison even when the email doesn't exist, so response time can't leak which accounts are real. Two roles, ADMIN and SUPERADMIN, are baked into the token payload at login and checked on every protected route — the role is never trusted from the request body, only from a verified signature.
Each invitation's variable fields — photo slots, programme, colour palette — live in a PostgreSQL JSONB column rather than a wide table of mostly-empty nullable columns, since every template needs a different shape of data. Earnings are computed on demand with a single SUM() query instead of a stored running total, which avoids the race condition of two simultaneous orders reading and overwriting the same counter.
Invitations aren't permanent by design. Each one carries an expiry date set at creation time (wedding date plus a configurable number of days), and a nightly cron job deletes expired rows and — checking first that no other invitation still references the same file — removes the now-unused images from Cloudinary. Uploaded photos never touch the server's disk: multer holds them in memory just long enough to stream straight to Cloudinary, which also handles CDN delivery and WebP conversion so guests anywhere get a fast-loading page.
The frontend and backend are deliberately separate: a Next.js 14 App Router site on Vercel talks to a standalone Express API on Railway over a pooled Postgres connection. Server components verify the admin's session cookie before rendering the dashboard shell, so an invalid token never gets a byte of protected HTML — and the same Express API is ready to serve a future mobile client without any changes.
Next.js 14, TypeScript, Tailwind CSS, next-intl — Node.js, Express, raw pg, Zod, JWT, bcryptjs — PostgreSQL (Neon), Cloudinary — Vercel, Railway