尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
SaaS multi-tenant pour centres de santé (CSRéf) — dossiers patients, consultations, registres réglementaires, facturation par abonnement, back-office admin plateforme. Une seule app Next.js 16 déployable — aucun backend séparé. Bâti à partir du starter izikit (auth, paiements, admin, webhooks, cron), sur lequel s'ajoute toute la couche métier santé. Voir STATUS.md pour l'historique du portage depuis le starter, et PRUNING.md pour retirer une surface optionnelle du starter encore présente (paiements, OAuth Google, uploads…).檢視完整 README ↗
SaaS multi-tenant pour centres de santé (CSRéf) — dossiers patients, consultations, registres réglementaires, facturation par abonnement, back-office admin plateforme. Une seule app Next.js 16 déployable — aucun backend séparé. Bâti à partir du starter izikit (auth, paiements, admin, webhooks, cron), sur lequel s'ajoute toute la couche métier santé.
Voir STATUS.md pour l'historique du portage depuis le starter, et PRUNING.md pour retirer une surface optionnelle du starter encore présente (paiements, OAuth Google, uploads…).
/admin/signalements.Plan payant ; cron quotidien qui facture, relance par email (J-7/J-5/J-3/impayé), et bloque l'accès (402 SUBSCRIPTION_INACTIVE) aux routes patients/consultations/registres si l'abonnement tombe en PAST_DUE/CANCELED.Organization) a ses propres patients, son personnel (OrganizationMember, rôles OWNER/ADMIN/MEMBER), ses paramètres (ClinicSettings).ADMIN/SUPERADMIN app-wide, indépendant du rôle par centre : vue d'ensemble (MRR, centres, personnel), gestion utilisateurs/centres/abonnements/plans, audit log, supervision outbox/emails/rate-limits.PaymentProvider du starter (défaut Bictorys) est en place mais pas encore configurée : le projet doit basculer sur un autre prestataire (Chariow) en attente d'informations. BICTORYS_* est vide en .env.local → /api/orders et /api/webhooks/bictorys renvoient 404, le reste de l'app fonctionne normalement.Un seul point d'entrée. Ouvre ce projet dans Claude Code et tape :
/setup-kit
/setup-kit est une skill bundlée dans ce repo. Elle te guide de bout en bout : audit de ton environnement (Git, Node, pnpm, gh CLI), détection des cas piégeux (ZIP-download → blocker explicite, env file au mauvais endroit), installation des 2 plugins Claude Code manquants (superpowers + context-mode — via la palette UI de l'extension ou en fallback paste-ready CLI), création du compte Neon Postgres gratuit (la seule dépendance obligatoire), génération des secrets, pnpm install, migrations Prisma. Compte ~5-10 min, principalement à attendre les installs.
Pour le détail (déploiement Vercel, surfaces optionnelles) : voir WORKFLOW.md.
Pré-requis avant de taper /setup-kit : avoir Claude Code installé (CLI ou extension dans VS Code / Cursor / Windsurf / Antigravity — tous les forks VS Code marchent à l'identique).
Le starter est cloud-only par design — aucun conteneur local, aucun daemon à installer. Neon est le provider Postgres par défaut : le kit est tuned pour son comportement serverless (le handler de webhooks évite le plafond de tx 2s en sortant les side-effects vers l'outbox, la mitigation timing-attack de /forgot-password calibre son floor à 350ms sur la base de la latence Neon-pooler, et un tripwire CI verrouille .env.example au format Neon).
git clone <fork-url> my-project
cd my-project
cp .env.example frontend/.env.local # remplis DATABASE_URL, JWT_SECRET, ENCRYPTION_KEY, CRON_SECRET au minimum
pnpm install
pnpm db:migrate:deploy # applique les migrations versionnées sur ta DB Neon
pnpm dev # http://localhost:3001
# dans un autre terminal, après le premier signup :
pnpm db:make-superadmin [email protected]
pnpm smoke:auth # vérifie le happy path auth de bout en bout
Pour obtenir DATABASE_URL + DIRECT_URL : crée un projet gratuit sur https://neon.tech, puis copie deux strings depuis le dashboard — la version avec -pooler dans le hostname comme DATABASE_URL (avec ?pgbouncer=true&connection_limit=1&pool_timeout=15&sslmode=require) et la version sans -pooler comme DIRECT_URL. Exemples dans .env.example.
app/api/<resource>/route.ts + Server Actions ; tout dans une seule app-pooler + DIRECT_URL pour les migrations)arctic, un provider de paiement mobile-money (Bictorys par défaut, en cours de bascule vers Chariow)@sentry/nextjs (instrumentation.ts + sentry.{client,server,edge}.config.ts) — no-op silencieux sans SENTRY_DSN ; @vercel/otel pour les traces distribuéesfrontend/), Vitest, ESLint 9 flat config, Prettier, Node 20+| Variable | Rôle |
|---|---|
DATABASE_URL | URL pooler Neon (?pgbouncer=true&connection_limit=1&pool_timeout=15&sslmode=require) |
DIRECT_URL | URL Neon directe (non-poolée) pour prisma migrate |
JWT_SECRET | ≥32 chars, générer avec openssl rand -base64 32 |
ENCRYPTION_KEY | 32 bytes base64, générer avec openssl rand -base64 32 |
CRON_SECRET | Bearer token requis par les handlers /api/cron/* ; openssl rand -base64 32 |
APP_URL | Utilisé pour la génération des liens email et la base de redirect OAuth ; défaut http://localhost:3001 |
Groupes optionnels (set les vars pour activer ; absent = inerte) :
| Groupe | Vars | Comportement quand absent |
|---|---|---|
| Storage (Cloudinary) | CLOUDINARY_CLOUD_NAME, CLOUDINARY_API_KEY, CLOUDINARY_API_SECRET, CLOUDINARY_UPLOAD_PRESET? | /api/upload renvoie 503 |
| Email (Resend) | RESEND_API_KEY, EMAIL_FROM | Les lignes en queue email s'accumulent mais ne partent jamais (drainage au cron suivant dès que la clé arrive) |
| Paiements (Bictorys — en cours de bascule vers Chariow) | BICTORYS_API_KEY, BICTORYS_PRIVATE_KEY, BICTORYS_WEBHOOK_SECRET, BICTORYS_MERCHANT_SECRET_CODE | /api/orders et /api/webhooks/bictorys renvoient 404 ; circuit breaker reste CLOSED. Actuellement vide dans ce projet — paiement patient non configuré. |
| Google OAuth | GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI | /api/auth/oauth/google/* renvoient 404 |
| Sentry | SENTRY_DSN, NEXT_PUBLIC_SENTRY_DSN, SENTRY_TRACES_SAMPLE_RATE?, ... | No-op silencieux (zéro coût perf) |
| Upstash Redis | UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN | Fallback rate-limit en mémoire avec logger.warn au boot — NE PAS lancer en prod sans Upstash |
Référence env complète avec toutes les flags : voir .env.example à la racine du repo.
74 routes sous frontend/src/app/api/. Toutes déclarent export const runtime = 'nodejs' (enforced par frontend/src/lib/server/observability/runtime-enforcement.test.ts).
| Famille | Routes | Détail |
|---|---|---|
Auth (/api/auth/*) | 12 | signup, login, logout, refresh, refresh-and-return, me, verify-email, resend-verification, forgot-password, reset-password, set-password, change-password |
| OAuth Google | 2 | /api/auth/oauth/google/{start,callback} |
| Notifications | 3 | liste + mark-read, count, prefs |
| Orders / paiement patient | 2 | /api/orders, /api/pay-redirect (inertes sans BICTORYS_*) |
| Uploads | 1 | /api/upload (503 sans Cloudinary) |
| Webhooks | 1 | /api/webhooks/bictorys (HMAC provider + replay window 60s) |
Cron (toutes Authorization: Bearer ${CRON_SECRET}) | 7 | outbox-drain (1min), email-queue-drain (1min), verification-cleanup (horaire), order-expiration (5min), webhook-log-purge (quotidien), email-job-purge (quotidien), subscription-billing (quotidien 06h) |
| Health | 2 | /api/health (liveness), /api/readyz (readiness) |
| Patients | 4 | CRUD dossier + sous-ressources consultations, maternite |
| Consultations | 2 | liste/filtre cross-patient + /[id] (annulation) |
| Registres | 8 | clôture mensuelle consultation (2) + maternité CPN/Accouchement/CPoN (6 — CPoN scaffoldée, inactive) |
| Maternité (listing cross-patient) | 1 | /api/maternite — CPN/Accouchement actives en V1, CPoN scaffoldée |
| Organizations (self-service centre) | 5 | org courante, membres (+ rôle), consultants |
| Facturation (abonnement SaaS) | 2 |
Shapes complètes des requêtes/réponses : lis les route handlers sous frontend/src/app/api/. Les route handlers SONT le contrat.
pnpm smoke:auth lance frontend/scripts/smoke-auth.ts contre un pnpm dev qui tourne. Le script fait un signup, lit le code de vérification dans la DB via Prisma, vérifie l'email, appelle GET /api/auth/me, et déconnecte. Exit 0 sur succès complet ; 1 + log descriptif sur n'importe quel échec.
Override la cible avec SMOKE_BASE_URL pour les déploiements preview :
SMOKE_BASE_URL=https://my-preview.vercel.app pnpm smoke:auth
Le smoke script demande DATABASE_URL et JWT_SECRET set (il lit le code de vérification directement via Prisma — pas d'endpoint /api/test/peek-code). Pas dans la CI ; UAT manuel uniquement.
frontend/ comme root directory (le projet est un workspace pnpm ; Vercel auto-détecte via pnpm-workspace.yaml).frontend/vercel.json déclare les 7 schedules cron — Vercel les enregistre automatiquement au deploy. Aucun setup additionnel.next build si SENTRY_ORG / SENTRY_PROJECT / SENTRY_AUTH_TOKEN sont définis comme build-time env vars.next.config.ts l'active) ; aucune config supplémentaire.frontend/instrumentation.ts et les fichiers sentry.*.config.ts — lis-les pour les détails d'ordre des hooks.Contrairement au starter d'origine (qui ne ship aucune UI), MediAfrica a sa propre interface complète : landing page publique (frontend/src/app/page.tsx), auth (login/signup/verify-email/forgot-reset-password), app staff (dashboard, patients, consultations, registres, commentaires, personnel, facturation, paramètres), back-office admin (/admin/* — vue d'ensemble, utilisateurs, centres, abonnements, plans, transactions, signalements, audit-log, configuration).
AuthProvider/ToastProvider.Aucune lib serveur ne touche au DOM. Les routes renvoient NextResponse.json(...) uniquement — le contrat JSON reste swappable vers un autre client si besoin.
| Skill | Phrases déclencheuses | Ce qu'elle fait |
|---|---|---|
setup-kit | « /setup-kit », « je débute », « qu'est-ce que je dois installer » | Audit Git / Node / pnpm / gh CLI / env vars / Claude Code surface, blocker explicite si l'user a téléchargé le ZIP au lieu de cloner, install paste-ready des plugins manquants, Neon en provider Postgres par défaut. |
banani-design-implementation | « build this from Banani », « use the Banani MCP », « reproduce this screen » | Reproduction pixel-perfect 1:1 des écrans Banani sélectionnés via MCP (optionnel). |
ui-ux-pro-max | « design », « build », « improve », « review UI » + élément/composant | Design intelligence searchable : styles, palettes, paires de fonts, guidelines UX, charts. Intégration MCP shadcn/ui. |
izisaas-payments-handler | « intégrer Stripe », « ajouter Moneroo », « swap Bictorys pour Chariow », « webhook signature failure » | Référence complète pour swap/ajout de provider de paiement (signature verification, idempotent fulfillment, credentials AES-256-GCM). Pertinent dès que la bascule Chariow est prête à démarrer. |
MediAfrica/
├── frontend/ L'app Next.js 16 (full-stack)
│ ├── prisma/ schema.prisma + migrations
│ ├── scripts/ make-superadmin.ts, seed-dev.ts, smoke-auth.ts (via tsx)
│ ├── vercel.json schedules cron (7 entrées)
│ ├── .env.example référence env
│ └── src/
│ ├── app/
│ │ ├── api/ route handlers (74 routes)
│ │ ├── admin/ back-office plateforme
│ │ ├── patients/, consultations/, registres/, commentaires/,
│ │ │ facturation/, personnel/, settings/, dashboard/ pages staff
│ │ └── (auth pages) login/, signup/, verify-email/, ...
│ └── lib/
│ ├── api.ts browser fetch wrapper (PROTÉGÉ)
│ └── server/ libs server-only : auth, crypto, payments, oauth,
│ webhook, outbox, cron, subscriptions/, admin/,
│ registers/, pagination/, ...
├── examples/frontend-pages/ UIs de référence du starter (non utilisées par l'app)
├── .planning/ features.json (manifeste pruning, hérité du starter)
├── pnpm-workspace.yaml workspace = frontend/ seulement
└── package.json scripts orchestrateurs (proxy `pnpm --filter frontend ...`)
| Sujet | Statut |
|---|---|
| Paiement des patients | Interface PaymentProvider prête, Bictorys non configuré — en attente de bascule vers Chariow |
| Module Maternité — CPoN (post-natal) | Code scaffoldé (schéma, routes, pages), volontairement caché de la navigation — prévu V2/V3 |
| Circuit breaker distribué | Limite single-instance côté paiements ; à remplacer par une variante Redis en multi-instance |
| Framework de test frontend (Playwright / RTL) | Vitest couvre lib/server/** + routes ; pas de tests UI automatisés |
| i18n au-delà du français / FCFA | Non prévu à ce stade |
| TOTP / 2FA | Non implémenté |
Ce sont les règles que chaque session Claude doit respecter — voir CLAUDE.md pour la liste complète. Version courte :
runtime = 'nodejs' (CI-enforced)req.arrayBuffer() AVANT tout JSON parse (intégrité HMAC)createNotification(prisma, input) — jamais prisma.notification.create directementenqueueOutbox(tx, event) — jamais fire-and-forgetAuthorization: Bearer ${CRON_SECRET}email_verified !== truelogAdminAction(prisma, {...}) — bypass = régression compliancerequireActiveSubscription(organizationId) — un centre PAST_DUE/CANCELED perd l'accès (402) jusqu'à régularisationRegisterClosure) refuse toute nouvelle écriture pour le mois concerné (409 REGISTER_CLOSED)api() frontend retry uniquement GET/HEAD sur erreur réseauUNLICENSED — usage privé.
/api/billing/{subscription,pay} |
| Commentaires | 1 | /api/reports |
| Settings | 1 | /api/settings/clinic |
Admin (/api/admin/*) | 20 | me, users (+role/status), organizations (+membres), orders, audit-log, outbox, email-queue, rate-limits, stats, plans, subscriptions, reports |