-
Notifications
You must be signed in to change notification settings - Fork 0
Admin Panel
apps/admin (package cms-admin): one FastAPI process serving the API and the server-rendered UI — Jinja templates on AdminLTE 4 (MIT, vendored verbatim with its license; Bootstrap 5 bundled), implemented 1:1 as its reference pages do — Source Sans 3 (OFL), Bootstrap Icons (MIT) and the theme's own behavior scripts vendored locally: collapsible sidebar, fullscreen toggle, light/dark/auto color mode (WCAG-gated in both palettes in CI), the canonical user menu. No CDN, no inline scripts, no build step. It drives cms-core, cms-validation and cms-build through their public APIs and never bypasses them.
Try it without installing anything: the demo site ships a read-only static snapshot at https://sardine.ph7x.com/admin/ — the real admin's pages, captured with demo content; nothing there saves, by construction.
pip install -e apps/admin
cms admin create-user editor-in-chief --role admin # prompts for a password
SARDINE_STORAGE_URL="sqlite:///content.sqlite3" \
SARDINE_ADMIN_COOKIE_SECURE=0 \
uvicorn --factory cms_admin.app:create_appSign in at /login. There are no default credentials — the first account always comes from the CLI.
| Variable | Default | Meaning |
|---|---|---|
SARDINE_STORAGE_URL |
sqlite:///content.db |
Storage URL (create_storage) |
SARDINE_ADMIN_SESSION_HOURS |
12 |
Session lifetime |
SARDINE_ADMIN_COOKIE_SECURE |
1 |
Set 0 only for plain-http local development |
SARDINE_MEDIA_DIR |
media |
Media upload directory (the project's media/) |
SARDINE_ADMIN_UPLOAD_MAX_MB |
10 |
Upload size limit in MB |
SARDINE_PROJECT_DIR |
. |
Project directory holding sardine.toml (panel builds) |
SARDINE_ADMIN_PUBLISH_GATE |
1 |
Set 0 to allow publishing despite validation errors |
- Roles (least-privilege ladder):
editor < reviewer < publisher < admin, enforced server-side. - Passwords: argon2id hashes; sessions server-side with only the token digest stored; cookies
HttpOnly+Secure+SameSite=Strict. - CSRF: synchronizer tokens on every authenticated state-changing request, double-submit token on the login form; failed-login rate limiting.
- Accounts live in the storage database (shared migrations) and are never exported.
- Dashboard: content by workflow status, the translation coverage matrix (missing/outdated/complete per language), a live validation report with the publish-gate verdict.
- Articles: list with per-language state badges, create, EN source editor (slug, category, tags, cover) with a preview rendered by the builder's own Markdown renderer (raw HTML disabled), and a side-by-side translation editor per language — the EN source read-only next to the translation form.
- Pages and sections: metadata editor, ordered typed sections (add/reorder/remove), a dynamic field editor with kind-aware suggestions, and per-section side-by-side translation.
Editing a source marks its translations outdated automatically (checksum model). Statuses are displayed but transitions arrive with the workflow phase.
-
Media library: uploads validated server-side (MIME sniffed from the bytes, size limit, parsed image dimensions), mandatory EN alt text plus translatable alt per language, and reference-checked deletion — assets used by covers or sections refuse to die.
-
Media filters: server-side search (id, path, type, alt) and quick views — images only, missing translated alt — with a shown-of-total counter.
-
Users screen: admins create accounts (role + panel language), change roles and delete from the panel — you cannot delete yourself, and the last admin can neither be deleted nor demoted.
-
Duplicate & per-entry preview: one-click duplicate-as-draft (collision-safe ids, workflow reset) and a direct jump from each editor to the entry's URL inside the preview build.
-
Trash: reversible deletion — trashed articles and pages disappear from builds, validation, export and lists; restore is exact, and "Delete forever" (admin-only, trash-only) is the panel's single permanent removal.
-
Revisions: every save keeps a snapshot (newest 20 per entity); editors show the history with a per-revision diff against the current content and one-click restore — the restore itself is recorded, so it is always undoable.
-
Scheduled publishing: articles and pages take an optional "Publish at (UTC)" moment — published content stays out of every build until a build runs after it (the build is the clock on a static host; a CI cron recipe ships in the admin guide). Scheduling never bypasses validation or the publish gate.
-
Markdown editor: article bodies get a real editing surface (EasyMDE, MIT, vendored — no CDN) with a localized formatting toolbar; the builder's server-rendered preview remains the single truth for what publishes, and the plain textarea still works without JavaScript.
-
Panel language (i18n): real gettext localization (PT-PT, ES, FR, DE shipped alongside English) — each editor picks a language in the user menu (or
cms admin create-user --language), with the browser's language as fallback; an anti-drift test keeps every catalog complete. -
Workflow and publishing: role-gated transitions (draft → review → published → archived, including one-click unpublish straight back to draft; publishing needs the publisher rung), the publish gate blocking on the entity's validation errors, and the Publishing panel — preview builds served under
/preview/, build & export with target extras written to the project output, every run recorded on the dashboard. -
Validation report (dashboard + Publishing panel): the gate never hides its work — a callout states the verdict and the validated scope (articles, pages, media, languages), a table lists every rule that ran with its outcome (passing rules included), and each issue links straight to the edit screen of the content that caused it.
cms validateprints the same per-rule outcomes in the terminal. The seeded demo keeps one article in review with a missing DE translation, so the report always shows a live warning in action. -
Hardening: security headers on every response — a CSP with no script source at all (the admin ships zero JavaScript), frame denial, nosniff — and the axe accessibility gate (WCAG 2.2 AA) running over the admin pages in CI, the same methodology as the public site. The full admin guide lives in
docs/ADMIN_GUIDE.md, anti-drift-checked.
Milestone 3 is complete: the full editorial cycle — create, translate, review, publish, build, export — works from the browser, with every security and accessibility gate green in CI. (role-gated transitions, publish gate, builds/exports from the panel), and the hardening pass (CSP, security suites, axe over admin pages). The phased plan lives in docs/PLAN.md.
python -m cms_admin.demo_export --storage content.sqlite3 --out _site/admin boots the real admin on a throwaway copy of the content, signs in as a generated demo user and captures every editorial page as inert static HTML (links prefixed, CSRF stripped, forms neutralized, read-only banner). The demo deploy runs it automatically.
Sardine CMS — multilingual, static-first CMS framework · Repository · Live demo · Apache-2.0