- C# 41%
- JavaScript 31.1%
- HTML 10.4%
- SCSS 6.1%
- Less 5%
- Other 6.3%
Replace the implicit 'ACL empty = private' convention with an
explicit two-axis model: Visibility is the master switch, the
ACL is the exception list.
Semantics (matches what BlogSpotService.Index / Details enforce):
Visibility.Public + empty ACL : every caller sees it
Visibility.Public + non-empty : only author + ACL circles + admin
Visibility.Private + any ACL : only author + admin (ACL ignored)
ACL is preserved across
Private/Public flips so
reopening is lossless
The Public+non-empty shape is the 'restrict by exception' case:
open by default, narrowed by the ACL. This is intentionally
different from the previous behaviour, where a Public post
with a non-empty ACL was effectively ACL-restricted anyway —
the new model makes that explicit and removes ambiguity.
Server (Yavsc.Blogs / Yavsc.Server)
- New enum Visibility { Private, Public } in
Yavsc.Abstract.Blogspot (so the wire DTO and the EF entity
share the same type). Stored as int via .HasConversion<int>()
on BlogPost.Visibility. Default Private on construction;
the column default in the migration is 0 so existing rows
land Private without any data migration.
- BlogSpotService.Index: filter rewritten to honour the two-
axis model. Authenticated and anonymous callers now share
the same shape (Public+emptyACL visible to all, otherwise
scoped). Admin reads still go through PermissionHandler.
- PermissionHandler.IsPublic: dropped the blogSpotPublications
lookup, replaced with the Visibility + empty-ACL check that
matches the new model. PermissionHandler.IsSponsor and
IsOwner unchanged.
- UserHelpers.UserPosts (the per-author feed for
/CircleMembers/Details and similar): mirror of the
Index filter, so the two code paths can't silently diverge.
- BlogPostEditViewModel.Publish untouched on this commit. It
still controls whether a row exists in BlogSpotPublication;
the two systems coexist (Publish = 'is this draft published',
Visibility = 'who can read it'). Follow-up to consolidate.
EF migration (Yavsc.Org/Migrations/20260818143013_AddBlogPostVisibility)
- Scaffolded by 'dotnet ef migrations add', not hand-edited,
per the repo preference for generated migrations.
- Adds the new Visibility column (int, NOT NULL, default 0).
- Also drops three shadow-state ClientId1 foreign keys and
their indexes/columns on ClientScopes, ClientRedirectUris,
ClientGrantTypes. These shadow FKs were created by EF from
HasOne<Client>().HasForeignKey(e => e.ClientId) mappings
that have long since been removed from
ApplicationDbContext.OnModelCreating, but the snapshot was
never regenerated against the current model. The columns
are nullable ints with no production data, so the drop is
lossless. Without this, EF Core would keep emitting
warnings on every migration add and the model would drift
further from reality.
DTO wire (Yavsc.Abstract.Blogspot.BlogPost)
- Visibility property added to BlogPostDto. System.Text.Json
serialises the enum as its underlying int, so the JSON
shape is a plain number, no JsonConverter needed.
Client UI (PostIt)
- MainPageViewModel: DraftVisibility ObservableProperty
mirroring the existing DraftTitle/DraftArticle pattern.
Initialised to Private so a fresh draft is private by
default. Save command writes the chosen value into the
BlogPostDto payload for both CreatePostAsync and
UpdatePostAsync. OnSelectedPostChanged hydrates the buffer
from the server-supplied value.
- AllVisibilities property on the VM exposes [Private, Public]
in that order, bound by the ComboBox in MainPage.axaml.
- VisibilityLabelConverter (PostIt.Views) maps the enum to
French user-facing labels ('Privé' / 'Public'); registered
in App.axaml as a static resource.
- MainPage.axaml: a new ComboBox row in the editor pane
between Title and Article. Uses the existing 'no hardcoded
Background without Foreground' lesson so dark mode works.
Tests (Yavsc.Blogs.Tests)
- BlogVisibilityTests (5 [Fact]): drive GET /api/v1/blog with
Visibility fixtures seeded directly in the in-memory DB:
* Private + ACL: only the author sees it
* Public + empty ACL: any authenticated caller sees it
* Public + non-empty ACL: caller without ACL membership
does NOT see it
* Private + ACL: ACL is ignored, only the author sees it
* Visibility round-trips through the JSON wire (int 1)
- UserHelpersVisibilityTests (4 [Fact]): exercise the helper
directly so the two code paths (Index filter vs per-author
feed) can't diverge silently. Same fixture, no HTTP.
Test totals: 29/29 Yavsc.Blogs.Tests (was 20, +5 BlogVisibility
+4 UserHelpersVisibility), 51/51 PostIt.Tests (no change), 44/44
Yavsc.Org.Tests (no change).
Out of scope (tracked in MEMORY.md, 2026-08-18):
- i18n: only the new 'Visibilité :' label is localised; the
rest of MainPage.axaml is still hard-coded French.
- BlogPostEditViewModel.Publish ↔ Visibility consolidation
(which system wins when both are set on the same post?).
- Org-side UI for editing Visibility (the admin web Yavsc
still edits posts without a visibility field).
|
||
|---|---|---|
| .forgejo/workflows | ||
| .github | ||
| .vscode | ||
| assets | ||
| contrib | ||
| doc | ||
| external | ||
| src | ||
| .dockerignore | ||
| .editorconfig | ||
| .env.sample | ||
| .eslintrc.json | ||
| .gitattributes | ||
| .gitignore | ||
| .gitmodules | ||
| .jshintrc | ||
| CHANGELOG.md | ||
| CONTRIBUTING.md | ||
| Directory.Build.props | ||
| Directory.Packages.props | ||
| docker-compose.yaml | ||
| Dockerfile | ||
| Dockerfile.backend | ||
| dotnet-tools.json | ||
| esbuild.config.mjs | ||
| INSTALL.md | ||
| LICENSE | ||
| Makefile | ||
| NuGet.config | ||
| package.json | ||
| README.md | ||
| ROADMAP.md | ||
| SECURITY.md | ||
| yavsc.sln | ||
Yavsc
C'est une application mettant en oeuvre une prise de contact entre un demandeur de services et son éventuel prestataire associé.
Statut actuel des actions Forgejo
Statut actuel des actions GitHub
Documentation
L'architecture, la roadmap et les détails métier sont documentés
sous doc/. Voir l'index de la documentation
pour le sommaire complet. La racine de l'architecture est
Architecture.md.
Construction et déploiement
Construction
dotnet build
et, pour execution en environment de développement
~/workspace/yavsc/Yavsc @ ASPNETCORE_ENV=Development dotnet run
Tests
Utilisez GNU/Makefile (et visitez le code, dans le dossier test ):
[TODO] Depuis le répertoire racine:
make test
Installation / Déploiement / Développement
les services et l'API
La Prod
cd srv/Yavsc : make pushInProd CONFIGURATION=Release.
puis, pour une première installation
make install_service.
Fonctionnalités (encore en cours de développement)
Elle est censée aboutir à une prise commande, un payement du client, à une collecte du retour du client, et à un paiement du prestataire de services.
Elle comprendra une gestion des litiges.
Elle expose une messagerie instantanée, disponible depuis un navigateur Web ou depuis l’application mobile, pouvant garantir la preservation du secret sur toute information personnelle, du client comme du prestataire.
Le client et le prestataire sont dès l'inscription formellement identifiés par l'application : ils sont authentifiés sur la base d'un compte nominatif, et ce n'est qu'au moment de leur premier acte de facturation qu'une vérification renforcée est déclenchée (KYC light côté client, validation du profil professionnel côté prestataire).
Plus précisément :
- pour le client, lors de la validation d'une commande facturée (de prestation à un prestataire, ou autre).
- pour le prestataire, lors de la validation de son profil professionnel, qui implique l’acquittement de son adhésion forfaitaire.
La séquence logique (et simplifiable) d'une prestation canonique (sans annulation ni reclamation) est la suivante :
- Une commande intervient auprès d'un prestataire, elle est chiffrée et le paiement est provisionné par PayPal, non collecté.
- Notifié, le prestataire valide un devis, avec arrhes ou avance. il signe son devis, qui peu contenir des documents attachés à faire signer par le client, un ou des contrats, stockés au format Markdown par le prestataire dans ses contrats à faire signer.
- à son tour, le client est notifié et signe le devis aussi
- Les arrhes ou avances sont débitées sur le champ
- 10 jours avant la date de la prestation le reste du paiement est collecté
Dans le cas des arrhes, à tout moment, jusqu'avant la date et l'heure de la prestation, le client ou le prestataire peuvent annuler:
- Le prestataire peut le faire, en rendant les arrhes majorées de 20%
- Le client peut le faire, en perdant les arrhes.
- Le prestataire peut déléguer à une équipe de son choix un filtrage des demandes des clients.
Limitations
- Aujourd'hui : une prestation par commande, sur un axe client → prestataire unique, sans sous-traitance. Cible roadmap : montages multi-parties (plusieurs clients et/ou plusieurs fournisseurs collaborant autour d'un même projet, avec sous-traitance validée par le client) — voir la ROADMAP.
- Annulation : partielle et non testée. Côté client,
HairCutCommandController.ClientCancel/ClientCancelConfirmsupprime la commande sans déclencher de refund PayPal ni logique arrhes vs avance ; aucune action d'annulation côté prestataire. La description du README (arrhes +20%, avance non-annulable) n'est pas implémentée. Cible : câblerRefundTransactionet le workflow complet, voir ROADMAP. - Réclamation post-prestation : aucun support applicatif. Passée la date de la prestation, le client n'a aucun chemin dans l'UI pour signaler un litige — aucune route, aucun contrôleur, aucun modèle. La fonctionnalité de conciliation est planifiée au Jalon 5 (cf. doc/ddd-exploration-2026-06-14.md) : double vue client/prestataire, dossier de conciliation, décision. En attendant, tout passe par e-mail au propriétaire de l'installation.
- Paiement : PayPal uniquement, via l'API NVP/SOAP. Aucun autre PSP n'est intégré (pas de Stripe, pas d'Adyen). L'API NVP/SOAP que PayPal a dépréciée au profit de REST reste fonctionnelle mais n'est plus recommandée par PayPal ; aucune migration n'est planifiée à court terme.
- Périmètre métier étroit. Pas de saisie de structures de projets complexes ; pas de ticketing associé à la prestation.
- Collecte centralisée. Tous les paiements PayPal transitent par le compte du propriétaire de l'installation — c'est le seul identifiant configuré côté PSP. Les professionnels apparaissent comme tierces parties du point de vue PayPal.
- Pas de gestion de paie. Aucune édition de fiche de paye, ni paiement en masse. Seuls les paiements unitaires sus-cités sont supportés.
Paramétrage
Fichiers de configuration d'Yavsc.Org
Le paramétrage runtime d'Yavsc.Org se fait via appsettings-org.json,
lu par ASP.NET Core selon la convention standard (appsettings.<ASPNETCORE_ENVIRONMENT>.json
est fusionné par-dessus). Trois fichiers coexistent dans
src/Yavsc.Org/, avec trois rôles distincts :
| Fichier | Rôle | Commité ? |
|---|---|---|
appsettings-org.json |
Modèle. Valeurs anonymisées ([Your domaine name], [YOURSMTPHOST], …). Sert de référence. |
Oui |
appsettings-org.Development.json |
Surcharge locale pour ASPNETCORE_ENVIRONMENT=Development. Concrètement, Site.Authority et Site.ExternalUrl pointent sur https://localhost:5001, Site.Title/Slogan sont adaptés, et la ConnectionStrings.YavscConnection est fournie. Ignoré par .gitignore (appsettings-*.*.json) : chaque développeur crée le sien à partir de ce qui est documenté ici et du modèle appsettings-org.json. |
Non |
appsettings-org-dist.json |
Généré par la cible copy-binaries du contrib/Makefile (alias make reinstall) à partir d'appsettings-org.json lors du déploiement, puis copié dans $(BASEAPPDIR). C'est un clone du modèle, juste renommé pour signaler « à éditer ». |
Non |
Première installation sur un serveur :
make install_service # construit, déploie, active systemd
cd $BASEAPPDIR # voir contrib/.env
ls appsettings-org*.json # -> appsettings-org-dist.json (le modèle, jamais éditer celui-là)
cp appsettings-org-dist.json appsettings-org.json
$EDITOR appsettings-org.json
Le Makefile renomme appsettings-org.json en appsettings-org-dist.json
juste avant le cp -a vers $(BASEAPPDIR), et supprime la version
appsettings-org.json du publish dir. Conséquence : un make reinstall
ultérieur n'écrasera jamais ton appsettings-org.json édité — il
recopiera un appsettings-org-dist.json neuf par-dessus, sans
supprimer ton édition. Si tu veux repartir d'un modèle vierge, supprime
d'abord appsettings-org.json du serveur ; sinon, laisse-le en place.
Valeurs minimales à renseigner pour un serveur de production :
Site.Authority— issuer OIDC visible de l'extérieur (URL exacte sous laquelle/.well-known/openid-configurationest servi, par exemplehttps://yavsc.pschneider.fr). C'est la valeur que PostIt et toutes les autres applications clientes passent dansAuthority.Site.ExternalUrl— URL canonique du serveur, utilisée pour générer les liens absolus dans les e-mails, construire les RedirectUris des clients OIDC tiers, etc. Depuis la migration PKCE de PostIt, le seed EF Core d'IdentityServer utiliseSite.ExternalUrlpour autoriser une RedirectUri du clientpostit: cela permet à PostIt d'être lancé depuis une page web de Yavsc.Org (iframe launcher) sans rejetredirect_uri mismatchde l'OP.ConnectionStrings.YavscConnection— chaîne de connexion PostgreSQL (utilisateur, mot de passe, hôte, base). Privilégierdotnet user-secretsou des variables d'environnementASPNETCORE_*plutôt qu'un mot de passe en clair dans le fichier.- Au démarrage, Yavsc.Org applique automatiquement ses migrations EF
Core. Sur cette base de code, EF Core 10 peut encore lever un
PendingModelChangesWarningmalgré des migrations et snapshots déjà alignés ; ce faux positif est ignoré sur les contextes PostgreSQL pour éviter un démarrage inutilement en mode dégradé. Si une erreur de migration apparaît encore en production, elle doit être traitée comme une vraie divergence de schéma ou de connexion. Smtp.*— hôte, port, identifiants SMTP pour l'envoi d'e-mails transactionnels.Authentication.PayPal.*etAuthentication.Google.*— clés d'API pour les fournisseurs d'identité externes utilisés dans les flows OAuth/OIDC.
Administration
Une fois le service disponible, s'enregistrer, et
Visiter l'url /Administration/Take
Une nouvelle activité
On gère les activité en faisant partie du groupe des commerciaux (FrontOffice),
on crée des activités en y associant des formulaires de commande et une
classe de paramétrage de profiles professionnels.
Développement
Un nouvel environnement d'execution
L'impact de l'usage d'un nouveau nom d’environnement d'execution, à l'heure de cet écrit, ressemble à ceci:
- Ajustement des listes d’environnements cités dans les pages:
- ~/Views/Shared/_Layout.cshtml
- ~/Views/Shared/_ValidationScriptsPartial.cshtml
- ~/Views/Home/Index.cshtml
- ~/Views/Home/About.cshtml
Remerciements
Photo de Dewang Guptasur Unsplash