feat: extract MediaController, wire into Dispatcher, delete media.php

This commit is contained in:
Pontoporeia
2026-04-17 11:44:08 +02:00
parent b03be51b92
commit 75f808bee4
157 changed files with 1713 additions and 452 deletions

0
app/storage/.gitkeep Normal file
View File

View File

@@ -0,0 +1,74 @@
,,,,,,,,,,,,,,,,,,,,
Identifiant,Titre,Sous-titre,Auteur·ice(s),Contact,Promoteur·ice(s),Format,Année,AP,Orientation,Finalité,Mots-clés,Synopsis,Contexte,Remarques,Langue,Autorisation,License,taille,Points sur 20,lien BAIU
,,,,,,,,,,,séparer par une virgule — max. 10,,,,,,,,,
Column1,Column2,Column3,Column4,Column5,Column6,Column7,Column8,Column9,Column10,Column11,Column12,Column13,Column14,Column15,Column16,Column17,Column18,Column19,Column20,
2025-002,"Plus haut, la poussière ira plus loin",,Lucie Jacquet,luciejacquetlucie@gmail.com,"Silvia Mesturini, Sasha Newell",objet éditorial,2025,,SC,Approfondi,"carrière, mémoire collective, frictions, folklore, récits","Ce mémoire aborde les frictions générées par les sites dextraction de pierre calcaire en Wallonie.
Ces espaces à ciel ouvert qui creusent le paysage et réveillent des tensions entre exploitation
industrielle, transformations environnementales et vécus du vivant. Au-delà des plaies visibles,
ce travail cherche à faire entendre les silences des carrières, à travers des récits fragmentés
mêlant observations, entretiens et souvenirs personnels.",,,français,,,128 pages,,
2025-003,La berge du verre,,Yasmine Salem,yasminexsalem@gmail.com,"Nicolas Prignot, Olivier Gosselain","vidéo, objet éditorial",2025,,VI,Approfondi,"patrimoine, apprentissage, technique du vitrail, artisanat, documentaire,","Lorsque Pierre Majerus décède, il donne latelier de vitrail aux aspirants
maitres-verriers. Dailleurs, il disait : « apprendre un métier, cest le
voler à quelquun dautre ». Après son décès, Marcelle son épouse,
continuera à fabriquer les vitraux avec Vincent, le fidèle collaborateur.
Ensuite, Saskia a rejoint latelier pour donner des cours de vitraux avec
Vincent. Il y a aussi quelques verriers inconnus, le couple François
et Amélie et maintenant, Youri qui sessaie à la technique du vitrail à
latelier Pierre Majerus. Désormais, Marcelle et Vincent accompagnent
toutes les arrivées et départs de ces aspirants maitres-verriers. Sauf le
mardi et le mercredi, quand la salle de cours se remplit dapprenantes et
dapprenants. Vincent rejoint Saskia pour donner les cours de vitraux
avec les petits gâteaux et les « Alors ? Cest pas mal du tout ça ! »
Marcelle sort de sa véranda et se dirige vers la salle de cours avec ses
verres et ses outils dans un panier en osier. Devenir maitre-verrier ?
Ça sapprend toujours pour Marcelle malgré une soixantaine dannée à
coconstruire un atelier de vitrail.",,Dvd : avoir un lecteur dvd externe,français,,,78 pages + ?? minutes,,
2025-005,Reflet fantôme,"Mémoire, trauma et narration Le trauma comme plan cinématographique",Darika Peou,darika.peou@gmail.com,"Silvia Mesturini, Vanessa Frangville",objet éditorial,2025,LIENS,CA,Approfondi,"mémoire, trauma, narration, cambodge, film, héritage, animation, génocide","""Reflet fantôme"" interroge la manière dont le cinéma peut reconstruire un récit identitaire à partir dun héritage khmer traumatique et fragmenté. À travers trois films sur le génocide cambodgien, jexplore comment les choix narratifs et esthétiques traduisent le trauma et ouvrent un espace pour transmettre et réinventer la mémoire. Ce mémoire croise analyse filmique, études sur la mémoire traumatique et réflexion sur la transmission transgénérationnelle.",,,français,,,70 pages,,
2025-006,Tohu-bohu,Vol. 1 Nitescences Spectrales,Lilo Joris,lilo.joris@erg.school,"Caroline Godart, David Berliner",objet éditorial,2025,DPM,,Approfondi,"mémoire, amnésie, mort, médiation, rêve, utopie, narration, magazine, anthropologie, poésie","Ce mémoire est le deuxième volume de la revue poétique Tohu-Bohu, le premier étant Vol. 0 : LIridescence du Brouhaha.
Il tente de mélanger différents champs référentiels en les considérant de manière égale, tout en bien tenant compte de leurs spécificités. Il varie entre approche scientifique et approche plus poétique et sensible, proposant ainsi de faire apparaître le « poétique » à travers le « scientifique ».
Nitescences Spectrales vient poser la question de la médiation de nos mort·es. Comment est-ce quon {ré}agit aux mort·es ? Quest-ce quiels laissent derrière elleux ? Quest-ce quiels emmènent avec ellux ? Et quest-ce quon peut faire des éclats amnésiques qui restent après leur « départ » ? Ces questions demandent à comprendre comment nos récits se forment malgré leurs trous, ainsi que de comprendre comment lémotion se transforme (de manière sensible ou de manière utilitaire) au fil du temps et donc de revoir la construction même du temps. L'enjeu sous-jacent du mémoire est dobserver les effets que produisent nos dialogues avec nos mort·es que ce soit des personnes ou des moments afin de comprendre comment demain se met en place et les implications que nous y avons.",,,français,,,92 pages + annexes,,
2025-007,La Prophétie des Bâtards,Danser et faire re(co)nnaître au monde des corps qui ne comptent pas,Moriane Richard,moriane.richard@gmail.com,"Hélène Bernard, Flavio Rodrigo Orzari Ferreira, Valérie Piette",objet éditorial,2025,,IP,Approfondi,"art, danse, performance, cartographies somatiques du pouvoir, justice, médicine, transe","
Nous vivons une épidémie invisible : linflammation chronique des systèmes nerveux et sociaux sous leffet cumulé des traumatismes individuels et structurels (racisme, patriarcat, impérialisme, validisme). Cette inflammation traverse les chairs, défait les liens, atrophie lattention, durcit la pensée. LArt—et la danse en particulier—peut y répondre par des pratiques dattention et de reliance : danser, toucher, trembler pour ré-accorder le c.o.r.p.s.e.s.p.r.i.t, ré-ouvrir limaginaire et relancer la capacité relationnelle.
Je travaille en auto-ethnographie incarnée, depuis des expériences qui débordent le discours : douleurs chroniques, gestes dauto-défense somatique, apprentissages empiriques. Je croise pratiques somatiques (TRE®—tremblement neurogénique guidé, Body-Mind Centering®, contact-impro) et enquêtes théoriques (traumatologie, écologies affectives), pour élaborer une recherche-création qui pense avec le mouvement et par le toucher. Ce cadre a donné naissance à une méthode en devenir : la DarkDance—un protocole souple, subversif et sans dogme, qui considère muscles, fascias, organes et liquides comme des milieux pensants, et les engage dans une politique de la sensation.
Les enjeux sont de déplacer la critique des systèmes de domination dans les tissus mêmes des corps (cartographies somatiques du pouvoir). Et douvrir des espaces de re(co)naissance pour celles et ceux dont larchive est manquante—« les corps qui ne comptent pas ».",,,français,,,99 pages,,
2025-008,"L'école, le parlement et la cuisine",,Alice Néron,alice.neron@outlook.com,"Ayoh Kré Duchâtelet,Karolina Svobodova",objet éditorial,2025,,DN,Approfondi,"art participatif, assemblée, bruxelles, joie, conversation, affects, collectif, pouvoir d'agir","Lécole, le parlement et la cuisine revient sur trois situations dart participatif engagées à Bruxelles ces cinq dernières années à partir de mon expérience: Bodies of Knowledge, le Code du numérique et «Cuisiner (...)». Bodies of Knowledge («Lécole»), de lartiste performeuse Sarah Vanhee, est une «salle de classe» nomade installée dans l'espace public pour apprendre des savoirs de vie des habitant·es. Le Code du Numérique («le parlement»),porté par lasbl reconnue en éducation permanente Habitant·es des images, est un faux vrai code de loi écrit à partir de témoignages pour réglementer le numérique. Il s'écrit pendant les «parlements humains»: un outil d'animation qui met en scène une assemblée législative. Les ateliers «Cuisiner (...)» organisés avec Zeste Le Reste visent à cuisiner des problèmes collectifs en même temps quun repas.
Ce mémoire questionne les potentiels transformateurs de ces trois dispositifs. Comment peuvent-ils participer ou non à nous faire sentir plus capables ensemble et à faire émerger des capacités de sentir, de penser et dagir en commun ? Comment peuvent-ils, ou non, nous permettre (artistes et participant·es) de reprendre joyeusement prise sur des affects tristes ? Que nous font-ils faire ?
",,,français,,,160 pages en plusieurs brochures,,
2025-009,Santurantikuy LIVE,"Objets, gestes, transactions",LALESHKA SALAS SALAZAR,laleshka.salas@gmail.com,Ivo Provoost,objet éditorial,2025,LIENS,,Enseignement,"Performance, Pérou, Art Populaire, Hawkaypata, Connexions Partielles, Andes, Andean Culture, Human-Non human, Postcolonial Studies","Ce travail de fin détudes, intitulé Santurantikuy LIVE : Objets, gestes, transactions, constitue
une exploration scénique du caractère spatial et performatif de la foire Santurantikuy, à travers
trois axes dramatiques : les croyances animistes, le commerce, et les racines communautaires.
Instaurée au XVIe siècle par lÉglise catholique dans le cadre des mesures du Concile de Trente,
la foire du Santurantikuy avait pour objectif déradiquer les croyances andines en promouvant la
vente de figurines et de saints chrétiens. Cependant, cet objectif na jamais été entièrement at
teint.
Aujourdhui, la foire constitue un espace où la cosmovision andine et la religion chrétienne coexis
tent dans un réseau complexe de relations. Par ailleurs, des tensions persistent entre les enjeux
commerciaux et la préservation des traditions.
Le choix de ce sujet découle dun ancrage personnel : la foire du Santurantikuy représente une
tradition profondément significative pour moi, car elle fut un moment de partage avec ma grand
mère et ma tante. Elles évoquaient leurs souvenirs de la foire pendant que nous y étions, et cest
cette mémoire dun moment en train de se vivre qui ma donné envie de revisiter et explorer cet
espace à travers une approche performative et scénique.",,,français,,,170 pages,,
2025-011,Apprendre comme pratique de la liberté au XXIe siècle ?,,Zem Azem,a.zem@myyahoo.com,Stéphane Noël,audio,2025,,TY,Enseignement,"éducation critique, numérique, émancipation, bell hooks, Paulo Freire, co-création, savoirs situés, logiciel libre, pédagogie, transmission","Ce mémoire, sous forme de podcast en cinq épisodes,
explore la pensée de bell hooks et de Paulo Freire
à travers la question: qu est-ce qu apprendre comme pratique de la liberté au XXIe siècle? En partant des fondements
de la pédagogie critique, ce mémoire interroge la manière dont léducation peut encore aujourdhui être un outil démancipation, de dialogue et de transformation sociale.
Dans un monde traversé par le numérique, les algorithmes, la post-vérité et la marchandisation du savoir, la question devient: comment rendre l apprentissage à nouveau
collectif, sensible et politique? À travers des enquêtes,
des récits personnels, des références théoriques et des interviews dartistes, de chercheur·ses et de praticien·nes du libre, ce podcast propose de penser autrement lacte dapprendre, en dehors des logiques verticales
et productivistes.
Chaque épisode explore une facette de cette problématique, de léducation critique à la culture numérique, en passant
par la typographie comme outil de réappropriation
du langage. Ce projet se veut à la fois réflexion
et expérimentation, à la croisée de la pédagogie,
du design, du militantisme et des communs.",,Audio + annexes en objet éditorial (brochures pour la bibliographie etc),français,,,68 minutes,,
2024-026,DepNum,,Théophile Gervreau-Mercier,theophile.gervreaumercier@erg.school,Audrey Samson,site web,2024,,,Spécialisé,"blog, dépendance, numérique, personnelle, collective, informatique, technologies, autobiographie, addiction","Mon mémoire de Master à l'ERG est un blog autobiographique sur ma dépendance numérique. Chaque post mêle vécu personnel, questions et recherche. J'explore les dynamiques complexes de notre dépendance collective aux technologies numériques, en croisant expérience individuelle et réflexion systémique.",,,français,,,,,https://ils.bib.uclouvain.be/global/documents/3830452
2024-036,Les sons de ma maison,,ségolène Chateau,chateau.segolene@icloud.com,Sylvie bouteiller,Audio,2024,,,Spécialisé,"Sons, maison, bruit, extension de bâtiment, Recording","Ce travail sera constitué de 5 pièces sonores, résultant denregistrements effectués dans différentes pièces de ma maison.
Le but étant de prendre conscience de notre environnement sonore, et du fait que nous sommes des êtres entendants, sensibles et réceptifs aux bruits qui nous entourent.
Il consiste également à rendre de nouveau audibles ces sons, oubliés mais pourtant bien présents dans nos environnements personnels et familiers.",,,français,,,,,https://ils.bib.uclouvain.be/global/documents/3828970
2024-043,So You!,,Nascimo Clette,nascimo.clette@gmail.com,Alexander Schellow,vidéo,2024,,,Spécialisé,"Mémoire, cinéma amateur, archivage, rapport matérialiste au médium vidéo, pratique naïve","So You! est un film que j'ai réalisé en 2024 pour mon Mémoire de fin de Master à l'ERG en Vidéographie. Il s'agit d'un montage de rush que j'ai rassemblé sur un petit caméscope depuis que j'ai 8 ans. Je me suis intéressé au fonctionnement de la mémoire et au développement d'une archive personnelle au travers du médium vidéographique. Une image en entraîne une autre, au rythme des souvenirs qui remontent et au gré de ce qu'ils m'évoquent. Interroger le geste commun dun archivage personnel, comment ce geste est modelé par la technologie et comment produit-il des regards et relations uniques avec le monde. La mémoire crée des connexions incongrues a travers le temps et l'espace et nos archives sont précieuses, car elle permettent de s'approprier des micro-récits qui sont souvent réduits au silence.",,,français,,,,,https://ils.bib.uclouvain.be/global/documents/3830451
1
2 Identifiant Titre Sous-titre Auteur·ice(s) Contact Promoteur·ice(s) Format Année AP Orientation Finalité Mots-clés Synopsis Contexte Remarques Langue Autorisation License taille Points sur 20 lien BAIU
3 séparer par une virgule — max. 10
4 Column1 Column2 Column3 Column4 Column5 Column6 Column7 Column8 Column9 Column10 Column11 Column12 Column13 Column14 Column15 Column16 Column17 Column18 Column19 Column20
5 2025-002 Plus haut, la poussière ira plus loin Lucie Jacquet luciejacquetlucie@gmail.com Silvia Mesturini, Sasha Newell objet éditorial 2025 SC Approfondi carrière, mémoire collective, frictions, folklore, récits Ce mémoire aborde les frictions générées par les sites d’extraction de pierre calcaire en Wallonie. Ces espaces à ciel ouvert qui creusent le paysage et réveillent des tensions entre exploitation industrielle, transformations environnementales et vécus du vivant. Au-delà des plaies visibles, ce travail cherche à faire entendre les silences des carrières, à travers des récits fragmentés mêlant observations, entretiens et souvenirs personnels. français 128 pages
6 2025-003 La berge du verre Yasmine Salem yasminexsalem@gmail.com Nicolas Prignot, Olivier Gosselain vidéo, objet éditorial 2025 VI Approfondi patrimoine, apprentissage, technique du vitrail, artisanat, documentaire, Lorsque Pierre Majerus décède, il donne l’atelier de vitrail aux aspirants maitres-verriers. D’ailleurs, il disait : « apprendre un métier, c’est le voler à quelqu’un d’autre ». Après son décès, Marcelle son épouse, continuera à fabriquer les vitraux avec Vincent, le fidèle collaborateur. Ensuite, Saskia a rejoint l’atelier pour donner des cours de vitraux avec Vincent. Il y a aussi quelques verriers inconnus, le couple François et Amélie et maintenant, Youri qui s’essaie à la technique du vitrail à l’atelier Pierre Majerus. Désormais, Marcelle et Vincent accompagnent toutes les arrivées et départs de ces aspirants maitres-verriers. Sauf le mardi et le mercredi, quand la salle de cours se remplit d’apprenantes et d’apprenants. Vincent rejoint Saskia pour donner les cours de vitraux avec les petits gâteaux et les « Alors ? C’est pas mal du tout ça ! » Marcelle sort de sa véranda et se dirige vers la salle de cours avec ses verres et ses outils dans un panier en osier. Devenir maitre-verrier ? Ça s’apprend toujours pour Marcelle malgré une soixantaine d’année à coconstruire un atelier de vitrail. Dvd : avoir un lecteur dvd externe français 78 pages + ?? minutes
7 2025-005 Reflet fantôme Mémoire, trauma et narration – Le trauma comme plan cinématographique Darika Peou darika.peou@gmail.com Silvia Mesturini, Vanessa Frangville objet éditorial 2025 LIENS CA Approfondi mémoire, trauma, narration, cambodge, film, héritage, animation, génocide "Reflet fantôme" interroge la manière dont le cinéma peut reconstruire un récit identitaire à partir d’un héritage khmer traumatique et fragmenté. À travers trois films sur le génocide cambodgien, j’explore comment les choix narratifs et esthétiques traduisent le trauma et ouvrent un espace pour transmettre et réinventer la mémoire. Ce mémoire croise analyse filmique, études sur la mémoire traumatique et réflexion sur la transmission transgénérationnelle. français 70 pages
8 2025-006 Tohu-bohu Vol. 1 – Nitescences Spectrales Lilo Joris lilo.joris@erg.school Caroline Godart, David Berliner objet éditorial 2025 DPM Approfondi mémoire, amnésie, mort, médiation, rêve, utopie, narration, magazine, anthropologie, poésie Ce mémoire est le deuxième volume de la revue poétique Tohu-Bohu, le premier étant Vol. 0 : L’Iridescence du Brouhaha. Il tente de mélanger différents champs référentiels en les considérant de manière égale, tout en bien tenant compte de leurs spécificités. Il varie entre approche scientifique et approche plus poétique et sensible, proposant ainsi de faire apparaître le « poétique » à travers le « scientifique ». Nitescences Spectrales vient poser la question de la médiation de nos mort·es. Comment est-ce qu’on {ré}agit aux mort·es ? Qu’est-ce qu’iels laissent derrière elleux ? Qu’est-ce qu’iels emmènent avec ellux ? Et qu’est-ce qu’on peut faire des éclats amnésiques qui restent après leur « départ » ? Ces questions demandent à comprendre comment nos récits se forment malgré leurs trous, ainsi que de comprendre comment l’émotion se transforme (de manière sensible ou de manière utilitaire) au fil du temps – et donc de revoir la construction même du temps. L'enjeu sous-jacent du mémoire est d’observer les effets que produisent nos dialogues avec nos mort·es – que ce soit des personnes ou des moments – afin de comprendre comment demain se met en place et les implications que nous y avons. français 92 pages + annexes
9 2025-007 La Prophétie des Bâtards Danser et faire re(co)nnaître au monde des corps qui ne comptent pas Moriane Richard moriane.richard@gmail.com Hélène Bernard, Flavio Rodrigo Orzari Ferreira, Valérie Piette objet éditorial 2025 IP Approfondi art, danse, performance, cartographies somatiques du pouvoir, justice, médicine, transe Nous vivons une épidémie invisible : l’inflammation chronique des systèmes nerveux et sociaux sous l’effet cumulé des traumatismes individuels et structurels (racisme, patriarcat, impérialisme, validisme). Cette inflammation traverse les chairs, défait les liens, atrophie l’attention, durcit la pensée. L’Art—et la danse en particulier—peut y répondre par des pratiques d’attention et de reliance : danser, toucher, trembler pour ré-accorder le c.o.r.p.s.e.s.p.r.i.t, ré-ouvrir l’imaginaire et relancer la capacité relationnelle. Je travaille en auto-ethnographie incarnée, depuis des expériences qui débordent le discours : douleurs chroniques, gestes d’auto-défense somatique, apprentissages empiriques. Je croise pratiques somatiques (TRE®—tremblement neurogénique guidé, Body-Mind Centering®, contact-impro) et enquêtes théoriques (traumatologie, écologies affectives), pour élaborer une recherche-création qui pense avec le mouvement et par le toucher. Ce cadre a donné naissance à une méthode en devenir : la DarkDance—un protocole souple, subversif et sans dogme, qui considère muscles, fascias, organes et liquides comme des milieux pensants, et les engage dans une politique de la sensation. Les enjeux sont de déplacer la critique des systèmes de domination dans les tissus mêmes des corps (cartographies somatiques du pouvoir). Et d’ouvrir des espaces de re(co)naissance pour celles et ceux dont l’archive est manquante—« les corps qui ne comptent pas ». français 99 pages
10 2025-008 L'école, le parlement et la cuisine Alice Néron alice.neron@outlook.com Ayoh Kré Duchâtelet,Karolina Svobodova objet éditorial 2025 DN Approfondi art participatif, assemblée, bruxelles, joie, conversation, affects, collectif, pouvoir d'agir L’école, le parlement et la cuisine revient sur trois situations d’art participatif engagées à Bruxelles ces cinq dernières années à partir de mon expérience: Bodies of Knowledge, le Code du numérique et «Cuisiner (...)». Bodies of Knowledge («L’école»), de l’artiste performeuse Sarah Vanhee, est une «salle de classe» nomade installée dans l'espace public pour apprendre des savoirs de vie des habitant·es. Le Code du Numérique («le parlement»),porté par l’asbl reconnue en éducation permanente Habitant·es des images, est un faux vrai code de loi écrit à partir de témoignages pour réglementer le numérique. Il s'écrit pendant les «parlements humains»: un outil d'animation qui met en scène une assemblée législative. Les ateliers «Cuisiner (...)» organisés avec Zeste Le Reste visent à cuisiner des problèmes collectifs en même temps qu’un repas. Ce mémoire questionne les potentiels transformateurs de ces trois dispositifs. Comment peuvent-ils participer ou non à nous faire sentir plus capables ensemble et à faire émerger des capacités de sentir, de penser et d’agir en commun ? Comment peuvent-ils, ou non, nous permettre (artistes et participant·es) de reprendre joyeusement prise sur des affects tristes ? Que nous font-ils faire ? français 160 pages en plusieurs brochures
11 2025-009 Santurantikuy LIVE Objets, gestes, transactions LALESHKA SALAS SALAZAR laleshka.salas@gmail.com Ivo Provoost objet éditorial 2025 LIENS Enseignement Performance, Pérou, Art Populaire, Hawkaypata, Connexions Partielles, Andes, Andean Culture, Human-Non human, Postcolonial Studies Ce travail de fin d’études, intitulé Santurantikuy LIVE : Objets, gestes, transactions, constitue une exploration scénique du caractère spatial et performatif de la foire Santurantikuy, à travers trois axes dramatiques : les croyances animistes, le commerce, et les racines communautaires. Instaurée au XVIe siècle par l’Église catholique dans le cadre des mesures du Concile de Trente, la foire du Santurantikuy avait pour objectif d’éradiquer les croyances andines en promouvant la vente de figurines et de saints chrétiens. Cependant, cet objectif n’a jamais été entièrement at teint. Aujourd’hui, la foire constitue un espace où la cosmovision andine et la religion chrétienne coexis tent dans un réseau complexe de relations. Par ailleurs, des tensions persistent entre les enjeux commerciaux et la préservation des traditions. Le choix de ce sujet découle d’un ancrage personnel : la foire du Santurantikuy représente une tradition profondément significative pour moi, car elle fut un moment de partage avec ma grand mère et ma tante. Elles évoquaient leurs souvenirs de la foire pendant que nous y étions, et c’est cette mémoire d’un moment en train de se vivre qui m’a donné envie de revisiter et explorer cet espace à travers une approche performative et scénique. français 170 pages
12 2025-011 Apprendre comme pratique de la liberté au XXIe siècle ? Zem Azem a.zem@myyahoo.com Stéphane Noël audio 2025 TY Enseignement éducation critique, numérique, émancipation, bell hooks, Paulo Freire, co-création, savoirs situés, logiciel libre, pédagogie, transmission Ce mémoire, sous forme de podcast en cinq épisodes, explore la pensée de bell hooks et de Paulo Freire à travers la question : qu’ est-ce qu’ apprendre comme pratique de la liberté au XXIe siècle ? En partant des fondements de la pédagogie critique, ce mémoire interroge la manière dont l’éducation peut encore aujourd’hui être un outil d’émancipation, de dialogue et de transformation sociale. Dans un monde traversé par le numérique, les algorithmes, la post-vérité et la marchandisation du savoir, la question devient : comment rendre l’ apprentissage à nouveau collectif, sensible et politique ? À travers des enquêtes, des récits personnels, des références théoriques et des interviews d’artistes, de chercheur·ses et de praticien·nes du libre, ce podcast propose de penser autrement l’acte d’apprendre, en dehors des logiques verticales et productivistes. Chaque épisode explore une facette de cette problématique, de l’éducation critique à la culture numérique, en passant par la typographie comme outil de réappropriation du langage. Ce projet se veut à la fois réflexion et expérimentation, à la croisée de la pédagogie, du design, du militantisme et des communs. Audio + annexes en objet éditorial (brochures pour la bibliographie etc) français 68 minutes
13 2024-026 DepNum Théophile Gervreau-Mercier theophile.gervreaumercier@erg.school Audrey Samson site web 2024 Spécialisé blog, dépendance, numérique, personnelle, collective, informatique, technologies, autobiographie, addiction Mon mémoire de Master à l'ERG est un blog autobiographique sur ma dépendance numérique. Chaque post mêle vécu personnel, questions et recherche. J'explore les dynamiques complexes de notre dépendance collective aux technologies numériques, en croisant expérience individuelle et réflexion systémique. français https://ils.bib.uclouvain.be/global/documents/3830452
14 2024-036 Les sons de ma maison ségolène Chateau chateau.segolene@icloud.com Sylvie bouteiller Audio 2024 Spécialisé Sons, maison, bruit, extension de bâtiment, Recording Ce travail sera constitué de 5 pièces sonores, résultant d’enregistrements effectués dans différentes pièces de ma maison. Le but étant de prendre conscience de notre environnement sonore, et du fait que nous sommes des êtres entendants, sensibles et réceptifs aux bruits qui nous entourent. Il consiste également à rendre de nouveau audibles ces sons, oubliés mais pourtant bien présents dans nos environnements personnels et familiers. français https://ils.bib.uclouvain.be/global/documents/3828970
15 2024-043 So You! Nascimo Clette nascimo.clette@gmail.com Alexander Schellow vidéo 2024 Spécialisé Mémoire, cinéma amateur, archivage, rapport matérialiste au médium vidéo, pratique naïve So You! est un film que j'ai réalisé en 2024 pour mon Mémoire de fin de Master à l'ERG en Vidéographie. Il s'agit d'un montage de rush que j'ai rassemblé sur un petit caméscope depuis que j'ai 8 ans. Je me suis intéressé au fonctionnement de la mémoire et au développement d'une archive personnelle au travers du médium vidéographique. Une image en entraîne une autre, au rythme des souvenirs qui remontent et au gré de ce qu'ils m'évoquent. Interroger le geste commun d’un archivage personnel, comment ce geste est modelé par la technologie et comment produit-il des regards et relations uniques avec le monde. La mémoire crée des connexions incongrues a travers le temps et l'espace et nos archives sont précieuses, car elle permettent de s'approprier des micro-récits qui sont souvent réduits au silence. français https://ils.bib.uclouvain.be/global/documents/3830451

222
app/storage/README.md Normal file
View File

@@ -0,0 +1,222 @@
# Database Documentation
Complete documentation for the Post-ERG thesis database.
## 📚 Available Documentation
### 1. **[DATABASE_SPECIFICATION.md](DATABASE_SPECIFICATION.md)** ⭐
**Complete technical specification** - 25KB comprehensive document
**Contents:**
- Complete table definitions with all columns
- Entity relationship diagrams
- Junction table specifications
- Lookup table values
- Business rules and workflows
- Sample queries and use cases
- Instructions for requesting schema changes
**Use when:** You need complete technical details about the database structure.
---
### 2. **[QUICK_SCHEMA_REFERENCE.md](QUICK_SCHEMA_REFERENCE.md)** 🚀
**Quick reference guide** - 5KB at-a-glance reference
**Contents:**
- Table summary
- Key relationships diagram
- Core fields reference
- Predefined lookup values
- Common SQL queries
- Constraint summary
**Use when:** You need quick lookup or common query examples.
---
### 3. **[schema.sql](schema.sql)** 💾
**The actual SQL schema** - Executable SQL file
**Contents:**
- Complete CREATE TABLE statements
- Indexes and triggers
- Predefined data (orientations, AP programs, etc.)
- Views for common queries
**Use when:** Setting up or resetting the database.
---
## 🚀 Quick Start
### View Database Schema
```bash
# Read the quick reference
cat database/QUICK_SCHEMA_REFERENCE.md
# Or full specification
cat database/DATABASE_SPECIFICATION.md
```
### Initialize Database
```bash
# Create test database from schema
just init-test-db
# Create with sample data
just create-fixtures
```
### Query Database
```bash
# Open SQLite prompt
just query-db
# Show specific thesis
just show-thesis 42
```
## 📝 Making Schema Changes
### Step 1: Document Your Request
Format:
```
**Table:** [table_name]
**Change Type:** [add/modify/remove]
**What:** [description]
**Why:** [reason/use case]
**Example Data:** [samples]
```
### Step 2: Specify Details
For **new columns**:
- Column name
- Data type (TEXT, INTEGER, BOOLEAN, DATETIME)
- NULL/NOT NULL
- Default value
- Indexes needed?
For **new tables**:
- Table name
- All columns
- Relationships to existing tables
- Sample data
### Step 3: Provide Context
Include:
- Use case scenario
- Who will use it?
- How will it be displayed?
- Any constraints?
### Example Request
```
**Table:** theses
**Change Type:** add column
**What:** Add column to track if thesis won an award
**Why:** Need to highlight award-winning theses on homepage
**Column Name:** has_award
**Data Type:** BOOLEAN
**Default:** 0 (false)
**Example:** 1 for "Prix du Jury 2025" winner
```
## 🗂️ Database Structure Overview
```
┌─────────────┐
│ theses │ ◄── Main table (500+ records/year)
└──────┬──────┘
├──► authors (via thesis_authors)
├──► supervisors (via thesis_supervisors)
├──► keywords (via thesis_keywords)
├──► languages (via thesis_languages)
├──► formats (via thesis_formats)
├──► thesis_files (attachments)
└──► Lookup tables:
• orientations
• ap_programs
• finality_types
• access_types
• license_types
```
## 📊 Key Statistics
- **Core tables:** 3 (theses, authors, supervisors)
- **Junction tables:** 5 (many-to-many relationships)
- **Lookup tables:** 7 (predefined values)
- **Support tables:** 2 (files, pages)
- **Views:** 2 (full data, public only)
- **Indexes:** 11 (for performance)
- **Triggers:** 4 (auto-update timestamps)
## 🔍 Common Scenarios
### Scenario 1: Student Submits Thesis
1. Create record in `theses` (is_published=0)
2. Add author to `authors`, link via `thesis_authors`
3. Add supervisor(s) to `supervisors`, link via `thesis_supervisors`
4. Set `orientation_id`, `ap_program_id`, `finality_id`
5. Upload file to `thesis_files`
6. Add keywords via `thesis_keywords`
7. Set `submitted_at` timestamp
### Scenario 2: Admin Publishes Thesis
1. Verify all required fields present
2. Set `defense_date`
3. Set `jury_points`
4. Optional: add `context_note`
5. Set `is_published = 1`
6. Set `published_at = CURRENT_TIMESTAMP`
### Scenario 3: Public User Searches
Query `v_theses_public` view with filters:
- By year
- By orientation
- By keyword
- By author name
- Full-text search in title/synopsis
## 🛠️ Development Workflow
### Local Development
1. Use `test.db` for development
2. Create via `just init-test-db`
3. Populate with `just create-fixtures`
4. Test queries before deployment
### Schema Changes
1. Update `schema.sql`
2. Update `DATABASE_SPECIFICATION.md`
3. Test on `test.db`
4. Deploy to production (manual migration)
### Testing
```bash
# Run tests on local database
just test-public-all
# Check database stats
just stats-public
```
## 📞 Need Help?
1. **Quick lookup** → Read `QUICK_SCHEMA_REFERENCE.md`
2. **Complete details** → Read `DATABASE_SPECIFICATION.md`
3. **Schema changes** → Follow format in this README
4. **SQL examples** → Check `QUICK_SCHEMA_REFERENCE.md`
## 🔗 Related Documentation
- [Deployment Guide](../nginx/DEPLOYMENT_COMPLETE.md)
- [Repository Structure](../REPOSITORY_STRUCTURE_ANALYSIS.md)
- [Test Database Guide](../nginx/TEST_DATABASE_SETUP.md)

0
app/storage/cache/.gitkeep vendored Normal file
View File

View File

@@ -0,0 +1 @@
[1776449542]

View File

@@ -0,0 +1,253 @@
<?php
/**
* Script to create a test database with sample data
* Run this script once to set up test.db for development
*/
$dbPath = __DIR__ . '/../test.db';
// Remove existing database if it exists
if (file_exists($dbPath)) {
unlink($dbPath);
echo "Removed existing test database\n";
}
try {
// Create database connection
$pdo = new PDO('sqlite:' . $dbPath);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "Created new database: $dbPath\n";
// Read and execute schema
$schemaPath = __DIR__ . '/../schema.sql';
if (!file_exists($schemaPath)) {
throw new Exception("Schema file not found: $schemaPath");
}
$schema = file_get_contents($schemaPath);
$pdo->exec($schema);
echo "Schema created successfully\n";
// Insert sample authors
$authors = [
['name' => 'Marie Dubois', 'email' => 'marie.dubois@example.com'],
['name' => 'Jean Martin', 'email' => 'jean.martin@example.com'],
['name' => 'Sophie Bernard', 'email' => 'sophie.bernard@example.com'],
['name' => 'Lucas Petit', 'email' => 'lucas.petit@example.com'],
['name' => 'Emma Leroy', 'email' => 'emma.leroy@example.com'],
];
foreach ($authors as $author) {
$stmt = $pdo->prepare("INSERT INTO authors (name, email) VALUES (:name, :email)");
$stmt->execute($author);
}
echo "Inserted " . count($authors) . " sample authors\n";
// Insert sample supervisors
$supervisors = [
['name' => 'Prof. Claire Fontaine'],
['name' => 'Dr. Thomas Moreau'],
['name' => 'Prof. Anne Laurent'],
];
foreach ($supervisors as $supervisor) {
$stmt = $pdo->prepare("INSERT INTO supervisors (name) VALUES (:name)");
$stmt->execute($supervisor);
}
echo "Inserted " . count($supervisors) . " sample supervisors\n";
// Insert sample tags (formerly keywords)
$sampleKeywords = [
'spéculation', 'narration', 'urbanisme', 'patrimoine', 'intime',
'collectivité', 'film', 'cinéma', 'sociologie', 'anthropologie',
'éphémérité', 'queer', 'écriture', 'poésie', 'écologie',
'technologies', 'design', 'performance', 'installation', 'art numérique'
];
foreach ($sampleKeywords as $keyword) {
$stmt = $pdo->prepare("INSERT INTO tags (name) VALUES (:name)");
$stmt->execute(['name' => $keyword]);
}
echo "Inserted " . count($sampleKeywords) . " sample tags\n";
// Insert sample theses
$theses = [
[
'identifier' => '2024-001',
'title' => 'Espaces Urbains et Narration Collective',
'subtitle' => 'Une exploration des récits de la ville',
'year' => 2024,
'is_doctoral' => 0,
'orientation_id' => 1, // Arts Numériques
'ap_program_id' => 1, // Narration Spéculative
'finality_id' => 1, // Approfondi
'synopsis' => 'Ce travail explore la manière dont les espaces urbains génèrent des récits collectifs. À travers une série d\'installations vidéo et sonores, je documente les histoires cachées des quartiers en transformation. Le projet interroge la mémoire collective et la façon dont l\'architecture influence nos récits personnels et communautaires.',
'access_type_id' => 1, // Libre
'is_published' => 1,
],
[
'identifier' => '2024-002',
'title' => 'Corps et Technologies',
'subtitle' => 'Interfaces sensorielles',
'year' => 2024,
'is_doctoral' => 0,
'orientation_id' => 4, // Installation-Performance
'ap_program_id' => 2, // Design et Politique du Multiple
'finality_id' => 1, // Approfondi
'synopsis' => 'Cette recherche artistique examine la relation entre le corps humain et les technologies numériques. À travers des performances interactives, j\'explore comment les interfaces technologiques transforment notre perception corporelle et créent de nouvelles formes de présence. Le projet questionne l\'hybridation entre organique et numérique.',
'access_type_id' => 1, // Libre
'is_published' => 1,
],
[
'identifier' => '2024-003',
'title' => 'Poétiques du Quotidien',
'subtitle' => NULL,
'year' => 2024,
'is_doctoral' => 0,
'orientation_id' => 6, // Photographie
'ap_program_id' => 3, // Atelier Pratiques Situées
'finality_id' => 2, // Enseignement
'synopsis' => 'Ce projet photographique documente les gestes ordinaires et les moments éphémères du quotidien. En utilisant une approche documentaire mêlée de fiction, je cherche à révéler la poésie cachée dans les rituels banals. Le travail questionne notre rapport au temps et à l\'attention dans un monde accéléré.',
'access_type_id' => 1, // Libre
'is_published' => 1,
],
[
'identifier' => '2023-015',
'title' => 'Écologies Affectives',
'subtitle' => 'Cartographies sensibles des liens',
'year' => 2023,
'is_doctoral' => 0,
'orientation_id' => 9, // Graphisme
'ap_program_id' => 4, // LIENS
'finality_id' => 1, // Approfondi
'synopsis' => 'Ce travail de design graphique développe une méthodologie visuelle pour cartographier les relations affectives et les réseaux de soin. À travers des visualisations de données sensibles et des éditions expérimentales, le projet explore comment représenter l\'invisible des liens humains et des solidarités.',
'access_type_id' => 1, // Libre
'is_published' => 1,
],
[
'identifier' => '2023-020',
'title' => 'Mémoires Spéculatives',
'subtitle' => 'Archives du futur',
'year' => 2023,
'is_doctoral' => 0,
'orientation_id' => 10, // Typographie
'ap_program_id' => 1, // Narration Spéculative
'finality_id' => 3, // Spécialisé
'synopsis' => 'Un projet éditorial qui imagine des archives futures à partir de traces présentes. En utilisant la typographie comme outil de spéculation temporelle, je crée des documents fictionnels qui interrogent notre rapport à l\'histoire et à la transmission. Le travail questionne la matérialité de la mémoire.',
'access_type_id' => 2, // Interne
'is_published' => 1,
],
[
'identifier' => '2025-002',
'title' => 'Performance et Politique du Geste',
'subtitle' => NULL,
'year' => 2025,
'is_doctoral' => 0,
'orientation_id' => 4, // Installation-Performance
'ap_program_id' => 3, // Atelier Pratiques Situées
'finality_id' => 1, // Approfondi
'synopsis' => 'Cette recherche performative explore la dimension politique des gestes quotidiens. À travers une série de performances filmées, j\'examine comment les micro-actions peuvent constituer des formes de résistance. Le projet s\'intéresse aux corps en mouvement et à leur capacité à transformer l\'espace public.',
'access_type_id' => 1, // Libre
'is_published' => 1,
],
];
foreach ($theses as $thesis) {
$columns = implode(', ', array_keys($thesis));
$placeholders = ':' . implode(', :', array_keys($thesis));
$stmt = $pdo->prepare("INSERT INTO theses ($columns) VALUES ($placeholders)");
$stmt->execute($thesis);
}
echo "Inserted " . count($theses) . " sample theses\n";
// Link authors to theses
$thesisAuthors = [
['thesis_id' => 1, 'author_id' => 1, 'author_order' => 1],
['thesis_id' => 2, 'author_id' => 2, 'author_order' => 1],
['thesis_id' => 3, 'author_id' => 3, 'author_order' => 1],
['thesis_id' => 4, 'author_id' => 4, 'author_order' => 1],
['thesis_id' => 5, 'author_id' => 5, 'author_order' => 1],
['thesis_id' => 6, 'author_id' => 1, 'author_order' => 1],
];
foreach ($thesisAuthors as $link) {
$stmt = $pdo->prepare("INSERT INTO thesis_authors (thesis_id, author_id, author_order) VALUES (:thesis_id, :author_id, :author_order)");
$stmt->execute($link);
}
echo "Linked authors to theses\n";
// Link supervisors to theses
$thesisSupervisors = [
['thesis_id' => 1, 'supervisor_id' => 1, 'supervisor_order' => 1],
['thesis_id' => 2, 'supervisor_id' => 2, 'supervisor_order' => 1],
['thesis_id' => 3, 'supervisor_id' => 1, 'supervisor_order' => 1],
['thesis_id' => 4, 'supervisor_id' => 3, 'supervisor_order' => 1],
['thesis_id' => 5, 'supervisor_id' => 2, 'supervisor_order' => 1],
['thesis_id' => 6, 'supervisor_id' => 3, 'supervisor_order' => 1],
];
foreach ($thesisSupervisors as $link) {
$stmt = $pdo->prepare("INSERT INTO thesis_supervisors (thesis_id, supervisor_id, supervisor_order) VALUES (:thesis_id, :supervisor_id, :supervisor_order)");
$stmt->execute($link);
}
echo "Linked supervisors to theses\n";
// Link tags to theses (thesis_tags junction)
$thesisKeywords = [
['thesis_id' => 1, 'tag_id' => 3], // urbanisme
['thesis_id' => 1, 'tag_id' => 2], // narration
['thesis_id' => 1, 'tag_id' => 6], // collectivité
['thesis_id' => 2, 'tag_id' => 16], // technologies
['thesis_id' => 2, 'tag_id' => 18], // performance
['thesis_id' => 2, 'tag_id' => 20], // art numérique
['thesis_id' => 3, 'tag_id' => 14], // poésie
['thesis_id' => 3, 'tag_id' => 11], // éphémérité
['thesis_id' => 3, 'tag_id' => 5], // intime
['thesis_id' => 4, 'tag_id' => 15], // écologie
['thesis_id' => 4, 'tag_id' => 17], // design
['thesis_id' => 5, 'tag_id' => 1], // spéculation
['thesis_id' => 5, 'tag_id' => 4], // patrimoine
['thesis_id' => 6, 'tag_id' => 18], // performance
['thesis_id' => 6, 'tag_id' => 9], // sociologie
];
foreach ($thesisKeywords as $link) {
$stmt = $pdo->prepare("INSERT OR IGNORE INTO thesis_tags (tag_id, thesis_id) VALUES (:tag_id, :thesis_id)");
$stmt->execute($link);
}
echo "Linked tags to theses\n";
// Link languages to theses (all in French)
for ($i = 1; $i <= 6; $i++) {
$stmt = $pdo->prepare("INSERT INTO thesis_languages (thesis_id, language_id) VALUES (:thesis_id, 1)");
$stmt->execute(['thesis_id' => $i]);
}
echo "Linked languages to theses\n";
// Link formats to theses
$thesisFormats = [
['thesis_id' => 1, 'format_id' => 3], // Vidéo
['thesis_id' => 1, 'format_id' => 6], // Installation
['thesis_id' => 2, 'format_id' => 4], // Performance
['thesis_id' => 3, 'format_id' => 5], // Objet éditorial
['thesis_id' => 4, 'format_id' => 1], // Site web
['thesis_id' => 4, 'format_id' => 5], // Objet éditorial
['thesis_id' => 5, 'format_id' => 5], // Objet éditorial
['thesis_id' => 6, 'format_id' => 4], // Performance
['thesis_id' => 6, 'format_id' => 3], // Vidéo
];
foreach ($thesisFormats as $link) {
$stmt = $pdo->prepare("INSERT INTO thesis_formats (thesis_id, format_id) VALUES (:thesis_id, :format_id)");
$stmt->execute($link);
}
echo "Linked formats to theses\n";
echo "\n✅ Test database created successfully!\n";
echo "Database location: $dbPath\n";
echo "\nYou can now test the search feature at: http://localhost/front-backend/repertoire.php\n";
} catch (Exception $e) {
echo "❌ Error: " . $e->getMessage() . "\n";
exit(1);
}

View File

@@ -0,0 +1,106 @@
-- Migration 001: Rename keywords→tags, thesis_keywords→thesis_tags, keyword column→name
-- SQLite does not support ALTER TABLE RENAME COLUMN before 3.25, so we recreate tables.
-- This migration is safe to run after 004 and 005 (no dependency ordering required
-- since SQLite processes this in one transaction).
PRAGMA foreign_keys = OFF;
BEGIN;
-- 1. Create new tags table
CREATE TABLE tags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- 2. Copy data from keywords → tags (keyword column → name)
INSERT INTO tags (id, name, created_at)
SELECT id, keyword, created_at FROM keywords;
-- 3. Create new junction table thesis_tags
CREATE TABLE thesis_tags (
tag_id INTEGER NOT NULL,
thesis_id INTEGER NOT NULL,
PRIMARY KEY (tag_id, thesis_id),
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE,
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
);
-- 4. Copy junction data (keyword_id → tag_id)
INSERT INTO thesis_tags (tag_id, thesis_id)
SELECT keyword_id, thesis_id FROM thesis_keywords;
-- 5. Drop old tables
DROP TABLE thesis_keywords;
DROP TABLE keywords;
-- 6. Recreate indexes with canonical names
CREATE INDEX idx_tags_name ON tags(name);
CREATE INDEX idx_thesis_tags_thesis ON thesis_tags(thesis_id);
CREATE INDEX idx_thesis_tags_tag ON thesis_tags(tag_id);
-- 7. Rebuild views to reference new tables
DROP VIEW IF EXISTS v_theses_full;
CREATE VIEW v_theses_full AS
SELECT
t.id,
t.identifier,
t.title,
t.subtitle,
t.year,
t.is_doctoral,
o.name as orientation,
ap.name as ap_program,
ft.name as finality_type,
t.synopsis,
t.context_note,
t.duration_minutes,
t.duration_pages,
t.file_size_info,
at.name as access_type,
lt.name as license_type,
t.license_id,
t.jury_points,
t.submitted_at,
t.defense_date,
t.published_at,
t.is_published,
t.baiu_link,
t.banner_path,
GROUP_CONCAT(DISTINCT a.name) as authors,
GROUP_CONCAT(DISTINCT s.name) as supervisors,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'president' THEN s.name END) as jury_president,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'promoteur' THEN s.name END) as jury_promoteurs,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'lecteur' THEN s.name END) as jury_lecteurs,
GROUP_CONCAT(DISTINCT l.name) as languages,
GROUP_CONCAT(DISTINCT fmt.name) as formats,
GROUP_CONCAT(DISTINCT tg.name) as keywords
FROM theses t
LEFT JOIN orientations o ON t.orientation_id = o.id
LEFT JOIN ap_programs ap ON t.ap_program_id = ap.id
LEFT JOIN finality_types ft ON t.finality_id = ft.id
LEFT JOIN access_types at ON t.access_type_id = at.id
LEFT JOIN license_types lt ON t.license_id = lt.id
LEFT JOIN thesis_authors ta ON t.id = ta.thesis_id
LEFT JOIN authors a ON ta.author_id = a.id
LEFT JOIN thesis_supervisors ts ON t.id = ts.thesis_id
LEFT JOIN supervisors s ON ts.supervisor_id = s.id
LEFT JOIN thesis_languages tl ON t.id = tl.thesis_id
LEFT JOIN languages l ON tl.language_id = l.id
LEFT JOIN thesis_formats tf ON t.id = tf.thesis_id
LEFT JOIN format_types fmt ON tf.format_id = fmt.id
LEFT JOIN thesis_tags tt ON t.id = tt.thesis_id
LEFT JOIN tags tg ON tt.tag_id = tg.id
GROUP BY t.id;
DROP VIEW IF EXISTS v_theses_public;
CREATE VIEW v_theses_public AS
SELECT * FROM v_theses_full
WHERE is_published = 1;
COMMIT;
PRAGMA foreign_keys = ON;

View File

@@ -0,0 +1,9 @@
-- Migration 002: Wire visibility states to existing access_type_id column.
-- The access_types table already has Libre (1), Interne (2), Interdit (3).
-- No structural changes needed — this migration is a no-op for the schema.
-- It documents the intent and ensures access_types seed rows exist.
INSERT OR IGNORE INTO access_types (id, name, description) VALUES
(1, 'Libre', 'TFE en libre accès à tout le monde sur la plateforme et en bibliothèque'),
(2, 'Interne', 'TFE accessible uniquement sur place en physique. Une note descriptive est disponible sur le site'),
(3, 'Interdit', 'TFE non disponible en physique ni sur le site. Une note descriptive est disponible sur le site');

View File

@@ -0,0 +1,19 @@
-- Migration 003: Seed license_types table
-- Safe to run on existing databases (INSERT OR IGNORE)
CREATE TABLE IF NOT EXISTS license_types (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
description TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT OR IGNORE INTO license_types (name) VALUES
('CC BY 4.0'),
('CC BY-SA 4.0'),
('CC BY-ND 4.0'),
('CC BY-NC 4.0'),
('CC BY-NC-SA 4.0'),
('CC BY-NC-ND 4.0'),
('Tous droits réservés'),
('Domaine public');

View File

@@ -0,0 +1,66 @@
-- Migration 004: Add jury role and is_external columns to thesis_supervisors
-- Existing rows get role = 'promoteur', is_external = 0 (no data loss)
ALTER TABLE thesis_supervisors ADD COLUMN role TEXT NOT NULL DEFAULT 'promoteur';
ALTER TABLE thesis_supervisors ADD COLUMN is_external INTEGER NOT NULL DEFAULT 0;
-- Recreate v_theses_full to include jury role columns
DROP VIEW IF EXISTS v_theses_full;
CREATE VIEW v_theses_full AS
SELECT
t.id,
t.identifier,
t.title,
t.subtitle,
t.year,
t.is_doctoral,
o.name as orientation,
ap.name as ap_program,
ft.name as finality_type,
t.synopsis,
t.context_note,
t.duration_minutes,
t.duration_pages,
t.file_size_info,
at.name as access_type,
lt.name as license_type,
t.license_id,
t.jury_points,
t.submitted_at,
t.defense_date,
t.published_at,
t.is_published,
t.baiu_link,
GROUP_CONCAT(DISTINCT a.name) as authors,
GROUP_CONCAT(DISTINCT s.name) as supervisors,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'president' THEN s.name END) as jury_president,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'promoteur' THEN s.name END) as jury_promoteurs,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'lecteur' THEN s.name END) as jury_lecteurs,
GROUP_CONCAT(DISTINCT l.name) as languages,
GROUP_CONCAT(DISTINCT fmt.name) as formats,
GROUP_CONCAT(DISTINCT k.keyword) as keywords
FROM theses t
LEFT JOIN orientations o ON t.orientation_id = o.id
LEFT JOIN ap_programs ap ON t.ap_program_id = ap.id
LEFT JOIN finality_types ft ON t.finality_id = ft.id
LEFT JOIN access_types at ON t.access_type_id = at.id
LEFT JOIN license_types lt ON t.license_id = lt.id
LEFT JOIN thesis_authors ta ON t.id = ta.thesis_id
LEFT JOIN authors a ON ta.author_id = a.id
LEFT JOIN thesis_supervisors ts ON t.id = ts.thesis_id
LEFT JOIN supervisors s ON ts.supervisor_id = s.id
LEFT JOIN thesis_languages tl ON t.id = tl.thesis_id
LEFT JOIN languages l ON tl.language_id = l.id
LEFT JOIN thesis_formats tf ON t.id = tf.thesis_id
LEFT JOIN format_types fmt ON tf.format_id = fmt.id
LEFT JOIN thesis_keywords tk ON t.id = tk.thesis_id
LEFT JOIN keywords k ON tk.keyword_id = k.id
GROUP BY t.id;
-- Recreate public view
DROP VIEW IF EXISTS v_theses_public;
CREATE VIEW v_theses_public AS
SELECT * FROM v_theses_full
WHERE is_published = 1;

View File

@@ -0,0 +1,65 @@
-- Migration 005: Add banner_path column to theses for home page card thumbnails
ALTER TABLE theses ADD COLUMN banner_path TEXT;
-- Recreate v_theses_full to include banner_path
DROP VIEW IF EXISTS v_theses_full;
CREATE VIEW v_theses_full AS
SELECT
t.id,
t.identifier,
t.title,
t.subtitle,
t.year,
t.is_doctoral,
o.name as orientation,
ap.name as ap_program,
ft.name as finality_type,
t.synopsis,
t.context_note,
t.duration_minutes,
t.duration_pages,
t.file_size_info,
at.name as access_type,
lt.name as license_type,
t.license_id,
t.jury_points,
t.submitted_at,
t.defense_date,
t.published_at,
t.is_published,
t.baiu_link,
t.banner_path,
GROUP_CONCAT(DISTINCT a.name) as authors,
GROUP_CONCAT(DISTINCT s.name) as supervisors,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'president' THEN s.name END) as jury_president,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'promoteur' THEN s.name END) as jury_promoteurs,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'lecteur' THEN s.name END) as jury_lecteurs,
GROUP_CONCAT(DISTINCT l.name) as languages,
GROUP_CONCAT(DISTINCT fmt.name) as formats,
GROUP_CONCAT(DISTINCT tg.name) as keywords
FROM theses t
LEFT JOIN orientations o ON t.orientation_id = o.id
LEFT JOIN ap_programs ap ON t.ap_program_id = ap.id
LEFT JOIN finality_types ft ON t.finality_id = ft.id
LEFT JOIN access_types at ON t.access_type_id = at.id
LEFT JOIN license_types lt ON t.license_id = lt.id
LEFT JOIN thesis_authors ta ON t.id = ta.thesis_id
LEFT JOIN authors a ON ta.author_id = a.id
LEFT JOIN thesis_supervisors ts ON t.id = ts.thesis_id
LEFT JOIN supervisors s ON ts.supervisor_id = s.id
LEFT JOIN thesis_languages tl ON t.id = tl.thesis_id
LEFT JOIN languages l ON tl.language_id = l.id
LEFT JOIN thesis_formats tf ON t.id = tf.thesis_id
LEFT JOIN format_types fmt ON tf.format_id = fmt.id
LEFT JOIN thesis_tags tt ON t.id = tt.thesis_id
LEFT JOIN tags tg ON tt.tag_id = tg.id
GROUP BY t.id;
-- Recreate public view
DROP VIEW IF EXISTS v_theses_public;
CREATE VIEW v_theses_public AS
SELECT * FROM v_theses_full
WHERE is_published = 1;

View File

@@ -0,0 +1,8 @@
-- Migration 006: Add composite covering index (is_published, year DESC) on theses
--
-- Every public-facing query filters on is_published = 1 AND orders/filters by year.
-- The existing separate idx_theses_published and idx_theses_year force the query
-- planner to pick one index and sort the other via a temp B-tree.
-- This single covering index eliminates the extra sort pass.
CREATE INDEX IF NOT EXISTS idx_theses_pub_year ON theses(is_published, year DESC);

View File

@@ -0,0 +1,8 @@
-- Migration 007: Add system_cache table for admin system page caching
-- Stores JSON-encoded status snapshots keyed by section with a TTL mechanism.
CREATE TABLE IF NOT EXISTS system_cache (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
updated_at INTEGER NOT NULL
);

View File

@@ -0,0 +1,89 @@
-- Migration 008: Formulaire settings + contact visibility
-- Adds site_settings key-value table for admin-configurable options
-- Adds show_contact column to authors table
-- Adds author_email + author_show_contact to views
-- ── 1. site_settings ─────────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS site_settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL DEFAULT '',
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Default formulaire settings:
-- access_type_interdit_enabled = 1 (Interdit is available in the add form)
-- access_type_interne_enabled = 1 (Interne is available in the add form)
-- access_type_libre_enabled = 0 (Libre is NOT yet available — next academic year)
INSERT OR IGNORE INTO site_settings (key, value) VALUES
('access_type_interdit_enabled', '1'),
('access_type_interne_enabled', '1'),
('access_type_libre_enabled', '0');
-- ── 2. show_contact on authors ────────────────────────────────────────────────
-- NOTE: SQLite has no IF NOT EXISTS for ALTER TABLE.
-- The migrate.sh script guards against re-running; ignore errors on existing DBs.
ALTER TABLE authors ADD COLUMN show_contact INTEGER NOT NULL DEFAULT 0;
-- ── 3. Rebuild views to expose author_email and author_show_contact ───────────
DROP VIEW IF EXISTS v_theses_public;
DROP VIEW IF EXISTS v_theses_full;
CREATE VIEW IF NOT EXISTS v_theses_full AS
SELECT
t.id,
t.identifier,
t.title,
t.subtitle,
t.year,
t.is_doctoral,
o.name as orientation,
ap.name as ap_program,
ft.name as finality_type,
t.synopsis,
t.context_note,
t.duration_minutes,
t.duration_pages,
t.file_size_info,
at.name as access_type,
lt.name as license_type,
t.license_id,
t.jury_points,
t.submitted_at,
t.defense_date,
t.published_at,
t.is_published,
t.baiu_link,
t.banner_path,
t.access_type_id,
GROUP_CONCAT(DISTINCT a.name) as authors,
GROUP_CONCAT(DISTINCT s.name) as supervisors,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'president' THEN s.name END) as jury_president,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'promoteur' THEN s.name END) as jury_promoteurs,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'lecteur' THEN s.name END) as jury_lecteurs,
GROUP_CONCAT(DISTINCT l.name) as languages,
GROUP_CONCAT(DISTINCT fmt.name) as formats,
GROUP_CONCAT(DISTINCT tg.name) as keywords,
-- First author's email and contact-visibility flag
(SELECT a2.email FROM authors a2 JOIN thesis_authors ta2 ON a2.id = ta2.author_id WHERE ta2.thesis_id = t.id ORDER BY ta2.author_order LIMIT 1) as author_email,
(SELECT a2.show_contact FROM authors a2 JOIN thesis_authors ta2 ON a2.id = ta2.author_id WHERE ta2.thesis_id = t.id ORDER BY ta2.author_order LIMIT 1) as author_show_contact
FROM theses t
LEFT JOIN orientations o ON t.orientation_id = o.id
LEFT JOIN ap_programs ap ON t.ap_program_id = ap.id
LEFT JOIN finality_types ft ON t.finality_id = ft.id
LEFT JOIN access_types at ON t.access_type_id = at.id
LEFT JOIN license_types lt ON t.license_id = lt.id
LEFT JOIN thesis_authors ta ON t.id = ta.thesis_id
LEFT JOIN authors a ON ta.author_id = a.id
LEFT JOIN thesis_supervisors ts ON t.id = ts.thesis_id
LEFT JOIN supervisors s ON ts.supervisor_id = s.id
LEFT JOIN thesis_languages tl ON t.id = tl.thesis_id
LEFT JOIN languages l ON tl.language_id = l.id
LEFT JOIN thesis_formats tf ON t.id = tf.thesis_id
LEFT JOIN format_types fmt ON tf.format_id = fmt.id
LEFT JOIN thesis_tags tt ON t.id = tt.thesis_id
LEFT JOIN tags tg ON tt.tag_id = tg.id
GROUP BY t.id;
CREATE VIEW IF NOT EXISTS v_theses_public AS
SELECT * FROM v_theses_full
WHERE is_published = 1;

View File

@@ -0,0 +1,14 @@
-- Share links table: enables students to submit TFEs via unique, optional-password-protected URLs
CREATE TABLE IF NOT EXISTS share_links (
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT NOT NULL UNIQUE, -- Format: YYYYMMDD-<random>, e.g. 20260416-a3f9k2
password_hash TEXT, -- bcrypt hash; NULL = no password required
is_active INTEGER NOT NULL DEFAULT 1, -- 1 = active, 0 = disabled
usage_count INTEGER NOT NULL DEFAULT 0, -- Number of successful submissions via this link
created_by INTEGER NOT NULL, -- admin user ID (references admin_sessions or admin_users)
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
expires_at DATETIME -- NULL = never expires
);
CREATE INDEX IF NOT EXISTS idx_share_links_slug ON share_links(slug);
CREATE INDEX IF NOT EXISTS idx_share_links_active ON share_links(is_active);

View File

@@ -0,0 +1,14 @@
-- ── apropos_contents table (structured data for the "À propos" page) ───────
-- Replaces config/apropos.php.
CREATE TABLE IF NOT EXISTS apropos_contents (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT NOT NULL UNIQUE, -- 'contacts', 'credits', 'erg_url'
value TEXT, -- JSON array for contacts/credits, plain string for erg_url
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Seed with the current defaults from config/apropos.php
INSERT OR IGNORE INTO apropos_contents (key, value) VALUES
('contacts', '[{"name":"Laurent Leprince","role":"Bibliothèque d''architecture, d''ingénierie architecturale, d''urbanisme (BAIU) :","email":"laurent.leprince@uclouvain.be"},{"name":"Xavier Gorgol","role":"Responsable des mémoires de l''ERG :","email":"xavier.gorgol@erg.be"},{"name":"Brigitte Ledune","role":"Cours de suivi de mémoire :","email":"brigitte.ledune@erg.be"}]'),
('credits', '[{"label":"Design & développement","value":"Olivia Marly, Théophile Gerveau-Mercie & Théo Hennequin"},{"label":"Typographies","value":"Ductus (Amélie Dumont) & BBB DM Sans"}]'),
('erg_url', 'https://erg.be');

View File

@@ -0,0 +1,46 @@
-- Transform apropos data: each row has a label/role and an entries[] of {text, url}.
-- Contacts also include email per entry.
UPDATE apropos_contents SET value = '
[
{
"label": "Design & développement",
"entries": [
{"text": "Olivia Marly", "url": ""},
{"text": "Théophile Gerveau-Mercie", "url": ""},
{"text": "Théo Hennequin", "url": ""}
]
},
{
"label": "Typographies",
"entries": [
{"text": "Ductus (Amélie Dumont)", "url": ""},
{"text": "BBB DM Sans", "url": ""}
]
}
]' WHERE key = 'credits';
UPDATE apropos_contents SET value = '
[
{
"role": "Bibliothèque d''architecture, d''ingénierie architecturale, d''urbanisme (BAIU) :",
"entries": [
{"text": "Laurent Leprince", "url": "", "email": "laurent.leprince@uclouvain.be"}
]
},
{
"role": "Responsable des mémoires de l''ERG :",
"entries": [
{"text": "Xavier Gorgol", "url": "", "email": "xavier.gorgol@erg.be"}
]
},
{
"role": "Cours de suivi de mémoire :",
"entries": [
{"text": "Brigitte Ledune", "url": "", "email": "brigitte.ledune@erg.be"}
]
}
]' WHERE key = 'contacts';
-- Remove erg_url from the table (hardcoded in template now)
DELETE FROM apropos_contents WHERE key = 'erg_url';

View File

@@ -0,0 +1,22 @@
-- SMTP relay credentials stored in the database.
-- A single active row is read at send-time for flexibility (change provider,
-- rotate passwords, etc. without touching code or env vars).
CREATE TABLE IF NOT EXISTS smtp_settings (
id INTEGER PRIMARY KEY CHECK (id = 1), -- singleton row
host TEXT NOT NULL DEFAULT '',
port INTEGER NOT NULL DEFAULT 587,
encryption TEXT NOT NULL DEFAULT 'tls', -- 'tls' | 'ssl' | 'none'
username TEXT NOT NULL DEFAULT '',
password TEXT NOT NULL DEFAULT '', -- stored in clear for now; encrypt later
from_email TEXT NOT NULL DEFAULT '',
from_name TEXT NOT NULL DEFAULT 'Post-ERG',
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Insert default empty row so the settings form can start working immediately.
INSERT OR IGNORE INTO smtp_settings (id) VALUES (1);
-- Helper view so callers always read the same row.
CREATE VIEW IF NOT EXISTS v_smtp_active AS
SELECT * FROM smtp_settings WHERE id = 1;

View File

@@ -0,0 +1,11 @@
-- Migration 013: Store admin password hash in site_settings
--
-- Previously stored in config/admin_credentials.php as the constant ADMIN_PASSWORD_HASH.
-- Now stored alongside SMTP credentials in the site_settings key-value table.
--
-- After applying this migration, import your existing hash manually:
-- UPDATE site_settings SET value = '$2y$12$...' WHERE key = 'admin_password_hash';
-- Or simply set a new one via the admin panel UI.
INSERT OR IGNORE INTO site_settings (key, value) VALUES
('admin_password_hash', '');

BIN
app/storage/posterg.db Normal file

Binary file not shown.

516
app/storage/schema.sql Normal file
View File

@@ -0,0 +1,516 @@
-- Post-ERG Thesis Database Schema
-- SQLite Database for managing final thesis projects (TFE) and doctoral theses
-- ============================================================================
-- CORE ENTITIES
-- ============================================================================
-- Students/Authors table
CREATE TABLE IF NOT EXISTS authors (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT,
show_contact INTEGER NOT NULL DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Supervisors/Promoters table
CREATE TABLE IF NOT EXISTS supervisors (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- ============================================================================
-- PREDEFINED REFERENCE DATA (lookup tables)
-- ============================================================================
-- Orientations (predefined list from specifications)
CREATE TABLE IF NOT EXISTS orientations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Insert predefined orientations
INSERT OR IGNORE INTO orientations (name) VALUES
('Arts Numériques'),
('Dessin'),
('Cinéma d''animation'),
('Installation-Performance'),
('Peinture'),
('Photographie'),
('Sculpture'),
('Vidéographie'),
('Graphisme'),
('Typographie'),
('Design Numérique'),
('Illustration'),
('Bande-Dessinée'),
('Sérigraphie'),
('Gravure');
-- AP (Ateliers Pratiques) - predefined list
CREATE TABLE IF NOT EXISTS ap_programs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
code TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Insert predefined AP programs
INSERT OR IGNORE INTO ap_programs (name, code) VALUES
('Narration Spéculative', NULL),
('Design et Politique du Multiple', 'DPM'),
('Atelier Pratiques Situées', 'APS'),
('Lieux, Interdisciplinarités, Écologie, Nécessité, Systèmes', 'LIENS');
-- Master finality types
CREATE TABLE IF NOT EXISTS finality_types (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT OR IGNORE INTO finality_types (name) VALUES
('Approfondi'),
('Enseignement'),
('Spécialisé');
-- Languages
CREATE TABLE IF NOT EXISTS languages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT OR IGNORE INTO languages (name) VALUES
('Français'),
('Anglais');
-- Format types (can select multiple)
CREATE TABLE IF NOT EXISTS format_types (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT OR IGNORE INTO format_types (name) VALUES
('Site web'),
('Audio'),
('Vidéo'),
('Performance'),
('Objet éditorial'),
('Installation'),
('Autre');
-- Tags (keywords — canonical M2M table; formerly 'keywords'/'keyword' column)
CREATE TABLE IF NOT EXISTS tags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_tags_name ON tags(name);
-- Access authorization types
CREATE TABLE IF NOT EXISTS access_types (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
description TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT OR IGNORE INTO access_types (name, description) VALUES
('Libre', 'TFE en libre accès à tout le monde sur la plateforme et en bibliothèque'),
('Interne', 'TFE accessible uniquement sur place en physique. Une note descriptive est disponible sur le site'),
('Interdit', 'TFE non disponible en physique ni sur le site. Une note descriptive est disponible sur le site');
-- License types
CREATE TABLE IF NOT EXISTS license_types (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
description TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT OR IGNORE INTO license_types (name) VALUES
('CC BY 4.0'),
('CC BY-SA 4.0'),
('CC BY-ND 4.0'),
('CC BY-NC 4.0'),
('CC BY-NC-SA 4.0'),
('CC BY-NC-ND 4.0'),
('Tous droits réservés'),
('Domaine public');
-- ============================================================================
-- MAIN THESIS TABLE
-- ============================================================================
CREATE TABLE IF NOT EXISTS theses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
identifier TEXT UNIQUE, -- e.g., "2025-002"
-- Basic information
title TEXT NOT NULL,
subtitle TEXT,
year INTEGER NOT NULL,
-- Type of work
is_doctoral BOOLEAN DEFAULT 0, -- 0 for TFE, 1 for doctoral thesis
-- Academic details
orientation_id INTEGER,
ap_program_id INTEGER,
finality_id INTEGER,
-- Content
synopsis TEXT, -- ~200 words
context_note TEXT, -- Note added by jury president (max 150 words)
remarks TEXT, -- Internal remarks
-- Duration/size
duration_minutes INTEGER, -- For audio/video works
duration_pages INTEGER, -- For written works
file_size_info TEXT, -- e.g., "128 pages", "78 pages + ?? minutes"
-- Access and licensing
access_type_id INTEGER,
license_id INTEGER,
-- Jury information
jury_points DECIMAL(4,2), -- Points out of 20
jury_note_added BOOLEAN DEFAULT 0, -- Whether jury president added a note
-- Publication status
submitted_at DATETIME, -- When student submitted
defense_date DATETIME, -- Date of defense/soutenance
published_at DATETIME, -- When made public (after jury review)
is_published BOOLEAN DEFAULT 0,
-- External links
baiu_link TEXT, -- Link to institutional repository
-- Home page card banner (optional, landscape image)
banner_path TEXT, -- path relative to STORAGE_ROOT (e.g. "banners/abc.jpg")
-- Timestamps
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-- Foreign keys
FOREIGN KEY (orientation_id) REFERENCES orientations(id),
FOREIGN KEY (ap_program_id) REFERENCES ap_programs(id),
FOREIGN KEY (finality_id) REFERENCES finality_types(id),
FOREIGN KEY (access_type_id) REFERENCES access_types(id),
FOREIGN KEY (license_id) REFERENCES license_types(id)
);
-- ============================================================================
-- JUNCTION TABLES (Many-to-Many relationships)
-- ============================================================================
-- Authors per thesis (can have multiple authors)
CREATE TABLE IF NOT EXISTS thesis_authors (
thesis_id INTEGER NOT NULL,
author_id INTEGER NOT NULL,
author_order INTEGER DEFAULT 1, -- Order of authors if multiple
PRIMARY KEY (thesis_id, author_id),
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE,
FOREIGN KEY (author_id) REFERENCES authors(id) ON DELETE CASCADE
);
-- Supervisors per thesis (jury: president, promoteur, lecteurs)
CREATE TABLE IF NOT EXISTS thesis_supervisors (
thesis_id INTEGER NOT NULL,
supervisor_id INTEGER NOT NULL,
supervisor_order INTEGER DEFAULT 1,
role TEXT NOT NULL DEFAULT 'promoteur', -- 'president'|'promoteur'|'lecteur'
is_external INTEGER NOT NULL DEFAULT 0, -- 0 = internal, 1 = external
PRIMARY KEY (thesis_id, supervisor_id),
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE,
FOREIGN KEY (supervisor_id) REFERENCES supervisors(id) ON DELETE CASCADE
);
-- Languages per thesis (can be multilingual)
CREATE TABLE IF NOT EXISTS thesis_languages (
thesis_id INTEGER NOT NULL,
language_id INTEGER NOT NULL,
PRIMARY KEY (thesis_id, language_id),
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE,
FOREIGN KEY (language_id) REFERENCES languages(id) ON DELETE CASCADE
);
-- Formats per thesis (can have multiple formats)
CREATE TABLE IF NOT EXISTS thesis_formats (
thesis_id INTEGER NOT NULL,
format_id INTEGER NOT NULL,
PRIMARY KEY (thesis_id, format_id),
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE,
FOREIGN KEY (format_id) REFERENCES format_types(id) ON DELETE CASCADE
);
-- Tags per thesis (max 10 as per specs; formerly thesis_keywords)
CREATE TABLE IF NOT EXISTS thesis_tags (
tag_id INTEGER NOT NULL,
thesis_id INTEGER NOT NULL,
PRIMARY KEY (tag_id, thesis_id),
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE,
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
);
-- ============================================================================
-- FILE ATTACHMENTS
-- ============================================================================
CREATE TABLE IF NOT EXISTS thesis_files (
id INTEGER PRIMARY KEY AUTOINCREMENT,
thesis_id INTEGER NOT NULL,
file_type TEXT NOT NULL, -- 'main', 'annex', 'written_part', 'other'
file_path TEXT NOT NULL,
file_name TEXT NOT NULL,
file_size INTEGER, -- in bytes
mime_type TEXT,
description TEXT,
uploaded_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (thesis_id) REFERENCES theses(id) ON DELETE CASCADE
);
-- ============================================================================
-- SITE SETTINGS
-- ============================================================================
CREATE TABLE IF NOT EXISTS site_settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL DEFAULT '',
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT OR IGNORE INTO site_settings (key, value) VALUES
('access_type_interdit_enabled', '1'),
('access_type_interne_enabled', '1'),
('access_type_libre_enabled', '0'),
('admin_password_hash', '');
-- ============================================================================
-- STATIC PAGES / CONTENT MANAGEMENT
-- ============================================================================
-- For managing editable static pages (charte, about, licenses, contact)
CREATE TABLE IF NOT EXISTS system_cache (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS pages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT NOT NULL UNIQUE, -- 'charte', 'about', 'licenses', 'contact'
title TEXT NOT NULL,
content TEXT, -- Markdown or HTML content
is_published BOOLEAN DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Initialize default pages
INSERT OR IGNORE INTO pages (slug, title, content) VALUES
('charte', 'Charte', 'Contenu à venir'),
('about', 'À propos', 'Contenu à venir'),
('licenses', 'Licences', 'Contenu à venir');
-- ============================================================================
-- SMTP SETTINGS
-- ============================================================================
-- Singleton row — id is always 1. Credentials stored in clear for now.
CREATE TABLE IF NOT EXISTS smtp_settings (
id INTEGER PRIMARY KEY CHECK (id = 1),
host TEXT NOT NULL DEFAULT '',
port INTEGER NOT NULL DEFAULT 587,
encryption TEXT NOT NULL DEFAULT 'tls', -- 'tls' | 'ssl' | 'none'
username TEXT NOT NULL DEFAULT '',
password TEXT NOT NULL DEFAULT '', -- stored in clear for now; encrypt later
from_email TEXT NOT NULL DEFAULT '',
from_name TEXT NOT NULL DEFAULT 'Post-ERG',
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT OR IGNORE INTO smtp_settings (id) VALUES (1);
-- ============================================================================
-- APROPOS CONTENTS (structured data for the "À propos" page)
-- ============================================================================
CREATE TABLE IF NOT EXISTS apropos_contents (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT NOT NULL UNIQUE, -- 'contacts', 'credits', 'erg_url'
value TEXT, -- JSON array or plain string
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT OR IGNORE INTO apropos_contents (key, value) VALUES
('contacts', '[
{"role":"Bibliothèque d'architecture, d'ingénierie architecturale, d'urbanisme (BAIU) :", "entries":[
{"text":"Laurent Leprince", "email":"laurent.leprince@uclouvain.be"}
]},
{"role":"Responsable des mémoires de l'ERG :", "entries":[
{"text":"Xavier Gorgol", "email":"xavier.gorgol@erg.be"}
]},
{"role":"Cours de suivi de mémoire :", "entries":[
{"text":"Brigitte Ledune", "email":"brigitte.ledune@erg.be"}
]}
]'),
('credits', '[
{"label":"Design & développement", "entries":[
{"text":"Olivia Marly"},
{"text":"Théophile Gerveau-Mercie"},
{"text":"Théo Hennequin"}
]},
{"label":"Typographies", "entries":[
{"text":"Ductus (Amélie Dumont)"},
{"text":"BBB DM Sans"}
]}
]');INSERT OR IGNORE INTO apropos_contents (key, value) VALUES
('contacts', '[
{"role":"Bibliothèque d\u0027architecture, d\u0027ingénierie architecturale, d\u0027urbanisme (BAIU) :", "entries":[
{"text":"Laurent Leprince", "email":"laurent.leprince@uclouvain.be"}
]},
{"role":"Responsable des mémoires de l\u0027ERG :", "entries":[
{"text":"Xavier Gorgol", "email":"xavier.gorgol@erg.be"}
]},
{"role":"Cours de suivi de mémoire :", "entries":[
{"text":"Brigitte Ledune", "email":"brigitte.ledune@erg.be"}
]}
]'),
('credits', '[
{"label":"Design & développement", "entries":[
{"text":"Olivia Marly"},
{"text":"Théophile Gerveau-Mercie"},
{"text":"Théo Hennequin"}
]},
{"label":"Typographies", "entries":[
{"text":"Ductus (Amélie Dumont)"},
{"text":"BBB DM Sans"}
]}
]');
-- ============================================================================
-- INDEXES for performance
-- ============================================================================
CREATE INDEX IF NOT EXISTS idx_theses_year ON theses(year);
CREATE INDEX IF NOT EXISTS idx_theses_published ON theses(is_published);
CREATE INDEX IF NOT EXISTS idx_theses_pub_year ON theses(is_published, year DESC);
CREATE INDEX IF NOT EXISTS idx_theses_identifier ON theses(identifier);
CREATE INDEX IF NOT EXISTS idx_theses_orientation ON theses(orientation_id);
CREATE INDEX IF NOT EXISTS idx_theses_ap_program ON theses(ap_program_id);
CREATE INDEX IF NOT EXISTS idx_theses_access_type ON theses(access_type_id);
CREATE INDEX IF NOT EXISTS idx_authors_email ON authors(email);
CREATE INDEX IF NOT EXISTS idx_thesis_authors_thesis ON thesis_authors(thesis_id);
CREATE INDEX IF NOT EXISTS idx_thesis_authors_author ON thesis_authors(author_id);
CREATE INDEX IF NOT EXISTS idx_thesis_tags_thesis ON thesis_tags(thesis_id);
CREATE INDEX IF NOT EXISTS idx_thesis_tags_tag ON thesis_tags(tag_id);
-- ============================================================================
-- TRIGGERS for automatic timestamp updates
-- ============================================================================
CREATE TRIGGER IF NOT EXISTS update_theses_timestamp
AFTER UPDATE ON theses
BEGIN
UPDATE theses SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
END;
CREATE TRIGGER IF NOT EXISTS update_authors_timestamp
AFTER UPDATE ON authors
BEGIN
UPDATE authors SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
END;
CREATE TRIGGER IF NOT EXISTS update_supervisors_timestamp
AFTER UPDATE ON supervisors
BEGIN
UPDATE supervisors SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
END;
CREATE TRIGGER IF NOT EXISTS update_pages_timestamp
AFTER UPDATE ON pages
BEGIN
UPDATE pages SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
END
CREATE TRIGGER IF NOT EXISTS update_apropos_contents_timestamp
AFTER UPDATE ON apropos_contents
BEGIN
UPDATE apropos_contents SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
END;
-- ============================================================================
-- VIEWS for common queries
-- ============================================================================
-- Full thesis information view
CREATE VIEW IF NOT EXISTS v_theses_full AS
SELECT
t.id,
t.identifier,
t.title,
t.subtitle,
t.year,
t.is_doctoral,
o.name as orientation,
ap.name as ap_program,
ft.name as finality_type,
t.synopsis,
t.context_note,
t.duration_minutes,
t.duration_pages,
t.file_size_info,
at.name as access_type,
lt.name as license_type,
t.license_id,
t.access_type_id,
t.jury_points,
t.submitted_at,
t.defense_date,
t.published_at,
t.is_published,
t.baiu_link,
t.banner_path,
GROUP_CONCAT(DISTINCT a.name) as authors,
GROUP_CONCAT(DISTINCT s.name) as supervisors,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'president' THEN s.name END) as jury_president,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'promoteur' THEN s.name END) as jury_promoteurs,
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'lecteur' THEN s.name END) as jury_lecteurs,
GROUP_CONCAT(DISTINCT l.name) as languages,
GROUP_CONCAT(DISTINCT fmt.name) as formats,
GROUP_CONCAT(DISTINCT tg.name) as keywords,
-- First author's email and contact-visibility flag
(SELECT a2.email FROM authors a2 JOIN thesis_authors ta2 ON a2.id = ta2.author_id WHERE ta2.thesis_id = t.id ORDER BY ta2.author_order LIMIT 1) as author_email,
(SELECT a2.show_contact FROM authors a2 JOIN thesis_authors ta2 ON a2.id = ta2.author_id WHERE ta2.thesis_id = t.id ORDER BY ta2.author_order LIMIT 1) as author_show_contact
FROM theses t
LEFT JOIN orientations o ON t.orientation_id = o.id
LEFT JOIN ap_programs ap ON t.ap_program_id = ap.id
LEFT JOIN finality_types ft ON t.finality_id = ft.id
LEFT JOIN access_types at ON t.access_type_id = at.id
LEFT JOIN license_types lt ON t.license_id = lt.id
LEFT JOIN thesis_authors ta ON t.id = ta.thesis_id
LEFT JOIN authors a ON ta.author_id = a.id
LEFT JOIN thesis_supervisors ts ON t.id = ts.thesis_id
LEFT JOIN supervisors s ON ts.supervisor_id = s.id
LEFT JOIN thesis_languages tl ON t.id = tl.thesis_id
LEFT JOIN languages l ON tl.language_id = l.id
LEFT JOIN thesis_formats tf ON t.id = tf.thesis_id
LEFT JOIN format_types fmt ON tf.format_id = fmt.id
LEFT JOIN thesis_tags tt ON t.id = tt.thesis_id
LEFT JOIN tags tg ON tt.tag_id = tg.id
GROUP BY t.id;
-- Published theses only (for public view)
CREATE VIEW IF NOT EXISTS v_theses_public AS
SELECT * FROM v_theses_full
WHERE is_published = 1;

BIN
app/storage/test.db Normal file

Binary file not shown.