Synaplan
开源 AI 软件平台,面向企业:自托管 AI 代理,符合 GDPR 的聊天机器人小部件,RAG 知识库,WhatsApp 与 Outlook AI,MCP,多模型路由。支持 Docker、Kubernetes 或在 Germ 托管。
AI 翻译
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证aquatrack
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
A mobile-first Progressive Web App for a water-selling business in Sri Lanka. Two
employees register sales in ~10 seconds each; the owner gets a real-time
dashboard, transaction history with corrections/audit log, and automatic
daily/weekly/monthly email reports.查看完整 README ↗A mobile-first Progressive Web App for a water-selling business in Sri Lanka. Two employees register sales in ~10 seconds each; the owner gets a real-time dashboard, transaction history with corrections/audit log, and automatic daily/weekly/monthly email reports.
Currency: LKR (Rs.) · Timezone: Asia/Colombo
prisma/schema.prisma) — swap the DATABASE_URL provider for Postgres/MySQL in production without touching app codenpm install
cp .env.example .env # fill in AUTH_SECRET, CRON_SECRET, and SMTP_* when ready
npx prisma migrate dev # creates prisma/dev.db and applies the schema
npm run db:seed # creates the owner + 2 employee accounts below
npm run dev
Seeded accounts (change these passwords after first login — there's no in-app "change my own password" screen yet, so ask an admin to reset it via Team → employee → Reset Password):
| Role | Username | Password |
|---|---|---|
| Owner | owner | Admin@123 |
| Employee | employee1 | Employee@123 |
| Employee | employee2 | Employee@123 |
Open the deployed URL on a phone:
No App Store / Play Store listing needed. Icons and manifest live in
public/icons/ and public/manifest.webmanifest (regenerate icons with
python3 scripts/generate_icons.py).
Report delivery is driven by /api/cron/reports. It's idempotent — safe to
call as often as you like; it only sends once per (report type, period,
recipient) and retries failed sends automatically, logging every attempt to
the EmailLog table (visible under Reports in the admin app).
On Vercel, vercel.json already wires this up automatically: a Vercel Cron
job hits GET /api/cron/reports once a day (see the crons entry there —
currently 5 16 * * * UTC, i.e. 21:35 Asia/Colombo, five minutes after the
default 21:30 daily send time configured in the app). Vercel authenticates
that request itself using the CRON_SECRET env var (sent as
Authorization: Bearer $CRON_SECRET) — no extra setup needed beyond having
that env var set.
Hobby-plan note: Vercel's free tier only allows one cron firing per day,
and the exact time can drift by up to an hour. If you change the daily send
time in Settings to something later than the cron schedule in
vercel.json, update the cron schedule too (and redeploy) so it still fires
after your new time — otherwise that day's report is skipped and goes out
on the next day's cron run instead.
Two other ways to trigger it manually if needed:
POST /api/cron/reports with header x-cron-secret: $CRON_SECRET (e.g. via curl) — useful for testing.npm run cron:reports on an interval (system
crontab, pm2, etc.) with APP_URL and CRON_SECRET set in the environment.Recipients, send times, and which reports are enabled are all configured
under Settings → Email Reports in the admin app (ReportSettings table).
Gmail SMTP: use an App Password
for SMTP_PASS, not your normal Gmail password (Google requires 2FA + app
passwords for SMTP).
PricingSetting.pricingMode): MANUAL (V1 default —
employee enters liters + amount), PER_LITER (owner sets a fixed price,
amount is calculated automatically), and PRODUCT (reserved for future
multi-product/customer-category pricing — schema-ready, not exposed in the UI yet).src/lib/pricing.ts): compares a manually
entered rate against the recent average and asks the employee to confirm
if it's out of range. It never auto-corrects the amount.requestId (UUID)
once per sale attempt; resubmitting the same requestId (double-tap, retry
after a dropped connection) returns the original sale instead of creating a
duplicate. The sale screen shows "SAVING…" until the server confirms.PATCH /api/sales/:id updates the sale but
also writes an AuditLog row with the old/new values and the admin's
reason — nothing is silently overwritten.src/middleware.ts (not just hidden in
the UI) — employees get 401/403 from admin-only APIs even if they guess the URL.public/sw.js caches the app shell for fast loads and an
offline fallback page. Sale submission is deliberately network-only for V1
(queued offline sales are a listed future enhancement, not implemented —
see section 22/26 of the product spec) so a sale is never silently lost or
double-counted.npm run dev / npm run build / npm run startnpm run db:migrate — create a new Prisma migrationnpm run db:seed — re-run the seed (upserts, safe to re-run)npm run db:studio — Prisma Studio to browse the databasenpm run cron:reports — trigger the report cron once (see above)