A private, self-hosted workspace for planning the people, places, and memories around your wedding.
Manage invitations and replies, arrange tables visually, assign seats, and share a private photo gallery-all from one elegant application.
Vowloom started as a quick idea for a simple wedding guest list. As new needs arose and more ideas came to me, it grew organically into a broader planning workspace for invitations, seating, custom floorplans, and sharing memories with guests. It was not originally intended to be a public project, but as it grew, making it public and easy for others to self-deploy felt like a natural next step.
Plan the seating - arrange tables and assign guests from one focused workspace.
Draw your venue - shape the outline, add walls, doors, labels, and a reference image on an infinite workspace.
Start your way - draw the real room or begin with a rectangle. |
A welcoming empty gallery - guests know their link works before the first upload. |
- Edit an existing guest's name directly from the guest list, with accessible save and cancel controls in all supported languages.
- Find guests faster with live search, RSVP filters, status counts, and a more readable responsive guest ledger.
- Move between focused guest-assignment and table-layout modes in the redesigned seating workspace, with clearer progress and table controls.
- Work with long unassigned lists without stretching the floorplan, and print refined seating charts and paginated place cards.
- Manage photos through a redesigned gallery studio with upload progress, overview metrics, on-demand previews, and clearer processing states.
- Create and review private gallery links through a refreshed access dashboard with clearer expiry controls and localized action feedback.
- Download gallery originals using their human-readable photo titles while retaining the correct file extension.
See the complete release history in the changelog.
- Tracks guests, invitation delivery, replies, and party sizes.
- Shows live totals for accepted, tentative, pending, and declined guests.
- Draws custom venue floorplans with editable outlines, walls, doors, and labels.
- Provides a zoomable seating plan with movable tables and drag-and-drop assignment.
- Produces printable guest lists and place cards.
- Hosts private wedding galleries backed by Cloudflare R2.
- Creates revocable guest gallery links with language and usage controls.
- Supports Italian, English, and Romanian.
- Keeps application data in a portable SQLite database.
Vowloom requires Node.js 20 or newer.
git clone https://github.com/dev-reedus/vowloom.git
cd vowloom
npm installcp .env.example .env
chmod 600 .envAt minimum, set distinct passwords and a long random token secret in .env:
COUPLE_PASSWORD=choose-a-strong-couple-password
ADMIN_PASSWORD=choose-a-different-admin-password
TOKEN_SECRET=replace-with-a-long-random-secret
WEDDING_COUPLE_NAMES=Alex & Sam
WEDDING_YEAR=2030
DEFAULT_LANGUAGE=enBuild the frontend and start the Express server:
npm run build
npm startThe server listens on port 80 by default. For frontend development with Vite
hot reload, run this in a second terminal:
npm run devVite proxies /api requests to the Express server.
Note
Local HTTP development requires ALLOW_INSECURE_AUTH=1. Never enable it on a
public deployment; production sessions require HTTPS.
The complete, commented configuration is in .env.example.
These are the main settings:
| Variable | Purpose |
|---|---|
WEDDING_COUPLE_NAMES |
Couple name displayed throughout the interface |
WEDDING_YEAR |
Optional four-digit year shown in the footer |
DEFAULT_LANGUAGE |
Initial language: it, en, or ro |
COUPLE_PASSWORD |
Password for day-to-day planning access |
ADMIN_PASSWORD |
Separate password for administrative access |
TOKEN_SECRET |
Protects guest tokens at rest |
SESSION_SECRET |
Optional separate secret for password-bound sessions |
R2_* |
Cloudflare R2 credentials and bucket configuration |
HOST_PORT |
Host port used by the deployment script |
APP_NAME |
Docker container/image name |
DATA_VOLUME |
Docker named volume or absolute host directory mounted at /app/data |
SEED_EXAMPLE_TABLES |
Set to 1 to add six demo tables to a new database |
.env, SQLite databases, and local guest lists are ignored by Git. The Docker
image does not contain your .env file.
To prefill a new database, create lista.txt next to package.json, with one
guest or party per line:
Olivia Bennett | yes | yes
Ethan Carter | yes |
Sofia Marin
Alice / James Turner | yes | yes
The optional columns are Name | invitation sent | accepted. Values such as
1, x, yes, si, sì, and true are treated as true. A / in a name
creates a party of two by default. Seeding only runs when the guest table is
empty, so restarts never overwrite changes made in the app.
The submitted password selects one of two roles:
| Role | Access |
|---|---|
couple |
Guests, tables, uploads, gallery preview and deletion, derivative generation, and existing guest links |
admin |
Everything above, plus guest-link management, gallery budget and metadata, R2 import, and database backup |
Sessions are stored server-side. Only a SHA-256 hash of each random session ID
is written to SQLite, while the browser receives the ID in an HttpOnly cookie.
Sessions expire after 30 days of inactivity or 180 days in total. Changing a
role password invalidates that role's sessions after restart.
The public surface is limited to the SPA shell, /healthz, and allowlisted
display configuration. App APIs require a valid session; gallery APIs require a
guest capability token.
Browser
│
▼
React + Vite ──build──▶ Express
├──▶ SQLite
└──▶ Cloudflare R2 (optional)
The production Express server serves the compiled React app and API from the same origin. SQLite holds planning data, sessions, gallery metadata, and guest links; large gallery objects can live in R2.
Back up the SQLite database, pull the new version, and run ./deploy.sh. Database
migrations run automatically at startup; no new environment variables are
required.
- Existing guests, floorplans, tables, gallery photos, and guest links are left unchanged.
- No manual migration or gallery re-import is needed.
The included script builds the image, creates or reuses the data volume, and restarts the container:
./deploy.shInline values override non-empty values loaded from .env:
HOST_PORT=8091 ./deploy.shTo build and run manually:
docker build -t vowloom .
docker run -d \
--name vowloom \
--restart unless-stopped \
-p 8091:80 \
-v vowloom-data:/app/data \
-e WEDDING_COUPLE_NAMES='Alex & Sam' \
-e WEDDING_YEAR='2030' \
-e COUPLE_PASSWORD='couple-password' \
-e ADMIN_PASSWORD='admin-password' \
-e TOKEN_SECRET='long-random-secret' \
vowloomThe container publishes plain HTTP. Place it behind an HTTPS reverse proxy in
production so secure session cookies work correctly. /healthz remains public
for health checks. DATA_VOLUME defaults to a Docker named volume; set it to an
absolute host directory if you prefer a bind mount and direct access to the
SQLite files.
Admins can download a consistent SQLite snapshot through Save backup or
GET /api/backup.
To restore one, replace the database inside the running container, remove stale write-ahead log files, and restart:
docker cp vowloom-backup-YYYY-MM-DD.db vowloom:/app/data/vowloom.db
docker exec vowloom sh -c 'rm -f /app/data/vowloom.db-wal /app/data/vowloom.db-shm'
docker restart vowloomThe Docker volume survives container replacement, but it is not a substitute for an off-device backup.
| Area | Endpoints |
|---|---|
| Authentication | POST /api/login, POST /api/logout, GET /api/me |
| Public configuration | GET /api/config |
| Guests | GET|POST /api/guests, PATCH|DELETE /api/guests/:id |
| Tables | GET|POST /api/tables, PATCH|DELETE /api/tables/:id |
| Floor plan | GET|PUT /api/floorplan, GET|POST|DELETE /api/floorplan/background |
| Backup | GET /api/backup (admin only) |
| Gallery admin | /api/admin/gallery/* |
| Guest gallery | /api/gallery* (capability token required) |
Run the complete verification suite before committing changes:
npm test
npm run buildbetter-sqlite3 is a native dependency. The Docker image uses Node.js 20, so
use a compatible Node version when developing outside Docker.
Vowloom is available under the MIT License.


