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
+234 -2
View File
@@ -2,7 +2,7 @@
Version 0.2.31 adds page namespaces as database metadata and extends wiki references to forms such as `RWS:ModelTreeWalker` and `[roadmap](racket:roadmap)`. Todo items and bookmarks are grouped by namespace. The source has also been documented more thoroughly, especially `static/js/wiki.js`.
Current development version: **0.2.99**.
Current development version: **0.2.100**.
A small self-hosted wiki with a Racket backend and an HTML5/CSS/JavaScript frontend.
@@ -16,7 +16,7 @@ The backend uses Racket `web-server-lib` for HTTP routing, `db-lib` for PostgreS
Passwords use PBKDF2-HMAC-SHA256 through the libcrypto/OpenSSL provider. Session tokens are random client values whose SHA-256 hashes are stored in PostgreSQL; authenticated write requests also use a per-session CSRF token.
The editor uses EasyMDE 2.21.0. EasyMDE bundles CodeMirror for editing and Marked for Markdown rendering. The application uses `easyMDE.markdown(...)` for the editor preview, normal page display and historical page display. DOMPurify sanitizes rendered Markdown, highlight.js highlights fenced code blocks, and diff2html renders page-version differences.
The editor uses EasyMDE 2.21.0. EasyMDE bundles CodeMirror for editing and Marked for Markdown rendering. The application uses `easyMDE.markdown(...)` for the editor preview, normal page display and historical page display. DOMPurify sanitizes rendered Markdown, Mermaid 11.17.1 renders `mermaid` fenced code blocks, highlight.js highlights other fenced code blocks, and diff2html renders page-version differences.
Lucide supplies the sidebar and EasyMDE toolbar icons. Its pinned browser build is installed locally by the setup procedure, so normal wiki use does not contact a CDN.
@@ -41,6 +41,8 @@ pages
page_versions
attachments
concept_maps
concept_map_versions
people
wiki_schema
```
@@ -102,6 +104,7 @@ lucide.min.js
easymde.min.js
easymde.min.css
purify.min.js
mermaid.min.js
highlight.min.js
highlight-scheme.min.js
highlight-github.min.css
@@ -111,6 +114,19 @@ diff2html.min.css
EasyMDE already bundles CodeMirror and Marked, so racket-wiki does not download a separate Markdown renderer or CodeMirror build.
Mermaid diagrams use ordinary fenced Markdown and are rendered in page view,
editor preview and page history:
````text
```mermaid
flowchart LR
A[Markdown] --> B[Diagram]
```
````
Mermaid runs locally with its strict security level; normal wiki use does not
contact a CDN.
The setup downloader validates HTTPS certificates and hostnames. The running wiki serves these files locally from the configured data directory, so no CDN is required after setup.
`setup-vendor.rkt` remains available as a manual/recovery command. It now writes to the same data directory as the web setup:
@@ -941,3 +957,219 @@ that page. Concepts are grouped by stable `conceptId`; each row shows the concep
placement count and clickable chips for every CMap containing it. Repeated placements in one CMap
show their local count. The panel follows page aliases and uses only current, non-archived CMap
documents—not historical versions.
### 0.2.100
Stored CMaps now have export metadata of their own: comma-separated tags, a summary and an optional
wiki page containing the longer CMap explanation. **Export Markdown** creates a report-oriented
Markdown file or copies the same source to the clipboard. The export includes concepts, readable
relations, CMap metadata and explanations, and follows linked stored CMaps to a selected depth from
zero through ten. A separate option includes linked wiki pages and concept-description pages. Cycles
and repeated links are emitted only once, and derived sub-CMap views export only their own subtree.
A person is represented as a typed concept tag rather than a separate responsibility object. A
concept can carry several person tags; linked placements sharing the same `conceptId` also share
those tags. The concept card displays the people marker and the Markdown report identifies those
people as the responsibility/action owners. Schema migration 13 adds a wiki-wide `people` registry
and imports names already present in CMap documents. The concept editor offers active people in a
multi-select dropdown. **Manage people** adds names and activates or deactivates them; deactivation
never removes the tag from existing CMaps.
### 0.2.101
Concept content is now truly shared between placements on different CMaps. Schema migration 14
creates a global `concept_definitions` repository keyed by stable `conceptId`; opening a CMap
hydrates its label, synopsis, aspects, tags, links, image and description-page reference from that
repository. Saving any placement updates that shared definition, so another CMap can no longer keep
a different explanation for the same concept. Position, dimensions, colours and typography remain
stored per placement and may still differ between maps. During migration, the most recently edited
CMap supplies the initial definition when older copies disagree.
### 0.2.102
Sub-CMap heads now follow the same identity rule as every other concept placement. Their structural
role is local to the map; it no longer excludes them from `concept_definitions`, shared-content
updates, copy-by-reference or global placement counts. Migration 15 imports definitions that older
documents stored only on sub-CMap items. Loading also hydrates item-only concept ids, so an existing
head such as **Processen LBS** immediately receives the same synopsis as its other placements while
retaining its own position, dimensions, colours and typography.
### 0.2.103
Concept identity now also follows stored CMap links. When a concept placement links to a derived
concept map, that placement and the target map's head are canonicalized to one `conceptId`.
Migration 16 records old ids in `concept_aliases` and merges their shared definition, retaining the
most recently edited content. The shared fields are deliberately limited to name, aspects, people,
concept-description page, synopsis, image, linked wiki page and linked concept map. Node kind,
sub-CMap navigation state, coordinates, dimensions, colours and typography remain placement data.
### 0.2.104
Concept names are now wiki-wide identity keys after trimming whitespace and case-folding. Migration
17 merges pre-existing definitions such as the two independently created **Processen LBS** records,
rewrites every current CMap placement and concept reference to the canonical id, removes the duplicate
definition and selects the most recently edited shared content. A retained alias only lets an old
editor or historical identifier resolve safely. Creation and save paths apply the same rule, so adding
the same concept name on another map directly reuses the existing id. Relations remain attached to
their placements while all item-level layout remains independent.
### 0.2.105
Schema migration 18 replaces the temporary alias approach with direct normalization of current
CMap data. It derives one canonical id per trimmed, case-folded concept name from the actual item
placements, rewrites every current `items[].conceptId` and `concepts[].id`, removes duplicate concept
definitions and rebuilds `concept_definitions` from the normalized documents. Connectors keep their
item endpoints, so every relation remains attached to the corresponding placement. The temporary
`concept_aliases` table is dropped. Historical CMap snapshots remain immutable and are not part of
the current concept repository.
### 0.2.106
Concept placements no longer persist denormalized copies of concept content. Migration 19 removes
name, summary, aspects, people, description-page reference, image and linked page/CMap fields from
every non-phrase `items[]` record. Those fields now exist only in `concepts[]` and the global
`concept_definitions` row. Items retain structural state, coordinates, dimensions, colours and
typography. This prevents a root map and submap context from rendering different stale summaries for
the same single placement. Linking phrases retain their label because they describe relations.
### 0.2.107
Schema migration 20 makes the central concept definition the only persisted source of concept
content. Current CMap documents retain only unique `{id}` references in `concepts[]`; non-phrase
`items[]` contain only placement, grouping and presentation data. API reads hydrate referenced
definitions for the editor and defensively remove legacy item content. Existing historical
snapshots remain unchanged.
### 0.2.108
Concept cards now treat their complete shared content as a minimum-height constraint in every map
context. Context-specific width, typography and larger manual height remain presentation settings,
but an old undersized sub-CMap layout can no longer clip the synopsis and make one concept appear to
have different content on two maps.
### 0.2.109
The concept editor now changes title and synopsis font sizes in 0.5-point increments. Existing
finer-grained values are displayed at the nearest half point, and typed values are normalized to
the same step when saved.
### 0.2.110
The wiki Todo view now also includes every current concept whose aspects contain `TODO`, matched
case-insensitively after trimming whitespace. Concept todos are derived directly from the global
concept definition, occur once regardless of placement count, show the shared synopsis and link to
the concept description page, linked page/CMap or current placement map. Removing the aspect removes
the item without maintaining a second index.
### 0.2.111
The linked-concept clipboard now belongs to the shared browser module instead of one disposable CMap
editor. Copy and the new Cut action therefore survive navigation to another root or derived CMap,
and Paste creates a placement from the stored reference without requiring the source concept to
already occur on the target map. `Ctrl/Cmd+X`, `Ctrl/Cmd+C` and `Ctrl/Cmd+V` mirror the context-menu
actions. Cut removes the source placement and its local relations but never deletes the global
concept. Derived CMaps now use their source slug when reconciling live and stored usage, preventing
one placement from being displayed as `(2)` merely because the same source document is open through
a sub-CMap route.
### 0.2.112
Het archiveren van een volledige CMap staat nu als afzonderlijke gevarenactie helemaal onderaan het
CMap-menu. Na de expliciete vraag moet de gebruiker ook de volledige kaartnaam exact intypen; de
server controleert daarnaast de titel en de actuele versie voordat hij archiveert. Beheerders kunnen
onder **Admin → Gearchiveerde CMaps** alle gearchiveerde kaarten met archiefdatum en gebruiker zien en
herstellen. Herstel behoudt de inhoud, relaties, identiteit en volledige versiegeschiedenis.
### 0.2.113
Asynchrone automatische maatcorrecties tijdens het renderen van een CMap gelden niet langer als
gebruikerswijziging. De renderer levert de toestand direct voor en na zo'n correctie aan de host;
alleen wanneer de opgeslagen baseline nog exact gelijk is aan de voorafgaande toestand schuift die
baseline mee. Een ongewijzigde kaart kan daardoor zonder opslagmelding worden verlaten, terwijl een
echte tussentijdse bewerking, verplaatsing of handmatige formaatwijziging zichtbaar blijft.
### 0.2.114
Conceptidentiteiten zijn voortaan kale, globaal unieke UUID's en bevatten dus geen CMap-slug of
`concept-`-voorvoegsel meer. Schemamigratie 21 behoudt het UUID-deel van bestaande
`concept-<uuid>`-identiteiten en kent met Rackets `uuid`-module een UUID v4 toe aan iedere oude
lokale of `legacy:`-identiteit. Zij herschrijft alle actuele plaatsingen, conceptverwijzingen en
centrale definities in één transactie; relaties blijven gekoppeld via hun lokale item-id en
historische CMap-snapshots blijven onveranderlijk. De slug blijft de stabiele, leesbare identiteit
van de CMap zelf en wordt niet gewijzigd. Nieuwe browserplaatsingen gebruiken Web Crypto; iedere
UUID die de server voor migratie of invoer moet toekennen komt uit dezelfde Racket-helper.
### 0.2.122
Relatiepijlen lopen visueel altijd achter conceptkaarten langs. De grafische basis gebruikt nu
afzonderlijke lagen voor relaties, concepten en tijdelijke verbindingshendels, waardoor ook het
selecteren of naar voren halen van een relatie haar niet over een concept heen tekent. De hit-test
volgt dezelfde volgorde: op een kruising krijgt het zichtbare concept de klik, niet de erachter
liggende pijl.
### 0.2.121
De selectietoolbar kan geselecteerde concepten nu ook horizontaal verdelen. Het meest linkse en
meest rechtse concept blijven staan; de tussenliggende concepten worden zo geplaatst dat alle
horizontale tussenruimtes gelijk zijn. Net als verticaal verdelen vereist dit minimaal drie
zichtbare geselecteerde concepten en wordt de handeling opgenomen in Undo/Redo en autosave.
### 0.2.120
Bij een meervoudige CMap-selectie is het laatst geselecteerde concept nu het referentieobject voor
alle maat- en uitlijncommando's. De breedte, hoogte, randen en middellijnen van dat concept bepalen
de doelgeometrie; het referentieconcept zelf blijft daardoor ongewijzigd. Binnen een bestaande
selectie kan het referentieobject met een gewone klik worden gewisseld en het heeft een blauwe
selectie-accentkleur, tegenover paars voor de overige selectie. Verticaal verdelen blijft de
bovenste en onderste selectie als grenzen gebruiken.
### 0.2.119
Links van het CMap-diagram staat nu een vaste selectietoolbar. Naast bewerken, groeperen,
ontgroeperen en verbergen bevat zij layoutcommando's voor gelijke breedte, gelijke hoogte, gelijke
afmetingen, links/midden/rechts uitlijnen, boven/midden/onder uitlijnen en verticaal verdelen.
Groottecommando's gebruiken de grootste geselecteerde afmeting om inhoud niet af te snijden.
Verticaal verdelen houdt het bovenste en onderste element vast en maakt de tussenruimtes gelijk.
Layoutacties worden als gewone edits opgenomen in Undo/Redo en autosave.
### 0.2.118
De terugknop van een afzonderlijk geopende sub-CMap gaat nu precies één kaartniveau terug. Bij een
afgeleide CMap werd voorheen direct naar de bronroute genavigeerd, ook wanneer `mapHistory` nog een
dieper geopende sub-CMap bevatte. Lokale submapgeschiedenis heeft nu voorrang; pas vanaf de wortel
van de afgeleide kaart navigeert de volgende terugactie naar de bron-CMap.
### 0.2.117
JSON-bundles nemen nu ook de werkelijk gebruikte attachments van gekoppelde wiki- en
uitlegpagina's mee. Iedere bijlage staat met de oorspronkelijke upload-URL, bestandsnaam,
MIME-type en base64-inhoud in `pages[].attachments`. Bij import worden de bestanden via de
normale upload-API opgeslagen en worden de Markdown-URL's herschreven naar hun nieuwe
pagina-eigen URL. Het uitwisselingsformaat blijft versie 1; oudere bundles zonder
`attachments` blijven geldig. De maximale lokale bundle-invoer is 256 MiB, terwijl iedere
afzonderlijke attachment onder de bestaande uploadgrens van 50 MiB blijft.
### 0.2.116
Het verslepen van een bron- of doeluiteinde van een CMap-pijl werkt nu de logische connector
(`sourceId`/`targetId`) direct bij. Voorheen veranderde alleen de lijn in de tekenlaag, waarna het
inklappen en opnieuw uitklappen van een submap de oude relatie opnieuw projecteerde. Ongeldige
losse eindpunten worden teruggezet op de bestaande relatie. Een regressietest dekt expliciet
bewerken, inklappen, uitklappen en serialiseren.
### 0.2.115
CMaps kunnen nu naast een leesbaar Markdownrapport ook als een versieerbare
`racket-wiki-cmap-bundle` in JSON worden geëxporteerd en opnieuw geïmporteerd. De bundle bewaart
CMap-slugs, de volledige diagramopmaak, submaps, verbindingszinnen en connectoren; gedeelde
conceptinhoud staat één keer per UUID in `concepts[]`. Gekoppelde wiki-, conceptuitleg- en
CMap-uitlegpagina's gaan met hun actuele Markdown en tags mee. Gekoppelde CMaps volgen de gekozen
diepte en de bron van een afgeleide CMap wordt altijd als noodzakelijke dependency opgenomen.
De import valideert het complete bestand voordat er API-mutaties plaatsvinden. Ieder concept moet
op minstens één diagram voorkomen, item-id's moeten per kaart uniek zijn en connectoren moeten naar
bestaande items wijzen. Externe generators zoals ChatGPT mogen voor nieuwe concepten een tijdelijke
id `new:<naam>` gebruiken; de server kent bij opslag een Racket-UUID toe. Bij slugconflicten kiest de
gebruiker of bestaande CMaps en pagina's worden vervangen of behouden. Het formele contract staat in
`static/schemas/racket-wiki-cmap-bundle-v1.schema.json`. Versiegeschiedenis en aliassen vallen
buiten formaatversie 1.