docs(concepts): migrate project docs into 7 concepts + code-grounded audit
Migrate .project/{knowledge,decisions,briefs} and the always-loaded
AGENTS.md/CLAUDE.md into the in-repo `concept` system (hook-delivered,
typed leaves). Then audit the actual code to verify the migrated doctrine
and capture knowledge that lived only in the source.
Concepts (53 leaves):
- functional-domain — produit : point de rencontre greffé, acteurs, déduplication
- app-architecture — modules, invariant d'imports, routing, écrans, styling-system,
screen-pattern, cookbook d'ajout d'écran
- tech-stack — Bun-first, APIs, build pipeline, deployment (Dockerfile), commandes
- data-layer — NextGraph mono-store, shapes, modes, règles + caveats (suppression,
champs non persistés, internals du contexte)
- bdd-testing — Cucumber multi-couches, contrat de couches, harness, cookbook
- app-security — posture actuelle (mono-store, confiance broker), auth wallet,
brief matrice d'autorisations cible
- nextgraph-platform — NextGraph système externe + briefs (multi-store, shim, fork)
Audit corrections:
- décision SPARQL-delete annulée (superseded) → caveat (le code utilise ngSet.delete,
persistance possiblement partielle)
- divergences relevées : routing path-based (pas hash), thème moderne sous components/sketchy,
ConnectScreen hors registre, build:orm au chemin périmé, champs d'event perdus en connecté
Strip migrated sources; AGENTS.md/CLAUDE.md réduits au cœur (but, invariants,
carte des concepts) + pointeurs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
---
|
||||
type: _overview
|
||||
summary: Sécurité & confidentialité de Festipod — posture ACTUELLE (mono-store, confiance broker, aucun contrôle d'accès côté app) et modèle d'autorisations CIBLE (incubation) ; authentification par wallet NextGraph
|
||||
triggers:
|
||||
keywords: [sécurité, security, confidentialité, privacy, accès, "access control", contrôle d'accès, trust, confiance, authz, autorisation, permission, wallet, auth, authentification, anonyme, identité, login]
|
||||
paths: ["src/modules/auth/**", "src/shared/context/NextGraphContext.tsx"]
|
||||
---
|
||||
|
||||
# App security
|
||||
|
||||
Le modèle de **sécurité, confidentialité et autorisations** de Festipod. Le pilier se lit en deux temps :
|
||||
|
||||
- **Actuel** — ce que le code applique aujourd'hui : voir [[knowledge_trust-model]]. Résumé brutal : **aucun contrôle d'accès côté app**, l'app affiche le `private_store` de l'utilisateur connecté et fait confiance au broker. Mono-user de fait.
|
||||
- **Cible** — le modèle d'autorisations dérivé (qui peut faire quoi, données personnelles = réseau, anonymat via inbox) : [[brief_2026-05-18_authorization-matrix]]. **Incubation, non implémenté.** Il graduera en `rule_`/`behavior_` quand le multi-user atterrira (chantiers data dans le concept `nextgraph-platform`).
|
||||
|
||||
L'écart entre les deux est volontaire : tant que l'app est mono-store (cf. concept `data-layer`), il n'y a rien à autoriser côté app.
|
||||
|
||||
## Liens
|
||||
|
||||
- [[knowledge_trust-model]] — posture de sécurité actuelle (mono-store, confiance broker, pas d'enforcement app)
|
||||
- [[knowledge_authentication]] — auth par wallet NextGraph, tous authentifiés, pas d'accès anonyme
|
||||
- [[brief_2026-05-18_authorization-matrix]] — modèle d'autorisations cible (incubation)
|
||||
- `nextgraph-platform` — les primitives (stores, capabilities, inbox) et les chantiers data qui porteront la cible
|
||||
@@ -0,0 +1,143 @@
|
||||
---
|
||||
type: brief
|
||||
summary: Matrice d'autorisations par type de donnée (PdR, inscription, événement, profil, connexion) ; dérive que 3 stores natifs par utilisateur + Dialog stores suffisent, aucun Group store sur le périmètre validé ; questions ouvertes sur modèle d'écriture événement et identité de l'hôte
|
||||
last_updated: 2026-05-18
|
||||
---
|
||||
|
||||
# Matrice d'autorisations et inventaire des requêtes
|
||||
|
||||
**Status:** Incubating — analyse en cours
|
||||
**Last updated:** 2026-05-18
|
||||
|
||||
## Context
|
||||
|
||||
Préalable au refactor multi-store ([[brief_2026-05-17_multi-store-refactor]]) et à toute évolution multi-user. La structure de stores NextGraph cible doit être *dérivée* de : (1) une matrice d'autorisations ; (2) un inventaire des requêtes par écran ; (3) les partitions naturelles qui en découlent (données partageant autorisations *et* schéma d'accès).
|
||||
|
||||
C'est aussi le **modèle de confidentialité/sécurité** de Festipod (pilier sécurité), non encore implémenté.
|
||||
|
||||
## Cadre
|
||||
|
||||
### Acteurs (tous authentifiés)
|
||||
|
||||
`Alice` (point de vue, propriétaire de la donnée en focus) · `Bob` (second protagoniste, relations bilatérales) · `D` (déclarant d'événement) · `H` (hôte d'un PdR) · `I` (inscrit) · `C` (connexion) · `U` (utilisateur lambda sans relation).
|
||||
|
||||
### Verbes
|
||||
|
||||
`créer` · `lire` (one-shot) · `s'abonner` (lecture réactive) · `modifier` · `supprimer`. Conventions : `✓` autorisé · `✗` interdit · `cond` sous condition · `—` sans objet.
|
||||
|
||||
## Décisions cadre (acquises)
|
||||
|
||||
- **Tous authentifiés.** Pas d'accès anonyme.
|
||||
- **Points de rencontre publics universels.** Tout utilisateur peut lire et s'abonner.
|
||||
- **Création de PdR ouverte à tous.** Pas de prérequis.
|
||||
- **Hôte = détenteur des droits d'écriture** sur un PdR (1 hôte, le créateur ; le fait d'être hôte est public).
|
||||
- **Informations personnelles = réservées au réseau.** Visibles seulement au titulaire et à ses connexions : participations, intégralité du profil, liste de connexions, et tout état déclaratif dont la divulgation serait une fuite. Statut « public » (PdR, événement) et « personnel » (profil, participations, connexions) coexistent dans le même utilisateur.
|
||||
- **Connexion bilatérale.** Existe après acceptation des deux côtés. Deux objets : `DemandeDeConnexion` (unilatérale, transitoire) et `Connexion` (bilatérale, persistante).
|
||||
- **Notification d'inscription via l'inbox NextGraph du PdR.** L'acte « s'inscrire » est composite : (a) écriture d'un objet `Inscription` dans le `protected_store` de l'inscrit, (b) dépôt d'un lien (DID cap) dans l'**inbox** du document PdR. Identification du sender par résolution du DID contre le graphe de connexions de l'hôte : connexion → inscription complète visible ; sinon → lien opaque (« quelqu'un (DID…) s'est inscrit »). Anonymat partiel **natif aux capabilities** (cf. [[knowledge_stores-permissions]] §Inbox).
|
||||
- **Adhésion à une communauté / suivi : hors périmètre actuel.**
|
||||
|
||||
## Matrice par type de donnée
|
||||
|
||||
### Point de rencontre
|
||||
|
||||
| Verbe | Alice (= Hôte) | I (autre inscrit) | D (déclarant parent) | U (lambda) |
|
||||
|---|---|---|---|---|
|
||||
| créer | ✓ (rend hôte) | — | ✗ | ✓ (rend hôte) |
|
||||
| lire | ✓ | ✓ | ✓ | ✓ |
|
||||
| s'abonner | ✓ | ✓ | ✓ | ✓ |
|
||||
| modifier | ✓ | ✗ | ✗ | ✗ |
|
||||
| supprimer | ✓ | ✗ | ✗ | ✗ |
|
||||
|
||||
Notes : pas de différenciation `C` (les connexions sont un filtre d'affichage UI, pas un droit, tout étant public). Le `D` n'a aucun droit particulier sur les PdR greffés sur son événement.
|
||||
|
||||
### Inscription à un point de rencontre
|
||||
|
||||
`Inscription` lie un utilisateur et un PdR. **Donnée personnelle** (inscrit + ses connexions). Acte composite (a)+(b) ci-dessus.
|
||||
|
||||
| Verbe | Alice (inscrite) | C (connexion) | H (hôte) | I (autre inscrit) | U |
|
||||
|---|---|---|---|---|---|
|
||||
| créer (acte composite) | ✓ | — | ✗ | ✗ | ✓ (rend inscrite) |
|
||||
| lire le contenu | ✓ | ✓ | cond : ✓ si H ∈ connexions(Alice) ; sinon lien opaque | cond : ✓ si I ∈ connexions(Alice) | ✗ |
|
||||
| s'abonner | ✓ | ✓ | cond (idem) | cond (idem) | ✗ |
|
||||
| lire l'inbox du PdR (entrées brutes) | — | — | ✓ | ✗ | ✗ |
|
||||
| modifier | ? **à trancher** (selon champs) | ✗ | ✗ | ✗ | ✗ |
|
||||
| supprimer | ✓ (se désinscrire ; retirer le lien de l'inbox si possible) | ✗ | cond : modération inbox seule (ne supprime pas l'objet) | ✗ | ✗ |
|
||||
|
||||
**Visibilité hôte : résolue** (identifiée si connecté, anonyme sinon — natif). **Questions ouvertes :** champs modifiables d'une inscription (booléen seul ou +commentaire/statut/accompagnants ?) ; **suppression côté inbox** — un déposant peut-il retirer son lien d'un doc qu'il ne contrôle pas ? (à vérifier au protocole).
|
||||
|
||||
### Événement
|
||||
|
||||
| Verbe | Alice (= D) | H (hôte d'un PdR greffé) | U |
|
||||
|---|---|---|---|
|
||||
| créer | ✓ (rend déclarant) | — | ✓ (rend déclarant) |
|
||||
| lire / s'abonner | ✓ | ✓ | ✓ |
|
||||
| modifier | ? **à trancher** | ? **à trancher** | ? **à trancher** |
|
||||
| supprimer | ? **à trancher** | ✗ | ✗ |
|
||||
|
||||
**Questions ouvertes :** qui peut **modifier** un événement déclaré — déclarant seul (propriétaire) ? tout utilisateur (wiki) ? personne (immuable) ? Central pour la déduplication (cf. concept `functional-domain`, [[brief_2026-06-15_event-deduplication]] côté functional-domain). Qui peut **supprimer**, et que deviennent les PdR greffés (orphelins/cascade/marqué supprimé) ?
|
||||
|
||||
### Profil utilisateur
|
||||
|
||||
**Rien dans le profil n'est public.** Deux périmètres : **profil réseau** (Alice + connexions : nom, avatar, bio, ville, intérêts) ; **profil privé** (Alice seule : settings, email, préférences).
|
||||
|
||||
| Verbe | Alice | C | U |
|
||||
|---|---|---|---|
|
||||
| créer | ✓ (à l'inscription) | — | — |
|
||||
| lire — réseau | ✓ | ✓ | ✗ |
|
||||
| lire — privé | ✓ | ✗ | ✗ |
|
||||
| s'abonner | ✓ | ✓ (réseau) | ✗ |
|
||||
| modifier | ✓ | ✗ | ✗ |
|
||||
| supprimer (compte) | ✓ | ✗ | ✗ |
|
||||
|
||||
**Tension à résoudre :** un PdR est lisible par tous, mais son hôte ne devrait pas être identifiable par un lambda. Trois positions : (i) **pseudonyme par DID seul** (nom/avatar résolus seulement aux connexions) ; (ii) **identité dénormalisée dans l'offre** (l'hôte choisit une « carte de visite » par PdR, vivant dans l'objet PdR, profil fermé) ; (iii) **anonymat de l'hôte** (identité révélée seulement aux connexions). À trancher. Autres : composition champ-par-champ de chaque périmètre ; statut du `username` (public/réseau/supprimé ?).
|
||||
|
||||
### Connexion (lien d'amitié)
|
||||
|
||||
Bilatérale. `DemandeDeConnexion` (unilatérale, en attente) → `Connexion` (bilatérale, à l'acceptation ; ouvre l'accès aux données personnelles). La liste de connexions d'Alice est **personnelle** (Alice + ses connexions).
|
||||
|
||||
| Verbe | Alice (initiatrice) | Bob (autre côté) | C | U |
|
||||
|---|---|---|---|---|
|
||||
| créer la demande | ✓ | — | — | — |
|
||||
| accepter | — | ✓ | — | ✗ |
|
||||
| lire la liste d'Alice | ✓ | ✓ | ✓ | ✗ |
|
||||
| s'abonner | ✓ | ✓ | ✓ | ✗ |
|
||||
| supprimer (rompre A↔B) | ✓ | ✓ | ✗ | ✗ |
|
||||
|
||||
**Questions ouvertes :** granularité côté Bob (voit-il toute la liste d'Alice ou juste A↔B ? — conséquence du principe : toute la liste) ; découvrabilité « amis d'amis » (Alice voit-elle Bob↔Carole ? — non, sauf si Carole ∈ connexions(Alice)).
|
||||
|
||||
## Partitions naturelles dérivées
|
||||
|
||||
Heuristique : même store si (a) même cellule d'autorisation en écriture *et* (b) accédées ensemble. À partir des seuls points validés, **trois périmètres** émergent — qui correspondent **presque parfaitement aux 3 stores natifs**.
|
||||
|
||||
| Périmètre | Écriture | Lecture | Données validées |
|
||||
|---|---|---|---|
|
||||
| **Public** ↔ `public_store` | Alice seule | Tous | PdR hébergés par Alice ; événements déclarés *(sous réserve du modèle d'écriture)* |
|
||||
| **Réseau** ↔ `protected_store` | Alice seule | Alice + connexions | Profil réseau ; participations ; index des connexions |
|
||||
| **Privé** ↔ `private_store` | Alice seule | Alice seule | Profil privé (settings, email, préférences) |
|
||||
|
||||
### Cas particulier : la Connexion bilatérale
|
||||
|
||||
Donnée à *deux* écrivains → ne tient dans aucun store individuel. Primitive native : le **Dialog store**. Modèle : **une `Connexion` A↔B = un Dialog store** (contient l'objet + matière à messagerie future) ; l'**index « toutes les connexions d'Alice »** vit dans le `protected_store` d'Alice (liste les NURIs des Dialog stores). La `DemandeDeConnexion` : soit dans un Dialog store provisoire, soit dans le `public_store` du destinataire (à trancher selon le SDK).
|
||||
|
||||
### Inbox du document PdR
|
||||
|
||||
Le doc PdR (dans le `public_store` de l'hôte) a une **inbox** native : reçoit les dépôts d'inscription (liens DID cap), plus tard commentaires/signaux. **Pas un store séparé**, attribut du document. Pas d'impact sur les partitions.
|
||||
|
||||
### Ce qui ne demande aucun Group store
|
||||
|
||||
Sur le périmètre validé, **aucune donnée ne demande de Group store**. Tout tient dans : 3 stores natifs par utilisateur + Dialog stores + inboxes natives. Les Group stores ne deviennent nécessaires que si le modèle d'écriture événement est « wiki », ou si communautés/suivi/collaboration multi-hôte reviennent dans le périmètre.
|
||||
|
||||
### Implication pour [[brief_2026-05-17_multi-store-refactor]]
|
||||
|
||||
Ce brief y propose une structure à 4 niveaux de Group stores. **Cette analyse dérive une structure différente** (3 stores natifs + Dialog, sans Group) parce que les concepts qui justifient les Group stores ont été mis hors périmètre. À reconcilier à l'exécution.
|
||||
|
||||
## Inventaire des requêtes par écran
|
||||
|
||||
*À remplir une fois la matrice stabilisée.* Schéma prévu : `| Écran | Lectures one-shot | Abonnements | Écritures | Acteur déclencheur |`. Écrans à analyser : voir la table de routes (concept `app-architecture`).
|
||||
|
||||
## See Also
|
||||
|
||||
- [[brief_2026-05-17_multi-store-refactor]] — consommateur principal
|
||||
- [[brief_2026-06-15_shared-wallet-shim]] — stopgap reprenant ces périmètres
|
||||
- `README.md §Modèle fonctionnel` / concept `functional-domain` — source des acteurs
|
||||
- Concept `data-layer` — état actuel mono-store
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
type: knowledge
|
||||
summary: Authentification = possession d'un wallet NextGraph ; tous les utilisateurs sont authentifiés (pas d'accès anonyme) ; l'auth passe par le redirect/iframe broker, et l'app n'auto-connecte que dans l'iframe
|
||||
---
|
||||
|
||||
# Authentification
|
||||
|
||||
**L'identité d'un utilisateur = son wallet NextGraph.** Il n'y a **pas d'accès anonyme** à l'app : tout utilisateur est authentifié (cf. concept `functional-domain`). Il n'y a pas de système de comptes/mots de passe applicatif — l'auth est déléguée à NextGraph.
|
||||
|
||||
## Flux
|
||||
|
||||
- `LoginScreen` (`src/modules/auth/screens/`) déclenche la connexion via `useNextGraph()` (ne consomme pas `useFestipodData`).
|
||||
- Le flux standard `@ng-org/web` est un **redirect vers le broker** (`nextgraph.net/redir/`) qui recharge l'app dans une **iframe** après authentification (détail dans concept `nextgraph-platform`, [[knowledge_integration-model]] côté nextgraph-platform).
|
||||
- **L'app n'auto-connecte que dans l'iframe broker** (`window.self !== window.top`) — sinon `initNgWeb()` redirigerait toute la page. Cette règle vit côté data-layer ([[rule_conditional-ng-init]]) car elle concerne le cycle `NextGraphContext`, mais elle a une conséquence sécurité directe : **hors iframe, aucune session n'est ouverte sans action explicite** de l'utilisateur.
|
||||
|
||||
## Le wallet de test
|
||||
|
||||
Les tests `@data`/`@e2e` créent/ouvrent un wallet réel (`festipod-tests`/`festipod-tests`, profil persistant) — voir concept `bdd-testing`. Ce sont des **credentials de test en clair**, sans enjeu de sécurité, dédiés au staging (cohérent avec la posture « utilisateurs amicaux » du stopgap, concept `nextgraph-platform`).
|
||||
|
||||
> Le modèle d'autorisations qui s'appuiera sur cette identité (connexions bilatérales, données personnelles = réseau, anonymat hôte) est en incubation : [[brief_2026-05-18_authorization-matrix]].
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
type: knowledge
|
||||
summary: Posture de sécurité actuelle — aucun contrôle d'accès côté app, l'app lit/affiche le private_store de l'utilisateur connecté et fait confiance au broker NextGraph pour ne retourner que des données autorisées ; mono-user de fait
|
||||
last_checked: 2026-06-15
|
||||
---
|
||||
|
||||
# Modèle de confiance actuel
|
||||
|
||||
**Posture observée dans `src/shared/context/FestipodDataContext.tsx` (`useNgData`) :** l'app lit tout ce que les subscriptions ORM retournent depuis le `private_store` de l'utilisateur connecté et l'affiche **sans aucun filtre d'autorisation côté app**.
|
||||
|
||||
Conséquences (à connaître avant de raisonner sécurité) :
|
||||
|
||||
1. **Aucun contrôle d'accès applicatif.** Pas de vérification « l'utilisateur a-t-il le droit de voir cette donnée ». L'app suppose que **le broker/NextGraph ne retourne que ce que l'utilisateur peut voir**. Toute la confidentialité repose sur cette confiance dans la couche NextGraph, pas sur du code Festipod.
|
||||
2. **Mono-store, donc mono-user de fait.** Tout (events, profils, participations) vit dans le `private_store` de l'utilisateur connecté (cf. concept `data-layer`, [[decision_2026-03-17_private-store-nuri-scope]] côté data-layer). Un autre utilisateur ne voit rien — par construction, le `private_store` n'est pas partageable. Il n'y a donc rien à « autoriser » : chacun ne voit que ses propres données.
|
||||
3. **Pas de séparation de périmètres.** Le découpage public / réseau / privé du modèle cible ([[brief_2026-05-18_authorization-matrix]]) **n'existe pas encore** dans le code : aucun `protected_store`/`public_store` n'est utilisé pour le métier.
|
||||
|
||||
## Le piège pour la suite
|
||||
|
||||
Le jour où le multi-user arrive (lecture cross-wallet, voir les briefs de `nextgraph-platform`), cette **absence d'enforcement applicatif devient un risque** : si la séparation reste portée seulement par la crypto/capabilities NextGraph et que l'app continue d'afficher « tout ce qu'elle reçoit », une fuite de capability = une fuite de données. Le stopgap `shared-wallet-shim` (concept `nextgraph-platform`) prévoit d'ailleurs un **filtre d'isolation applicatif** explicite parce que, dans ce mode, un seul wallet rend tout physiquement lisible.
|
||||
|
||||
> À vérifier si on doute : `useNgData` dans `FestipodDataContext.tsx` ne contient aucune branche de filtrage par identité ; les seuls IDs manipulés sont ceux du wallet courant.
|
||||
Reference in New Issue
Block a user