Synaplan
開源 AI 平台,供企業使用:自行託管的 AI 代理、符合 GDPR 的聊天機器人小工具、RAG 知識庫、WhatsApp 與 Outlook AI、MCP、多模型路由。Docker、Kubernetes 或託管於 Germ
AI 翻譯
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗Mobile-first PWA for Swedish construction sites and plants: workers report near-misses (tillbud), hazards and accidents in three taps; the safety organisation follows up with CAPA, weekly skyddsronder (AFS 2001:1) and AML 3:3a notices to Arbetsmiljöverket.
npm install
npm run dev # http://localhost:3000 — demo mode until Supabase is configured
npm test # vitest unit tests
npm run lint
npm run typecheck
Copy .env.local.example to .env.local and set NEXT_PUBLIC_SUPABASE_URL and
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY (or ..._ANON_KEY). Both are public values.
Apply the schema (tables, RLS policies, RPCs, storage bucket, realtime):
npx supabase login
npx supabase link --project-ref <your-project-ref>
npx supabase db push
npx supabase db query -f supabase/seed.sql # optional demo sites and locations
Without the CLI, paste supabase/apply-all.sql (migrations + seed in one script) into the
SQL editor of the Supabase dashboard and run it. Regenerate it after editing a migration:
node scripts/build-apply-all.mjs
Create the safety officers' accounts under Authentication → Users (email + password, or invite by e-mail). Field workers never need an account.
| Role | Can |
|---|---|
| Anonymous visitor (field worker) | read sites and locations, submit a report through the submit_incident RPC, upload photos / voice notes |
| Signed-in user (safety officer) | read and update incidents, CAPA actions, skyddsronder and media |
The dashboard and /skyddsrond redirect to /login when Supabase is configured. Media lives in
the private incident-media bucket and is served through short-lived signed URLs.
Workers never sign in. Each company and each place has a report key; the QR code carries it (/report?k=<key>).
The submit_incident RPC refuses an anonymous report without the current key of that company or place, so the
form cannot be used for another company. A manager (or the owner) replaces a key in Settings / Projects and the
old printed code stops working at once. The RPC also limits reports per phone, per network and per company per
hour, and flags a report sent from outside the place (a flag, not a block). Signed-in people of the company
report without a key. Optional: Cloudflare Turnstile (NEXT_PUBLIC_TURNSTILE_SITE_KEY, TURNSTILE_SECRET_KEY).
Staff see only the places a manager ticks for them (People page); managers see their whole company.
With NEXT_PUBLIC_ROOT_DOMAIN set, each company gets <slug>.<root domain> (add a wildcard domain in Vercel).
Set RESEND_API_KEY, SAFETY_ALERT_RECIPIENT (comma-separated allowed), optionally RESEND_FROM
and NEXT_PUBLIC_APP_URL. The browser pings /api/alerts/critical-incident after a report; the
route calls the claim_incident_alert RPC, which returns the incident only if it is critical and
has not been alerted before, so the e-mail can be neither forged nor duplicated.
For delivery that does not depend on the reporter's browser, add a Database Webhook in
Supabase (table incidents, event INSERT, URL https://<your-app>/api/alerts/critical-incident,
HTTP header x-alert-secret: <ALERT_WEBHOOK_SECRET>) and set ALERT_WEBHOOK_SECRET in the app.
app/ routes (report, dashboard, skyddsrond, login, api/alerts)
components/ UI: report wizard, dashboard, skyddsrond checklist, auth, shell
lib/data/ repository contract + Supabase and in-memory implementations
lib/supabase/ client/server factories, row mappers, hand-maintained DB types
lib/offline/ IndexedDB queue for reports written without a connection
lib/alerts/ critical-incident payload, parsing and e-mail template
lib/compliance/ AML 3:3a notice model and print template
supabase/ migrations, seed data, CLI config
tests/ vitest unit tests for the pure modules
public/sw.js caches the app shell (network-first for pages, cache-first for static assets) and is
registered in production builds only. iOS splash screens are generated by
node scripts/generate-ios-assets.mjs.