Synaplan
開源 AI 平台,供企業使用:自行託管的 AI 代理、符合 GDPR 的聊天機器人小工具、RAG 知識庫、WhatsApp 與 Outlook AI、MCP、多模型路由。Docker、Kubernetes 或託管於 Germ
AI 翻譯
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證RFQ
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗Arabic-first RFQ and quote comparison for Saudi businesses. Send a request for quotation, collect supplier quotes by web form or emailed PDF, compare them line by line excluding VAT, and auto-approve the best one within rules the buyer sets. Every step is recorded on a decision trail.
Screenshots: add
docs/screenshots/landing.png,compare.png,dashboard.pngandsupplier-form-ar.png. The live demo needs no sign-up: open the site and press Explore the live demo.
A Saudi contractor or office manager who buys every week runs the same loop by hand:
Nobody records why that supplier won, the spreadsheet is never the same twice, and the cheapest quote isn't always the right one.
Clarix turns the loop into one flow, in Arabic or English, right to left where it should be:
flowchart LR
subgraph Browser
B[Buyer app<br/>Next.js RSC + server actions]
S[Supplier form<br/>/quote/token]
V[Public site<br/>/ and /pricing]
end
subgraph Vercel
MW[Middleware<br/>2.5 s auth cap]
SA[Server actions]
WH["/api/webhooks/resend-inbound<br/>svix-verified"]
JR["/api/jobs/process<br/>CRON_SECRET"]
end
subgraph Supabase
DB[(Postgres + RLS<br/>jobs queue, audit_events)]
ST[(Storage: quote-pdfs)]
AU[Auth]
end
G[Gemini Flash<br/>zod-validated JSON]
R[Resend<br/>email in/out]
B --> MW --> SA --> DB
S --> SA
V --> SA
R -- inbound PDF --> WH -- enqueue --> DB
SA -- enqueue + waitUntil --> JR
JR -- claim_jobs skip locked --> DB
JR --> G
JR --> R
SA --> G
SA --> ST
MW --> AU
GH[GitHub Actions every 15 min<br/>+ Vercel daily cron] --> JR
auth.uid() through RLS. The demo
account is read-only at the database.waitUntil, and swept every 15 minutes. claim_jobs uses
for update skip locked, so runs never collide.More detail: docs/ARCHITECTURE.md, docs/SECURITY.md,
docs/DECISIONS.md (75 numbered decisions), and DESIGN.md.
| Choice | Why |
|---|---|
| Next.js 14 App Router | Server components read through RLS with the user's cookie, and server actions keep every write on the server. One deployable runs the buyer app, the public supplier form, webhooks and the job runner. |
| Supabase (Postgres, RLS, Auth, Storage) | Tenancy enforced by the database, not by where clauses someone forgets. Postgres also hosts the job queue and rate limits, so there is no extra infrastructure. |
Gemini Flash via @google/genai | Reads scanned PDFs natively, handles Arabic, supports structured output, and has a free tier for a pre-revenue product. The model is GEMINI_MODEL, which matters: see the challenges below. |
| Resend | Outbound invitations and POs plus inbound email in one service. The inbound webhook makes "reply with your PDF" work. |
| next-intl, cookie-based | Full Arabic/English without locale URLs, so every existing link (emails, supplier tokens, webhooks) keeps working. The language follows the buyer across devices through profiles.locale. |
| Tailwind and shadcn/ui (Radix) | Accessible primitives. Logical properties (ms, ps, start, end) make RTL a direction flip, not a second stylesheet. |
| Vitest and PGlite | 701 tests. Migrations and RLS are tested against real Postgres in WASM, with no Docker and no hosted database. Gemini and Resend are always mocked. |
| Vercel and GitHub Actions | Hobby-tier hosting. CI runs typecheck, lint, tests, the offline evals and the build on every PR, and a free schedule sweeps the job queue. |
1. Background work that silently never happened. The supplier form, manual entry and PDF
confirmation called maybeAutoGenerateRecommendation() without await. On a laptop that works.
On a serverless platform the function freezes as soon as the response is sent, so the
recommendation, the auto-approval and the PO email were dropped at random, with no error
anywhere.
waitUntil. A cron sweep finishes anything a frozen instance
left behind.2. The middleware that took the whole site down. Middleware called
supabase.auth.getUser() on every matched request with no timeout. When Supabase Auth was slow,
every page hung until Vercel killed it with MIDDLEWARE_INVOCATION_TIMEOUT (504), including the
public supplier form and the webhook. The fix:
fetch, plus a Promise.race./login with an explanation.3. Race conditions in auto-approval. Two suppliers submitting the last quotes at the same moment could both create a recommendation, and both runs could send a PO. The award insert now gates every side effect, and the database enforces the uniqueness.
4. A model that quietly disappeared. The extraction evals (below) failed every case one
morning. gemini-2.5-flash had started returning 404 "no longer available to new users". The
default moved to gemini-3.5-flash (the newest models were overloaded that day), and
GEMINI_MODEL now changes it without a deploy of code. Because evals run against the real API on
demand, this was caught before any buyer was affected.
5. Arabic that wasn't really Arabic.
next/font places a size-matched Arial fallback right after Geist in the font
stack. Arial has Arabic glyphs, so every Arabic word rendered in Arial instead of IBM Plex Sans
Arabic. Removing the generated fallback fixed it.6. Security without a security team. Every server action checks the session on the server. On top of that:
Details: docs/SECURITY.md.
22 deliberately messy synthetic quotes in Arabic, English and mixed (VAT-inclusive prices, Arabic-Indic digits, line totals only, emails, tables, other currencies). Each runs through the production prompt, schema and repair path.
| Field | Rule-based baseline | Gemini (gemini-3.5-flash) |
|---|---|---|
| Unit price (excl. VAT) | 46.3% | 100% (32/32) |
| Currency | 100% | 100% |
| Delivery days | 90.9% | 94.1% |
| Warranty period | 100% | 100% |
Method and full results: docs/EVALS.md.
npx tsx evals/extraction/run.ts # offline baseline
RUN_LIVE_EVALS=true npx tsx --env-file=.env.local evals/extraction/run.ts --write # real Gemini
Requirements: Node 22, a Supabase project (hosted or supabase start), and optionally Gemini and
Resend keys.
npm install
cp .env.example .env.local # fill in the values; names are documented in the file
supabase/migrations/0001 to 0020 in order (supabase db push, or paste
them into the SQL editor). They are additive.npm run dev
Open http://localhost:3000. Signed out, you see the landing page; sign up to reach the app.ALLOW_SEED=true npm run seed:demo # local Supabase
ALLOW_SEED=true DEMO_SEED_PROJECT_REF=<ref> npm run seed:demo # a hosted project, on purpose
npm run typecheck && npm run lint && npm test && npm run build
Without a Gemini key, the AI features fail gracefully and quotes can be entered by hand. Without Resend, nothing is emailed. Tests never call either.
docs/PROGRESS.md: every phase, its PR, and how it was verified.docs/plans/: the plan for each phase.docs/METRICS.md: how savings and scorecards are calculated.PRODUCT.md and DESIGN.md: product truth and the design system.