65 Commits

Author SHA1 Message Date
Thomas Fransolet
b87e49d808 Cle d'API sur les routes visiteur, canal VR et contenu immersif
Securite
- RequireAppKey : filtre qui exige une cle d'API valide ou un utilisateur du
  manager. Pose sur les routes de contenu consommees par les apps visiteur
  (Configuration, Section, Resource, SectionMap, SectionEvent, SectionAgenda,
  SectionParcours, SectionQuiz, ApplicationInstance). Un [Authorize] d'action
  ne peut pas assouplir celui de la classe ; seul [AllowAnonymous] le
  court-circuite, et le filtre redevient le controle d'acces. Il ferme
  l'enumeration par identifiant, pas la confidentialite : la cle s'obtient
  par le slug ou le pincode.
- Instance/slug/{slug} rendait le pinCode, l'adresse de facturation, la TVA et
  les quotas a qui lit l'URL du site visiteur. StripCommercialFields est
  desormais applique sur slug et byPin ; isTrialActive reste expose pour le
  filigrane d'essai.
- Device.Create et Device/{id}/detail repondaient 403 a toute tablette depuis
  a452f4a (13/03) : la classe exige InstanceAdmin, une cle ne porte que
  AppRead. Ouverts a la cle, le cloisonnement par instance etait deja ecrit.

Canal VR
- Device.AppType (defaut Tablet, backfill a 1) ; Create resout
  l'ApplicationInstance sur ce type au lieu de Tablet en dur.
- Get filtre optionnellement par appType ; DeviceDetailDTO expose appVersion
  et lastSeen.
- PUT Device/{id}/heartbeat : batterie, version, connexion. Volontairement
  etroit, une app ne peut ni se renommer ni changer d'instance.
- ApiKeyAppType.VrApp en fin d'enum.

Contenu immersif
- ResourceType : Image360 (11), Video360 (12), Model3D (13), en fin d'enum.
- Section Scene3D : un modele GLB et ses points d'interet, en objet manipule
  ou en decor habite. Les points sont des GeoPoint, avec une LocalTransform
  en jsonb (convention glTF) ; CRUD dans SectionScene3DController.
- Instance.HasImmersiveContent : l'add-on ajoute 100 Go au quota de stockage,
  repose apres un changement de plan et retire a la desactivation.
- ImmersiveBackground (owned) sur Configuration et ApplicationInstance, avec
  une image de repli pour les canaux qui ne rendent pas l'immersif.

Export de configuration
- exportVersion (1) et generatedAt : le JSON devient un contrat, lu tel quel
  par l'app Unity.
- Section.ToDTO() n'etant pas virtuelle, l'export ne portait aucun champ
  specifique de sous-type. Passe par SectionFactory.ToDTO, et charge les
  points des Map et des Scene3D.
- Le fond immersif et son repli partent avec les ressources, URL resolues.

Migrations : AddAppTypeToDevice, AddScene3DSectionAndImmersiveAddon,
AddImmersiveBackground.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-13 16:54:10 +02:00
Thomas Fransolet
9cc45c5767 Ouvrir l'export de configuration aux apps visiteur
`Configuration/{id}/export` portait `[Authorize(AppReadAccess)]`, mais ASP.NET
Core combine les `[Authorize]` de la classe et de l'action : le controleur exige
`ContentEditor`, qu'une cle API n'a pas. La cle authentifiait la requete, puis
l'autorisation la refusait — 403 sans corps. Cote mymuseum-visitapp, le
telechargement d'une visite echouait donc systematiquement.

Seul `[AllowAnonymous]` court-circuite la policy du controleur ; le controle
d'acces se fait dans l'action, qui declenche le schema ApiKey explicitement et
verifie que la cle porte bien l'instance de la configuration demandee. Meme
correctif que InstanceController.GetDetail.

Les trois `catch` renvoyaient `null` : l'app recevait un 200 vide et croyait la
visite exportee. Ils renvoient les codes qui etaient deja ecrits, en commentaire.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 15:03:42 +02:00
Thomas Fransolet
3d23e05351 Misc update ressource to mediatheque ! 2026-09-04 16:49:26 +02:00
Thomas Fransolet
f9059ed198 D1 : la visite hors ligne embarque enfin ses médias
Le switch de collecte des ressources était commenté : 157 lignes mortes dans
Export, 126 dans Import. Une visite téléchargée n'embarquait donc que l'image
de la configuration, celle du loader et l'image de chaque section — ni
contenus d'articles, ni audios, ni icônes de carte, ni images de quiz.

Export matérialise désormais les entités, pas seulement leurs DTO, et appelle
GetReferencedResourceIds(language) : la méthode existait déjà sur les 13
sous-types et n'attendait que d'être appelée. Elle filtre aussi les audios par
langue, ce que le switch ne faisait pas.

