Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

158 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Monete app icon

Monete

Account-free RSVP for kids' birthday parties — host creates a party with standard or custom questions; each family RSVPs once listing one or more children; the host gets a live headcount and a venue-ready summary.

Latest release CI Last commit Conventional Commits License: MIT

What you can do

  • Create a party in seconds — no signup, no email.
  • Share a guest link via WhatsApp or any channel. Each family RSVPs once and can list multiple children.
  • Standard one-click questions: adult count, allergies, date of birth, preferred snack.
  • Custom questions per family or per child — choice (dropdown), free text, number, or date.
  • Watch RSVPs arrive live; the headcount updates in real time.
  • Export a venue-ready summary (WhatsApp-formatted) with every family's answers.
  • Hybrid add-to-calendar: .ics file on iOS and desktop, Google Calendar link on Android.
  • Six languages: Spanish, English, Galician, Basque, Catalan, Valencian.
  • Install it as a PWA on any device.

Security model

  • No direct table access — anonymous clients cannot read, list, insert, or update the parties table directly. Row-Level Security denies all direct access; every operation goes through SECURITY DEFINER RPCs. There is no bulk read: a party can only be fetched by its exact id (get_party), so the anon key cannot enumerate or dump other families' data.
  • Server-side edit PIN — when a party has an edit PIN, config edits and PIN changes are verified server-side (the PIN hash is computed in Postgres and never shipped to clients). A party without a PIN stays editable by anyone holding its link — that is by design, to keep the no-signup flow; treat the host link as the capability and keep it private.
  • Bounded writes — RSVP submissions are capped (per-RSVP size, RSVP count, and total blob size) to prevent storage/egress abuse. RSVP appends are atomic, so concurrent families never clobber each other.

Privacy

  • No cookies, no tracking, no ads — so no consent banner. An in-app privacy notice (Footer → Privacy) states what's stored and links the erasure path.
  • Erasure — the host can hard-delete a party (and all family data) any time via "Delete party" (delete_party RPC, PIN-gated). This is the data-subject erasure mechanism.
  • Retention — a daily pg_cron job (monete-retention) deletes parties 90 days after the event date.
  • Personal data lives only in parties.data (child names, optional DOB + allergies, parent label); the table is COMMENT-tagged as holding special-category (health) data of minors.

Accepted limitations (by the no-signup design)

  • A PIN-less party is fully open to link-holders. Anyone with the link can edit it, and can set the first PIN themselves — so the no-signup model can't stop a malicious link-holder from locking a host out of a party the host left PIN-less. Set a PIN if that matters.
  • Online PIN guessing is not rate-limited. The 4–6 digit PIN is verified server-side and the hash never ships, so offline cracking is gone — but a link-holder can still try PINs against the API without a lockout. The PIN raises the bar for a link-holder; it is not a strong secret. Keep the host link private regardless.

For developers

Open-source, MIT licensed. PRs welcome.

Stack — React 19, Vite, TypeScript (strict), Tailwind CSS 4, Supabase (Postgres + Realtime), vite-plugin-pwa, i18next, Vitest.

Architecture — Hexagonal (domain → application → infrastructure → presentation). DI via a hand-rolled container. Tests use in-memory fakes — no DB mocks.

Local dev

git clone git@github.com:Endika/Monete.git
cd Monete
cp .env.example .env.local   # fill VITE_SUPABASE_URL + VITE_SUPABASE_ANON_KEY
npm install
npm run dev

Database

Apply the migration once to your Supabase project:

supabase db push

Or paste the files in supabase/migrations/ (in order) directly into the Supabase SQL editor. 0004_harden_access.sql closes direct table access and routes everything through RPCs — apply it on top of the earlier migrations.

Commands

Command Description
npm run dev Start the dev server
npm run build Production build (tsc -b && vite build)
npm run test:run Run tests once
npm run lint ESLint (zero warnings)
npm run type:check TypeScript type check

CI runs lint, typecheck, tests, and the production build on every PR.

Environment variables

Copy .env.example to .env.local and fill in your Supabase project values:

Variable Description
VITE_SUPABASE_URL Your Supabase project URL
VITE_SUPABASE_ANON_KEY Your Supabase anon (public) key
VITE_GOOGLE_MAPS_KEY Google Maps/Places key (optional, address + map)

Restrict the Google Maps key. VITE_GOOGLE_MAPS_KEY ships in the client bundle by design, so it cannot be kept secret. Lock it down in the Google Cloud Console or anyone can run up your bill: set an HTTP-referrer restriction to your production domain, an API allowlist (Maps Embed + Places API only), and a billing budget + alert. This control lives in GCP — the code cannot enforce it.

About

Account-free RSVP for kids' birthday parties: standard/custom questions, per-child answers, live headcount and a venue-ready guest list. PWA.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages