Aller au contenu principal

Architecture

Vue d'ensemble de la structure technique de HeartCo.

Schéma global

┌─────────────────────────────────────────────────────────┐
│                     Client (Browser)                     │
│              Next.js App Router + React 19               │
└────────────────────────┬────────────────────────────────┘
                         │ tRPC (HTTP / WebSocket)
┌────────────────────────▼────────────────────────────────┐
│                   Serveur Next.js                        │
│  ┌──────────┐  ┌──────────┐  ┌────────────────────┐    │
│  │ NextAuth │  │  tRPC    │  │  API Routes        │    │
│  │   v5     │  │ Routers  │  │  (webhooks, crons) │    │
│  └────┬─────┘  └────┬─────┘  └────────┬───────────┘    │
│       │              │                  │                │
│  ┌────▼──────────────▼──────────────────▼───────────┐   │
│  │              Prisma 7 (ORM)                       │   │
│  │         generated/prisma/ (client)                │   │
│  └──────────────────────┬───────────────────────────┘   │
└─────────────────────────┼───────────────────────────────┘
                          │ SQL
┌─────────────────────────▼───────────────────────────────┐
│              Supabase PostgreSQL                         │
│         (pgBouncer pour le pooling)                      │
└─────────────────────────────────────────────────────────┘

Services externes

Stripe ───────── Paiements, abonnements, webhooks
Resend ───────── Envoi d'emails transactionnels
Mistral AI ───── Copilote IA, génération, analyse
Pusher ───────── Temps réel (chat, notifications)
Upstash Redis ── Cache, rate limiting, locks distribués
Bridge API ───── Connexion bancaire (agrégation)
Iopole ───────── E-facturation B2B (Factur-X)
Google/Microsoft OAuth + Calendar + Drive

Arborescence des dossiers

src/
├── app/                          # Pages (Next.js App Router)
│   ├── (admin)/                  # Panel d'administration
│   ├── (examples)/               # Templates d'exemple (dashboard, landing)
│   ├── (legal)/                  # Pages légales (CGU, CGV, confidentialité)
│   ├── (marketing)/              # Pages marketing (about, showcase)
│   ├── (public)/                 # Pages publiques (désabonnement)
│   ├── dashboard/                # Application SaaS principale
│   │   ├── agenda/               # Calendrier
│   │   ├── analytics/            # Tableaux de bord
│   │   ├── clients/              # Gestion clients
│   │   ├── copilote/             # Assistant IA
│   │   ├── crm/                  # Pipeline commercial
│   │   ├── facturation/          # Factures
│   │   ├── devis/                # Devis
│   │   ├── comptabilite/         # Comptabilité
│   │   ├── equipe/               # Gestion d'équipe
│   │   ├── rh/                   # Ressources humaines
│   │   ├── parametres/           # Paramètres
│   │   └── ...                   # 37 modules au total
│   ├── api/                      # API Routes
│   │   ├── auth/                 # NextAuth + routes auth custom
│   │   ├── cron/                 # 11 tâches planifiées
│   │   ├── webhooks/             # Webhooks (Stripe, Iopole, Resend)
│   │   ├── trpc/                 # Endpoint tRPC
│   │   └── ...
│   ├── login/                    # Page de connexion
│   ├── register/                 # Inscription
│   ├── onboarding/               # Onboarding post-inscription
│   └── portal/                   # Portail client
│
├── components/                   # Composants React
│   ├── ui/                       # Primitives (shadcn/Radix)
│   ├── layout/                   # Layout (sidebar, topbar)
│   ├── landing/                  # Composants landing page
│   └── <feature>/                # Composants par feature
│
├── lib/                          # Utilitaires et logique métier
│   ├── ai/                       # Mistral AI (service, prompts, tools)
│   ├── config/                   # Branding, configuration app
│   ├── emails/                   # Templates email (Resend)
│   ├── freemium/                 # Limites et guards freemium
│   ├── navigation/               # Configuration sidebar
│   ├── permissions/              # Matrice RBAC
│   ├── prisma-org-scope.ts       # Isolation multi-tenant
│   ├── rate-limit.ts             # Rate limiting (Redis)
│   ├── redis.ts                  # Client Upstash Redis
│   ├── stripe-plan.ts            # Plans et pricing Stripe
│   └── utils.ts                  # cn(), helpers généraux
│
├── modules/                      # Modules métier certifiés
│   ├── bridge/                   # Intégration bancaire
│   ├── facturx/                  # E-facturation (NE PAS MODIFIER)
│   └── iopole/                   # E-facturation B2B (NE PAS MODIFIER)
│
├── server/                       # Couche serveur
│   ├── api/
│   │   ├── root.ts               # Registre de tous les routers
│   │   ├── trpc.ts               # Procédures et middlewares
│   │   └── routers/              # ~75 routers tRPC
│   ├── auth/
│   │   └── config.ts             # Configuration NextAuth v5
│   └── db.ts                     # Instance Prisma
│
└── styles/
    └── globals.css               # Tailwind v4 + tokens CSS

