41 Commits

Author SHA1 Message Date
Thomas Fransolet
3d23e05351 Misc update ressource to mediatheque ! 2026-09-04 16:49:26 +02:00
Thomas Fransolet
269b3f6703 Lot C : backfill des colonnes de stockage (C2) et quota autoritaire (C3)
C2 — POST /api/Resource/backfill-storage, SuperAdmin, dryRun à true par
défaut : la migration se joue sur une base vide, ce backfill sur des lignes
de production. StoragePath par ResourceStorage.PathFor, SizeBytes par HEAD.

La méthode annoncée au plan — « SizeBytes par listing du bucket Firebase » —
était inapplicable : le serveur n'avait aucun client de stockage. Le sondage
passe donc par HEAD sur l'URL publique, comme le fait déjà la migration, et
le sondeur est extrait plutôt que recopié (Helpers/ResourceSizeProbe,
consommé par MigrationController et par le backfill). Même raisonnement que
pour ResourceStorage : deux copies auraient divergé sur ce qui compte, le
sort réservé aux échecs.

L'extraction a bouché un trou que personne ne cherchait. L'original ne notait
l'échec que dans son catch, or un HEAD sur un blob absent ne lève pas : il
répond 404, sans Content-Length. Ces ressources arrivaient à 0 octet sans
figurer dans le rapport — invisibles au quota et invisibles au diagnostic,
exactement ce que le commentaire d'origine voulait empêcher.

Le « 37 lignes sur 45 » du plan n'étant pas vérifiable, le backfill rend son
propre inventaire : Orphans (aucune URL, blob peut-être jamais téléversé) et
Unsized (URL présente, bucket muet) restent séparés, ce sont deux causes
distinctes.

C3 — pré-vol du quota sur les deux chemins de création, suppression du blob
à Delete, angle mort d'Update tranché.

Deux défauts trouvés en câblant, qui n'étaient documentés nulle part :

- Le pré-vol existait déjà à moitié. Upload (multipart) contrôlait et
  renvoyait 413, Create (JSON) ne contrôlait rien — or c'est le chemin
  qu'emprunte manager-app, qui crée la ligne puis téléverse.
- Les deux lectures du quota divergeaient. Upload lisait le quota du plan,
  GetQuota celui de l'instance avec le plan en repli. Une instance à quota
  surchargé — le mécanisme même de l'add-on — affichait un chiffre à l'écran
  et se faisait bloquer sur un autre. Helpers/StorageQuota devient la seule
  source de vérité pour les deux.

Delete supprime le blob AVANT la ligne et renvoie 502 en conservant la ligne
si le bucket échoue. manager-app faisait l'inverse en avalant l'échec dans un
print : la ligne disparaissait, le blob restait, et n'ayant plus de ligne il
devenait invisible au quota tout en restant facturé. Une ressource encore
listée se rattrape ; un blob que plus aucune ligne ne désigne, non.

L'angle mort laissé ouvert par C1 était une fausse crainte : PathFor ne
construit qu'un pictures/{instanceId}/{resourceId}, le type n'entre pas dans
le chemin, il décide seulement s'il y en a un. Recalculer ne peut donc pas
pointer ailleurs, et Update rejoue Apply.

Aucun secret nouveau : FirebaseAdmin était déjà référencé pour les
notifications push et Startup charge déjà un service account, donc
Google.Cloud.Storage.V1 réutilise le même GoogleCredential. Seule s'ajoute la
clé Firebase:StorageBucket, vide par défaut — à renseigner en prod (I9),
sans quoi Delete ne supprime rien et ne prétend pas le contraire.

dotnet build vert, dotnet test 163/163 (148 au départ, +7 pour C2, +8 pour C3).

Contient aussi le correctif d'indexation préparé en parallèle : un job
Hangfire par section dans BackfillInstanceAsync au lieu d'une boucle, et un
backoff sur 429/503 dans GoogleEmbeddingService.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 12:05:25 +02:00
Thomas Fransolet
7625487806 Lot B : geler le schéma, plus sécurité rapide et calculateur de stockage
LOT B — une seule migration EF (LotB_FreezeSchema) :
- SectionMap.MapResourceId → IconResourceId. L'écart (g) de la bascule tombe
  avec. Il fallait renommer aussi la propriété de navigation MapResource :
  la convention EF l'appariait au FK, la laisser aurait fabriqué un FK
  fantôme. Elle n'était utilisée nulle part ailleurs.
