simple_module_pagebuilder
Drag-and-drop visual page builder for simple_module
apps. Pages are composed from a reusable block library using
Puck and stored as JSON; published pages are served
at /p/{slug}.
Features
- Visual editor — Puck-based drag-and-drop with a block library (heading, text, image, button, columns, spacer) and a media picker.
- Site layout — a shared header/footer layout, edited the same way, wrapped around every public page.
- Media library — uploads with magic-byte content sniffing, folder organisation, and server-generated WebP thumbnails.
- Revisions — every status transition snapshots the page, with a diff view and restore-as-draft.
- Approval workflow — edit → submit for review → approve / reject, gated by three separate permissions.
- Scheduled publishing — set
publish_at/unpublish_at; a background poller flips status at the due time. - SEO — per-page meta description, canonical URL, OG image, JSON-LD, plus
/sitemap.xmland/robots.txt.
Installation
uv add simple_module_pagebuilder
Then add it to your host's pyproject.toml dependencies. The module is
discovered at boot through the simple_module entry point — no registration
code required.
Its frontend ships inside the wheel. Pull its JS dependencies into your host's client app and regenerate the page manifest with:
smpy host sync-js-deps --host-client-app=host/client_app
smpy host gen-pages --host-dir=host/client_app
Usage
Once installed and migrated, sign in and open /pagebuilder:
- Create a page —
/pagebuilder/new. Give it a title; the slug is derived from it and stays editable. - Compose it — drag blocks from the Puck sidebar. Images come from the media library, which uploads and thumbnails them for you.
- Publish it — publish directly with
pagebuilder.publish, or submit for review if your role only carriespagebuilder.edit. Reviewers work through/pagebuilder/pending. - Schedule it — set
publish_at/unpublish_atinstead of publishing now, and the poller flips the status at the due time. - View it — the page is live at
/p/{slug}, wrapped in the site layout from/pagebuilder/layout.
Every transition writes a revision, so /pagebuilder/{id}/edit can compare any
two revisions and restore either one as a draft.
Contributing blocks from another module
A module ships Puck blocks by calling registerPuckBlocks from its
puck-blocks.ts; the host imports every module's registration eagerly at app
start, so the registry is populated before the first render.
Because registration is eager, a block that statically imports a heavy render
component puts that component's whole dependency graph in the entry chunk —
on every page of the site, for every visitor. Measured on a consuming site, a
map block's static import put maplibre-gl (1 MB minified, 62% of the bundle)
in front of visitors who never opened the map. Register heavy blocks with
lazyBlock instead, which keeps fields and defaults eager but loads the
component the first time a page actually renders the block:
import { lazyBlock } from '@simple-module-py/pagebuilder/pagebuilder/components/lazyBlock';
import { registerPuckBlocks } from '@simple-module-py/pagebuilder/pagebuilder/components/blockRegistry';
registerPuckBlocks({
blocks: {
AtlasMap: lazyBlock(
() => import('./components/AtlasMap').then((m) => m.AtlasMapEmbed),
{ label: 'Atlas map', fields: { /* … */ }, defaultProps: { /* … */ } },
(props) => <div className={heightClass[props.height]} aria-busy="true" />,
),
},
});
Light blocks (text, cards, lists) can keep their static imports — the split only pays for itself when the component drags in something big.
Migrations
This module ships no migrations — that is the framework convention. Its
SQLModel tables are picked up by your host's build_module_metadata(), so
after installing it run:
make migration msg="add pagebuilder"
make migrate
Add branch_labels = ("pagebuilder",) to that first generated revision so the
module can later be removed on its own with
alembic downgrade pagebuilder@base.
Permissions
| Permission | Grants |
|---|---|
pagebuilder.edit |
Draft, save, submit for review, restore a revision |
pagebuilder.publish |
Publish and unpublish directly |
pagebuilder.approve |
Approve or reject a submitted page |
DEFAULT_ROLE_MAP in pagebuilder.permissions suggests three roles —
pagebuilder_editor, pagebuilder_publisher, pagebuilder_approver —
cumulatively mapped to those permissions.
Settings
All settings use the SM_PAGEBUILDER_ env prefix.
| Setting | Default | Purpose |
|---|---|---|
public_route_prefix |
/p |
Where published pages are served |
requires_auth |
true |
Gate the admin surface behind authentication |
csrf_protect |
true |
Require a CSRF token on mutating admin requests |
media_root |
var/pagebuilder/media |
Upload storage directory |
media_url_prefix |
/media/pagebuilder |
Public URL prefix for uploads |
media_max_bytes |
10485760 |
Per-upload size ceiling |
media_thumbnail_widths |
320,640,1280,1920 |
Widths generated as WebP |
media_webp_quality |
82 |
WebP encoder quality |
public_csp |
see settings.py |
CSP header on public pages |
public_cache_max_age |
60 |
max-age on public pages |
public_base_url |
None |
Absolute base for canonical URLs and the sitemap |
site_name |
None |
OpenGraph site name |
sitemap_enabled |
true |
Serve /sitemap.xml |
robots_enabled |
true |
Serve /robots.txt |
scheduler_enabled |
true |
Run the scheduled publish/unpublish poller |
scheduler_interval_seconds |
30 |
Poll interval |
Routes
Admin views (under /pagebuilder): /, /new, /{page_id}/edit,
/pending, /layout, /media.
Admin API (under /api/pagebuilder): pages CRUD, workflow transitions,
revisions and diffs, layout and its revisions, uploads.
Public: /p/{slug}, /sitemap.xml, /robots.txt.
Contracts
DTOs other modules may depend on are exported from pagebuilder.contracts.
Everything else in the package is internal and may change without a major
version bump.
Licence
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file simple_module_pagebuilder-0.0.6.tar.gz.
File metadata
- Download URL: simple_module_pagebuilder-0.0.6.tar.gz
- Upload date:
- Size: 273.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5d0e3a3c9a49127cc9705c460c788fd6119ffab6a57f3c63ba8e869add7bad1b
|
|
| MD5 |
3fe013ae07b19fb4652cf8d2b7a7eb5d
|
|
| BLAKE2b-256 |
7b50a7e2340aed61f22b48c0b58d4c21c15980578bd37864d4fd53fe0b45b1e6
|
Provenance
The following attestation bundles were made for simple_module_pagebuilder-0.0.6.tar.gz:
Publisher:
release.yml on antosubash/smpy_modules
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
simple_module_pagebuilder-0.0.6.tar.gz -
Subject digest:
5d0e3a3c9a49127cc9705c460c788fd6119ffab6a57f3c63ba8e869add7bad1b - Sigstore transparency entry: 2583456955
- Sigstore integration time:
-
Permalink:
antosubash/smpy_modules@bf5c8bfe5f38039b209febce9d43fa5a1d6717ab -
Branch / Tag:
refs/heads/main - Owner: https://github.com/antosubash
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bf5c8bfe5f38039b209febce9d43fa5a1d6717ab -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file simple_module_pagebuilder-0.0.6-py3-none-any.whl.
File metadata
- Download URL: simple_module_pagebuilder-0.0.6-py3-none-any.whl
- Upload date:
- Size: 368.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b5f7c0c5a16bc4ba686c4b98f9aa1c5466c6113e7538659e1c0638ddfe2e169b
|
|
| MD5 |
a0eb216a2b431b29c8609b29be945cac
|
|
| BLAKE2b-256 |
6568be952ddc1a87b2c9f87dcf5e28981b58ea9206c5da1d7537c16e24b945ca
|
Provenance
The following attestation bundles were made for simple_module_pagebuilder-0.0.6-py3-none-any.whl:
Publisher:
release.yml on antosubash/smpy_modules
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
simple_module_pagebuilder-0.0.6-py3-none-any.whl -
Subject digest:
b5f7c0c5a16bc4ba686c4b98f9aa1c5466c6113e7538659e1c0638ddfe2e169b - Sigstore transparency entry: 2583456996
- Sigstore integration time:
-
Permalink:
antosubash/smpy_modules@bf5c8bfe5f38039b209febce9d43fa5a1d6717ab -
Branch / Tag:
refs/heads/main - Owner: https://github.com/antosubash
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bf5c8bfe5f38039b209febce9d43fa5a1d6717ab -
Trigger Event:
workflow_dispatch
-
Statement type: