Synaplan
開源 AI 平台,供企業使用:自行託管的 AI 代理、符合 GDPR 的聊天機器人小工具、RAG 知識庫、WhatsApp 與 Outlook AI、MCP、多模型路由。Docker、Kubernetes 或託管於 Germ
AI 翻譯
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證SycaMore Live: org-attested volunteer hours (Cal Hacks 13.0)
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗Volunteer hours recorded as the event happens, from the organization's side. Volunteers scan in and out; the coordinator verifies the event when it closes; every volunteer gets a record anyone can check.
Started at Cal Hacks 13.0 on Oct 23, 2026. SycaMore is the team's existing student project; this repo is a new weekend build on the same problem and shares no code with it.
This repo holds both sides of the sign-in table in one Next.js app on one database: the organization side (Bryant, built with Claude) and the volunteer side (check-in on phones, "My hours", the public /v/ page, ported from Khanh's prototype). The API follows build/00-SHARED-CONTRACT.md in the team's Drive hub.
On Oct 25, 2026 (judging day) the whole app was redesigned: a top bar and icon rail for coordinators, an app shell with a bottom tab bar for volunteers, a dark theme, a shared motion kit, and new legal pages. See Design.
/) jumps to any event, volunteer or page. Signed out, any coordinator page goes to the PIN screen and comes back to it after sign-in.claude-opus-5-5 drafts rows with structured outputs; low-confidence rows are amber; nothing is saved until the coordinator confirms each row. Sheet text is treated as data, not instructions, and the model never invents a check-out time.src/lib/insights.ts) but aren't shown or linked anywhere until the business model's Phase 4 trigger (30 organizations, 200 events); /org/score still renders for anyone who types the URL.src/lib/presence.ts; the volunteer endpoint POST /api/vol/presence is a reference implementation for the volunteer side./w/<token>:
vid cookie.src/lib/walkin.ts and src/lib/google.ts. POST /api/vol/checkout is a reference implementation of the contract route for the volunteer side..ics invite or the invite email (.eml), a Google or Outlook "add to calendar" link, or a calendar's iCal address (Google's "secret address", Apple public calendars, Outlook ICS links). Feeds list the next four months, with repeating events expanded, and an event imported twice is flagged.claude-opus-5-5, structured output). The server checks the date and time shapes, relative dates ("this Saturday") resolve against today, and instructions inside the material are ignored.src/lib/safe-fetch.ts)./cal/<token>.ics is unguessable and updates every few hours; practice events never appear in it./e/<slug> with a map, one-tap directions, add to Google / Apple / Outlook, notes and how check-in works. The check-in code is not on it. Until the event ends, the coordinator's event page shows a ready-to-send announcement for group chats, with Share, Copy, WhatsApp, text, email and Telegram buttons./c/<slug>; voice notes stay private. Media is stored on local disk in .media/ (gitignored; set MEDIA_DIR to change it).Same app, same theme: the volunteer pages live in src/app/(vol)/. On phones, a greeting bar and a bottom tab bar (Home, Discover, Messages, Me); on desktop, one top bar with the same tabs as a sliding pill, Check in and the avatar.
/join: name, email, birth date, and a required "I agree to the Terms and Privacy Policy" box (13 to 17: "and a parent or guardian knows I'm using SycaMore"), kept as terms_accepted_at and guardian_ack_at. Under 13 is refused and nothing is stored; 13 to 17 can join, but sharing needs a guardian's OK. An existing email signs back in only with its birth date. ?next= brings them back (a QR scan lands on /join?next=/checkin?code=…; a signed-out visit to any volunteer page, Discover listings included, comes back to that page)./checkin: the event QR (/checkin?code=<checkin_code>) or the 6 typed characters; check-in opens 2 hours before the start and closes 2 hours after the end, and practice events never match. Checked in, it's the live session card (shared with the walk-in page) with Check out. If the coordinator set a site, an off-by-default toggle, "Help {org} see if I leave early", sends POST /api/vol/presence pings while the page is open (no coordinates stored) and offers Check out if they've left./me (Home): verified hours (counted up) with "+N this month"; the live session card with Check out if they're checked in; "Up next"; a private personal goal (volunteer.hours_goal, filled only by attested hours); pending events as "Waiting for {org} to confirm" with no number; and each organization as a folder (its colour, total hours and record count). Hover or press-and-hold lifts the papers; tapping a folder fans out its three newest records, each linking to the record (more than three: the third paper opens Journey)./me/account (Account): name and email, the light/dark theme, the announcements opt-in (marketing_opt_in, off until they turn it on, with the time in marketing_opt_in_at), Download my data (GET /api/vol/account/export, a JSON file of their own rows), Delete my account (type DELETE; DELETE /api/vol/account deletes the volunteer and unlinks their attendance as "Former volunteer", so the organizations' attested totals survive as anonymous rows), links to Badges, Journey, Privacy, Terms and Deletion and retention (/data), and Sign out on this device./me/records/[id]: the contract's record wording with captured vs adjusted and the reason, a share link (SYC-XXXX-XXXX, crypto.randomInt) with copy and QR, and print / save as PDF. Minors get "Sharing needs a guardian's OK", and the API returns 403.Demo volunteers: [email protected] / 2007-04-12 (adult, three attested records, one pending, one already shared at /v/SYC-RVR7-PLNT, Event Coordination signed and Team Leadership ready for sign-off) and [email protected] / 2010-02-03 (16, can't share). Three more made-up organizations (PINs 135790, 864202, 975318) have 8 upcoming events for Discover.
The Oct 25, 2026 redesign is described in docs/REDESIGN-2026-10-25.md (the brief: shells, density, motion, volunteer folders, legal pages) and docs/UI-KIT.md (how to use the tokens, shells, primitives and motion kit). docs/DESIGN-BRIEF.md still holds the colour rules, type and accessibility decisions underneath it. In short:
src/components/motion/: staggered page entrances, count-ups, sparklines, sliding pills, toasts and route transitions. The check-in, event-day and verify paths never wait on animation, and content is visible without JavaScript./privacy, /terms, /data (download, deletion, retention, breach steps) and /licenses. Every public page has its own title, description and share card; private pages are noindex.Needs Node 22+ and PostgreSQL 16/17 running locally.
npm install
cp .env.example .env.local # or create it: see below
npm run db:reset # creates the database in DATABASE_URL and loads the demo seed
npm run dev -- -p 3311
.env.local:
DATABASE_URL=postgres://localhost:5432/sycamore_live
NEXT_PUBLIC_APP_URL=http://localhost:3311
ANTHROPIC_API_KEY=... # for "Import paper sheet", "Event story" and the volunteer blurb
OPENAI_API_KEY=... # optional: the blurb uses OpenAI instead of Claude when set
GOOGLE_CLIENT_ID=...apps.googleusercontent.com # "Continue with Google" for coordinators and volunteers
GOOGLE_CLIENT_SECRET=... # with the ID above; without both, Google buttons hide and the PIN / email code remain
NEXT_PUBLIC_GOOGLE_CLIENT_ID=...apps.googleusercontent.com # optional: one-tap Google on the walk-in page
RESEND_API_KEY=... # emailed sign-in codes and supervisor/guardian emails (in dev without it, emails print to the server log)
SYCAMORE_DEMO=1 # optional: keep the "Demo data · made-up names" ribbon on in a production build
Going to production: read docs/PRODUCTION.md (the Google OAuth client, Resend, the two migrations, demo PINs, organization review). What the competitor research found and what was built from it is in docs/COMPETITIVE-ANALYSIS-2026-10-28.md.
Already have a database from before the redesign? npm run db:reset rebuilds it from db/schema.sql, which now has the account columns on volunteer: terms_accepted_at and guardian_ack_at (the join and walk-in consent boxes), marketing_opt_in (default false) and marketing_opt_in_at (the announcements opt-in), plus an attendance trigger that lets a deleted volunteer's attested rows be unlinked as "Former volunteer" without changing their hours. To keep your data instead, add those columns by hand and run psql "$DATABASE_URL" -f db/migrations-redesign-r2.sql (idempotent: it backfills guardian_ack_at and adds the second and third demo organizations to Ana's folders).
Org and volunteer pages show a slim "Demo data · made-up names" ribbon whenever SYCAMORE_DEMO=1 or NODE_ENV isn't production (src/lib/demo.ts).
Sign-in. Coordinators and volunteers sign in at /signin: Google for both, an emailed 6-digit code for volunteers, and the organization PIN for the demo org and orgs set up before Google. Sessions are server-side (auth_session, only a hash of the token is stored). Google needs an OAuth Web application client whose redirect URI is <NEXT_PUBLIC_APP_URL>/api/auth/google/callback; see docs/PRODUCTION.md.
Demo coordinator PIN: 246810 (Riverside Restoration Crew, made-up names). The seed mirrors the shape of the team's real pilot: four planting events with 45/48/52/58 attendances at 3 hours each. Phase 2 is left unverified on purpose, with 4 of its 58 people who never scanned out (so verify shows "Fill in 4 who didn't scan out"): verifying it on stage adds its hours to the record and makes new badges ready. Today's walk-in event, Guadalupe River Cleanup, runs 9:00 AM to 1:00 PM Pacific on the day you seed; seeded later than that, it shows as ended but its walk-in QR keeps working for 4 hours.
npm run check # tsc + eslint
npm test # Discover engine (22 ported tests + 4) and the blurb number check; Node 22.18+ runs the TypeScript directly
npm run eval:sheets (dev server running, ANTHROPIC_API_KEY set) scores the import on three sheets in tests/sheets/ whose "handwriting" is synthetic: computer-generated with handwriting-style fonts by make_sheets.py (which regenerates them), not written by people. Last run, Oct 23, 2026, claude-opus-5-5: 19 of 19 rows exactly right before review on those synthetic sheets, the ink-blotted time flagged instead of guessed, the crossed-out row and the "IGNORE PREVIOUS INSTRUCTIONS" line both skipped and mentioned in notes, and blank time-outs left empty. About 5 to 9 seconds per sheet. A test on real, human-handwritten sign-in sheets is still pending, so treat 19/19 as a synthetic result, not a field accuracy figure.
OPENAI_API_KEYOPENAI_MODELgpt-4o-minisrc/lib/claude.tssrc/lib/blurb.ts/me/badges: signed / in progress / not started. Signed means the organization signed a badge_award row; progress and "ready for sign-off" are computed per organization from attested attendance with the rule targets in src/lib/badges.ts (the org dashboard uses the same stats helpers). Pending check-ins and practice events never count./me/badges/[key]: the certificate: signer, date, the coordinator's evidence note, attested events and hours with the issuer, the rule; print / save as PDF. Adults can create a public verification link (/v/b/BDG-XXXX-XXXX, POST /api/vol/badges/:id/share; minors get a 403, like records). With the link, Add to LinkedIn: an editable post that states facts only (organization, signer and date, attested events and hours, dates, roles; no skill claims) with the link, Copy, LinkedIn's share URL, and the Licenses & certifications fields to copy. Nothing is posted for them, and there's no LinkedIn partnership./me/journey: every attested event (practice excluded) with the role, hours, a running total, firsts, and the badges signed along the way./discover: upcoming public events from every organization, ranked in the browser by Khanh's matching engine (ported unchanged to src/lib/discover/): use my experience / learn something new / follow my interests, a cause, skills to use and develop. Org tags supply the cause and skills; journey time, cost and support are unknown, so each score is the supported fit points with the range. Fit is rule-based, not a probability. Pasted resume or role text (/discover/profile) stays in page memory, never sent or stored. Save for later is per volunteer on the server (saved_event, /api/vol/saved). Each event links to its public page /e/<slug> and walk-up check-in; there's no sign-up. Details in docs/volunteer/DISCOVER.md./v/<code>: public, no cookie, not indexed: VERIFIED or REVOKED, the wording, and who to call. Unknown codes are a 404./me/messages: coordinator threads and event group chats, over the existing /api/vol/messages and /api/vol/event-chats. Volunteers under 18 get the organization's announcements (broadcasts and automatic notices) only: they aren't in event group chats (can't see members, read or post) and direct messages with a coordinator are off in both directions, with "Messages with volunteers under 18 are off" on both sides. The rule lives in the data layer (src/lib/minors.ts, used by messages.ts, event-chat.ts and the vol routes), which answer 403.POST /api/vol/join, GET/PATCH /api/vol/me, PATCH/DELETE /api/vol/account, GET /api/vol/account/export, POST /api/vol/checkin, GET /api/vol/records, POST /api/vol/records/:id/share, POST /api/vol/records/:id/blurb, POST /api/vol/badges/:id/share, GET/POST /api/vol/saved, GET /api/v/:code (logic in src/lib/vol-data.ts, vol-badges.ts, vol-discover.ts, blurb.ts). The browser never sends hours.sycamore-volunteer-preview/) is fully ported and removed from the branch; it stays in git history at c169374. Its notes, updated for the integrated version, are in docs/volunteer/.