- SectionEvent.ParcoursIds supprimé (champ, DTO, SectionFactory, et une
  initialisation dans un montage de test).
- Instance.IsImageWatermark remplace le `instanceId == "633ee379…"` en dur
  de ResourceController.

EF a généré un RenameColumn, pas un drop+add : les icônes déjà configurées
survivent. L'avertissement de perte de données ne porte que sur le DropColumn
de ParcoursIds, ce qui est l'intention.

Non fait, et c'était une erreur de doc : « supprimer SectionEvent.IconResourceId ».
Ce champ n'existe pas — la ligne visée appartient à la classe imbriquée
MapAnnotation, partagée par SectionEvent, SectionAgenda et SectionMap, lue par
cinq contrôleurs et par GetReferencedResourceIds. La supprimer aurait cassé
les icônes d'annotation des trois types et la collecte offline.

SÉCURITÉ (lot A, même repo) :
- AuthenticationController.Authenticate : un bloc #if DEBUG écrasait l'email
  et le mot de passe reçus par un compte de test, donc toute compilation en
  Debug authentifiait n'importe quelle saisie. Retiré.
- EnableSensitiveDataLogging (qui écrit les valeurs des paramètres dans les
  logs) passe sous #if DEBUG, l'idiome déjà employé dans Startup.cs pour le
  CORS et Hangfire. Le Dockerfile publiant en -c Release, c'est un verrou réel.

LOT C1 :
- Calculateur StoragePath/SizeBytes extrait dans Helpers/ResourceStorage.cs,
  avec 13 tests fixant l'invariant des types URL. Il ferme le lien L5 : le
  backfill (C2) et l'écart (e) de la migration appelleront le même code.
- L'extraction a révélé la divergence qu'elle devait empêcher : des deux
  chemins de création de ResourceController, le chemin multipart écrivait
  SizeBytes mais laissait StoragePath nul.

dotnet build Debug et Release verts, dotnet test 143/143 (130 + 13).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 15:32:19 +02:00
Thomas Fransolet
18e4240f0f RAG: pipeline d'ingestion, endpoints du guide IA, journalisation RGPD
Ingestion et indexation
- IIngestionService/IngestionService : chargement des collections filles par
  sous-type, un jeu de morceaux par langue, ChunkIndex continu.
- SectionIndexingInterceptor retenu comme unique déclencheur : les 5
  sous-contrôleurs totalisaient 30 SaveChanges et 0 Enqueue, donc ajouter des
  points d'intérêt à une carte ne réindexait rien.
- HTML retiré avant l'embedding et lignes trop longues recoupées : sans cela un
  article dépassait l'entrée max du modèle et emportait son lot de 50 morceaux.
- Gabarits de LanguageInit filtrés, DistinctBy(Text) avant le Take : ils
  occupaient les cinq premiers résultats d'une recherche en néerlandais.

Endpoints du guide IA
- GET /api/Ai/knowledge/{id} : agrégats sur ContentEmbedding, donc sur ce qui
  est réellement indexé — compter les sections publiées serait plus flatteur et faux.
- GET /api/Ai/insights/{id} : miroir de GuideIaInsights côté manager-app, c'est
  l'écran qui a fixé la forme pour que le job de thèmes la remplisse.

RGPD
- VisitorQuestion journalisée dans AiController.Chat. HasAnswer se déduit des
  sources du retrieval, pas du texte : un repli poli ressemble à une réponse.
  L'écriture n'échoue jamais la réponse au visiteur.
- VisitorQuestionPurgeService, 90 jours, actif sans condition de configuration :
  une durée écrite dans les CGU n'est pas un réglage commercial.

Corrections
- Updateinstance ne recopiait pas les quotas du nouveau plan.
- CheckQuota ne bloquait ni ne comptait à quota 0 — IA gratuite non comptée.
- StoragePath et SizeBytes renseignés à Create, types URL exclus.

