200 lines
8.4 KiB
Racket
200 lines
8.4 KiB
Racket
#lang scribble/manual
|
|
|
|
@(require (for-label racket/base
|
|
racket/contract
|
|
racket/path
|
|
racket-wiki
|
|
racket-wiki/architecture/import
|
|
racket-wiki/translate))
|
|
|
|
@title{racket-wiki}
|
|
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
|
|
|
|
@defmodule[racket-wiki]
|
|
|
|
The @racketmodname[racket-wiki] module starts a small self-hosted Markdown wiki.
|
|
Racket provides the HTTP API, authentication, PostgreSQL-backed user and page
|
|
storage, versioning, full-text search, and the initial web setup. Markdown
|
|
rendering and the editing interface run in the browser.
|
|
|
|
@section{Starting the Wiki}
|
|
|
|
@defproc[(start
|
|
[#:data-dir data-dir path-string? "wiki-data"]
|
|
[#:port port exact-positive-integer? 8080]
|
|
[#:listen-ip listen-ip (or/c string? #f) "127.0.0.1"]
|
|
[#:secure-cookie? secure-cookie? boolean? #f]
|
|
[#:site-title site-title string? "Racket Wiki"]
|
|
[#:session-seconds session-seconds exact-positive-integer? (* 12 60 60)]
|
|
[#:language language string? "en"])
|
|
any] {
|
|
Starts the wiki using explicit server parameters. The data directory is made
|
|
absolute before the server starts.
|
|
|
|
Use @racket["*"] or @racket[#f] for @racket[listen-ip] to listen on all
|
|
interfaces. The default address only listens on the local machine.
|
|
|
|
This procedure is the convenient entry point when starting the wiki from
|
|
DrRacket or another interactive Racket session.
|
|
}
|
|
|
|
@defproc*[([(start-wiki) any]
|
|
[(start-wiki [config any/c]) any])] {
|
|
Starts the wiki using either the default configuration or the supplied wiki
|
|
configuration.
|
|
}
|
|
|
|
@section{Initial Setup}
|
|
|
|
When PostgreSQL has not been configured, the schema is unavailable, no enabled
|
|
administrator exists, or one of the required browser libraries is missing,
|
|
normal application requests are redirected to @tt{/setup}.
|
|
|
|
The setup page itself requires no JavaScript. On a fresh installation it asks for
|
|
PostgreSQL server, port, database, user, password and SSL mode. The database must
|
|
already exist. After testing the connection, setup creates the racket-wiki schema,
|
|
asks for the first administrator, and downloads the pinned EasyMDE, Lucide,
|
|
DOMPurify, highlight.js, and diff2html browser files. PostgreSQL connection
|
|
settings are stored in @tt{database.rktd} below the configured data directory.
|
|
After setup the browser is redirected to @tt{/login}; setup does not create an
|
|
authenticated browser session.
|
|
|
|
|
|
@section{Page Slugs}
|
|
|
|
For a normal new page, the backend derives the slug from the title when the page
|
|
is first saved. A later title change leaves the slug unchanged so existing links
|
|
remain stable.
|
|
|
|
When an editor or administrator follows a wiki-page link to a slug that does not
|
|
yet exist, the browser opens an empty create view for that requested slug. A
|
|
reader receives a normal not-found view. Unauthenticated browser requests are
|
|
redirected to @tt{/login} before the wiki application is served.
|
|
|
|
|
|
|
|
@section{Page namespaces}
|
|
|
|
Pages have an explicit namespace in addition to their stable slug. Existing pages
|
|
are migrated to the root namespace. A compact page reference uses
|
|
@tt{namespace:slug}, for example @tt{racket:roadmap}. Explicit Markdown links
|
|
may therefore use @tt{[Roadmap](racket:roadmap)}. A classic WikiWord can also be
|
|
qualified, for example @tt{RWS:ModelTreeWalker}.
|
|
|
|
The namespace and slug are stored separately in PostgreSQL and their combination
|
|
is unique. Todo items and bookmarks are grouped by namespace in the browser.
|
|
|
|
@section{Page contents}
|
|
|
|
The application sidebar gives the current page's headings priority over the
|
|
global page list. The contents list follows Markdown headings and is updated
|
|
while a page is edited.
|
|
|
|
@section{Editor appearance}
|
|
|
|
EasyMDE and the rendered wiki page use matching body and heading sizes. The
|
|
source editor keeps Markdown syntax visible, but heading text uses the same
|
|
scale as the rendered page. Toolbar icons are provided by a locally installed
|
|
Lucide copy.
|
|
|
|
|
|
@section{Page navigation and metadata}
|
|
|
|
The sidebar gives priority to a table of contents derived from the headings in
|
|
the current Markdown document. The page list is secondary. The editor updates
|
|
the table of contents while the document is being edited.
|
|
|
|
A breadcrumb is displayed above the document. The footer displays creation and
|
|
modification timestamps, the current version, and page tags. Tags are stored in
|
|
the page metadata and version metadata.
|
|
|
|
@section{Full-text search}
|
|
|
|
Current pages are indexed by PostgreSQL using a weighted @tt{tsvector}; title
|
|
terms have a higher weight than Markdown body terms. A GIN index accelerates
|
|
searches. The wiki uses PostgreSQL's @tt{simple} text-search configuration so
|
|
technical Dutch, English and identifier-like terms are not subjected to a
|
|
language-specific stemmer.
|
|
|
|
@section{Database schema migrations}
|
|
|
|
Racket Wiki records PostgreSQL schema migrations in @tt{wiki_schema}. The current page is stored in @tt{pages}; every saved historical revision is stored in @tt{page_versions}. Attachments, including their binary content, are stored in @tt{attachments}. Schema migrations run in order when the application starts. Schema 7 adds page namespaces and a unique namespace/slug index.
|
|
|
|
@section{Todo items}
|
|
|
|
Wiki-wide todo items are written as @tt{todo(text)} in Markdown. Markers inside
|
|
fenced code blocks are ignored. Current todo markers are indexed in PostgreSQL
|
|
and collected in the Todo view. Ordinary Markdown task lists remain available
|
|
for page-local checklists.
|
|
|
|
@section{Translations}
|
|
|
|
@defmodule[racket-wiki/translate]
|
|
|
|
@defproc[(tr [config any/c] [key symbol?]) string?] {
|
|
Returns the effective UI translation for @racket[key]. Built-in English and
|
|
Dutch translations are available before the database is configured. Once the
|
|
database is available, assignments in the special @tt{wiki-translations} page
|
|
override the built-in strings. A line can contain several languages, for example
|
|
@tt{save = nl:Opslaan, en:Save, de:Speichern}.
|
|
}
|
|
|
|
The UI language is selected with @tt{--language} or @racket[#:language]. The
|
|
frontend obtains the same effective table from the server, so server and browser
|
|
labels use one translation source.
|
|
|
|
@section{Connectivity}
|
|
|
|
The browser calls @tt{/api/ping} every 15 seconds. Failed or timed-out requests
|
|
show an Offline indicator. A recovered connection briefly shows Online.
|
|
|
|
@section{Architecture Documentation Import}
|
|
|
|
@defmodule[racket-wiki/architecture/import]
|
|
|
|
The package includes twelve linked Dutch architecture pages below namespace
|
|
@tt{racket-wiki} and two native CMaps. The source files live below
|
|
@tt{architecture/}; importing them uses the normal page and CMap storage
|
|
procedures and therefore creates ordinary immutable versions.
|
|
|
|
@defproc[(validate-racket-wiki-architecture!) (values list? list?)] {
|
|
Reads and validates the bundled manifest, Markdown and JSON documents without
|
|
accessing wiki content. Page references, CMap embeds, item identifiers and
|
|
connector endpoints must all resolve inside the set.
|
|
}
|
|
|
|
@defproc[(import-racket-wiki-architecture!
|
|
[config any/c]
|
|
[#:author author string? "racket-wiki architecture import"]
|
|
[#:dry-run? dry-run? boolean? #f]
|
|
[#:overwrite-modified? overwrite-modified? boolean? #f])
|
|
(listof architecture-import-result?)] {
|
|
Creates missing architecture pages and CMaps and updates imported content that
|
|
has not been edited locally. Every imported document contains a source hash.
|
|
Locally modified documents are returned with status
|
|
@racket['skipped-modified] unless @racket[overwrite-modified?] is true. Equal
|
|
content remains unchanged and does not receive a needless new version.
|
|
}
|
|
|
|
@defproc[(import-racket-wiki-architecture-from-data-directory!
|
|
[data-directory path-string?]
|
|
[#:author author string? "racket-wiki architecture import"]
|
|
[#:dry-run? dry-run? boolean? #f]
|
|
[#:overwrite-modified? overwrite-modified? boolean? #f])
|
|
(listof architecture-import-result?)] {
|
|
Convenience entry point for DrRacket and small scripts. It constructs the wiki
|
|
configuration from @racket[data-directory] and performs the same validated,
|
|
locally-change-aware import.
|
|
}
|
|
|
|
@defstruct*[architecture-import-result
|
|
([kind symbol?]
|
|
[reference string?]
|
|
[status symbol?]
|
|
[message string?])]
|
|
|
|
From the package source directory, run a non-writing preview with
|
|
@tt{racket architecture/import.rkt --data ./wiki-data --dry-run}. Remove
|
|
@tt{--dry-run} to import and use @tt{--author} to select the author recorded in
|
|
page and CMap history.
|