Some checks are pending
CI / Lint bridge (Biome) (push) Waiting to run
CI / Type-check bridge (push) Blocked by required conditions
CI / Tests unit bridge (push) Blocked by required conditions
CI / Tests integration bridge (push) Blocked by required conditions
CI / Security scan (push) Waiting to run
CI / Docker build + healthcheck (push) Blocked by required conditions
Pivot strategique : DocAdenice = produit Notion-like generique. Le bridge
est livre vide a un user qui cree ses tables Baserow comme il veut. Code
sans aucune ontologie metier.
Suppressions :
- 9 entites domain metier (Personne, Formation, Bloc, Module, Attribution,
Client, Projet, Tache, Intervention) + types.ts (Role, statuts)
- baserow-repo.ts (mega-fichier 554 LOC avec 9 repos heritant BaseRepo)
- 6 routes metier (personnes, formations, projets, modules, interventions,
attributions) + tests associes
- Lookup PersonneRepo.findByEmail dans middleware auth
- Mapping DEFAULT_ROLE_SCOPES dans middleware/scopes.ts
- Cascade rollup metier dans webhooks/baserow-handler.ts
Ajouts :
- Domain generique : Table, Row, Field, View + schemas zod refondus
- 4 repos generiques : tables / rows / fields / views
- Route unique routes/tables.ts avec 9 endpoints REST CRUD generiques
- Claim JWT acadenice_permissions[] lu directement dans le middleware auth
(alimente par RBAC dynamique cote DocAdenice en R2)
- examples/acadenice-formation-hub/ : README + seed-baserow.md schema
9 tables + example-roles.md (Formateur, Developpeur, Direction, Support,
Admin avec permissions generiques)
Refactors :
- BaserowClient etendu : listTables, getTable, listFields, listViews,
getGridViewRows
- middleware/auth.ts : extractPermissions(payload), AuthenticatedUser
remplace roles[] par permissions[]
- middleware/scopes.ts : computeOidcScopes(groups, permissions, map)
- webhooks/baserow-handler.ts : invalidation generique
bridge:tables:<tableId>:* sans cascade cross-table
- lib/cache.ts : invalidateEntity -> invalidateTable(redis, tableId, rowId?)
- container.ts : drop tableIds, RepoSet={tables, rows, fields, views}
- 501 NOT_IMPLEMENTED si DB token sur endpoints /tables qui exigent JWT
Tests : 250/250 verts (depuis 319). Coverage : domain 98.9%, adapters 89%,
auth 97.08%, rate-limit 100%, cache 100%, webhooks 100%.
Quality gates verts : typecheck, lint biome, vitest, coverage thresholds.
Refs: R1 dans le pivot strategique DocAdenice Notion-like generique.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
157 lines
10 KiB
Markdown
157 lines
10 KiB
Markdown
# Seed Baserow — schema formation-hub Acadenice
|
||
|
||
Schema reference des 9 tables Baserow pour cet exemple metier.
|
||
|
||
> Ce document decrit le **modele** que l'utilisateur cree dans son Baserow.
|
||
> Le bridge ne sait rien de tout cela : il proxie generique. Le code de
|
||
> seeding (Python ou autre) peut venir plus tard ; c'est la mise en oeuvre
|
||
> typique de la doc 19 Bridge API design (cas Acadenice).
|
||
|
||
## Database
|
||
|
||
- Workspace : `Acadenice`
|
||
- Database : `formation-hub`
|
||
- 9 tables au singulier
|
||
|
||
## Table Personne
|
||
|
||
Pivot multi-roles. Capacite annuelle d'heures splittee entre formation et
|
||
agence.
|
||
|
||
| Field name | Type | Notes |
|
||
|-------------------------------------|-----------------------------------|----------------------------------------------------|
|
||
| `personne_nom` | text (primary) | |
|
||
| `personne_prenom` | text | |
|
||
| `personne_email` | text (email) | Unique. Lie au sub Authentik via DocAdenice. |
|
||
| `personne_telephone` | text | Optionnel. |
|
||
| `personne_capacite_annuelle` | number | Heures annuelles theoriques (ex 1500). |
|
||
| `personne_split_formation_pct` | number | 0-100. Doit sommer 100 avec split_agence. |
|
||
| `personne_split_agence_pct` | number | 0-100. |
|
||
| `personne_roles` | multi_select | Choix : formateur, developpeur, admin, direction, support |
|
||
| `personne_statut` | single_select | actif / inactif |
|
||
| `personne_heures_attribuees_formation` | formula (rollup sum attributions) | Auto. |
|
||
| `personne_heures_attribuees_agence` | formula (rollup sum interventions)| Auto. |
|
||
| `personne_heures_restantes_formation` | formula | capacite × split_formation_pct - heures_attribuees |
|
||
|
||
## Table Formation
|
||
|
||
| Field name | Type | Notes |
|
||
|-----------------------------|----------------|--------------------------------|
|
||
| `formation_nom` | text (primary) | |
|
||
| `formation_filiere` | single_select | dev, graphisme, marketing, iot, cybersec |
|
||
| `formation_heures_totales` | number | |
|
||
| `formation_statut` | single_select | draft, actif, termine, archive |
|
||
| `formation_date_debut` | date | |
|
||
| `formation_date_fin` | date | |
|
||
| `formation_heures_attribuees` | formula | Sum rollup blocs.heures_prevues |
|
||
|
||
## Table Bloc
|
||
|
||
Decoupage pedagogique d'une Formation.
|
||
|
||
| Field name | Type | Notes |
|
||
|------------------------|-----------------------------|----------------------|
|
||
| `bloc_nom` | text (primary) | |
|
||
| `bloc_formation` | link_row -> Formation | FK obligatoire. |
|
||
| `bloc_heures_prevues` | number | |
|
||
| `bloc_ordre` | number | |
|
||
|
||
## Table Module
|
||
|
||
Brique elementaire d'un Bloc, attribuable a une Personne.
|
||
|
||
| Field name | Type | Notes |
|
||
|-------------------------|---------------------|------------------------------------|
|
||
| `module_nom` | text (primary) | |
|
||
| `module_bloc` | link_row -> Bloc | |
|
||
| `module_heures_prevues` | number | |
|
||
| `module_statut` | single_select | a_attribuer, attribue, en_cours, realise, annule |
|
||
| `module_heures_attribuees` | formula | Sum rollup attributions. |
|
||
| `module_heures_realisees` | formula | Sum rollup attributions. |
|
||
|
||
## Table Attribution
|
||
|
||
Lien Module <-> Personne[role=formateur] avec heures et statut.
|
||
|
||
| Field name | Type | Notes |
|
||
|----------------------------------|-----------------------|----------------------|
|
||
| `attribution_module` | link_row -> Module | |
|
||
| `attribution_personne` | link_row -> Personne | role=formateur exige cote DocAdenice |
|
||
| `attribution_heures_attribuees` | number | RG-01 : sum <= module.heures_prevues |
|
||
| `attribution_heures_realisees` | number | Saisi par le formateur |
|
||
| `attribution_date_debut` | date | |
|
||
| `attribution_date_fin` | date | |
|
||
| `attribution_statut` | single_select | planifie, en_cours, realise, annule |
|
||
|
||
## Table Client
|
||
|
||
| Field name | Type | Notes |
|
||
|-------------------------|----------------|-----------------------------------------------|
|
||
| `client_nom` | text (primary) | |
|
||
| `client_contact_principal` | text | |
|
||
| `client_contact_email` | text (email) | |
|
||
| `client_contact_telephone` | text | |
|
||
| `client_secteur` | text | |
|
||
| `client_notes` | long_text | |
|
||
| `client_statut` | single_select | prospect, actif, inactif, archive |
|
||
|
||
## Table Projet
|
||
|
||
| Field name | Type | Notes |
|
||
|-------------------------------|----------------------------|------------------------------------------|
|
||
| `projet_nom` | text (primary) | |
|
||
| `projet_client` | link_row -> Client | |
|
||
| `projet_type` | single_select | site_web, app_mobile, api, infra, audit, support, autre |
|
||
| `projet_charge_heures` | number | Devis valide. |
|
||
| `projet_statut` | single_select | devis, en_cours, livre, cloture, abandonne |
|
||
| `projet_formation_pedagogique`| link_row -> Formation | Optionnel. Lien projet pedagogique. |
|
||
| `projet_heures_realisees` | formula | Sum rollup taches.heures_realisees |
|
||
|
||
## Table Tache
|
||
|
||
| Field name | Type | Notes |
|
||
|-------------------------|-----------------------|----------------------------------------|
|
||
| `tache_titre` | text (primary) | |
|
||
| `tache_projet` | link_row -> Projet | |
|
||
| `tache_charge_heures` | number | |
|
||
| `tache_priorite` | single_select | faible, normale, haute, critique |
|
||
| `tache_statut` | single_select | todo, in_progress, review, done, abandoned |
|
||
| `tache_heures_realisees`| formula | Sum rollup interventions.heures |
|
||
|
||
## Table Intervention
|
||
|
||
Lien Tache <-> Personne[role=developpeur] avec heures saisies.
|
||
|
||
| Field name | Type | Notes |
|
||
|-------------------------|------------------------|--------------------------------------|
|
||
| `intervention_tache` | link_row -> Tache | |
|
||
| `intervention_personne` | link_row -> Personne | role=developpeur exige cote DocAdenice |
|
||
| `intervention_heures` | number | > 0 |
|
||
| `intervention_date` | date | |
|
||
| `intervention_notes` | long_text | Optionnel. |
|
||
| `intervention_statut` | single_select | planifie, realise, annule |
|
||
|
||
## Webhooks Baserow vers le bridge
|
||
|
||
Configurer un webhook par table (ou un seul global selon la version Baserow)
|
||
qui pointe sur `POST /api/webhooks/baserow` du bridge avec :
|
||
- header `X-Baserow-Signature: <hmac-sha256-hex>`
|
||
- secret partage via env `BASEROW_WEBHOOK_SECRET` du bridge
|
||
|
||
Le bridge invalidera juste `bridge:tables:<tableId>:*` — sans cascade
|
||
metier. Si vous avez besoin de mettre a jour une table parente, posez une
|
||
formule Baserow qui fait le rollup ; Baserow emettra son propre webhook
|
||
quand la formule recalcule.
|
||
|
||
## Regles de gestion principales (RG)
|
||
|
||
Ces regles vivent **cote frontend / DocAdenice** — pas dans le bridge.
|
||
|
||
| Code | Regle |
|
||
|--------|------------------------------------------------------------------------------|
|
||
| RG-01 | Sum(attributions.heures_attribuees) <= module.heures_prevues |
|
||
| RG-02 | personne.split_formation_pct + split_agence_pct = 100 |
|
||
| RG-03 | Attribution exige personne.role contient 'formateur' |
|
||
| RG-04 | Intervention exige personne.role contient 'developpeur' |
|
||
| RG-05 | personne.heures_attribuees_formation <= capacite × split_formation_pct |
|
||
| RG-06 | personne.heures_attribuees_agence <= capacite × split_agence_pct |
|