maribakulj commited on
Commit
179bb0f
·
unverified ·
1 Parent(s): 0c1b534

Create product and technical specification document

Browse files

Added a comprehensive product and technical specification document outlining the objectives, features, architecture, and development phases for the IIIF research portal application.

Files changed (1) hide show
  1. specs.md +1160 -0
specs.md ADDED
@@ -0,0 +1,1160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Spécification produit et technique
2
+
3
+ ## Portail universel de recherche IIIF + lecture Mirador + connecteurs MCP
4
+
5
+ ## 1. Résumé exécutif
6
+
7
+ Objectif : créer une application web déployable sur un Hugging Face Space permettant de rechercher des objets patrimoniaux dans plusieurs bibliothèques et musées numériques du monde, d’afficher une galerie de résultats unifiée, puis d’ouvrir directement les objets sélectionnés dans Mirador pour lecture, comparaison et navigation.
8
+
9
+ Le produit doit être pensé comme trois couches distinctes :
10
+
11
+ 1. **Couche découverte** : moteur fédéré de recherche multi-sources.
12
+ 2. **Couche lecture** : viewer IIIF basé sur Mirador.
13
+ 3. **Couche interopérabilité** : API interne normalisée et outils MCP permettant à un agent IA ou à un autre client de lancer une recherche, récupérer un manifest et ouvrir une ressource dans Mirador.
14
+
15
+ Le projet ne doit pas supposer que Mirador sait faire la recherche. Mirador est uniquement la couche d’affichage.
16
+
17
+ ---
18
+
19
+ ## 2. Vision produit
20
+
21
+ ### 2.1 Problème
22
+
23
+ Aujourd’hui, les ressources IIIF sont dispersées entre de nombreuses institutions. Même quand les objets sont accessibles, l’utilisateur doit souvent :
24
+
25
+ * connaître l’institution à l’avance ;
26
+ * chercher sur plusieurs interfaces différentes ;
27
+ * comprendre des modèles de données hétérogènes ;
28
+ * récupérer manuellement les manifests ;
29
+ * changer de viewer selon l’établissement.
30
+
31
+ ### 2.2 Proposition de valeur
32
+
33
+ Le produit doit offrir une expérience simple :
34
+
35
+ **Chercher partout, lire tout de suite, comparer dans le même viewer.**
36
+
37
+ ### 2.3 Utilisateurs cibles
38
+
39
+ * chercheurs en histoire, histoire de l’art, philologie, humanités numériques ;
40
+ * conservateurs, documentalistes, bibliothécaires ;
41
+ * étudiants ;
42
+ * amateurs avancés ;
43
+ * développeurs IA ou agents utilisant MCP.
44
+
45
+ ### 2.4 Promesse utilisateur
46
+
47
+ Un utilisateur tape une requête unique, obtient une galerie d’objets provenant de plusieurs institutions, filtre les résultats, puis ouvre un ou plusieurs objets dans Mirador sans avoir à manipuler les manifests manuellement.
48
+
49
+ ---
50
+
51
+ ## 3. Périmètre du MVP
52
+
53
+ Le MVP doit rester réaliste, robuste et simple à déployer.
54
+
55
+ ### 3.1 Ce que le MVP doit faire
56
+
57
+ * proposer une recherche fédérée sur un petit nombre de sources initiales ;
58
+ * normaliser les résultats dans un format unique ;
59
+ * afficher une galerie de résultats ;
60
+ * ouvrir un résultat dans Mirador via son manifest IIIF ;
61
+ * permettre l’ouverture de plusieurs objets en parallèle dans Mirador ;
62
+ * exposer les fonctions principales via une API interne ;
63
+ * exposer éventuellement ces fonctions via MCP.
64
+
65
+ ### 3.2 Sources initiales recommandées pour le MVP
66
+
67
+ Commencer avec 3 à 5 connecteurs maximum.
68
+
69
+ Je recommande :
70
+
71
+ * Gallica / BnF
72
+ * Bodleian Digital
73
+ * Europeana
74
+ * un connecteur générique IIIF manifest-by-URL
75
+ * éventuellement une source de démonstration simple et stable
76
+
77
+ ### 3.3 Ce que le MVP ne doit pas faire
78
+
79
+ * pas de moissonnage global du web patrimonial ;
80
+ * pas d’index mondial complet ;
81
+ * pas de promesse de couverture exhaustive ;
82
+ * pas de création de compte utilisateur ;
83
+ * pas d’annotation collaborative persistante dans la première version ;
84
+ * pas de recherche plein texte universelle sur tous les OCR du monde.
85
+
86
+ ---
87
+
88
+ ## 4. Principes de conception
89
+
90
+ ### 4.1 Architecture modulaire
91
+
92
+ Chaque source doit être branchée via un connecteur indépendant. L’ajout d’une nouvelle institution ne doit pas nécessiter de modifier le cœur applicatif.
93
+
94
+ ### 4.2 Dégradation élégante
95
+
96
+ Si une source ne fournit pas toutes les métadonnées attendues, le système doit renvoyer un résultat partiel plutôt qu’un échec global.
97
+
98
+ ### 4.3 Transparence
99
+
100
+ Chaque résultat doit afficher clairement :
101
+
102
+ * l’institution source ;
103
+ * le type de source ;
104
+ * l’URL de notice ;
105
+ * la disponibilité ou non d’un manifest IIIF ;
106
+ * les droits si connus.
107
+
108
+ ### 4.4 IIIF-first mais pas IIIF-only
109
+
110
+ Le système privilégie les ressources IIIF, mais il doit accepter que certains catalogues aient une recherche propre et un accès au manifest indirect.
111
+
112
+ ### 4.5 Viewer séparé du moteur
113
+
114
+ Mirador ne contient aucune logique de recherche métier. Il reçoit des manifests déjà identifiés par la couche découverte.
115
+
116
+ ---
117
+
118
+ ## 5. Cas d’usage
119
+
120
+ ### 5.1 Recherche simple
121
+
122
+ L’utilisateur tape « book of hours » et voit des résultats venant de plusieurs institutions.
123
+
124
+ ### 5.2 Filtrage
125
+
126
+ L’utilisateur filtre par institution, type d’objet, langue, période ou disponibilité IIIF.
127
+
128
+ ### 5.3 Lecture
129
+
130
+ L’utilisateur clique sur un résultat et l’objet s’ouvre dans Mirador.
131
+
132
+ ### 5.4 Comparaison
133
+
134
+ L’utilisateur sélectionne plusieurs résultats et les ouvre côte à côte dans Mirador.
135
+
136
+ ### 5.5 Import manuel
137
+
138
+ L’utilisateur colle l’URL d’un manifest IIIF ou d’une notice ; le système tente de détecter le manifest et l’ouvre.
139
+
140
+ ### 5.6 Usage agentique
141
+
142
+ Un agent appelle le serveur MCP pour rechercher « Dante manuscript », filtre les résultats par institution, récupère les manifests et renvoie au client une URL d’ouverture dans Mirador.
143
+
144
+ ---
145
+
146
+ ## 6. Fonctionnalités détaillées
147
+
148
+ ## 6.1 Onglet Recherche
149
+
150
+ Doit contenir :
151
+
152
+ * champ de recherche plein texte ;
153
+ * bouton rechercher ;
154
+ * filtres latéraux ;
155
+ * sélecteur de sources ;
156
+ * mode recherche simple / avancée ;
157
+ * affichage galerie ;
158
+ * pagination ou scroll infini.
159
+
160
+ ### 6.1.1 Recherche simple
161
+
162
+ Un seul champ libre interroge plusieurs sources.
163
+
164
+ ### 6.1.2 Recherche avancée
165
+
166
+ Champs optionnels :
167
+
168
+ * mots-clés ;
169
+ * institution ;
170
+ * type de document ;
171
+ * langue ;
172
+ * date min ;
173
+ * date max ;
174
+ * disponibilité IIIF ;
175
+ * présence d’image ;
176
+ * présence d’OCR.
177
+
178
+ ### 6.1.3 Galerie de résultats
179
+
180
+ Chaque carte doit afficher :
181
+
182
+ * miniature ;
183
+ * titre ;
184
+ * institution ;
185
+ * type d’objet ;
186
+ * date ;
187
+ * auteur / créateur si disponible ;
188
+ * indicateur IIIF ;
189
+ * indicateur OCR ;
190
+ * lien notice ;
191
+ * bouton « Ouvrir dans Mirador » ;
192
+ * case à cocher « comparer ».
193
+
194
+ ## 6.2 Onglet Lecture
195
+
196
+ Cet onglet embarque Mirador.
197
+
198
+ Fonctions attendues :
199
+
200
+ * ouverture d’un manifest ;
201
+ * ouverture de plusieurs manifests ;
202
+ * disposition multi-fenêtres ;
203
+ * zoom, rotation, navigation canvas/page ;
204
+ * panneau métadonnées ;
205
+ * bouton partage d’URL ;
206
+ * bouton retour résultats.
207
+
208
+ ## 6.3 Barre d’actions rapides
209
+
210
+ Visible depuis les cartes de résultats :
211
+
212
+ * ouvrir ;
213
+ * ajouter à la comparaison ;
214
+ * copier manifest ;
215
+ * copier notice ;
216
+ * ouvrir dans un nouvel onglet.
217
+
218
+ ## 6.4 Import manuel
219
+
220
+ Une interface doit permettre :
221
+
222
+ * de coller une URL de manifest ;
223
+ * de coller une URL de notice ;
224
+ * de saisir un identifiant connu selon certaines sources.
225
+
226
+ Le backend tente alors :
227
+
228
+ 1. de reconnaître la source ;
229
+ 2. de récupérer le manifest ;
230
+ 3. de charger Mirador.
231
+
232
+ ## 6.5 Journal de transparence
233
+
234
+ Pour chaque résultat, un panneau optionnel « Voir la provenance » doit pouvoir afficher :
235
+
236
+ * connecteur utilisé ;
237
+ * requête envoyée ;
238
+ * temps de réponse ;
239
+ * niveau de confiance de normalisation ;
240
+ * champs absents.
241
+
242
+ ---
243
+
244
+ ## 7. Architecture globale
245
+
246
+ ## 7.1 Vue d’ensemble
247
+
248
+ Le système comporte :
249
+
250
+ ### Frontend
251
+
252
+ * application React ou Next.js ;
253
+ * interface utilisateur ;
254
+ * intégration Mirador ;
255
+ * gestion de l’état ;
256
+ * appel à l’API backend.
257
+
258
+ ### Backend
259
+
260
+ * FastAPI ;
261
+ * orchestrateur de recherche ;
262
+ * normalisation des métadonnées ;
263
+ * cache ;
264
+ * résolution de manifests ;
265
+ * endpoints REST ;
266
+ * couche MCP optionnelle.
267
+
268
+ ### Déploiement
269
+
270
+ * Hugging Face Space Docker ;
271
+ * variables d’environnement ;
272
+ * stockage léger pour cache local ;
273
+ * logs standardisés.
274
+
275
+ ---
276
+
277
+ ## 8. Choix techniques recommandés
278
+
279
+ ## 8.1 Frontend
280
+
281
+ * React + TypeScript
282
+ * Vite ou Next.js
283
+ * TanStack Query pour les appels réseau
284
+ * Zustand ou Redux Toolkit pour l’état global
285
+ * composant Mirador intégré dans une vue dédiée
286
+ * Tailwind CSS pour l’UI
287
+
288
+ ## 8.2 Backend
289
+
290
+ * Python 3.11+
291
+ * FastAPI
292
+ * httpx pour appels asynchrones
293
+ * pydantic pour modèles
294
+ * cachetools ou redis optionnel si disponible
295
+ * structlog ou logging JSON
296
+
297
+ ## 8.3 MCP
298
+
299
+ * couche séparée, facultative au démarrage
300
+ * outils exposés par-dessus les mêmes services métiers que le REST
301
+ * surtout aucune logique dupliquée entre REST et MCP
302
+
303
+ ## 8.4 Déploiement
304
+
305
+ * conteneur unique au MVP
306
+ * frontend servi soit statiquement, soit via le backend
307
+ * config simple via variables d’environnement
308
+
309
+ ---
310
+
311
+ ## 9. Architecture logique détaillée
312
+
313
+ ## 9.1 Modules backend
314
+
315
+ ### a. Search Orchestrator
316
+
317
+ Responsabilités :
318
+
319
+ * recevoir une requête utilisateur ;
320
+ * sélectionner les connecteurs à appeler ;
321
+ * lancer les appels en parallèle ;
322
+ * agréger les réponses ;
323
+ * normaliser les résultats ;
324
+ * classer ;
325
+ * renvoyer la réponse unifiée.
326
+
327
+ ### b. Connector Registry
328
+
329
+ Registre de tous les connecteurs disponibles.
330
+
331
+ Fonctions :
332
+
333
+ * lister les connecteurs ;
334
+ * indiquer leurs capacités ;
335
+ * savoir lesquels sont activés ;
336
+ * fournir l’instance du connecteur demandé.
337
+
338
+ ### c. Source Connectors
339
+
340
+ Un connecteur par source.
341
+
342
+ Interface commune obligatoire :
343
+
344
+ * `search(query, filters, page, page_size)`
345
+ * `get_item(source_id)`
346
+ * `resolve_manifest(item_or_url)`
347
+ * `healthcheck()`
348
+ * `capabilities()`
349
+
350
+ ### d. Normalization Layer
351
+
352
+ Transforme des réponses hétérogènes en schéma commun.
353
+
354
+ ### e. Manifest Resolver
355
+
356
+ Essaye de trouver un manifest à partir de :
357
+
358
+ * métadonnées de résultat ;
359
+ * URL de notice ;
360
+ * endpoint spécifique de la source ;
361
+ * heuristiques configurées.
362
+
363
+ ### f. Cache Layer
364
+
365
+ Cache des requêtes de recherche et des résolutions de manifest.
366
+
367
+ ### g. MCP Adapter
368
+
369
+ Expose certains services backend sous forme d’outils MCP.
370
+
371
+ ---
372
+
373
+ ## 10. Contrat des connecteurs
374
+
375
+ Chaque connecteur doit implémenter une classe abstraite commune.
376
+
377
+ ### 10.1 Interface conceptuelle
378
+
379
+ ```python
380
+ class BaseConnector(ABC):
381
+ name: str
382
+ source_type: str
383
+
384
+ @abstractmethod
385
+ async def search(self, query: str, filters: dict, page: int, page_size: int) -> SearchResultPage:
386
+ ...
387
+
388
+ @abstractmethod
389
+ async def get_item(self, source_id: str) -> NormalizedItem | None:
390
+ ...
391
+
392
+ @abstractmethod
393
+ async def resolve_manifest(self, item: NormalizedItem | None = None, url: str | None = None) -> str | None:
394
+ ...
395
+
396
+ @abstractmethod
397
+ async def capabilities(self) -> dict:
398
+ ...
399
+
400
+ @abstractmethod
401
+ async def healthcheck(self) -> dict:
402
+ ...
403
+ ```
404
+
405
+ ### 10.2 Capacités déclaratives
406
+
407
+ Un connecteur doit déclarer explicitement :
408
+
409
+ * recherche libre oui/non ;
410
+ * recherche structurée oui/non ;
411
+ * pagination oui/non ;
412
+ * facettes oui/non ;
413
+ * résolution manifest directe oui/non ;
414
+ * OCR signalé oui/non ;
415
+ * miniature disponible oui/non.
416
+
417
+ ---
418
+
419
+ ## 11. Schéma de données normalisé
420
+
421
+ ## 11.1 Objet principal : NormalizedItem
422
+
423
+ ```json
424
+ {
425
+ "id": "global-unique-id",
426
+ "source": "gallica",
427
+ "source_label": "Gallica / BnF",
428
+ "source_item_id": "ark-or-internal-id",
429
+ "title": "string",
430
+ "subtitle": "string|null",
431
+ "creators": ["string"],
432
+ "date_display": "string|null",
433
+ "date_sort": "string|null",
434
+ "languages": ["string"],
435
+ "object_type": "manuscript|book|image|map|newspaper|other",
436
+ "description": "string|null",
437
+ "thumbnail_url": "string|null",
438
+ "preview_image_url": "string|null",
439
+ "institution": "string|null",
440
+ "collection": "string|null",
441
+ "rights": "string|null",
442
+ "license": "string|null",
443
+ "record_url": "string|null",
444
+ "manifest_url": "string|null",
445
+ "iiif_image_service_url": "string|null",
446
+ "has_iiif_manifest": true,
447
+ "has_images": true,
448
+ "has_ocr": false,
449
+ "availability": "public|restricted|unknown",
450
+ "relevance_score": 0.0,
451
+ "raw_source_payload": {},
452
+ "normalization_warnings": ["string"]
453
+ }
454
+ ```
455
+
456
+ ## 11.2 Réponse de recherche
457
+
458
+ ```json
459
+ {
460
+ "query": "book of hours",
461
+ "page": 1,
462
+ "page_size": 24,
463
+ "total_estimated": 214,
464
+ "results": [],
465
+ "sources_used": ["gallica", "bodleian", "europeana"],
466
+ "partial_failures": [
467
+ {
468
+ "source": "bodleian",
469
+ "error": null,
470
+ "status": "ok"
471
+ }
472
+ ],
473
+ "duration_ms": 942,
474
+ "facets": {
475
+ "source": [],
476
+ "object_type": [],
477
+ "language": []
478
+ }
479
+ }
480
+ ```
481
+
482
+ ---
483
+
484
+ ## 12. API REST interne
485
+
486
+ ## 12.1 Endpoints principaux
487
+
488
+ ### `GET /api/health`
489
+
490
+ Retourne l’état global de l’application.
491
+
492
+ ### `GET /api/sources`
493
+
494
+ Retourne la liste des connecteurs actifs et leurs capacités.
495
+
496
+ ### `POST /api/search`
497
+
498
+ Entrée :
499
+
500
+ ```json
501
+ {
502
+ "query": "book of hours",
503
+ "sources": ["gallica", "bodleian"],
504
+ "filters": {
505
+ "object_type": ["manuscript"],
506
+ "language": ["lat"],
507
+ "has_iiif_manifest": true
508
+ },
509
+ "page": 1,
510
+ "page_size": 24,
511
+ "sort": "relevance"
512
+ }
513
+ ```
514
+
515
+ Sortie : SearchResponse normalisée.
516
+
517
+ ### `GET /api/item/{global_id}`
518
+
519
+ Retourne le détail d’un item normalisé.
520
+
521
+ ### `POST /api/resolve-manifest`
522
+
523
+ Entrée :
524
+
525
+ ```json
526
+ {
527
+ "source": "gallica",
528
+ "source_item_id": "identifier",
529
+ "record_url": "optional"
530
+ }
531
+ ```
532
+
533
+ Sortie :
534
+
535
+ ```json
536
+ {
537
+ "manifest_url": "https://.../manifest",
538
+ "status": "resolved",
539
+ "method": "metadata|heuristic|source-api"
540
+ }
541
+ ```
542
+
543
+ ### `POST /api/open`
544
+
545
+ Entrée :
546
+
547
+ ```json
548
+ {
549
+ "manifest_urls": ["https://example.org/manifest/1"],
550
+ "workspace": "default"
551
+ }
552
+ ```
553
+
554
+ Sortie :
555
+
556
+ ```json
557
+ {
558
+ "mirador_state": {}
559
+ }
560
+ ```
561
+
562
+ ### `POST /api/import`
563
+
564
+ Permet d’importer une URL libre.
565
+
566
+ Entrée :
567
+
568
+ ```json
569
+ {
570
+ "url": "https://example.org/item/or/manifest"
571
+ }
572
+ ```
573
+
574
+ Sortie :
575
+
576
+ ```json
577
+ {
578
+ "detected_source": "bodleian",
579
+ "record_url": "...",
580
+ "manifest_url": "...",
581
+ "item": {}
582
+ }
583
+ ```
584
+
585
+ ---
586
+
587
+ ## 13. Outils MCP à exposer
588
+
589
+ Le serveur MCP doit réutiliser les mêmes services métiers que l’API REST.
590
+
591
+ ### Outils minimum
592
+
593
+ #### `search_items`
594
+
595
+ Paramètres :
596
+
597
+ * query
598
+ * sources
599
+ * filters
600
+ * page
601
+ * page_size
602
+
603
+ Retour : liste normalisée de résultats.
604
+
605
+ #### `get_item`
606
+
607
+ Paramètres :
608
+
609
+ * global_id
610
+
611
+ Retour : détail d’un item.
612
+
613
+ #### `resolve_manifest`
614
+
615
+ Paramètres :
616
+
617
+ * global_id ou URL
618
+
619
+ Retour : manifest URL.
620
+
621
+ #### `open_in_mirador`
622
+
623
+ Paramètres :
624
+
625
+ * une ou plusieurs manifest URLs
626
+
627
+ Retour : URL d’ouverture ou état Mirador sérialisé.
628
+
629
+ #### `list_sources`
630
+
631
+ Retour : sources actives et capacités.
632
+
633
+ ### Ressources MCP éventuelles
634
+
635
+ * catalogue des sources
636
+ * documentation des schémas
637
+ * exemples de requêtes
638
+
639
+ ---
640
+
641
+ ## 14. Intégration Mirador
642
+
643
+ ## 14.1 Attentes fonctionnelles
644
+
645
+ Mirador doit être embarqué comme composant de lecture.
646
+
647
+ L’application doit pouvoir :
648
+
649
+ * initialiser Mirador avec zéro, une ou plusieurs fenêtres ;
650
+ * injecter dynamiquement les manifests sélectionnés ;
651
+ * mémoriser l’état courant de la session ;
652
+ * permettre un partage d’URL si possible.
653
+
654
+ ## 14.2 Mode d’intégration
655
+
656
+ Créer un composant `MiradorWorkspace` qui reçoit une liste de manifests et une configuration.
657
+
658
+ Exemple de props :
659
+
660
+ ```ts
661
+ interface MiradorWorkspaceProps {
662
+ manifestUrls: string[]
663
+ initialView?: "single" | "compare"
664
+ showMetadata?: boolean
665
+ onStateChange?: (state: unknown) => void
666
+ }
667
+ ```
668
+
669
+ ## 14.3 État applicatif
670
+
671
+ Le frontend doit stocker séparément :
672
+
673
+ * résultats de recherche ;
674
+ * sélection pour comparaison ;
675
+ * manifests ouverts ;
676
+ * configuration du workspace.
677
+
678
+ ---
679
+
680
+ ## 15. UI et UX détaillées
681
+
682
+ ## 15.1 Navigation principale
683
+
684
+ * onglet Recherche
685
+ * onglet Lecture
686
+ * onglet Import
687
+ * onglet Sources
688
+ * onglet À propos
689
+
690
+ ## 15.2 Page Recherche
691
+
692
+ ### Colonne gauche
693
+
694
+ * sources
695
+ * type d’objet
696
+ * période
697
+ * langue
698
+ * disponibilité IIIF
699
+ * présence OCR
700
+
701
+ ### Zone centrale
702
+
703
+ * barre de recherche
704
+ * tri
705
+ * nombre de résultats
706
+ * cartes résultats
707
+
708
+ ### Colonne droite optionnelle
709
+
710
+ * panier de comparaison
711
+ * aperçu rapide du résultat sélectionné
712
+
713
+ ## 15.3 Cartes résultats
714
+
715
+ Doivent être lisibles, homogènes et sobres.
716
+
717
+ Actions visibles :
718
+
719
+ * ouvrir
720
+ * comparer
721
+ * détails
722
+
723
+ ## 15.4 Page Lecture
724
+
725
+ * bandeau avec titres des objets ouverts
726
+ * zone Mirador principale
727
+ * panneau latéral avec métadonnées et provenance
728
+
729
+ ## 15.5 Page Sources
730
+
731
+ Affiche pour chaque source :
732
+
733
+ * nom
734
+ * description
735
+ * statut
736
+ * capacités
737
+ * notes spécifiques
738
+ * exemple de requête test
739
+
740
+ ---
741
+
742
+ ## 16. Classement et fusion des résultats
743
+
744
+ Le système doit agréger des résultats hétérogènes. Il faut donc définir une stratégie de ranking simple au MVP.
745
+
746
+ ### 16.1 Score de base
747
+
748
+ Combiner :
749
+
750
+ * score natif de la source si disponible ;
751
+ * qualité de correspondance textuelle locale ;
752
+ * disponibilité d’un manifest ;
753
+ * présence d’une miniature ;
754
+ * complétude des métadonnées.
755
+
756
+ ### 16.2 Déduplication légère
757
+
758
+ Tenter de détecter des doublons faibles via :
759
+
760
+ * titre normalisé ;
761
+ * identifiants communs ;
762
+ * URLs canoniques ;
763
+ * manifest identique.
764
+
765
+ En cas de doute, ne pas fusionner automatiquement au MVP.
766
+
767
+ ---
768
+
769
+ ## 17. Performance et robustesse
770
+
771
+ ## 17.1 Appels concurrents
772
+
773
+ Le backend doit appeler les connecteurs en parallèle avec timeout par source.
774
+
775
+ ## 17.2 Timeouts
776
+
777
+ Chaque source doit avoir :
778
+
779
+ * timeout connexion ;
780
+ * timeout lecture ;
781
+ * timeout global par requête.
782
+
783
+ ## 17.3 Partial success
784
+
785
+ Si une source échoue, les autres résultats doivent quand même apparaître.
786
+
787
+ ## 17.4 Cache
788
+
789
+ Mettre en cache :
790
+
791
+ * résultats de recherche récents ;
792
+ * résolutions de manifest ;
793
+ * capacités des sources.
794
+
795
+ ## 17.5 Limitation
796
+
797
+ Ajouter un plafond raisonnable de sources interrogées simultanément au MVP.
798
+
799
+ ---
800
+
801
+ ## 18. Sécurité et conformité
802
+
803
+ ## 18.1 Sécurité minimale
804
+
805
+ * validation stricte des URLs importées ;
806
+ * blocage des schémas non autorisés ;
807
+ * prévention SSRF basique ;
808
+ * limitation des domaines si nécessaire ;
809
+ * logs sans données sensibles.
810
+
811
+ ## 18.2 Respect des sources
812
+
813
+ * afficher la source d’origine ;
814
+ * ne pas masquer les droits ;
815
+ * ne pas revendiquer la propriété des données ;
816
+ * lien systématique vers la notice d’origine.
817
+
818
+ ## 18.3 CORS et proxy
819
+
820
+ Prévoir un backend pouvant agir comme intermédiaire pour certains appels si le frontend rencontre des restrictions cross-origin.
821
+
822
+ ---
823
+
824
+ ## 19. Observabilité
825
+
826
+ Prévoir :
827
+
828
+ * logs structurés ;
829
+ * mesure des temps par source ;
830
+ * taux de résolution des manifests ;
831
+ * taux d’échec par connecteur ;
832
+ * nombre moyen de résultats par source.
833
+
834
+ ---
835
+
836
+ ## 20. Arborescence de projet recommandée
837
+
838
+ ```text
839
+ app/
840
+ frontend/
841
+ src/
842
+ components/
843
+ pages/
844
+ hooks/
845
+ store/
846
+ lib/
847
+ types/
848
+ backend/
849
+ app/
850
+ api/
851
+ services/
852
+ connectors/
853
+ models/
854
+ mcp/
855
+ utils/
856
+ config/
857
+ tests/
858
+ unit/
859
+ integration/
860
+ docs/
861
+ Dockerfile
862
+ docker-compose.yml
863
+ README.md
864
+ ```
865
+
866
+ ---
867
+
868
+ ## 21. Plan de développement par étapes
869
+
870
+ ## Phase 1 — socle
871
+
872
+ * boot frontend ;
873
+ * boot backend ;
874
+ * endpoint health ;
875
+ * intégration Mirador minimale ;
876
+ * schéma `NormalizedItem`.
877
+
878
+ ## Phase 2 — connecteurs MVP
879
+
880
+ * connecteur Gallica ;
881
+ * connecteur Bodleian ;
882
+ * connecteur Europeana ;
883
+ * registre de connecteurs ;
884
+ * orchestration de recherche.
885
+
886
+ ## Phase 3 — UX recherche
887
+
888
+ * galerie ;
889
+ * filtres ;
890
+ * pagination ;
891
+ * détail item ;
892
+ * ouverture Mirador.
893
+
894
+ ## Phase 4 — import et résolution
895
+
896
+ * import URL ;
897
+ * résolution manifest ;
898
+ * comparaison multi-fenêtres.
899
+
900
+ ## Phase 5 — MCP
901
+
902
+ * outils minimum ;
903
+ * documentation ;
904
+ * exemples clients.
905
+
906
+ ## Phase 6 — polissage
907
+
908
+ * cache ;
909
+ * logs ;
910
+ * robustesse ;
911
+ * amélioration ranking.
912
+
913
+ ---
914
+
915
+ ## 22. Critères d’acceptation du MVP
916
+
917
+ Le MVP est considéré comme acceptable si :
918
+
919
+ 1. une requête simple renvoie des résultats depuis au moins trois sources ;
920
+ 2. les résultats sont affichés dans une galerie homogène ;
921
+ 3. au moins 80 % des résultats disposant réellement d’un manifest peuvent être ouverts dans Mirador ;
922
+ 4. l’ouverture de plusieurs objets dans Mirador fonctionne ;
923
+ 5. l’échec d’une source n’empêche pas la réponse globale ;
924
+ 6. l’API `/api/sources` décrit clairement les capacités ;
925
+ 7. l’import d’une URL de manifest fonctionne ;
926
+ 8. les fonctions principales sont exposées aussi via MCP si la couche MCP est activée.
927
+
928
+ ---
929
+
930
+ ## 23. Non-objectifs explicites
931
+
932
+ Le document doit clairement indiquer ce que le produit n’est pas :
933
+
934
+ * ce n’est pas un moteur de recherche web généraliste ;
935
+ * ce n’est pas un catalogue mondial exhaustif ;
936
+ * ce n’est pas une base propriétaire remplaçant les institutions ;
937
+ * ce n’est pas un viewer maison destiné à remplacer Mirador ;
938
+ * ce n’est pas une solution d’annotation scientifique complète au MVP.
939
+
940
+ ---
941
+
942
+ ## 24. Spécification pour génération de code par LLM
943
+
944
+ Le LLM chargé de coder le projet doit respecter les consignes suivantes.
945
+
946
+ ### 24.1 Contraintes générales
947
+
948
+ * tout le code doit être typé ;
949
+ * tout le code doit être modulaire ;
950
+ * aucune logique métier dupliquée entre REST et MCP ;
951
+ * chaque connecteur doit être isolé ;
952
+ * chaque fonction publique doit avoir docstring ou commentaire clair ;
953
+ * les erreurs doivent être gérées proprement ;
954
+ * les appels réseau doivent être asynchrones côté backend.
955
+
956
+ ### 24.2 Contraintes frontend
957
+
958
+ * TypeScript strict ;
959
+ * composants réutilisables ;
960
+ * éviter les dépendances inutiles ;
961
+ * UI simple et claire ;
962
+ * aucun style inline massif ;
963
+ * préférer Tailwind.
964
+
965
+ ### 24.3 Contraintes backend
966
+
967
+ * FastAPI ;
968
+ * modèles Pydantic ;
969
+ * services séparés des routes ;
970
+ * tests unitaires des connecteurs ;
971
+ * tests d’intégration des endpoints.
972
+
973
+ ### 24.4 Livrables attendus du LLM
974
+
975
+ * code complet frontend ;
976
+ * code complet backend ;
977
+ * Dockerfile ;
978
+ * README d’installation ;
979
+ * exemples `.env.example` ;
980
+ * tests minimum ;
981
+ * documentation d’API.
982
+
983
+ ---
984
+
985
+ ## 25. Prompt maître pour un LLM codeur
986
+
987
+ ```text
988
+ Tu dois générer un projet complet déployable sur Hugging Face Spaces sous forme d’application web Docker.
989
+
990
+ Objectif du produit : une interface de recherche fédérée sur plusieurs sources patrimoniales, avec affichage d’une galerie de résultats normalisés, puis ouverture directe des objets dans Mirador à partir de leurs manifests IIIF.
991
+
992
+ Contraintes :
993
+ - frontend React + TypeScript ;
994
+ - backend FastAPI Python ;
995
+ - architecture modulaire ;
996
+ - connecteurs par source ;
997
+ - schéma de données normalisé ;
998
+ - Mirador intégré comme couche de lecture ;
999
+ - API REST interne ;
1000
+ - couche MCP optionnelle mais prévue ;
1001
+ - code propre, typé, documenté, testable.
1002
+
1003
+ Fonctionnalités MVP :
1004
+ - champ de recherche ;
1005
+ - sélection de sources ;
1006
+ - filtres simples ;
1007
+ - galerie de résultats ;
1008
+ - bouton ouvrir dans Mirador ;
1009
+ - comparaison multi-objets ;
1010
+ - import manuel d’URL de manifest ;
1011
+ - endpoint listant les sources et capacités.
1012
+
1013
+ Architecture attendue :
1014
+ - dossier frontend ;
1015
+ - dossier backend ;
1016
+ - dossier tests ;
1017
+ - Dockerfile ;
1018
+ - README.
1019
+
1020
+ Backend :
1021
+ - créer une interface abstraite BaseConnector ;
1022
+ - implémenter un registry de connecteurs ;
1023
+ - implémenter un orchestrateur de recherche ;
1024
+ - définir les modèles Pydantic NormalizedItem, SearchResponse, SourceCapability ;
1025
+ - créer les endpoints /api/health, /api/sources, /api/search, /api/item/{id}, /api/resolve-manifest, /api/import.
1026
+
1027
+ Frontend :
1028
+ - créer une page Recherche ;
1029
+ - créer une page Lecture avec Mirador ;
1030
+ - créer un store pour la sélection des résultats ;
1031
+ - créer des cartes de résultats ;
1032
+ - permettre d’ouvrir un ou plusieurs manifests dans Mirador.
1033
+
1034
+ Important :
1035
+ - ne pas coder de logique de recherche dans Mirador ;
1036
+ - séparer nettement découverte et lecture ;
1037
+ - gérer les erreurs partielles des sources ;
1038
+ - prévoir des mocks si certaines API réelles sont instables.
1039
+
1040
+ Commence par générer l’arborescence complète du projet, puis le backend, puis le frontend, puis les tests, puis le Dockerfile et le README.
1041
+ ```
1042
+
1043
+ ---
1044
+
1045
+ ## 26. Prompts spécialisés par lot
1046
+
1047
+ ## Prompt lot 1 — backend socle
1048
+
1049
+ ```text
1050
+ Génère uniquement le backend FastAPI du projet.
1051
+
1052
+ Exigences :
1053
+ - Python 3.11+
1054
+ - FastAPI
1055
+ - Pydantic
1056
+ - httpx async
1057
+ - architecture modulaire
1058
+ - BaseConnector abstraite
1059
+ - ConnectorRegistry
1060
+ - SearchOrchestrator
1061
+ - modèles NormalizedItem, SearchResponse, SourceInfo
1062
+ - endpoints : /api/health, /api/sources, /api/search, /api/item/{id}, /api/resolve-manifest, /api/import
1063
+ - gestion d’erreurs propre
1064
+ - docstrings
1065
+ - tests unitaires de base
1066
+
1067
+ Ne génère pas encore le frontend.
1068
+ ```
1069
+
1070
+ ## Prompt lot 2 — frontend socle
1071
+
1072
+ ```text
1073
+ Génère uniquement le frontend React + TypeScript du projet.
1074
+
1075
+ Exigences :
1076
+ - page Recherche
1077
+ - filtres latéraux
1078
+ - galerie de résultats
1079
+ - composant ResultCard
1080
+ - store global pour manifests sélectionnés
1081
+ - page Lecture intégrant Mirador
1082
+ - navigation simple entre Recherche et Lecture
1083
+ - Tailwind CSS
1084
+ - code propre et typé
1085
+
1086
+ Le frontend doit appeler les endpoints du backend déjà définis.
1087
+ ```
1088
+
1089
+ ## Prompt lot 3 — connecteurs
1090
+
1091
+ ```text
1092
+ Ajoute au backend un système de connecteurs source.
1093
+
1094
+ Exigences :
1095
+ - implémenter BaseConnector
1096
+ - créer au moins 3 connecteurs d’exemple
1097
+ - chaque connecteur doit renvoyer des résultats normalisés
1098
+ - prévoir un mode mock si la source distante n’est pas disponible
1099
+ - ne pas dupliquer la logique de normalisation
1100
+ ```
1101
+
1102
+ ## Prompt lot 4 — MCP
1103
+
1104
+ ```text
1105
+ Ajoute une couche MCP au backend existant.
1106
+
1107
+ Exigences :
1108
+ - exposer les outils search_items, get_item, resolve_manifest, open_in_mirador, list_sources
1109
+ - réutiliser les mêmes services métiers que les routes REST
1110
+ - ne créer aucune duplication de logique
1111
+ - fournir un exemple minimal d’utilisation par un client MCP
1112
+ ```
1113
+
1114
+ ---
1115
+
1116
+ ## 27. Backlog post-MVP
1117
+
1118
+ Après le MVP, prévoir :
1119
+
1120
+ * sauvegarde de sessions ;
1121
+ * favoris ;
1122
+ * export CSV / JSON des résultats ;
1123
+ * partage de workspace Mirador ;
1124
+ * annotation persistante ;
1125
+ * index local optionnel ;
1126
+ * détection de doublons plus avancée ;
1127
+ * recherche intra-document via Content Search IIIF quand disponible ;
1128
+ * enrichissement sémantique ;
1129
+ * facettes avancées ;
1130
+ * recommandation d’objets similaires.
1131
+
1132
+ ---
1133
+
1134
+ ## 28. Décisions produit à ne pas perdre
1135
+
1136
+ 1. Mirador est la couche de lecture, jamais la couche de recherche.
1137
+ 2. Les connecteurs sont les unités fondamentales d’extension.
1138
+ 3. Le schéma normalisé est le cœur du projet.
1139
+ 4. Le MVP privilégie la simplicité et la robustesse sur l’exhaustivité.
1140
+ 5. Le MCP est utile comme surcouche d’interopérabilité, pas comme justification unique du produit.
1141
+
1142
+ ---
1143
+
1144
+ ## 29. Version courte à remettre à un développeur ou à un LLM
1145
+
1146
+ Créer une application web déployable sur Hugging Face Spaces qui permet de rechercher des objets patrimoniaux dans plusieurs institutions, d’afficher les résultats sous forme de galerie homogène, puis d’ouvrir directement les objets dans Mirador à partir de leurs manifests IIIF.
1147
+
1148
+ Le produit comprend :
1149
+
1150
+ * un frontend React/TypeScript ;
1151
+ * un backend FastAPI ;
1152
+ * des connecteurs source modulaires ;
1153
+ * un schéma de données normalisé ;
1154
+ * Mirador intégré ;
1155
+ * une API REST ;
1156
+ * une couche MCP optionnelle.
1157
+
1158
+ Le MVP doit inclure recherche fédérée, filtres simples, galerie, ouverture Mirador, comparaison multi-objets et import manuel d’URL de manifest.
1159
+
1160
+ Le système doit être robuste aux échecs partiels, simple à étendre et proprement documenté.