Import cesse de redécouvrir les ressources section par section : l'export
embarquant tout ce qui est référencé, une passe unique sur la charge suffit.
createResource étant idempotente, les quelques appels ciblés qui subsistent
sont sans effet.

4 tests, dont un qui vérifie par réflexion que les 13 sous-types implémentent
la collecte : le trou venait d'un switch où un type oublié passait dans le
default sans bruit, et c'est ce qu'il ne faut plus pouvoir refaire.

dotnet test 148/148.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 16:57:22 +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
f2228617ca Add instance index + date update audit + ai quota to token 2026-07-17 15:21:51 +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
b5396643ce to lowerCase in all DTO + update to GeometryDTO 2025-07-16 15:28:54 +02:00
Thomas Fransolet
d241720102 Breaking changes ! WIP new format (ApplicationInstance) + SectionEvent and updated SectionMap 2025-07-09 17:37:30 +02:00
Thomas Fransolet
e3639589b0 Clean + reorder quiz + menu + working all 2025-05-23 15:32:30 +02:00
Thomas Fransolet
0229793c88 MISC 2025-05-15 17:21:18 +02:00
Thomas Fransolet
f4919801b7 Misc 2025-05-13 17:18:59 +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
1242d6c790 clean configuration + user controller done 2025-03-19 15:01:58 +01:00
Thomas Fransolet
7fb3feace4 Instance controller done 2025-03-19 10:57:53 +01:00
Thomas Fransolet
11cfeab210 Updated DB (wip) 2025-03-19 08:57:29 +01:00
Thomas Fransolet
20c35b2c8d Configurations controller (to be tested) + wip for subsection 2025-03-06 18:21:42 +01:00
Thomas Fransolet
8c18825c5d Wip clean code and pass by postgres ! 2025-03-06 17:39:08 +01:00
Thomas Fransolet
9ff5a7fec8 fix issue 2024-04-24 15:23:34 +02:00
Thomas Fransolet
c237c69c56 Added main image to geopoint + localication center to mapDTO 2024-04-18 17:13:27 +02:00
Thomas Fransolet
1fa4e188fa Update weather result (in all configuration's section) 2024-04-11 17:37:10 +02:00
Thomas Fransolet
68b45333da Update weather section on get configuration detail 2024-04-10 17:15:10 +02:00
Thomas Fransolet
0ccfda46a1 Update default IsSectionImageBackground default value 2024-04-10 10:37:01 +02:00
Thomas Fransolet
747ce5f064 missing files 2024-04-10 09:20:59 +02:00
Thomas Fransolet
b5a3336670 Export fix 2024-03-21 16:02:31 +01:00
Thomas Fransolet
fe48dddce2 Update section objects to support multiple PDF at once + MapBox in Map + MapProvider in Agenda 2024-03-12 22:49:32 +01:00
Thomas Fransolet
aa25e0d4a0 Update agenda (multiple languages) 2024-02-28 11:56:53 +01:00
Thomas Fransolet
8cd69c7d8b Add weather result 2024-02-24 22:42:41 +01:00
Thomas Fransolet
8825795ff5 Add loader image in export 2024-01-26 16:53:26 +01:00
Thomas Fransolet
52e5d85d2e Add resourceId to export (pdf and agenda) 2024-01-26 15:11:42 +01:00
Thomas Fransolet
b193763e73 Added weather fields + Added JSONUrl resourceType 2024-01-23 17:49:31 +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
ab562f886c Add isHour, IsDate to config + Resource to response in quizz 2023-12-26 11:42:10 +01:00
Thomas Fransolet
27e20568d8 Clean 2023-12-22 15:59:41 +01:00
Thomas Fransolet
04c6e01e50 Add loader image + weather city to configuration + clean config 2023-12-22 15:25:13 +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
Thomas Fransolet
2866c12985 Add MQTT events 2023-12-05 15:40:51 +01:00
Thomas Fransolet
1e31ebe094 Add pinCode to instance + endpoints 2023-11-30 15:42:18 +01:00
19d84b4417 Configurations orderBy date creation 2023-03-30 16:59:55 +02:00
33f782346b Add nullable int beaconId + ensure ressource has no duplicate 2023-02-17 16:53:24 +01:00
74101d9939 Add sectionIds to ConfigurationDTO 2023-02-15 10:16:18 +01:00
a0b2d5ba9c Update encoding + add from query language 2023-02-10 17:33:59 +01:00
88ab87c9ee Add audio in export configuration 2023-02-10 17:06:23 +01:00
9e8109225a Clean code + add Beacon handling 2022-12-27 21:47:52 +01:00
85ca1368a2 Add resize image + small fixs 2022-12-20 17:34:15 +01: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