yavsc/doc/Architecture.md

208 lines
11 KiB
Markdown
Raw Normal View History

2026-06-12 12:34:02 +01:00
# Architecture de Yavsc
## Vision générale
Yavsc est une plateforme de mise en relation client/fournisseur,
spécialisable par domaine d'activité, avec une origine musicale.
Elle gère des **devis** (pas de facturation directe), et s'intègre
dans des workflows collaboratifs pouvant aboutir à des livrables
sous licence libre.
doc: split Architecture.md into per-topic pages doc/Architecture.md was 436 lines and growing; this commit extracts each non-trivial subject into its own page under doc/architecture/ and reduces the root document to a table of contents + transversal sections (vision, stack, admin rights). New pages (under doc/architecture/): - workflow-multi-parties.md : client / fournisseur / coordinateur roles, sous-traitance, project states, B2B/B2C, domaine musical production flow. - domaine-musical.md : titres collaboratifs (formats, flux de production, contraintes de licence). - licences.md : LicenceModele, CC/ODbL seed, badge projet, cycle de vie. - domaines-activite.md : arbre des activites, Droit a la racine, DomaineActivite model. - dictionnaires-metier.md : regle d'heritage, DictionnaireMetier + TermeMetier, cycle de vie d'un terme. Absorbs the previous doc/Dictionnaire.md draft. - offres-frontmatter.md : ClasseFormulaire / ClasseDevis, OffreFournisseur, Demande, parsing YamlDotNet (introduit dans 4034c399 Front matters). Absorbs the previous doc/Formulaires-devis.md and doc/Demande.md fragments. - postit-oidc.md : documentation du client desktop PostIt, custom URI scheme (RFC 8252 §7.1), composants partages, plateformes, UX observable, persistance et reprise au boot, garanties testees. Architecture.md (436 -> 66 lines) keeps the vision, the stack overview, the admin rights section, and a TOC table pointing at each detail page. The "A documenter ensuite" backlog is kept at the end. Cross-links are relative: from Architecture.md the links go architecture/<page>.md; from inside doc/architecture/ they go ../Architecture.md or <sibling>.md.
2026-06-27 13:45:31 +01:00
## Pages de détail
2026-06-12 12:34:02 +01:00
doc: split Architecture.md into per-topic pages doc/Architecture.md was 436 lines and growing; this commit extracts each non-trivial subject into its own page under doc/architecture/ and reduces the root document to a table of contents + transversal sections (vision, stack, admin rights). New pages (under doc/architecture/): - workflow-multi-parties.md : client / fournisseur / coordinateur roles, sous-traitance, project states, B2B/B2C, domaine musical production flow. - domaine-musical.md : titres collaboratifs (formats, flux de production, contraintes de licence). - licences.md : LicenceModele, CC/ODbL seed, badge projet, cycle de vie. - domaines-activite.md : arbre des activites, Droit a la racine, DomaineActivite model. - dictionnaires-metier.md : regle d'heritage, DictionnaireMetier + TermeMetier, cycle de vie d'un terme. Absorbs the previous doc/Dictionnaire.md draft. - offres-frontmatter.md : ClasseFormulaire / ClasseDevis, OffreFournisseur, Demande, parsing YamlDotNet (introduit dans 4034c399 Front matters). Absorbs the previous doc/Formulaires-devis.md and doc/Demande.md fragments. - postit-oidc.md : documentation du client desktop PostIt, custom URI scheme (RFC 8252 §7.1), composants partages, plateformes, UX observable, persistance et reprise au boot, garanties testees. Architecture.md (436 -> 66 lines) keeps the vision, the stack overview, the admin rights section, and a TOC table pointing at each detail page. The "A documenter ensuite" backlog is kept at the end. Cross-links are relative: from Architecture.md the links go architecture/<page>.md; from inside doc/architecture/ they go ../Architecture.md or <sibling>.md.
2026-06-27 13:45:31 +01:00
Chaque sujet est détaillé dans sa propre page (sous
`doc/architecture/`) ; cette racine tient lieu de sommaire.
2026-06-12 12:34:02 +01:00
doc: split Architecture.md into per-topic pages doc/Architecture.md was 436 lines and growing; this commit extracts each non-trivial subject into its own page under doc/architecture/ and reduces the root document to a table of contents + transversal sections (vision, stack, admin rights). New pages (under doc/architecture/): - workflow-multi-parties.md : client / fournisseur / coordinateur roles, sous-traitance, project states, B2B/B2C, domaine musical production flow. - domaine-musical.md : titres collaboratifs (formats, flux de production, contraintes de licence). - licences.md : LicenceModele, CC/ODbL seed, badge projet, cycle de vie. - domaines-activite.md : arbre des activites, Droit a la racine, DomaineActivite model. - dictionnaires-metier.md : regle d'heritage, DictionnaireMetier + TermeMetier, cycle de vie d'un terme. Absorbs the previous doc/Dictionnaire.md draft. - offres-frontmatter.md : ClasseFormulaire / ClasseDevis, OffreFournisseur, Demande, parsing YamlDotNet (introduit dans 4034c399 Front matters). Absorbs the previous doc/Formulaires-devis.md and doc/Demande.md fragments. - postit-oidc.md : documentation du client desktop PostIt, custom URI scheme (RFC 8252 §7.1), composants partages, plateformes, UX observable, persistance et reprise au boot, garanties testees. Architecture.md (436 -> 66 lines) keeps the vision, the stack overview, the admin rights section, and a TOC table pointing at each detail page. The "A documenter ensuite" backlog is kept at the end. Cross-links are relative: from Architecture.md the links go architecture/<page>.md; from inside doc/architecture/ they go ../Architecture.md or <sibling>.md.
2026-06-27 13:45:31 +01:00
| Sujet | Page |
|------------------------------------------------|-------------------------------------------------------------------|
| Workflow multi-parties (client / fournisseur / coordinateur, sous-traitance, états) | [workflow-multi-parties.md](architecture/workflow-multi-parties.md) |
| Domaine musical (titres collaboratifs) | [domaine-musical.md](architecture/domaine-musical.md) |
| Licences (`LicenceModele`, seed CC/ODbL, badge)| [licences.md](architecture/licences.md) |
| Domaines d'activité (arbre, `DomaineActivite`) | [domaines-activite.md](architecture/domaines-activite.md) |
| Dictionnaires métier (héritage en arbre) | [dictionnaires-metier.md](architecture/dictionnaires-metier.md) |
| Offre fournisseur + frontmatter (`ClasseFormulaire`, `ClasseDevis`, parsing) | [offres-frontmatter.md](architecture/offres-frontmatter.md) |
| PostIt / OIDC (client desktop, custom URI scheme, silent refresh) | [postit-oidc.md](architecture/postit-oidc.md) |
| Notifications Web/PostIt, ChatHub et service Android SignalR | [notifications.md](architecture/notifications.md) |
2026-06-12 12:34:02 +01:00
## Stack technique
- **Backend** : ASP.NET Core, C#
- **ORM** : Entity Framework Core (migrations générées)
- **Base de données** : PostgreSQL (provider Npgsql)
- **Frontend** : Razor views
2026-06-27 13:30:28 +01:00
- **Parsing frontmatter** : YamlDotNet
doc: split Architecture.md into per-topic pages doc/Architecture.md was 436 lines and growing; this commit extracts each non-trivial subject into its own page under doc/architecture/ and reduces the root document to a table of contents + transversal sections (vision, stack, admin rights). New pages (under doc/architecture/): - workflow-multi-parties.md : client / fournisseur / coordinateur roles, sous-traitance, project states, B2B/B2C, domaine musical production flow. - domaine-musical.md : titres collaboratifs (formats, flux de production, contraintes de licence). - licences.md : LicenceModele, CC/ODbL seed, badge projet, cycle de vie. - domaines-activite.md : arbre des activites, Droit a la racine, DomaineActivite model. - dictionnaires-metier.md : regle d'heritage, DictionnaireMetier + TermeMetier, cycle de vie d'un terme. Absorbs the previous doc/Dictionnaire.md draft. - offres-frontmatter.md : ClasseFormulaire / ClasseDevis, OffreFournisseur, Demande, parsing YamlDotNet (introduit dans 4034c399 Front matters). Absorbs the previous doc/Formulaires-devis.md and doc/Demande.md fragments. - postit-oidc.md : documentation du client desktop PostIt, custom URI scheme (RFC 8252 §7.1), composants partages, plateformes, UX observable, persistance et reprise au boot, garanties testees. Architecture.md (436 -> 66 lines) keeps the vision, the stack overview, the admin rights section, and a TOC table pointing at each detail page. The "A documenter ensuite" backlog is kept at the end. Cross-links are relative: from Architecture.md the links go architecture/<page>.md; from inside doc/architecture/ they go ../Architecture.md or <sibling>.md.
2026-06-27 13:45:31 +01:00
- **Client desktop** : Avalonia 12 (PostIt — détails dans
[postit-oidc.md](architecture/postit-oidc.md))
2026-06-14 18:26:40 +01:00
2026-06-27 13:30:28 +01:00
## Droits de Yavsc
2026-06-14 18:26:40 +01:00
2026-06-27 13:30:28 +01:00
### Administration
2026-06-14 18:26:40 +01:00
2026-06-27 13:30:28 +01:00
Le groupe des administrateurs prend la charge de :
doc: split Architecture.md into per-topic pages doc/Architecture.md was 436 lines and growing; this commit extracts each non-trivial subject into its own page under doc/architecture/ and reduces the root document to a table of contents + transversal sections (vision, stack, admin rights). New pages (under doc/architecture/): - workflow-multi-parties.md : client / fournisseur / coordinateur roles, sous-traitance, project states, B2B/B2C, domaine musical production flow. - domaine-musical.md : titres collaboratifs (formats, flux de production, contraintes de licence). - licences.md : LicenceModele, CC/ODbL seed, badge projet, cycle de vie. - domaines-activite.md : arbre des activites, Droit a la racine, DomaineActivite model. - dictionnaires-metier.md : regle d'heritage, DictionnaireMetier + TermeMetier, cycle de vie d'un terme. Absorbs the previous doc/Dictionnaire.md draft. - offres-frontmatter.md : ClasseFormulaire / ClasseDevis, OffreFournisseur, Demande, parsing YamlDotNet (introduit dans 4034c399 Front matters). Absorbs the previous doc/Formulaires-devis.md and doc/Demande.md fragments. - postit-oidc.md : documentation du client desktop PostIt, custom URI scheme (RFC 8252 §7.1), composants partages, plateformes, UX observable, persistance et reprise au boot, garanties testees. Architecture.md (436 -> 66 lines) keeps the vision, the stack overview, the admin rights section, and a TOC table pointing at each detail page. The "A documenter ensuite" backlog is kept at the end. Cross-links are relative: from Architecture.md the links go architecture/<page>.md; from inside doc/architecture/ they go ../Architecture.md or <sibling>.md.
2026-06-27 13:45:31 +01:00
2026-06-14 18:26:40 +01:00
- la Gestion des licences
- la Gestion des groupes d'utilisateurs (les modérateurs, en particulier)
- la Gestion des projets
- la Gestion des utilisateurs
### Gestion des utilisateurs et des groupes
doc: split Architecture.md into per-topic pages doc/Architecture.md was 436 lines and growing; this commit extracts each non-trivial subject into its own page under doc/architecture/ and reduces the root document to a table of contents + transversal sections (vision, stack, admin rights). New pages (under doc/architecture/): - workflow-multi-parties.md : client / fournisseur / coordinateur roles, sous-traitance, project states, B2B/B2C, domaine musical production flow. - domaine-musical.md : titres collaboratifs (formats, flux de production, contraintes de licence). - licences.md : LicenceModele, CC/ODbL seed, badge projet, cycle de vie. - domaines-activite.md : arbre des activites, Droit a la racine, DomaineActivite model. - dictionnaires-metier.md : regle d'heritage, DictionnaireMetier + TermeMetier, cycle de vie d'un terme. Absorbs the previous doc/Dictionnaire.md draft. - offres-frontmatter.md : ClasseFormulaire / ClasseDevis, OffreFournisseur, Demande, parsing YamlDotNet (introduit dans 4034c399 Front matters). Absorbs the previous doc/Formulaires-devis.md and doc/Demande.md fragments. - postit-oidc.md : documentation du client desktop PostIt, custom URI scheme (RFC 8252 §7.1), composants partages, plateformes, UX observable, persistance et reprise au boot, garanties testees. Architecture.md (436 -> 66 lines) keeps the vision, the stack overview, the admin rights section, and a TOC table pointing at each detail page. The "A documenter ensuite" backlog is kept at the end. Cross-links are relative: from Architecture.md the links go architecture/<page>.md; from inside doc/architecture/ they go ../Architecture.md or <sibling>.md.
2026-06-27 13:45:31 +01:00
En supposant que les certificats de letsencrypt sont au groupe
`www-data`, on peut créer l'utilisateur `yavsc` avec les droits
suivants :
2026-06-14 18:26:40 +01:00
2026-06-27 13:30:28 +01:00
```bash
2026-06-14 18:26:40 +01:00
sudo addgroup yavsc --system
sudo adduser --ingroup yavsc --add-extra-groups www-data \
--disabled-password --system yavsc
2026-06-27 13:30:28 +01:00
```
2026-11-02 10:40:29 +00:00
## Catalogue Web de podcasts
`/Podcast` (vue `src/Yavsc.Org/Views/Podcast/Index.cshtml`) exige une
session Identity Yavsc.Org, y compris pour chaque requête de lecture.
Yavsc.Org interroge Yavsc.Api côté serveur ; aucun jeton n'est transmis
au navigateur et aucun second catalogue de stockage n'est créé.
Les replays MP4 prêts prennent en charge GET, HEAD et les plages
d'octets. Les directs et replays non encore convertis utilisent HLS
natif ou hls.js (servi localement, installé par `npm install` et copié par
`npm run build:podcasts`, également inclus dans la copie d'assets de
`npm run build:js`). Sans support vidéo compatible, la page affiche un
avertissement et invite à utiliser PostIt. Cette page ne crée ni ne
supprime de podcast.
Depuis le lecteur PostIt, « Ouvrir dans le navigateur » ouvre `/Podcast`
sur l'hôte `Authentication.Authority`, pas la playlist API authentifiée.
La session Web reste distincte de celle de PostIt : le navigateur peut
donc demander une connexion.
Il n'y a pas de section de configuration `PodcastWeb`, ni de client OAuth
technique à enregistrer. L'adresse API est celle de `Site:ApiUrl`, en HTTPS
(avec ou sans suffixe `/api/v1`). Yavsc.Org est l'autorité : comme pour
l'envoi d'avatar, `IdentityServerTools.IssueJwtAsync` utilise sa signature
existante pour émettre un jeton de cinq minutes au nom de l'utilisateur
connecté (`sub`, audience `api`, scope `api` attendu par Yavsc.Api).
Ce jeton reste côté serveur. Une adresse API manquante renvoie 503 ;
une panne de l'API renvoie une erreur explicite, pas un catalogue vide.
### Emissions preparees
PostIt memorise dans ses parametres utilisateur les cameras et microphones
detectes, leurs identifiants selectionnes et le titre par defaut. La page
les restaure sans redetection automatique ; le bouton de detection actualise
le materiel disponible en conservant les choix encore presents. Le choix
« sans microphone » est memorise lui aussi. Charger le titre d'une emission
preparee ne remplace pas le titre par defaut ; une saisie explicite le modifie.
Les erreurs de sauvegarde sont affichees dans la page.
Les appels des salons de discussion reutilisent ces memes choix camera/micro
et enregistrent leurs changements dans les memes parametres. La page Podcasts
les recharge a son activation. Les appels exigent toujours un microphone :
le choix podcast « sans microphone » laisse donc le micro d'appel non selectionne.
L'adresse LAN/VPN choisie pour les appels est aussi memorisee, mais restauree
uniquement si elle est encore presente sur une interface locale active.
Sinon, une nouvelle selection est requise. Le consentement au partage
d'adresse avec le pair n'est jamais memorise.
PostIt permet de preparer, modifier et supprimer une emission avant son
demarrage : titre, date/heure locale, duree entiere positive en minutes et
annonce publique optionnelle. Les horaires sont previsionnels : la camera,
le demarrage et l'arret restent manuels. Les heures locales inexistantes ou
ambigues au changement d'heure sont refusees.
La table existante `LiveFlow` conserve la preparation et son proprietaire ;
`PodcastId` (GUID unique) relie cette emission au manifeste media sur disque.
`PodcastResponse` reste un DTO, enrichi de `FlowId`, `ScheduledStartAt`,
`PlannedDurationMinutes` et `PublicAnnouncement`. Un etat `Planned`
precede le direct ; la date previsionnelle n'est jamais confondue avec
`CreatedAt` du direct ni la duree previsionnelle avec les secondes enregistrees.
Les anciens manifestes sans `LiveFlow` restent lisibles ; aucune copie ou
migration de leurs medias n'est requise. Le demarrage immediat historique
reste disponible sans preparation.
L'API propose `POST /api/v1/podcasts/planned`,
`PUT /api/v1/podcasts/{id}/planned` et `POST /api/v1/podcasts/{id}/start`.
La preparation n'est visible que du proprietaire, meme avec une annonce ;
les nouvelles routes de mutation exigent le scope `api`. Le demarrage
conserve le GUID et les tentatives concurrentes reutilisent le meme direct.
Une emission demarree ne peut plus etre reprogrammee ou redemarree apres
sa fin. Les medias restent geres par `ILiveProcessor`, avec ses quotas,
expiration, reprise et preparation MP4. Une suppression conserve un
marqueur en base pour ne pas ressusciter une emission deja supprimee.
Le verrou de coordination suit le deploiement mono-processus du stockage
media actuel ; un deploiement multi-instance necessiterait un stockage et
une coordination distribues.
Seul `GET /api/v1/podcasts/announcements` est anonyme : titre, nom d'auteur,
horaire UTC, duree et texte public, sans URL de flux ni metadonnees privees.
`/Podcast/Announcements` affiche ces annonces avec encodage Razor et sans
jeton utilisateur. Retirer le texte public avant le debut retire l'annonce.
Les annonces restent disponibles apres le direct jusqu'a suppression du
podcast. Les pages et toutes les routes de lecture restent authentifiees.
Appliquer la migration `PodcastScheduling` au deploiement, apres celle des
dons ; aucune migration de production n'est appliquee automatiquement ici.
2026-11-02 10:40:29 +00:00
### Dons PayPal aux performers
Les dons sont gérés par Yavsc.Org, pas par un lien de paiement externe
configuré par l'opérateur :
1. Depuis **Mon compte > Dons PayPal**, le performer renseigne l'adresse
de son propre compte PayPal (`/Donation/Settings`). Un champ vide
désactive les nouveaux dons. Seuls les performers actifs ayant
configuré leur compte proposent un bouton de don dans le catalogue.
Le formulaire est aussi accessible depuis le catalogue de podcasts et
le profil professionnel Web. Dans PostIt : **Mon profil > Gérer mon
activité professionnelle > Dons PayPal**, puis **Enregistrer**.
L'API privée `GET/PUT /api/v1/account/performer-profile` transporte
`DonationPayPalEmail` uniquement pour le compte connecté ; une chaîne
vide désactive les dons, une propriété omise ou nulle préserve
l'adresse existante pour les anciens clients.
2. Le donateur connecté choisit un montant en euros (`/Donation/Create`).
Yavsc conserve le don et son bénéficiaire avant de créer le checkout.
3. Yavsc utilise les paramètres marchands existants
`Authentication:PayPal` (mode sandbox/production et identifiants NVP).
Express Checkout désigne le compte du performer par
`PAYMENTREQUEST_0_SELLERPAYPALACCOUNTID` : le paiement va directement
au performer ; Yavsc ne collecte pas les fonds et ne les reverse pas.
4. PayPal recueille l'accord du donateur puis le renvoie dans Yavsc.
Une confirmation POST avec protection antiforgery déclenche le
paiement, après vérification côté serveur du token, du montant,
de la devise, de la référence et du bénéficiaire. Un simple retour
du navigateur n'est jamais considéré comme une preuve de paiement.
5. Seule une réponse PayPal vérifiée permet d'afficher le don comme payé.
Les notifications IPN reçues sur `/Donation/Notify` sont revalidées
auprès de PayPal, puis rapprochées du bénéficiaire, du montant, de la
devise et de la transaction. Elles permettent aussi de confirmer
ultérieurement un paiement Pending ou une réponse de capture perdue.
`Site:ExternalUrl` doit être l'URL HTTPS publique de Yavsc.Org, utilisée
pour les retours et notifications (jamais le Host fourni par le client).
PayPal doit pouvoir joindre `/Donation/Notify`. Le compte marchand
doit être autorisé par PayPal pour les paiements directs à un tiers ;
valider ce parcours en sandbox avec deux comptes distincts avant mise
en production. Les tests locaux utilisent un serveur PayPal simulé,
pas de véritables transactions.
`PerformerDonations` conserve la référence, le donateur, le performer,
le bénéficiaire figé à la création, le montant et l'état du paiement.
La migration `PerformerPayPalDonations` ajoute ce suivi et l'adresse
PayPal optionnelle du performer. Les profils ayant un historique de
dons ne peuvent pas être supprimés. Les rééditions du profil général
ne remplacent pas la configuration du bénéficiaire.
Le paiement n'est capturé qu'une fois : contrôle de concurrence,
référence de déduplication PayPal (`MSGSUBID`) et transaction unique.
En cas de réponse ambiguë, le don reste en vérification sans nouvelle
capture automatique. Le donateur retrouve son suivi dans **Mon compte >
Mes dons** (`/Donation`). Si l'IPN ne réconcilie pas cet état, l'opérateur
doit vérifier la transaction auprès de PayPal avant toute nouvelle
tentative. Les dons sont facultatifs et n'ouvrent pas droit à un reçu
fiscal émis par cette page.
2026-06-12 12:34:02 +01:00
## À documenter ensuite
- Modèle `ProjetMusical`
- Gestion des fichiers (audio, partition, MIDI)
- Workflow de validation de licence par l'administration
2026-06-27 13:30:28 +01:00
- Workflow de modération des termes métier
- Workflow complet de parsing et validation du frontmatter à la sauvegarde