Three changes the product model asked for.
The fixture seed no longer writes anything into a connected wallet, by any
route. `bootstrapWallet` is the single enforcement point -- both call sites
funnel through it -- so the switch cannot be walked around by a screen or a
bridge. The fixtures, the seeding code, the demo path and the rendering tests
are untouched; a unit test now fails if a document is created after all.
An event has no host. The domain says so -- the meeting point has a host, the
event is only the anchor -- while the shape carried `hostName`/`hostInitials`
and every created event was written with the fabricated `'Moi'` / `'MD'`. Gone
from the shape, the ORM bindings, the type, the adapters, the writes and the
screens. `fp:MeetingPoint.host` stays: that one is real.
Regenerating the ORM revealed the committed bindings had drifted from what the
generator emits -- stylistic, verified predicate by predicate, plus the loss of
the `Fp` prefix. The prefix cannot be restored at the generator: the name comes
from the shape IRI, and those IRIs are the persisted RDF classes. Aliased at the
three import sites instead, so nothing downstream moved and the DOM `Event` and
`Notification` types are never shadowed.
Write rights are ownership, read from the list
The contract leaves no other reading -- only an owner writes, and no call adds a
writer -- so `listMyEntityDocs('public')` is what says which events are mine.
The hard-coded `isOwner = true` is replaced by a three-state answer, and the
UNKNOWN state renders neither a pencil nor a greyed one: a disabled look-alike
invites a dead click.
Two adversarial passes refuted the first attempt and both defects are fixed. A
latched boolean denied an owner their own event forever once a listing had
missed it; the ruling is now rebuilt rather than accumulated, so a later listing
overturns an earlier one.
Residual, deliberate and commented: "not mine" is inferred from absence, and the
reactive read and the listing are separate mechanisms, so a freshly arrived
event is ruled out for the window between them. Closing it needs a timer, which
the doctrine forbids.
Festipod
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.
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.
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 l'inventaire des routes et des écrans dans le concept app-architecture.
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. Voir le concept nextgraph-platform (briefs multi-store, matrice d'autorisations, wallet partagé, fork inbox).
Quick Start
bun install
bun run dev # Dev server avec HMR (port 3000)
Commandes utiles
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
- AGENTS.md — cœur : but produit, invariants, carte des concepts
- .project/concepts/ — toute la doctrine projet (savoir, règles, décisions, briefs), typée et livrée par hook au moment pertinent. 6 concepts :
functional-domain,app-architecture,tech-stack,data-layer,bdd-testing,nextgraph-platform.