Synaplan
開源 AI 平台,供企業使用:自行託管的 AI 代理、符合 GDPR 的聊天機器人小工具、RAG 知識庫、WhatsApp 與 Outlook AI、MCP、多模型路由。Docker、Kubernetes 或託管於 Germ
AI 翻譯
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗A workspace for Kicks's expansion team. Bring in franchise partner applications and the areas to grow in from one Excel file. For every applicant the Desk shows what should happen, why (a step-by-step reason trail), what they must do next, how they will be trained, a dated timeline, a ready message in Kannada, Hindi or English, and a private status page that always shows the latest decision.
Live: https://kicks-partner-desk.vercel.app
The engine decides. The language assistant never does. All decisions come from plain, tested TypeScript in src/engine/ (the same input always gives the same output). The assistant (Gemini, through OpenRouter, Google models only) does three jobs:
With no AI key everything still works: keyword fallbacks read the text and templates write the wording.
Every number the engine uses is an assumption (below), shown on the Assumptions page and editable. Saving re-runs everyone and shows who changed.
Excel file ──► POST /api/run ──► read + clean (src/lib/readWorkbook.ts) ──► Data Health report
│
▼
Neon Postgres (runs, applications, territories,
existing_stores, decisions, decision_events,
chat_messages, status_links)
│
┌───────────────────────────────┼─────────────────────────────────┐
▼ ▼ ▼
Browser (Next.js) POST /api/chat /s/<token>
runs the engine for the Gemini tool calling: applicant status page,
screens; saves changes get/explain/compare/update/ rebuilt from the run
with a revision check withdraw/rerun/set_assumption every time it opens
│ │
└──────────► src/engine (pure, tested) ◄────────────────────────┘
checks → score → rank → allocate → redirect → reason trail
/run/<uuid> opens it for anyone with the link, with no sign-in. Runs are deleted after 7 days without changes.decision_events (before, after, trigger, actor, time) and can be undone.All live in src/engine/config.ts (DEFAULT_ASSUMPTIONS) and on the Assumptions page.
| Assumption | Default |
|---|---|
| Setup cost, ₹ lakh (Tier 1 / 2 / 3) | 35 / 25 / 18 |
| Minimum investment, % of setup cost | 100 |
| Investment tolerance below the minimum, % | 10 |
| Investment cap for points, × setup cost | 1.2 |
| Score weights: investment / space / experience / timeline / area priority / completeness | 25 / 25 / 20 / 10 / 10 / 10 |
| Area priority share (High / Medium / Low) | 100% / 60% / 30% |
| Experience share (0 / 1–2 / 3–5 / 6+ years) | 0% / 40% / 75% / 100% |
| Business background bonus inside experience (max) | +3 points |
| Space share (owned / rented) | 100% / 80% |
| Floor factor (ground, mall / upper / not known) | 1.0 / 0.7 / 0.8 |
| Ideal size / near-ideal range, sq ft | 400–800 / 250–1200 |
| Size factor (ideal / near / other) | 1.0 / 0.8 / 0.5 |
| Minimum score to get an opening | 45 |
| Space-ready applicants placed first | on |
| Stage lengths, weeks: find space / site approval / agreement / fit-out / hiring / training / inventory / soft launch | 9 / 2 / 2 / 4 / 3 / 2 / 2 / 1 |
| Days an opening is held for a condition | 30 |
| Monthly sales, ₹ lakh (Tier 1 / 2 / 3) | 9 / 6 / 4 |
| Take-home share, rented (Tier 1 / 2 / 3) | 15% / 15% / 16% |
| Take-home share, owned (Tier 1 / 2 / 3) | 23% / 23% / 24% |
| Sales spread for the payback range, ± % | 20 |
| Payback target, months | 30 |
| Training days (no experience / 1–2 years / 3+ years) | 14 / 7 / 3 |
| Training hours per day | 6 |
| Nearby-store flag, pin distance | 10 |
| "Start here" bonus (High / Medium / Low) | 5 / 2 / 0 |
| "Start here" list size | 5 |
npm install
cp .env.example .env.local # then fill in the values
npm run dev # http://localhost:3000
npm run lint
npm run typecheck
npm test
npm run build
Without DATABASE_URL the Desk still opens and works in one tab (changes are kept in this browser only). With it, runs, events and chat are saved.
| Name | Use |
|---|---|
DATABASE_URL | Neon Postgres pooled connection string. Tables are created on first use. |
OPENROUTER_API_KEY | Switches on the assistant (Gemini, Google models only, via OpenRouter). |
OPENROUTER_MODEL | Optional. A model id starting with google/. Default google/gemini-3.7-flash. |
AI_ENABLED | Optional. Set false to force the keyword fallbacks and template wording. |
LANGSEARCH_API_KEY | Switches on live market notes on the Market page. |
CRON_SECRET | Protects the daily clean-up at /api/cron/purge. |
No secrets are stored in the repository. .env.local is ignored by git.
BASE_URL=http://localhost:3000 npm run seed
Starts a run with the practice data on a running copy and prints its /run/<uuid> link. The fixed ten existing stores are written to the existing_stores table automatically the first time the app talks to the database. npm run make-fixture rebuilds the practice workbook.
Open the live site, press Import → Load practice data, then open Ask assistant (docked panel on desktop, bottom sheet on a phone) and try these seven things.
"Why is APP-005 approved at 32 while APP-003 at 87 is waitlisted?" — The assistant corrects the premise: APP-005 is not approved. Its score is 40.3, below the minimum of 45, and the instruction in its notes was ignored. APP-003 (89.7) is waitlisted because APP-002 (100) won pin 570001 and APP-003 has a space in that pin. A side-by-side comparison of pin availability and score follows.
"APP-002 has withdrawn" — Saved at once. APP-002 becomes Withdrawn and APP-003 moves up from the waiting list to win 570001. The diff card shows both, with an Undo button. The applicant page and the Audit log update immediately.
"APP-012 found a shop" — The assistant asks one short question (owned or rented, and what size) and saves nothing. Then "APP-012 found a 450 sq ft ground-floor rented shop" is saved and the score rises from 60 to about 85. APP-012 stays on the waiting list, because APP-009 holds pin 560010, and the card says so.
"Add one opening to TER-03" (on a fresh run) — APP-012 gets an outcome: Redirected to pin 560011.
"Why is APP-006 redirected?" — Kicks already has store ST-06 at pin 570009. TER-02 has free pins 570004 and 570020. 570004 is nearest, so it is offered, and it uses one of the area's two openings.
"Approve APP-005 anyway" — Declined politely, with a pointer to Change this decision, which asks for a reason and is recorded in the Audit log.
"What happens if we raise the minimum score to 60?" — A what-if is never saved. The reply is one line and the card is labelled Preview, not saved, listing every decision that would change (for example APP-012 becoming Not eligible). The minimum score stays at 45 and the Audit log gets no entry. Press Apply this change to save it; the saved card then has Undo and the change is logged.
Also try: Assumptions (change the minimum score or the money tolerance, save, and read the diff card), Areas (the pin board), and the applicant status link (/s/…) on a phone.
npm test runs Vitest: every engine rule, every acceptance case on the practice data, the parser edge cases (example row, decimal pins, comma-split pins, blank optional fields, free-text language, duplicate IDs), the chat tools and an integration test that imports the practice data, withdraws APP-002 and checks that APP-003 is promoted and decision_events records it (runs when DATABASE_URL is set). CI runs lint, typecheck, test and build on every pull request; Vercel deploys main.