dotnet build 0 erreur, dotnet test 130/130.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 10:48:10 +02:00
Thomas Fransolet
e0ff0eeba6 Quota update in controller, audit log (serilog) + ai translator + Unit tests ! (to be tested) + migration update 2026-04-10 16:28:33 +02:00
Thomas Fransolet
f72d94f30f Subscription plans 2026-04-01 17:00:13 +02:00
Thomas Fransolet
a452f4af04 Add migration, need to check if migration with apikey correct.. ! + add roles and security (role and apikey) - need to be tested + visitevent stats + ai etc + all need to be tested ! 2026-03-13 17:45:01 +01:00
Thomas Fransolet
94443fa411 Update puzzle to game + misc 2025-11-27 16:19:00 +01:00
Thomas Fransolet
75a6b0c323 fix puzzle + added order in back 2025-05-27 14:44:33 +02:00
Thomas Fransolet
8635e75c06 update service (ressource deletion) + EF update link 2025-05-14 15:24:43 +02:00
Thomas Fransolet
cef69a61df section (to be tested when front) + section map controller + section quiz controller + update useless entities to DTO 2025-03-24 17:18:59 +01:00
Thomas Fransolet
9aa5e7df5e Resource controller done + section WIP 2025-03-20 16:25:23 +01:00
Thomas Fransolet
11cfeab210 Updated DB (wip) 2025-03-19 08:57:29 +01:00
Thomas Fransolet
8c18825c5d Wip clean code and pass by postgres ! 2025-03-06 17:39:08 +01:00
Thomas Fransolet
c237c69c56 Added main image to geopoint + localication center to mapDTO 2024-04-18 17:13:27 +02:00
Thomas Fransolet
8cd69c7d8b Add weather result 2024-02-24 22:42:41 +01:00
Thomas Fransolet
22ffe09dd8 Add TranslationAndResource 2023-12-27 15:06:31 +01:00
Thomas Fransolet
9f1740c129 Update service DTOs 2023-12-27 11:08:56 +01:00
Thomas Fransolet
cc89f7b717 redirect to 1.2.0 + update entities and other for visitNamur 2023-12-15 17:00:07 +01:00
Thomas Fransolet
17f9cd2334 Update all object to visitNamur request 2023-12-14 17:49:07 +01:00
eb50590684 Update file download (add file name) + update max audio and other file size 2023-03-10 19:46:37 +01:00
006aa541cd Fix image url not working 2023-01-27 21:10:15 +01:00
52d5467b85 Add watermark and shrink images only if fort 2023-01-26 17:09:48 +01:00
63654bdcf9 Allow all file size for image 2023-01-13 17:47:08 +01:00
85ca1368a2 Add resize image + small fixs 2022-12-20 17:34:15 +01:00
3e6439433e Update get ressources endpoint by adding types filter 2022-10-27 13:31:38 +02:00
cf2d7759de Split resource in Resource and resourceData + Add Audio ResourceType 2022-10-26 17:11:45 +02:00
390852ce4f import => support instanceId + Delete resource, delete imageId and ref for configuration 2022-10-21 17:38:17 +02:00
79be291113 Add instanceId to config, section and resource 2022-10-20 16:09:34 +02:00
3b6c480cc6 Add instance model, dto, controller and service + update other objects and controllers 2022-10-06 17:07:11 +02:00
55a612fd0c Add new subsection ArticleDTO + add offline and mobile option 2022-06-11 20:58:43 +02:00
e157cd1cb0 Fix delete ressource for quizz 2022-03-24 21:39:35 +01:00
Thomas Fransolet
4b10635522 Upload multiple files at once (resource) 2021-12-23 14:06:58 +01:00
Thomas Fransolet
f55d4aefcd Fix resource bug 2021-10-14 22:15:23 +02:00
Thomas Fransolet
86ad5a2792 Fix resource bug 2021-10-14 19:48:00 +02:00
Thomas Fransolet
5e40190c6d Add import and export configuration method 2021-08-04 18:07:21 +02:00
Thomas Fransolet
43d95c2ab2 Fix return create resource 2021-07-29 16:33:44 +02:00
Thomas Fransolet
cbd4773697 Fix bugs + delete all resource occurence (when delete resource) 2021-07-26 17:18:06 +02:00
Thomas Fransolet
62aa7453c0 Update first char for every dto variables + add password utils (hash password) 2021-07-25 00:53:47 +02:00
Thomas Fransolet
1ee6f9f382 Delete allow anonymous for post resource 2021-06-19 14:41:28 +02:00
Thomas Fransolet
fed416d078 ressource to reSource + fixs + resourceController (upload and show) 2021-05-07 22:57:06 +02:00