Path alias

HeartCo utilise le path alias ~/ qui pointe vers ./src/ :

// Au lieu de :
import { cn } from "../../../lib/utils";
 
// Écrire :
import { cn } from "~/lib/utils";

Configuré dans tsconfig.json :

{
  "compilerOptions": {
    "paths": {
      "~/*": ["./src/*"],
      "generated/prisma": ["./generated/prisma"]
    }
  }
}

Route Groups (App Router)

Next.js App Router utilise des route groups (dossiers entre parenthèses) pour organiser les pages sans affecter l'URL :

GroupeURLUsage
(admin)/admin/*Panel admin (challenge 2FA)
(examples)Templates démo (pas de route publique)
(legal)/cgu, /cgv, ...Pages légales
(marketing)/about, /showcasePages marketing
(public)/unsubscribed, ...Pages publiques sans auth
dashboard/dashboard/*Application SaaS principale

Procédures tRPC

Les routers tRPC utilisent des procédures avec des niveaux d'accès croissants :

ProcédureAccèsUsage
publicProcedureTout le mondePages publiques, contact, booking
protectedProcedureAuthentifié (tous rôles)Profil, portail client
staffProcedureAuthentifié, rôle ≠ CLIENTToutes les features internes
managerProcedureADMIN, DIRECTION, MANAGER, HRGestion d'équipe, RH
adminProcedureADMIN uniquementParamètres critiques
requirePermission("x:y")staffProcedure + permission RBACAccès granulaire
requireAnyPermission([...])staffProcedure + au moins 1 permissionAccès multi-permission

Exemple d'utilisation

// Router facturation — nécessite la permission "facturation:create"
export const facturationRouter = createTRPCRouter({
  create: requirePermission("facturation:create")
    .input(createInvoiceSchema)
    .mutation(async ({ ctx, input }) => {
      const invoice = await ctx.orgDb.invoice.create({
        data: {
          ...input,
          organizationId: ctx.session.user.organizationId,
        },
      });
      return invoice;
    }),
});

Routers tRPC

75 routers sont enregistrés dans src/server/api/root.ts :

search, permissions, facturation, clients, crm, organization, members, devis,
products, comptabilite, rh, onboarding, notesDefrais, workOrders, workReports,
suppliers, payslips, employeeProfiles, payslipTemplates, contributionRates,
ideas, mood, teams, notifications, freemium, marketplace, portal, recouvrement,
signatures, suggestions, reportTemplates, reports, conversations, messages,
calendars, calendarEvents, calendarPermissions, chatbot, itineraires, blog,
projets, analytics, timesheets, appointments, publicBooking, leaveTypes,
leaveBalances, publicHolidays, leavePolicy, recurringInvoices, facturx, iopole,
iso20022, settings, dashboard, okrs, trial, marketing, adminEmail,
userPreferences, automation, deliveryNotes, bank, tickets, timeLogs, stock,
pushTokens, socialContent, regulatoryAssistant, copilote, testMode, betaCode,
adminPromoCode, contactForm

Conventions TypeScript

  • Strict mode activé avec noUncheckedIndexedAccess: true
  • Type imports obligatoires : import { type Foo } ou import type { Foo }
  • Path alias : ~/ pour tous les imports depuis src/
  • Pas de any : utiliser unknown + type guards
  • Langue : noms de variables/types en anglais, textes UI en français