This commit is contained in:
@@ -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
|
||||
copy-pasteable; deeper detail lives in its own section, linked.
|
||||
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 →
|
||||
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 &
|
||||
|
||||
@@ -70,6 +70,8 @@ From here, render real pages against the app shell and fetch upstream data — s
|
||||
|
||||
## Contents
|
||||
|
||||
- [Goals](#goals)
|
||||
- [Audience](#audience)
|
||||
- [Overview](#overview)
|
||||
- [Users, groups & permissions](#users-groups--permissions)
|
||||
- [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)
|
||||
- [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
|
||||
|
||||
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
|
||||
blocks the admin plugin uses.
|
||||
|
||||
**Priorities:** simplicity, few dependencies, strict TypeScript, no build step, Docker-only,
|
||||
environment-agnostic (no `NODE_ENV` — every behaviour is an explicit config toggle). Identity,
|
||||
sessions, SSO, OAuth2 and permission checks are delegated to **Ory** sidecar services. The shape
|
||||
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.
|
||||
Identity, sessions, SSO, OAuth2 and permission checks are delegated to **Ory** sidecar
|
||||
services. The shape 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,
|
||||
predictable, and overloadable — a plugin can take over as much of a page as it wants. The host
|
||||
|
||||
Reference in New Issue
Block a user