added mermaid and a lot of cmap changes

This commit is contained in:
2026-08-27 13:13:39 +02:00
parent 20c1584016
commit 2215d1d04a
35 changed files with 6442 additions and 350 deletions
+12 -2
View File
@@ -17,6 +17,8 @@ De database bevat zowel de huidige toestand als de auditgeschiedenis. De browser
| `attachment_references` | Huidige en historische verwijzingen vanuit paginaversies |
| `concept_maps` | Actuele titel, JSONB-document en versieteller per CMap |
| `concept_map_versions` | Expliciete CMap-snapshots en maximaal vijf handmatige opslagversies per CMap |
| `concept_definitions` | Wiki-brede inhoud per stabiele `conceptId`; plaatsing en opmaak blijven in het CMap-document |
| `people` | Wiki-breed register van actieve en inactieve namen voor getypeerde persoonstags |
| `password_reset_tokens` | Gehashte, tijdelijke en eenmalige herstelcodes |
| `wiki_settings` | Beheerinstellingen, momenteel vooral e-mail |
| `wiki_schema` | Geïnstalleerde migratieversie |
@@ -39,7 +41,7 @@ Een paginaopslag is één atomaire transactie:
6. Vervang huidige bijlageverwijzingen en leg historische verwijzingen voor de nieuwe versie vast.
7. Commit alles, of niets.
Een CMap-opslag volgt voor de actuele projectie hetzelfde kernpatroon: rij vergrendelen, versienummer vergelijken en actuele JSONB bijwerken. Autosave verhoogt wel het optimistische versienummer, maar maakt geen historieregel. Een expliciete opslag voegt een volledige toestand aan `concept_map_versions` toe en verwijdert oudere handmatige versies boven de grens van vijf. Benoemde snapshots vallen niet onder die grens.
Een CMap-opslag volgt voor de actuele projectie hetzelfde kernpatroon: rij vergrendelen, versienummer vergelijken en actuele JSONB bijwerken. In dezelfde transactie worden de aangeleverde inhoudelijke velden op `conceptId` in `concept_definitions` gezet. Een `conceptId` is een kale, lowercase en globaal unieke UUID; hij bevat bewust geen CMap-slug. De getrimde, hoofdletterongevoelige conceptnaam is wiki-breed uniek; een tweede plaatsing met dezelfde naam krijgt direct de bestaande id. Het opgeslagen CMap-document bevat zelf geen inhoudelijke kopie: `items[]` bewaart alleen structuur en opmaak en `concepts[]` bevat uitsluitend `{id}`-verwijzingen. `concept_definitions` is de enige persistente bron voor naam, samenvatting, aspecten, personen, koppelingen, afbeelding en toelichtingspagina. Bij uitlezen hydrateert de server die verwijzingen voor de editor. Ieder item behalve een verbindingszin is een plaatsing van een concept; `submap`, `page` en `concept` zijn lokale structurele rollen en geen afzonderlijke conceptsoorten. Positie, afmetingen, kleuren, typografie en structurele rol kunnen per plaatsing verschillen. De CMap zelf houdt haar stabiele, leesbare `concept_maps.slug`; die slug identificeert de kaart en staat los van de concept-UUID's. Autosave verhoogt wel het optimistische versienummer, maar maakt geen historieregel. Een expliciete opslag voegt een volledige toestand aan `concept_map_versions` toe en verwijdert oudere handmatige versies boven de grens van vijf. Benoemde snapshots vallen niet onder die grens.
## Waarom volledige snapshots
@@ -49,10 +51,16 @@ De prijs is lineaire databasegroei met het aantal versies maal de documentgroott
## Afgeleide gegevens
`pages.search_document`, `todo_items` en `attachment_references.current_reference` zijn afgeleide gegevens. Zij moeten in dezelfde transactie als hun bron worden aangepast. Een los herstelcommando mag ze opnieuw kunnen opbouwen, maar gewone reads mogen niet afhankelijk zijn van een toevallig later achtergrondproces.
`pages.search_document`, `todo_items` en `attachment_references.current_reference` zijn afgeleide gegevens. Zij moeten in dezelfde transactie als hun bron worden aangepast. Een los herstelcommando mag ze opnieuw kunnen opbouwen, maar gewone reads mogen niet afhankelijk zijn van een toevallig later achtergrondproces. Concepten met het aspect `TODO` worden daarentegen rechtstreeks uit `concept_definitions` geselecteerd en met de pagina-todo's samengevoegd; daarvoor bestaat bewust geen tweede index.
De gecombineerde navigatiegraaf is momenteel volledig afgeleid in de browser. Zij wordt niet als databasegraaf bewaard.
## CMap-uitwisselingsformaat
Het versieerbare JSON-formaat `racket-wiki-cmap-bundle` volgt dezelfde scheiding als de database. `cmaps[]` bevat per stabiele slug het volledige structuur- en opmaakdocument, `concepts[]` bevat de gedeelde inhoud per UUID en `pages[]` bevat de actuele titel, Markdown, tags en daarin gebruikte attachments van gekoppelde wiki- en uitlegpagina's. De binaire inhoud staat base64-gecodeerd bij de pagina. Daardoor kan één concept op meerdere kaarten dezelfde inhoud houden terwijl positie, formaat, kleuren en typografie per plaatsing behouden blijven. Verbindingszinnen en connectoren verwijzen naar lokale item-id's en blijven dus bij hun diagramcontext.
Een nieuw extern gegenereerd concept mag een tijdelijke `new:<naam>`-identiteit hebben, maar moet altijd in minstens één `items[]`-plaatsing met coördinaten voorkomen. De opslaglaag vervangt die tijdelijke identiteit bij de eerste import door een Racket-gegenereerde UUID en hergebruikt die via de wiki-breed unieke conceptnaam in volgende kaarten. Het JSON Schema staat onder `/schemas/racket-wiki-cmap-bundle-v1.schema.json`. Pagina- en CMap-versiegeschiedenis horen niet bij versie 1; alleen de actuele gekoppelde pagina-inhoud en haar actuele attachmentverwijzingen worden meegenomen.
## Bijlagen
Een upload hoort bij de id van de eigenaarpagina en krijgt een veilige opgeslagen naam. PostgreSQL bewaart zowel metadata als bytes. Markdown verwijst via de pagina en opgeslagen naam. Huidige en historische referenties worden afzonderlijk gevolgd, zodat beheer kan zien of een bestand alleen nog in oude versies voorkomt.
@@ -77,6 +85,8 @@ De volgende regels mogen niet alleen in de browser staan:
- iedere actuele paginaversie heeft een overeenkomstige onveranderlijke snapshot;
- CMap-autosave wijzigt alleen de actuele projectie; CMap-historie bevat alleen snapshots en maximaal vijf handmatige versies;
- alle actuele plaatsingen met dezelfde `conceptId` lezen hun inhoud uit dezelfde `concept_definitions`-rij;
- iedere actuele `conceptId` is een kale lowercase UUID; de CMap-slug blijft afzonderlijk bewaard;
- versienummers nemen per object strikt toe;
- een stale editor overschrijft geen nieuwere toestand;
- e-mailadressen zijn hoofdletterongevoelig uniek wanneer ingevuld;
+26
View File
@@ -46,6 +46,32 @@ Iedere serveropslag controleert opnieuw het basisversienummer en schrijft de act
Wanneer een actueel CMap-concept een `pageSlug` heeft, toont de gelezen wikipagina onder de inhoud een verwijzing naar dat concept. Plaatsingen worden op `conceptId` gegroepeerd en iedere betrokken CMap is rechtstreeks aanklikbaar. Alleen actuele, niet-gearchiveerde CMap-documenten tellen mee; historische CMap-versies leveren geen navigatielinks op.
Een CMap bewaart exportmetadata met tags, een samenvatting en een optionele uitlegpagina. De Markdown-export volgt gekoppelde CMaps tot de gekozen diepte, breekt cycli af en kan gekoppelde wiki- en conceptbeschrijvingspagina's als bijlage opnemen. Een persoon bij een concept is een getypeerde tag met type `person`. De personenlijst is wiki-breed; deactiveren verbergt een naam voor nieuwe selecties maar verandert bestaande CMap-documenten niet.
Een versleept bron- of doeluiteinde van een CMap-connector wijzigt zowel de zichtbare lijn als de
logische `sourceId`/`targetId`-relatie. Submapprojectie mag alleen zichtbare eindpunten vervangen en
mag een handmatige relatiebewerking bij inklappen of uitklappen niet terugdraaien. Een eindpunt dat
op lege ruimte of op het andere uiteinde wordt losgelaten, keert terug naar de laatste geldige
relatie.
Bij navigatie in afzonderlijk geopende sub-CMaps gaat de CMap-terugknop één niveau per actie terug.
Een lokale ouder in `mapHistory` heeft voorrang op navigatie naar de bronroute van een afgeleide
CMap. Alleen wanneer de wortel van die afgeleide kaart actief is, gaat terug naar de bron-CMap.
De vaste selectietoolbar naast het diagram biedt veelgebruikte selectieacties en groepslayout.
Het laatst geselecteerde concept is het blauwe referentieobject: zijn maat, randen en middellijnen
bepalen het doel voor gelijke breedte/hoogte en uitlijnen. Een klik op een reeds geselecteerd concept
wisselt dit referentieobject zonder de meervoudige selectie op te heffen. Verticaal verdelen houdt
het bovenste en onderste element vast; horizontaal verdelen houdt het meest linkse en rechtse
element vast. De overige elementen krijgen in de gekozen richting gelijke tussenruimte. Iedere
layoutactie wordt via dezelfde historie en autosave als slepen en handmatig schalen bewaard.
Relatiepijlen worden altijd in een lagere tekenlaag dan concepten en verbindingszinnen geplaatst.
Ook wanneer een relatie wordt geselecteerd of naar voren wordt gehaald, blijft zij achter alle
conceptkaarten. De hit-test gebruikt dezelfde laagprioriteit, zodat een achterliggende lijn geen
klik kan afvangen op de kaart die haar bedekt. Tijdelijke eindpunthendels blijven wel bovenop liggen
zolang een relatie wordt versleept.
## Zoeken, Recent en navigatiegraaf
Paginazoeken gebruikt een opgeslagen gewogen `tsvector` en GIN-index. CMap-zoeken verzamelt titel, slug, labels en synopses uit JSONB. Recent voegt de nieuwste pagina- en CMapwijzigingen samen.
+19
View File
@@ -6,6 +6,10 @@ De backendfuncties zijn meestal procedureel en krijgen `config` expliciet mee. D
Versie 0.2.93 introduceert wel tests in `architecture/import.rkt`. Die controleren de manifestset, interne paginalinks, CMap-embeds, unieke node-id's, connector-endpoints en de bronmarkeringen waarmee lokaal gewijzigde importinhoud wordt beschermd. Dit is een begin, geen voldoende dekking van de wiki.
Versie 0.2.100 voegt pure Node-tests toe voor de Markdown-export: dieptebegrenzing, cycli, optionele wikipagina's, persoonstags, leesbare relaties en afgeleide sub-CMapweergaven. De extractie van persoonsnamen uit CMap-documenten heeft daarnaast een kleine RackUnit-test; database- en browsergedrag blijven integratietestwerk.
Versie 0.2.115 voegt pure roundtrip- en validatietests toe voor het JSON-uitwisselingsformaat. Zij controleren dat coördinaten, afmetingen, kleuren, typografie, groepering en connectoren in de diagramlaag blijven, dat gedeelde conceptinhoud apart wordt opgeslagen en bij import wordt teruggekoppeld, en dat losse concepten, dubbele namen/slugs en ongeldige connector-endpoints worden geweigerd.
## Testpiramide voor racket-wiki
| Laag | Doel | Voorbeelden |
@@ -47,6 +51,21 @@ Introduceer geen groot mockframework. Gewone procedures en expliciete parameters
Voor frontendcode zijn browsercomponenttests met een echte DOM geschikter dan het namaken van ieder element. De CMap-adapter moet met een klein vast document getest kunnen worden zonder de hele wiki te starten.
De JavaScript-regressietest `test/cmap-connector-rewire.test.js` simuleert het verslepen van een
connector naar een andere verbindingszin, klapt de submap in en uit en controleert daarna zowel de
tekenlaag als de geserialiseerde `sourceId`.
`test/cmap-submap-navigation.test.js` opent twee geneste afzonderlijke sub-CMaps en bewijst dat één
terugactie alleen het diepste niveau verlaat en de tussenliggende kaart actief houdt.
`test/cmap-selection-layout.test.js` controleert dat het laatst geselecteerde referentieconcept de
doelmaat en uitlijning bepaalt, naast horizontale en verticale verdeling, documentserialisatie en
opname van layoutcommando's in Undo.
`test/cmap-layering.test.js` rendert concepten en een kruisende relatie in een kleine test-DOM. De
test bewijst dat de relatie ook na `toFront()` een lagere z-index houdt en dat de hit-test op het
kruispunt het concept selecteert in plaats van de verborgen relatie.
## Contract- en structuurcontroles
Naast functionele tests hoort de releasecontrole automatisch te verifiëren: