Join the Agent Deck Discord Server!
Check out the Agent Deck community on Discord – hang out with 357 other members and enjoy free voice and text chat.
Run your family, friends or office Secret Santa from one link. Giftr draws names around your rules, shares wishlists and keeps every match secret. Free, with no ads.
SocialTypeScript · CSSGitHub @djschnei21OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗A calm, mobile-first Secret Santa app. Invite people with one link, share wishlists, set the rules, and let Giftr draw names. Everyone finds out who they're shopping for, and nobody else does.
Production is giftr.christmas. Pushes to main deploy there. Every other branch gets a preview deployment.
Next.js 16 (App Router, Server Actions, src/proxy.ts), React 19, TypeScript, Tailwind CSS v4 and shadcn/ui, Better Auth (Google, Facebook, email sign-in links), Postgres with Drizzle ORM, Resend with React Email, and Vercel Cron. Tests use Vitest with fast-check (including property-based tests of the draw engine) and Playwright.
You need Node 22+, pnpm, and Docker (or any Postgres 16+).
pnpm install
docker compose up -d # Postgres with `giftr` and `giftr_test` databases
cp .env.example .env.local # then set BETTER_AUTH_SECRET: openssl rand -base64 32
pnpm db:migrate
pnpm db:seed # optional: demo users and an exchange
pnpm dev
Open http://localhost:3000. Without RESEND_API_KEY, emails aren't sent. Instead they appear at http://localhost:3000/dev/outbox, so you can sign in as anyone (seeded users are [email protected], [email protected], [email protected], [email protected] and [email protected]) by requesting a sign-in link and opening it from the outbox. Google and Facebook buttons appear once their credentials are set.
pnpm lint
pnpm typecheck
pnpm test # unit and property-based tests
pnpm build && pnpm test:e2e # end-to-end tests against the giftr_test database
The end-to-end suite walks four people through a whole exchange (create, invite by email and link, join, wishlists, a household and an exclusion, the draw, each reveal, and the anonymous chat), checks that the organizer can't see pairings and that Santas stay anonymous in the UI, the database and emails, and runs axe accessibility checks along the way.
WALKTHROUGH=1 pnpm test:e2e walkthrough records a desktop and a phone walkthrough to test-results/walkthrough/.
| Command | What it does |
|---|---|
pnpm db:generate | Create a migration after changing src/db/schema.ts |
pnpm db:migrate | Apply migrations (uses DATABASE_URL_UNPOOLED when set) |
pnpm db:studio | Browse the database with Drizzle Studio |
To run the daily job locally: curl -H "Authorization: Bearer $CRON_SECRET" http://localhost:3000/api/cron/daily.
Import the repo at vercel.com/new. vercel.ts sets the build command (pnpm db:migrate && pnpm build, so every deploy applies pending migrations) and the daily cron.
Add Neon from the Vercel Marketplace (Storage → Neon Postgres) and connect it to the project. It sets DATABASE_URL and DATABASE_URL_UNPOOLED. Turn on "Create a database branch for each preview deployment" so previews never touch production data.
Add Resend from the Marketplace (or create an API key at resend.com) and set RESEND_API_KEY. In Resend, verify the domain you'll send from, then set EMAIL_FROM, for example Giftr <[email protected]>. Until a domain is verified, Resend only delivers to your own address.
Set the remaining environment variables (Settings → Environment Variables):
| Variable | Environments | Value |
|---|---|---|
BETTER_AUTH_SECRET | All | openssl rand -base64 32 |
BETTER_AUTH_URL | Production only | https://giftr.christmas |
NEXT_PUBLIC_APP_URL | Production only | https://giftr.christmas |
CRON_SECRET | All | openssl rand -hex 32 (Vercel Cron sends it automatically) |
CONTACT_EMAIL | All | Shown on the privacy and terms pages |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | Production | See below |
FACEBOOK_CLIENT_ID, FACEBOOK_CLIENT_SECRET | Production | See below |
Leave BETTER_AUTH_URL and NEXT_PUBLIC_APP_URL unset for previews; they use their own deployment URL automatically.
Deploy from main. That branch is production. Then smoke test: open the site, sign in with an email link, create an exchange, and check that the invite email arrives. In the project's Cron Jobs tab you can trigger manually.
giftr.christmas is the production domain (www.giftr.christmas redirects to it). Use that host everywhere below.
https://giftr.christmas/privacy and https://giftr.christmas/terms. The email, profile and openid scopes are all Giftr needs. Publish the app when you're ready for anyone to sign in.https://giftr.christmas (and http://localhost:3000 for local testing)https://giftr.christmas/api/auth/callback/google (and http://localhost:3000/api/auth/callback/google)GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.https://giftr.christmas/api/auth/callback/facebook. Make sure the email permission is enabled.giftr.christmas, the privacy policy URL to https://giftr.christmas/privacy, the terms URL to https://giftr.christmas/terms, and the user data deletion instructions URL to https://giftr.christmas/privacy#delete.FACEBOOK_CLIENT_ID and FACEBOOK_CLIENT_SECRET, then switch the app to Live.Accounts are linked by email, so someone invited by email who later signs in with Google or Facebook lands in the same account.
Google and Facebook only redirect to registered URLs, so on preview deployments use email sign-in links. Previews need RESEND_API_KEY to send them; the dev outbox is disabled on every Vercel deployment because it would expose working sign-in links.
src/
app/ (marketing)/ (auth)/ (app)/ join/[code]/ unsubscribe/ api/ dev/outbox/
components/ app components; ui/ holds the shadcn primitives
db/ schema.ts, index.ts, seed.ts
emails/ React Email templates
lib/ auth, authz, draw/ (the draw engine), email/, link-preview, validation
server/ server-only queries and Server Actions
proxy.ts keeps signed-out visitors out of app pages
e2e/ Playwright tests
drizzle/ SQL migrations
vercel.ts build command and cron
/api/cron/daily