diff --git a/.project/briefs/authorization-matrix.md b/.project/briefs/authorization-matrix.md new file mode 100644 index 0000000..bbc4f20 --- /dev/null +++ b/.project/briefs/authorization-matrix.md @@ -0,0 +1,175 @@ +# 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](./multi-store-refactor.md)) et à toute évolution multi-user. La structure de stores NextGraph cible doit être *dérivée* de : + +1. Une matrice d'autorisations (qui peut faire quoi sur quel type de donnée). +2. Un inventaire des requêtes nécessaires (lectures, abonnements, écritures par écran). +3. Les partitions naturelles qui en découlent (regroupements de données qui partagent autorisations *et* schéma d'accès). + +Ce brief porte cette analyse. Il alimentera la décision finale sur la structure de stores. + +## Cadre + +### Acteurs (tous authentifiés) + +- `Self` — propriétaire de la donnée (varie par type : auteur d'un message, titulaire d'un profil…) +- `D` — Déclarant d'un événement (celui qui a inséré la référence dans Festipod ; pas l'organisateur réel) +- `H` — Hôte d'un point de rencontre (celui qui l'a créé) +- `I` — Inscrit à un point de rencontre +- `C` — Connexion (« ami ») d'un autre acteur lié à la donnée +- `U` — Utilisateur authentifié quelconque, sans relation à la donnée + +### Verbes + +- `créer` +- `lire` (one-shot) +- `s'abonner` (lecture longue / réactive) +- `modifier` +- `supprimer` + +### Conventions + +`✓` autorisé · `✗` interdit · `cond` autorisé sous condition (notée) · `—` sans objet + +## Décisions cadre (acquises) + +- **Tous les utilisateurs sont authentifiés.** Pas d'accès anonyme. +- **Points de rencontre publics universels.** Tout utilisateur peut lire et s'abonner. +- **Création de point de rencontre ouverte à tous.** Pas de prérequis (adhésion, invitation). +- **Hôte = détenteur technique des droits d'écriture** sur un point de rencontre. À ce stade : 1 hôte par PdR, celui qui l'a créé. +- **Adhésion à une communauté : hors périmètre actuel.** Le rôle « Membre de communauté » n'est pas analysé ici. +- **Suivi de communauté ou d'utilisateur : hors périmètre actuel.** À reprendre quand la fonctionnalité de discovery par abonnement sera traitée. + +## Matrice par type de donnée + +### Point de rencontre + +| Verbe | Self (= Hôte) | I (autre inscrit) | D (déclarant de l'événement parent) | U (utilisateur lambda) | +|---|---|---|---|---| +| créer | ✓ (l'acte de créer rend l'utilisateur hôte) | — | ✗ | ✓ (l'acte le rend hôte) | +| lire | ✓ | ✓ | ✓ | ✓ | +| s'abonner | ✓ | ✓ | ✓ | ✓ | +| modifier | ✓ | ✗ | ✗ | ✗ | +| supprimer | ✓ | ✗ | ✗ | ✗ | + +**Notes :** +- Pas de différenciation `C` (connexion de l'hôte) — les connexions sont un filtre d'affichage côté UI, pas un droit d'accès, puisque tout est public. +- Le `D` n'a pas de droit particulier sur les PdR greffés sur son événement déclaré — il a juste déclaré la référence. + +### Inscription à un point de rencontre + +L'objet « Inscription » lie un utilisateur et un point de rencontre. Représente l'engagement à participer. + +| Verbe | Self (l'inscrit) | H (hôte du PdR) | I (autre inscrit au même PdR) | U (utilisateur lambda) | +|---|---|---|---|---| +| créer | ✓ (s'inscrire) | ✗ | ✗ | ✓ (l'acte le rend inscrit) | +| lire | ✓ | ✓ | ? **à trancher** | ? **à trancher** | +| s'abonner | ✓ | ✓ | ? **à trancher** | ? **à trancher** | +| modifier | ? **à trancher** (selon les champs modifiables) | ✗ | ✗ | ✗ | +| supprimer | ✓ (se désinscrire) | ? **à trancher** (modération ? blacklist ?) | ✗ | ✗ | + +**Questions ouvertes :** +- **Visibilité de la liste des inscrits.** Cohérent avec « tout est public » : tous les utilisateurs voient qui s'est inscrit. Mais à confirmer — y a-t-il un cas où on veut cacher la liste (PdR à inscription confidentielle) ? +- **Champs modifiables d'une inscription.** Booléen seul, ou champs additionnels (commentaire, statut "peut-être", nombre d'accompagnants) ? +- **Modération par l'hôte.** L'hôte peut-il désinscrire un inscrit (= blacklist) ? + +### Événement + +| Verbe | Self (= D, déclarant) | H (hôte d'un PdR greffé) | U (utilisateur lambda) | +|---|---|---|---| +| créer | ✓ (l'acte rend déclarant) | — | ✓ (l'acte le rend déclarant) | +| lire | ✓ | ✓ | ✓ | +| s'abonner | ✓ | ✓ | ✓ | +| modifier | ? **à trancher** | ? **à trancher** | ? **à trancher** | +| supprimer | ? **à trancher** | ✗ | ✗ | + +**Questions ouvertes :** +- **Qui peut modifier un événement déclaré ?** Le déclarant seul (modèle propriétaire) ? Tout utilisateur (modèle wiki, pour compléter/corriger) ? Personne après création (modèle immuable, pour éviter les modifications mal intentionnées) ? Cette question est centrale pour le défi de déduplication évoqué dans le README — un modèle wiki facilite la convergence, un modèle propriétaire complique. +- **Qui peut supprimer ?** Si le déclarant supprime, que deviennent les PdR greffés (orphelins ? supprimés en cascade ? l'événement reste mais marqué supprimé ?) ? + +### Profil utilisateur + +À déterminer : un seul objet ou split public/privé ? + +| Verbe | Self | C (connexion) | U (utilisateur lambda) | +|---|---|---|---| +| créer | ✓ (à l'inscription) | — | — | +| lire (partie publique) | ✓ | ✓ | ? **à trancher** | +| lire (partie privée) | ✓ | ? **à trancher** | ✗ | +| s'abonner | ✓ | ? | ? | +| modifier | ✓ | ✗ | ✗ | +| supprimer | ✓ (auto-destruction du compte) | ✗ | ✗ | + +**Questions ouvertes :** +- **Split public/privé ?** Le profil contient-il des champs réservés aux connexions ou à l'utilisateur seul (préférences, paramètres, email) ? +- **Profil entièrement public ?** Cohérent avec « points de rencontre publics » : un visiteur peut voir le profil de l'hôte d'un PdR. Mais le détail (bio, photos, ville…) ? + +### Connexion (lien d'amitié) + +| Verbe | Self (A, demandeur) | Other (B, l'autre côté de la connexion) | U (utilisateur lambda) | +|---|---|---|---| +| créer (demande) | ✓ | — | — | +| accepter | — | ✓ | ✗ | +| lire (sa propre liste d'amis) | ✓ | — | — | +| lire (la liste d'amis d'un autre) | — | — | ? **à trancher** | +| s'abonner (à sa liste) | ✓ | — | — | +| modifier | — | — | — | +| supprimer (rompre la connexion) | ✓ | ✓ | ✗ | + +**Questions ouvertes :** +- **Bilatérale ou unilatérale ?** Le concept « connexion / ami » suggère bilatérale (les deux acceptent). À confirmer ; si oui, il y a deux objets distincts : `DemandeDeConnexion` (unilatérale) et `Connexion` (bilatérale). +- **Visibilité de la liste d'amis.** Une connexion est-elle observable par des tiers ? « Marie est connectée à Bob » est-il public, restreint, ou privé ? + +## Hors périmètre actuel + +À reprendre quand ces concepts deviendront actifs : + +- **Communauté d'intérêt** (membres, modération, création) +- **Adhésion à une communauté** +- **Liste curated** (création, partage, abonnement) +- **Suivi d'utilisateur ou de communauté** pour discovery distribuée + +## Inventaire des requêtes par écran + +*À remplir une fois la matrice des autorisations stabilisée.* + +Schéma prévu : + +| Écran | Lectures one-shot | Abonnements | Écritures | Acteur déclencheur | +|---|---|---|---|---| + +Écrans à analyser (depuis [AGENTS.md](../../AGENTS.md#routing)) : + +- `WelcomeScreen` `/` +- `LoginScreen` `/login` +- `HomeScreen` `/home` +- `EventsScreen` `/events` +- `CreateEventScreen` `/events/new` +- `EventDetailScreen` `/events/:id` +- `UpdateEventScreen` `/events/:id/edit` +- `InviteScreen` `/events/:id/invite` (à voir si encore pertinent) +- `ParticipantsListScreen` `/events/:id/participants` +- `MeetingPointsScreen` `/events/:id/meeting-points` +- `ProfileScreen` `/profile` +- `UpdateProfileScreen` `/profile/edit` +- `FriendsListScreen` `/profile/friends` +- `ShareProfileScreen` `/profile/share` +- `UserProfileScreen` `/users/:id` +- `SettingsScreen` `/settings` + +## Partitions naturelles dérivées + +*À remplir une fois la matrice + l'inventaire stabilisés.* + +Heuristique de dérivation : on regroupe dans un même store les données qui (a) partagent leur cellule d'autorisation pour les verbes d'écriture, et (b) sont accédées ensemble dans la majorité des requêtes (pour éviter de multiplier les abonnements). + +## See Also + +- [Brief : refactor multi-store](./multi-store-refactor.md) — consommateur principal de cette analyse +- [README §Modèle fonctionnel](../../README.md) — source des acteurs et concepts +- [Knowledge : data layer](../knowledge/data-layer.md) — état actuel mono-store diff --git a/AGENTS.md b/AGENTS.md index d2c1e4f..e14e2f8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -72,3 +72,4 @@ bun run build:orm # Regenerate ORM from SHEX shapes ## Briefs (work not yet started) - [Multi-store refactor](.project/briefs/multi-store-refactor.md) — passer du mono-store actuel à une structure de Group stores par communauté/event/RDV (prérequis multi-user) +- [Matrice d'autorisations et requêtes](.project/briefs/authorization-matrix.md) — analyse qui doit guider la structure de stores cible diff --git a/README.md b/README.md index 44d238a..f82de17 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,84 @@ # Festipod -A prototyping tool for the Festipod mobile app - an event discovery and networking platform. +**Festipod permet aux utilisateurs de créer des points de rencontre qui viennent se « greffer » sur des événements publics existants. L'objectif est de favoriser les rencontres autour de ces événements.** -## What's Inside +L'événement public (festival, conférence, salon…) n'est qu'un *prétexte* et un *point d'ancrage temporel et géographique* : la valeur produite par l'app, c'est le **point de rencontre** que les utilisateurs viennent y greffer pour se retrouver. -- **Mobile App Mockups** - 13 interactive screens with hand-drawn "sketchy" UI -- **User Stories** - 26 stories across 5 categories (Events, Workshops, Users, Meetings, Notifications) -- **BDD Specifications** - Cucumber feature files in French with test integration +Application web mobile-first. Stack : Bun + React + NextGraph (P2P, local-first, chiffré de bout en bout). + +## Modèle fonctionnel + +Tous les utilisateurs sont authentifiés — il n'y a pas d'accès anonyme à l'app. + +### Acteurs + +- **Utilisateur** — toute personne ayant un compte (un wallet NextGraph). Tous les acteurs ci-dessous sont des spécialisations d'un utilisateur dans un contexte donné. +- **Connexion (« ami »)** — un autre utilisateur avec qui je suis connecté. Sert à scoper les listes (« mes amis qui participent à… ») et la confiance. +- **Déclarant d'un événement** — l'utilisateur qui a inséré l'événement dans Festipod. *N'est pas (forcément) un organisateur* de l'événement réel : c'est juste quelqu'un qui le référence pour que d'autres puissent y attacher des points de rencontre. +- **Hôte d'un point de rencontre** — l'utilisateur qui a créé un point de rencontre rattaché à un événement. +- **Inscrit à un point de rencontre** — un utilisateur qui s'est inscrit à un point de rencontre. De fait, il devient participant à l'événement parent. +- **Membre d'une communauté d'intérêt** — un utilisateur abonné à une communauté pour découvrir les événements qu'elle référence. + +### Concepts métier + +- **Point de rencontre** — *l'unité de valeur de l'app*. Un moment de rencontre proposé par un hôte à un endroit et à un horaire donnés, greffé sur un événement public. C'est ce à quoi on s'inscrit (on ne s'inscrit pas à un événement). Sans points de rencontre, un événement Festipod n'a pas d'intérêt. +- **Événement** — l'ancrage. Un événement public réel (festival, conférence, salon, exposition…) référencé dans Festipod pour servir de support à des points de rencontre. C'est simplement un *prétexte* (titre, dates, lieu, thèmes) ; le déclarant n'est pas l'organisateur officiel de l'événement, juste celui qui l'a inscrit dans Festipod. +- **Communauté d'intérêt** — un groupement thématique d'utilisateurs. Sert principalement à découvrir des événements (via abonnement) et à délimiter les périmètres de référencement. +- **Liste curated** — une liste d'événements éditorialisée (par un utilisateur ou une communauté), distincte de « les événements que j'ai déclarés » ou « les événements de la communauté ». Permet d'organiser/recommander. +- **Connexion** — lien de confiance entre deux utilisateurs (équivalent « ami »). + +### Fonctionnalités actuelles + +Implémentées dans le code (écrans visibles via le router) : + +- Authentification via wallet NextGraph +- Cycle de vie d'événement (déclaration, consultation, mise à jour) +- Cycle de vie de point de rencontre (rattaché à un événement) +- Inscription / désinscription à un point de rencontre +- Liste des participants à un événement +- Profil utilisateur, mise à jour, partage de profil +- Liste d'amis (connexions) +- Profil d'un autre utilisateur + +Voir le tableau des routes dans [AGENTS.md](./AGENTS.md#routing) et l'inventaire des écrans dans [.project/knowledge/screens.md](./.project/knowledge/screens.md). + +### Défis ouverts + +- **Déduplication des événements en infra décentralisée.** NextGraph étant P2P, rien n'empêche deux utilisateurs de déclarer indépendamment le même événement public (par ex. « Eurockéennes 2027 ») et de produire deux entrées distinctes. La dispersion qui en résulte fragmente les points de rencontre greffés et réduit leur visibilité — ce qui va à l'encontre de la fonction première de l'app. Pistes envisagées, non tranchées : + - proposer à l'utilisateur, lors de la déclaration, les événements déjà déclarés dans son réseau / ses communautés qui correspondent à sa saisie (recherche avant création) ; + - utiliser un identifiant externe canonique (URL officielle de l'événement, Wikidata, schema.org/Event) pour reconnaître les doublons et les présenter comme un seul événement à l'affichage ; + - laisser des curators (humains ou communautaires) fusionner / vetter les entrées canoniques. + +### Évolutions à venir + +Identifiées comme nécessaires (notamment pour la scalabilité et la découverte) mais pas encore implémentées : + +- **Abonnement à une communauté d'intérêt** pour découvrir ses événements (mécanisme de discovery distribué). +- **Abonnement à un utilisateur** pour suivre les événements qu'il déclare (sans nécessairement être ami). +- **Listes curated** — créer et partager des sélections d'événements éditorialisées. +- **Multi-utilisateurs collaboratif** : aujourd'hui chaque utilisateur a ses données isolées dans son wallet. Le passage en mode collaboratif (un point de rencontre vu par plusieurs personnes) suppose un refactor de la couche données vers les Group stores NextGraph. Voir [brief multi-store-refactor](./.project/briefs/multi-store-refactor.md). ## Quick Start ```bash bun install -bun run dev +bun run dev # Dev server avec HMR (port 3000) ``` -Open http://localhost:3000 - -## Navigation - -| Page | Route | Description | -|------|-------|-------------| -| Gallery | `#/` | Browse all mockup screens | -| Demo | `#/demo/{screen}` | Interactive screen preview | -| Stories | `#/stories` | User stories browser | -| Specs | `#/specs` | BDD specifications with test status | - -## Commands +## Commandes utiles ```bash -bun run dev # Start dev server with HMR -bun run test:cucumber # Run Cucumber tests -bun run features:parse # Regenerate features from .feature files -bun run steps:extract # Extract step definitions +bun run build # Build production vers dist/ +bun run storybook # Parcourir écrans et composants +bun run test:cucumber # Tests BDD +bun run features:parse # Régénérer features.ts depuis les .feature +bun run steps:extract # Extraire les step definitions pour les tooltips +bun run build:orm # Régénérer l'ORM depuis les SHEX shapes ``` ## Documentation -See [docs/](./docs/) for detailed documentation: - -- [Festipod App](./docs/festipod-app.md) - Mobile app design -- [Prototyping Tool](./docs/prototyping-tool.md) - Web app architecture -- [Cucumber Integration](./docs/cucumber-integration.md) - BDD testing setup +- [AGENTS.md](./AGENTS.md) — architecture, routes, points d'entrée pour contribuer +- [.project/knowledge/](./.project/knowledge/) — comment les choses fonctionnent (data layer, BDD, écrans…) +- [.project/decisions/](./.project/decisions/) — choix techniques figés +- [.project/briefs/](./.project/briefs/) — chantiers à venir, recherche préparatoire