Synaplan
開源 AI 平台,供企業使用:自行託管的 AI 代理、符合 GDPR 的聊天機器人小工具、RAG 知識庫、WhatsApp 與 Outlook AI、MCP、多模型路由。Docker、Kubernetes 或託管於 Germ
AI 翻譯
尚未收集儲存庫資訊。
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
AMASI Membership Management System
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗Membership and credentialing system for the Association of Minimal Access Surgeons of India (AMASI) — handles new applications, document verification, payment, member login, support tickets, and partner-facing APIs for AMASICON event apps.
The portal is the single front door for AMASI membership. A surgeon visits /apply, uploads their medical registration and degree certificates, the system extracts details from the documents using AI vision, the applicant verifies their email and phone via OTP, pays the membership fee through Razorpay, and (depending on tier and document quality) is either auto-approved or queued for an admin to review. Once approved they receive an AMASI number, a digital membership card (with Apple/Google Wallet pass), and ongoing access to a member-only profile, a public verification link, and a support-ticket system.
Behind the application flow, the same codebase runs the admin console — review queues, member directory, FMAS skill-credential tracking, ticketing with SLA tracking, email campaigns, and the partner API consumed by AMASI's event apps (AMASICON) for member lookup at registration.
/apply, /login (OTP), /profile, /card, /tickets, and the public /verify/<token> credential check./admin/* and most /api/*.*.amasi.org subdomains) consume /api/v1/members/<email|phone|amasi_number> and /api/members/search for member lookup. Browser CORS is reflected dynamically against an allowlist; server-to-server callers use a Bearer API key.supabase gen types.KV_REST_API_* aliases)membership.amasi.orgNode runtime: .nvmrc and package.json pin Node 24.x for local development.
| Service | Purpose |
|---|---|
| Supabase | Primary database, file storage (uploads bucket owned by this app) |
| Razorpay | Membership-fee payments + Route split to a partner account for the processing fee |
| Resend | Outbound email (OTP, receipts, approval/rejection, ticket replies) |
| MSG91 | SMS OTP for phone verification |
| Gallabox | WhatsApp notifications |
| Anthropic API (Claude Vision) | OCR / document field extraction |
| OCR.space | Fallback OCR provider when Claude Vision fails |
| Upstash Redis | Rate limiting and short-lived KV |
| Apple Wallet / Google Wallet | Digital membership card pass |
| Zoho Campaigns | Sync members into mailing lists |
| Sentry | Error tracking and performance |
| Airtable | Referenced by historical seed scripts; verify before relying on them |
Prerequisites: Node 24.x, npm, a .env.local populated with the variables below, and access to the Supabase project (or your own dev project).
git clone https://github.com/Prabhugems/amasi-membership.git
cd amasi-membership
npm install
cp .env.example .env.local # then fill in real values — never commit .env.local
npm run dev # http://localhost:3000
Other scripts:
npm run build # production build (CI runs this on every push — do not bypass)
npm run lint # eslint
npm run test # vitest unit tests (vitest run)
npm run test:e2e # playwright
npm run gen:types # regenerate src/types/database.types.ts from Supabase schema
There is no separate backend service — API routes live under src/app/api/* and run on Vercel Functions.
All names below are referenced from the codebase. Never commit real values. See .env.example for the canonical list.
Supabase
NEXT_PUBLIC_SUPABASE_URL — project URL (browser-safe)NEXT_PUBLIC_SUPABASE_ANON_KEY — anon key (browser-safe)SUPABASE_SERVICE_ROLE_KEY — service-role key, server-onlyAuth / sessions
JWT_SECRET — signs admin + member JWTs and public verification linksAdmin notifications
ADMIN_DEFAULT_EMAIL, ADMIN_DEFAULT_PASSWORD — see internal admin onboarding docsADMIN_NOTIFICATION_EMAIL, ADMIN_EMAIL — destination addresses for ticket and admin notificationsRazorpay
NEXT_PUBLIC_RAZORPAY_KEY_ID — public key for the checkout widgetRAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET — server-side API credentialsRAZORPAY_WEBHOOK_SECRET — verifies webhook signaturesEVENTS360_RAZORPAY_ACCOUNT_ID — Razorpay-Route linked-account for the processing-fee splitPROCESSING_FEE_INR — optional override (defaults to ₹100)Email (Resend)
RESEND_API_KEYRESEND_FROM_EMAIL — e.g. "AMASI <[email protected]>"SMS / OTP (MSG91)
MSG91_AUTH_KEY, MSG91_OTP_TEMPLATE_ID, MSG91_TEMPLATE_IDWhatsApp (Gallabox)
GALLABOX_API_KEY, GALLABOX_API_SECRET, GALLABOX_CHANNEL_IDAI extraction / OCR
ANTHROPIC_API_KEY — Claude Vision for document extractionOCR_SPACE_API_KEY — fallback providerAirtable (scripts only)
AIRTABLE_PAT — Personal Access Token used by historical seed scriptsZoho Campaigns
ZOHO_CLIENT_ID, ZOHO_CLIENT_SECRET, ZOHO_REDIRECT_URI, ZOHO_DEFAULT_LIST_KEYWallet passes
APPLE_WALLET_CERT, APPLE_WALLET_KEYGOOGLE_WALLET_ISSUER_ID, GOOGLE_WALLET_SERVICE_ACCOUNT_KEYRate limiting / KV (Upstash)
UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKENKV_REST_API_URL, KV_REST_API_TOKEN — legacy aliases some routes still readCron
CRON_SECRET — bearer token Vercel cron sends; checked inside each cron routeApp URLs / flags
NEXT_PUBLIC_APP_URL — e.g. https://membership.amasi.orgNEXT_PUBLIC_MAINTENANCE_MODE — "true" to show maintenance bannerCORS_ALLOWED_ORIGINS — optional comma-separated extra origins beyond the built-in *.amasi.org allowlistsrc/app/apply/page.tsx + src/app/api/applications/*) — multi-step flow: select type → upload documents → OCR extract → email+phone OTP → review → pay → submit. Drafts are saved server-side at every step so users can resume from a tokenised email link. Note: this file is large and historically fragile (see .claude/CONTEXT.md "Fragile areas"); read that section before editing.src/lib/document-extraction.ts, /api/ocr) — Claude Vision primary, OCR.space fallback. Centralised; do not reimplement extraction in routes./api/payments/create-order, /api/payments/verify, /api/webhooks/razorpay) — Razorpay order with built-in Route split for the processing fee. Webhook handlers require care when adding side effects; see internal notes in .claude/CONTEXT.md.src/lib/auto-approval.ts, /api/applications/approve) — assigns the AMASI number via the next_amasi_number Postgres sequence, or honours a pre-assigned number on the application row (used to fill historical sequence gaps)./login, /api/otp/*) — OTP-based, no passwords. Includes a legacy-member fallback for accounts that exist in members but never had a membership_applications row./verify/<token>, /v/<token>, /api/credential) — anyone with a credential link can verify a member's status without logging in./card, /api/card, /api/card/wallet) — generates a printable PDF card and Apple/Google Wallet pass./admin/*, /members, /applications, /tickets, /campaigns, /audit, /reports) — cookie-based auth. Auth model is an opt-out allowlist in src/middleware.ts (PUBLIC_API_ROUTES); every new public endpoint must be added there./tickets, /api/tickets/*) — CSAT-rated tickets with SLA breach detection (cron-driven) and per-ticket reply history..vercel/.main (per vercel.json git.deploymentEnabled.main: true). Preview deployments fire on every other branch./monitoring.vercel.json and run by Vercel cron.*.amasi.org, e.g. eventz360) — maintained by external event partners (e.g. eventz360). They consume the partner API exposed here. Buckets form-uploads, event-assets, and downloads in the shared Supabase project belong to those apps; this app only owns uploads.AGENTS.md and .claude/CONTEXT.md before non-trivial changes. They list fragile areas and recent bug-fix history.useSearchParams, usePathname, useRouter) — npx tsc and eslint do not catch missing <Suspense> boundaries; only next build does. CI also enforces this; do not bypass.PUBLIC_API_ROUTES in src/middleware.ts. Decide and add this in the same commit that introduces the new route..claude/CONTEXT.md for the canonical list before adding new member columns.uploads bucket. The other buckets in the shared Supabase project belong to the AMASICON apps — don't modify them.src/lib/audit-log.ts. Don't swallow insert errors — surface to Sentry or use .throwOnError()./api/* is owned by src/middleware.ts (dynamic origin reflection via src/lib/cors.ts). Do not move it back into next.config.ts static headers.src/types/database.types.ts) are generated from the live Supabase schema by npm run gen:types. Run after any DB migration.__tests__/critical-paths.test.ts holds regression tests for the highest-value flows. New fixes in those areas should add a test or a TODO with a CHANGELOG link.CHANGELOG.md and a row in .claude/CONTEXT.md "Recently fixed bugs". Future maintainers rely on this — don't skip it./api/v1/members/<email|phone|amasi_number>/api/members/search*.amasi.orgvercel.json) — sla-breach every 10 min, weekly-digest Mondays 04:00, sync-members every 6 h, bulk-draft-reminders daily 03:30. Each route enforces Bearer ${CRON_SECRET}.src/lib/audit-log.ts, membership_audit_log table) — always go through the helper; direct inserts have caused silent breakage.