State the project's goals and audience in the README
CI / full-gate (push) Successful in 4s

This commit is contained in:
2026-10-30 20:32:28 +01:00
parent b81c136fe5
commit 667d589401
2 changed files with 54 additions and 6 deletions
+1 -1
View File
@@ -367,7 +367,7 @@ docker compose -f compose.yml up --build -d # production
stack up and a *minimal* plugin live. Nothing comes before Quick start. Keep its commands stack up and a *minimal* plugin live. Nothing comes before Quick start. Keep its commands
copy-pasteable; deeper detail lives in its own section, linked. copy-pasteable; deeper detail lives in its own section, linked.
2. **Returning developer (rest).** A **Contents** ToC right after Quick start, then sections ordered 2. **Returning developer (rest).** A **Contents** ToC right after Quick start, then sections ordered
by **what an adopter reaches for first**, not by architectural layering: Overview → Users, groups by **what an adopter reaches for first**, not by architectural layering: Goals → Audience → Overview → Users, groups
& permissions → Building plugins → menu/blocks/interactivity → Configuration → Auth → Email → & permissions → Building plugins → menu/blocks/interactivity → Configuration → Auth → Email →
Architecture → Testing → Production → Observability → JWT-rotation runbook → Project-layout file Architecture → Testing → Production → Observability → JWT-rotation runbook → Project-layout file
map → Extending. Place a new section by how early an adopter needs it. **Users, groups & map → Extending. Place a new section by how early an adopter needs it. **Users, groups &
+53 -5
View File
@@ -70,6 +70,8 @@ From here, render real pages against the app shell and fetch upstream data — s
## Contents ## Contents
- [Goals](#goals)
- [Audience](#audience)
- [Overview](#overview) - [Overview](#overview)
- [Users, groups & permissions](#users-groups--permissions) - [Users, groups & permissions](#users-groups--permissions)
- [naming a permission](#naming-a-permission) - [naming a permission](#naming-a-permission)
@@ -121,6 +123,54 @@ From here, render real pages against the app shell and fetch upstream data — s
- [Project layout](#project-layout) - [Project layout](#project-layout)
- [Extending the core](#extending-the-core) - [Extending the core](#extending-the-core)
## Goals
1. **Achieve:** Less boilerplate for a server-rendered web GUI: a new project starts at
its own domain, not at sign-in, a menu or a table.
- Signal: a new plugin reaches a working, gated page with a menu, tables, filters and
forms built only from the core building blocks.
- Counter-signal: the core grows features only one project needs.
- Why: boilerplate removed by absorbing a project's domain only moves it into the core.
2. **Maintain:** Plainpages solves only the parts every project shares: auth, the GUI
building blocks (menu, tables, filters, forms) and the plugin structure. Everything
else is a plugin.
3. **Maintain:** Every page is a server-rendered document that works with zero JavaScript.
4. **Maintain:** State lives in the URL. Only state the URL can't carry lives in the
database, never in local storage or JavaScript. A cookie carries only what must be bound
to the browser: the session and its CSRF token.
5. **Maintain:** The frontend is semantic: the HTML says what each thing is, and the CSS
styles meaning, not looks. That keeps every page accessible.
6. **Achieve:** Hackable: a plugin can change anything, and Plainpages stays out of its way.
- Signal: a plugin replaces any page, partial, menu entry or string without forking the
host, and fewer plugins need a host change to get unblocked.
- Counter-signal: plugins break on upgrade with no version signal, or a plugin mistake
shows up at runtime instead of at boot.
- Why: freedom that breaks silently costs more than the boilerplate it saved.
7. **Achieve:** Speed: pages render fast and stay small.
- Signal: server time per page and bytes sent per page fall.
- Counter-signal: a building block loses a feature or accessibility to save bytes.
- Why: a fast page that does less only moves the work back into each plugin.
8. **Achieve:** LLM-friendly: an LLM builds a correct plugin from the README and the
examples alone.
- Signal: an agent given only those writes a plugin that passes discovery and its E2E
test on the first try.
- Counter-signal: the README grows to restate what the code already shows.
- Why: docs that pass the test by growing cost every later reader, human or LLM.
9. **Maintain:** Every behaviour is an explicit configuration choice, the same in every
environment.
## Audience
- **Developers starting a web GUI project, and the LLMs that build plugins with them.**
They may rely on `@plainpages/plugin-api`, the core partials and the packaging promises,
all versioned by `apiVersion`. A change that breaks a plugin takes a major bump.
- **Operators** who self-host Plainpages. They may rely on semver-tagged images, on
configuration through environment variables and the drop-in mounts (`plugins/`,
`config/`, `locales/`), and on upgrades within a minor version that need no change on
their side.
- **Visitors** to a site built on Plainpages. They may rely on pages that load fast and
work without JavaScript, with a keyboard and a screen reader.
## Overview ## Overview
Plainpages gives you the boring-but-hard parts of a web app — a design system, a menu, Plainpages gives you the boring-but-hard parts of a web app — a design system, a menu,
@@ -136,11 +186,9 @@ public front with an authenticated area behind it.
- **You add:** everything else domain-specific, as **plugins** — built from the same building - **You add:** everything else domain-specific, as **plugins** — built from the same building
blocks the admin plugin uses. blocks the admin plugin uses.
**Priorities:** simplicity, few dependencies, strict TypeScript, no build step, Docker-only, Identity, sessions, SSO, OAuth2 and permission checks are delegated to **Ory** sidecar
environment-agnostic (no `NODE_ENV` — every behaviour is an explicit config toggle). Identity, services. The shape doesn't change as it grows: every plugin is the same self-contained folder,
sessions, SSO, OAuth2 and permission checks are delegated to **Ory** sidecar services. The shape the hot path is the same I/O-free JWT check, and there is no app database.
doesn't change as it grows: every plugin is the same self-contained folder, the hot path is the
same I/O-free JWT check, and there is no app database.
**Plugins are the extension model.** The plugin API is the product's main surface: powerful, **Plugins are the extension model.** The plugin API is the product's main surface: powerful,
predictable, and overloadable — a plugin can take over as much of a page as it wants. The host predictable, and overloadable — a plugin can take over as much of a page as it wants. The host