尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗Vánoční losování dárků. Každý si na jedné adrese klikne na své jméno, jednou zalosuje a dozví se jednoho člověka, kterého obdaruje — a nic víc. Dárek musí začínat na stejné písmeno jako jméno obdarovaného.
Stack: Next.js 16 (App Router) · React 19 · TypeScript · Tailwind v4 · Drizzle ORM + Postgres (Supabase) · Vercel
/admin seznam lidí — jméno i příjmení, protože
v losu se zobrazí přesně to, co zadá.
Pár nebo domácnost napíše na jeden řádek a jména oddělí „+“
(Jan Novák + Jana Nováková) — navzájem se nevylosují.Název události, datum a cena dárku jsou pohromadě v konstantách v
lib/game/countdown.ts — na další rok se mění
jen tam.
Kdo chce, může místo toho použít osobní odkaz („Jan Novák“ → /jannovak).
Je odvozený ze jména, takže ho administrace nevypisuje — kdo ho potřebuje,
složí si ho sám (seznam i s odkazy ukáže npm run stav). Na přesný tvar si vzpomínat nemusí —
/Jan-Novák, /JanNovak i /jan_novak skončí přesměrováním na /jannovak.
Odkaz zůstává platný, takže se k losu dá vrátit kdykoli a odkudkoli.
Každý daruje i dostane právě jednou, nikdo nedaruje sám sobě ani partnerovi či nikomu z vlastní domácnosti a losování nikdy neuvázne — ani když všichni zmáčknou Losovat! ve stejný okamžik. Losuje se v transakci pod advisory lockem, takže dva lidé nemohou dostat téhož obdarovaného, a kdyby logika selhala, odmítne to databáze.
Nikdo se nedozví, z kolika lidí losoval ani jak dopadli ostatní — páry se nezobrazují ani v administraci. Animace je pro všechny stejně dlouhá, i pro posledního, kterému už zbývá jediná možnost.
Přeověřit to jde kdykoli: npm run kontrola -- --force. Podrobnosti a pravidla
pro úpravy jsou v AGENTS.md.
| Příkaz | Co dělá |
|---|---|
npm run dev | vývojový server na http://localhost:3000 |
npm run build / npm start | produkční build / jeho spuštění |
npm test | testy losovací logiky (Vitest) |
npm run typecheck / npm run lint | tsc --noEmit / ESLint |
npm run db:push | vytvoří tabulky podle lib/db/schema.ts |
npm run seed | naplní testovací jména (scripts/seed.ts) |
npm run stav | vypíše jména, odkazy a kolik lidí už losovalo |
npm run kontrola -- --force | prověří koncovku a souběh proti databázi (destruktivní) |
# 1. Databáze — buď Supabase, nebo Postgres v Dockeru:
docker run -d --name pipi-tree-pg \
-e POSTGRES_PASSWORD=pipi -e POSTGRES_DB=pipitree \
-p 55432:5432 postgres:16-alpine
# 2. Konfigurace — doplň DATABASE_URL a ADMIN_PASSWORD
cp .env.local.example .env.local
# 3. Tabulky, testovací data, start
npm install
npm run db:push
npm run seed
npm run dev
Administrace je na http://localhost:3000/admin (uživatel libovolný, heslo
ADMIN_PASSWORD). Až databázi nebudeš potřebovat: docker rm -f pipi-tree-pg.
Všechno v Postgresu, v prohlížeči nic — žádné localStorage ani cookies. Los tak nezmizí smazáním dat prohlížeče; kdo má odkaz, dostane ho ze serveru.
participants — seznam lidí a jejich odkazy (name, slug, …)draws — vylosované páry. Pravidla hry vynucuje i databáze, ne jen kód:
giver_id je primární klíč (daruje se jednou), receiver_id má unique index
(dostane se jednou), omezení draws_not_self zakáže darovat sám sobě
a draws_not_same_group partnerovi či nikomu z vlastní domácnosti.Schéma je v lib/db/schema.ts. Lokálně běží Postgres
v Dockeru na portu 55432, v produkci Supabase přes DATABASE_URL.
DATABASE_URL — Supabase session pooler, port 5432
(Supabase → Connect → Session pooler)ADMIN_PASSWORD — heslo do /adminmain = produkční deploy. npm run db:push se pouští z lokálu
(DIRECT_URL je stejná adresa a Vercel ji nepotřebuje).Po deployi musí GET /api/health vrátit {"ok":true}.
Ne transaction pooler (port
6543) — postgres.js na něm při souběžných dotazech zamrzá. Aplikace ho proto odmítne a health check vrátí"kod":"TRANSACTION_POOLER". Ani přímá adresadb.…supabase.conejde: je jen přes IPv6 a Vercel se k ní nepřipojí. Podrobnosti vlib/db/client.ts.
Aplikace nemá přihlašování: kdo klikne na cizí jméno (nebo uhádne cizí odkaz —
je odvozený ze jména, takže /petrsvoboda je snadné), dostane se k cizímu
losu. Vědomá volba ve prospěch jednoduchosti; hra je pro jednu domácnost, kde
se lidi znají. Proti překliknutí je aspoň potvrzovací krok.
Kdyby to nestačilo, přidej v lib/game/slug.ts ke slugu
náhodnou příponu a rozesílej jen osobní odkazy — zbytek aplikace se měnit
nemusí.
Co hra nedovolí ani tak: zjistit, kolik lidí ještě zbývá, přečíst si los někoho, kdo už losoval, ani losovat dvakrát.
app/
page.tsx odpočet do oslavy + výběr jména ze seznamu
[slug]/page.tsx osobní stránka: zalosovat / připomenout si los
[slug]/loading.tsx okamžitá odezva, než se stránka načte
actions.ts server actions: losování, admin
admin/page.tsx seznam lidí, stav losování, kontrola losů, reset
api/health/route.ts health check
not-found.tsx česká 404
globals.css designové tokeny (@theme), tlačítka, animace
components/
VyberJmena.tsx výběr jména ze seznamu + potvrzení proti překliknutí
PersonalDraw.tsx hra na klientovi — losovat, válec, odhalení
DrawReel.tsx výherní válec se jmény
Backdrop.tsx fotka na pozadí, ztmavení, sněžení
CandyButton.tsx / Confetti.tsx / Snow.tsx
lib/
game/draw.ts čistá logika losování (derangement + dokončitelnost)
game/letters.ts první písmeno jména česky (háčky, „Ch“, Á → A)
game/groups.ts řádky z administrace na skupiny (páry, domácnosti)
game/audit.ts zpětná kontrola losů — jen ano/ne, žádná jména
game/slug.ts osobní odkaz ze jména + tolerance k zápisu
game/countdown.ts fakta o události (název, datum, cena) + odpočet
game/random.ts kryptografická náhoda
db/schema.ts participants, draws
db/queries/game.ts serverová pravidla hry (transakce + advisory lock)
admin.ts kontrola admin hesla
proxy.ts brána pro /admin
scripts/ seed.ts, stav.ts, kontrola.ts
tests/game/ testy logiky, písmen, odkazů a odpočtu