Remove contributing and component docs from the public docs site

Drop the Contributing and internals section, Architecture, Frontend,
and dp-* component pages from the docs registry, prose files, nav, and
legacy redirect target. Guard with tests that fail if they return.
This commit is contained in:
2026-10-05 15:55:35 +02:00
parent a66f2df958
commit 874c37350b
19 changed files with 93 additions and 93 deletions
+1 -13
View File
@@ -10,9 +10,7 @@ from molodetz.rendering import normalize_dashes
PROSE_DIR = config.TEMPLATES_DIR / "docs" / "prose"
SECTIONS = ("Start here", "Building with the API", "Contributing and internals", "Admin")
COMPONENTS = ("avatar", "code", "content", "title", "toast", "dialog", "context-menu", "upload", "lightbox", "chat")
SECTIONS = ("Start here", "Building with the API", "Admin")
DOCS_PAGES = [
{"slug": "welcome", "title": "Welcome", "section": "Start here", "file": "welcome.md"},
@@ -20,18 +18,8 @@ DOCS_PAGES = [
{"slug": "join", "title": "Joining", "section": "Start here", "file": "join.md"},
{"slug": "legal", "title": "Terms and privacy", "section": "Start here", "file": "legal.md"},
{"slug": "api", "title": "API and authentication", "section": "Building with the API", "file": "api.md"},
{"slug": "architecture", "title": "Architecture", "section": "Contributing and internals", "file": "architecture.md"},
{"slug": "frontend", "title": "Frontend and components", "section": "Contributing and internals", "file": "frontend.md"},
{"slug": "admin", "title": "Admin and services", "section": "Admin", "file": "admin.md", "admin": True},
{"slug": "backups", "title": "Backups and maintenance", "section": "Admin", "file": "backups.md", "admin": True},
] + [
{
"slug": f"component-{name}",
"title": f"dp-{name}",
"section": "Contributing and internals",
"file": f"component-{name}.md",
}
for name in COMPONENTS
]
+1 -1
View File
@@ -14,7 +14,7 @@ LEGACY_PATHS = {
"/docs/schrijven": "/docs/writing",
"/docs/binnen": "/docs/join",
"/docs/juridisch": "/docs/legal",
"/docs/architectuur": "/docs/architecture",
"/docs/architectuur": "/docs/welcome",
"/docs/beheer": "/docs/admin",
"/docs/api/inhoud": "/docs/api/content",
"/docs/api/binnen": "/docs/api/join",
@@ -1,18 +0,0 @@
# Architecture
FastAPI with Jinja2, rendered on the server. SQLite through `dataset`, synchronous and deliberately without a threadpool. Sessions with PBKDF2-SHA256 passwords.
## Layers
- `molodetz/database/`: one file per subject, always import from the package root.
- `molodetz/routers/`: mirrors the URL path.
- `molodetz/services/`: background services under one supervisor with a file lock.
- `molodetz/templates/`: one Jinja environment in `templating.py`.
## Deleting
Everything is soft deleted with `deleted_at` and `deleted_by`. Only cleanup jobs delete for real.
## Static files
Assets go through `static_url()`, which versions them under `/static/v<version>/`. Those are immutably cacheable for a year.
@@ -1,5 +0,0 @@
# dp-avatar
Shows a deterministic SVG avatar plus a presence dot. Attributes `seed`, `size`, `uid`.
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
@@ -1,5 +0,0 @@
# dp-chat
Simple log with an input line. Emits a `dp-chat-send` event.
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
@@ -1,5 +0,0 @@
# dp-code
Highlights a code block with highlight.js and adds a Copy button.
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
@@ -1,5 +0,0 @@
# dp-content
Renders live markdown on the client through marked, then DOMPurify. Only for live content, such as the editor preview.
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
@@ -1,5 +0,0 @@
# dp-context-menu
Small context menu with buttons, positioned at the cursor.
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
@@ -1,5 +0,0 @@
# dp-dialog
Confirmation dialog. Forms with `data-confirm` go through it.
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
@@ -1,5 +0,0 @@
# dp-lightbox
Full screen view for images with `data-lightbox`. Escape or a click closes it.
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
@@ -1,5 +0,0 @@
# dp-title
Inline variant of dp-content for titles.
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
@@ -1,5 +0,0 @@
# dp-toast
Host for short notices. Use `Toast.flash(el, message)` or `app.toast(message)`.
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
@@ -1,5 +0,0 @@
# dp-upload
Drop zone for files. Emits a `dp-files` event with the chosen files.
Light DOM, no shadow DOM. Registers itself with `customElements.define`.
@@ -1,7 +0,0 @@
# Frontend and components
ES6 modules, one class per file, no framework and no bundler. `Application.js` creates all singletons and sets `window.app`.
Components are custom elements with the `dp-` prefix, without shadow DOM. See the component pages in the sidebar.
Client rendering with marked and DOMPurify is only for live content: the preview in the editor. Published posts are rendered on the server.
+1 -1
View File
@@ -12,4 +12,4 @@ Molodetz is a quiet blog roll. Notes about the work, finishing it, and judgement
## Where to start
Read [Writing on the roll](/docs/writing) for the content, [API and authentication](/docs/api) for integrations, and [Architecture](/docs/architecture) if you want to know how it is built.
Read [Writing on the roll](/docs/writing) for the content, and [API and authentication](/docs/api) for integrations.
+1 -1
View File
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "molodetz"
version = "1.0.15"
version = "1.0.16"
description = "Molodetz, a calm community blog roll."
readme = "README.md"
requires-python = ">=3.12"
+87
View File
@@ -0,0 +1,87 @@
# retoor <retoor@molodetz.nl>
import re
from molodetz.docs_prose import DOCS_PAGES, PROSE_DIR, SECTIONS
BANNED_SECTION = "Contributing and internals"
BANNED_TITLES = {
"Architecture",
"Frontend and components",
"dp-avatar",
"dp-code",
"dp-content",
"dp-title",
"dp-toast",
"dp-dialog",
"dp-context-menu",
"dp-upload",
"dp-lightbox",
"dp-chat",
}
BANNED_SLUGS = {
"architecture",
"frontend",
"component-avatar",
"component-code",
"component-content",
"component-title",
"component-toast",
"component-dialog",
"component-context-menu",
"component-upload",
"component-lightbox",
"component-chat",
}
BANNED_FILES = {
"architecture.md",
"frontend.md",
*[
f"component-{name}.md"
for name in (
"avatar",
"code",
"content",
"title",
"toast",
"dialog",
"context-menu",
"upload",
"lightbox",
"chat",
)
],
}
def _docs_surfaces(html):
sidebar = re.search(r'<aside class="docs-sidebar">(.*?)</aside>', html, re.S)
content = re.search(r'<article class="docs-content[^"]*">(.*?)</article>', html, re.S)
return (sidebar.group(1) if sidebar else ""), (content.group(1) if content else "")
def test_docs_registry_excludes_removed_internals():
assert BANNED_SECTION not in SECTIONS
titles = {page["title"] for page in DOCS_PAGES}
slugs = {page["slug"] for page in DOCS_PAGES}
sections = {page["section"] for page in DOCS_PAGES}
assert not titles & BANNED_TITLES
assert not slugs & BANNED_SLUGS
assert BANNED_SECTION not in sections
for name in BANNED_FILES:
assert not (PROSE_DIR / name).exists(), name
def test_served_docs_hide_removed_internals(anon, admin):
banned_hrefs = {f"/docs/{slug}" for slug in BANNED_SLUGS}
for client in (anon, admin):
for path in ("/docs", "/docs/welcome", "/docs/api"):
html = client.get(path).text
sidebar, content = _docs_surfaces(html)
surface = f"{sidebar}\n{content}"
assert BANNED_SECTION not in surface, path
for title in BANNED_TITLES:
assert title not in surface, (path, title)
for href in banned_hrefs:
assert href not in surface, (path, href)
for slug in sorted(BANNED_SLUGS):
assert anon.get(f"/docs/{slug}").status_code == 404, slug
+1 -1
View File
@@ -14,7 +14,7 @@ REDIRECTS = [
("/docs/schrijven", "/docs/writing"),
("/docs/binnen", "/docs/join"),
("/docs/juridisch", "/docs/legal"),
("/docs/architectuur", "/docs/architecture"),
("/docs/architectuur", "/docs/welcome"),
("/docs/api/inhoud", "/docs/api/content"),
("/docs/api/binnen", "/docs/api/join"),
]
+1 -1
View File
@@ -1,7 +1,7 @@
# retoor <retoor@molodetz.nl>
from tests.conftest import assert_no_horizontal_overflow, goto_ready
PUBLIC_PAGES = ["/", "/roll", "/standard", "/flyers", "/memes", "/people", "/people/retoor", "/join", "/docs", "/docs/welcome", "/docs/api/content", "/docs/component-code", "/terms", "/privacy"]
PUBLIC_PAGES = ["/", "/roll", "/standard", "/flyers", "/memes", "/people", "/people/retoor", "/join", "/docs", "/docs/welcome", "/docs/api/content", "/terms", "/privacy"]
def test_home_renders_without_errors(page, app_server):