158 lines
4.7 KiB
Markdown
158 lines
4.7 KiB
Markdown
# Markdown and linking
|
|
|
|
## Canonical content
|
|
|
|
The canonical human-authored body of a page is Markdown stored in PostgreSQL and included
|
|
in immutable revisions. HTML is derived and disposable.
|
|
|
|
Full exports use Markdown plus a manifest/frontmatter representation. Database metadata
|
|
remains authoritative during normal operation.
|
|
|
|
## Supported syntax
|
|
|
|
Initial profile:
|
|
|
|
- CommonMark;
|
|
- headings;
|
|
- emphasis and strikethrough;
|
|
- ordered/unordered lists;
|
|
- task lists;
|
|
- block quotes;
|
|
- fenced code blocks with language;
|
|
- inline code;
|
|
- tables;
|
|
- links;
|
|
- safe images through attachment references;
|
|
- footnotes when the selected parser supports deterministic export;
|
|
- Mermaid fenced blocks.
|
|
|
|
Raw HTML is disabled by default.
|
|
|
|
### Managed import regions
|
|
|
|
Imported and derived pages may store four exact control tokens in canonical Markdown:
|
|
|
|
```text
|
|
<!-- managed-source:start -->
|
|
<!-- managed-source:end -->
|
|
<!-- user-notes:start -->
|
|
<!-- user-notes:end -->
|
|
```
|
|
|
|
These tokens remain in PostgreSQL and immutable revisions so synchronization can replace
|
|
only the managed source region and preserve user notes byte-exact. The renderer removes
|
|
only these four exact tokens from a transient render copy, replacing them with line
|
|
boundaries before Markdown parsing. Stored Markdown is never normalized by rendering.
|
|
Unknown comments, HTML, scripts and event handlers are not recognized as controls and
|
|
remain subject to the normal raw-HTML-disabled and allowlist-sanitized pipeline.
|
|
|
|
## Internal wiki links
|
|
|
|
Author syntax:
|
|
|
|
```text
|
|
[[Target title]]
|
|
[[Target title|Visible label]]
|
|
```
|
|
|
|
The editor autocomplete may insert an invisible stable marker or structured editor
|
|
metadata, but exported Markdown must remain human-readable.
|
|
|
|
At publish time, each link records:
|
|
|
|
- source page/revision;
|
|
- authored target text;
|
|
- optional display text;
|
|
- resolved stable target ID;
|
|
- resolution state;
|
|
- occurrence or source range where practical.
|
|
|
|
Resolution order:
|
|
|
|
1. explicit stable target marker;
|
|
2. exact title in the same collection/subtree;
|
|
3. exact title in the workspace;
|
|
4. unique normalized match;
|
|
5. unresolved or ambiguous.
|
|
|
|
The UI must ask the editor to resolve ambiguity before or after publishing; it must not
|
|
silently choose an arbitrary page.
|
|
|
|
## Slugs
|
|
|
|
- Derived from title for readability.
|
|
- Unique only where required by routing policy; stable page ID prevents identity loss.
|
|
- Old canonical URLs redirect using ID.
|
|
- Slugs contain no authorization meaning.
|
|
- Import preserves the legacy path separately as provenance.
|
|
|
|
## Heading anchors
|
|
|
|
Heading IDs are deterministic within a rendered revision. Duplicate headings receive
|
|
stable suffixes. Links to headings use page ID plus anchor.
|
|
|
|
A heading rename may break an authored anchor; the system should detect this as a link
|
|
maintenance warning but need not maintain a permanent heading identity in v1.
|
|
|
|
## Rendering safety
|
|
|
|
- Parse using a fixed configured extension set.
|
|
- Do not pass raw HTML through.
|
|
- Remove only the four documented import control tokens from render input; never expose
|
|
them in reader views, snippets or revision previews.
|
|
- Sanitize generated HTML with an allowlist.
|
|
- Rewrite external links with safe `rel` attributes.
|
|
- Reject `javascript:`, `data:` and unsafe protocols except explicitly generated safe
|
|
image data where controlled.
|
|
- Render Mermaid with strict security and sanitized labels.
|
|
- Never allow Mermaid directives to access network/filesystem.
|
|
- Syntax highlighting is client-side or server-side without executing code.
|
|
- Cap nesting, token count and rendered size to resist pathological input.
|
|
|
|
## Attachments in Markdown
|
|
|
|
Use a stable application URI:
|
|
|
|
```text
|
|

|
|
```
|
|
|
|
The renderer resolves it through authorized metadata/content endpoints. Exports rewrite it
|
|
to a deterministic relative file path and include the attachment.
|
|
|
|
Ordinary external image hotlinking is disabled by default for privacy. The editor may
|
|
store an external hyperlink instead.
|
|
|
|
## Draft and revision behavior
|
|
|
|
The draft stores raw Markdown and typed metadata. Preview never changes published
|
|
relations or search.
|
|
|
|
Publish:
|
|
|
|
1. validates size and parser limits;
|
|
2. parses internal links and attachment references;
|
|
3. authorizes all referenced private resources;
|
|
4. creates current state and immutable revision;
|
|
5. updates derived relations/search;
|
|
6. writes audit/outbox;
|
|
7. returns the new ETag.
|
|
|
|
## Export frontmatter
|
|
|
|
Export may include:
|
|
|
|
```yaml
|
|
id: 550e8400-e29b-41d4-a716-446655440000
|
|
title: PostgreSQL back-up herstellen
|
|
documentType: runbook
|
|
status: active
|
|
tags:
|
|
- PostgreSQL
|
|
- Back-up
|
|
updatedAt: 2026-07-31T18:00:00Z
|
|
```
|
|
|
|
Importers must not trust privileged fields such as author IDs, permissions or executable
|
|
paths from frontmatter.
|