? Paper CMS ?
A document-based headless CMS with API + back office.
Made primarly for editorial content management. Stock definitions are modelled after Schema.org vocabulary.
? Usage
Live demo
? Check here for a Paper CMS online tryout.
? Default dataset is reseted periodically.
? Use good ol’ admin
/ password
.
or… local quick start ?
# Clone this repo
git clone [email protected]:JulianCataldo/paper-cms.git
cd paper-cms
code ./
# Install all dependencies
npm run deps:i
# Run and watch API + back office
npm run dev
# Open back office in browser
open http://localhost:7777
# Default credentials
# > User : `admin`
# > Password : `password`
# Edit API definition
code -r ./models/api-v1.yaml
# Created entries and uploaded medias + variations
# are stored in root project by default in `.data`
tree ./.data
or… with Docker Compose ?
cd ./docker
make rdc-std
-
# Data persistence folder
tree ./docker/std/.volume/.data
See the Makefile
for all containers variants and shorthands.
Some views ?
❄️ Features
Auto-generated forms from OpenAPI definitions
auto-formgen.mp4
JSON Schema validation on run-time for both client and server sides
client-validation.mp4
UI Schema augmentation (non-standard)
ui-schema.mp4
Settings are splitted in two different schemas at runtime. Standard compliant JSON Schema alongside non standard UI Schema.
JSON files database
All your textual data is hosted unded ./data/docs
(root can be overriden with DATA_DIR
).
Run multiple instances of Paper CMS easily by setting different PORT
.
Quickly swip datasets : demo / tests / staging / production…
Image(s) upload + dynamic resize while fetching + caching
…
JWT authentication for both human editors and API consumers
auth.mp4
Full live reload for models / client / server
When editing model definitions, server or client code, everything is re-runned/builded/bundled. Also, browser is automatically refreshed thanks to a long polling web socket.
You can also trigger browser refresh by hitting curl localhost:${PORT:-7777}/reload
.
Document revisions history
…
Soft deletion, restore from trash
…
“Has many” relationship via references
has-many-diverse-refs.mp4
for full examples.
Nested referenced documents editing
A “sub” document is just another document reference.
There is no hierarchy or inheritance,
only cross-references betweens entities.
While you can create, edit or associate an existing document from the main document form,
only $refs
URI for child references actually gets recorded, not the entire subtree.
Everything can be a document collection, as soon as it make sense to reference the entity from elsewhere. Self-sufficient data should live embedded in the document itself.
There is no limit for nesting, though stacked modal editors force us to save only one (sub)document at a time: no full tree update propagation. This design choice is meant to prevent data-loss / infinite recursive nesting.
Schema.org inspired default definitions
While Schema.org states that:
The type hierarchy presented on this site is not intended to be a ‘global ontology’ of the world.
While true, it provides a great starting point with commonly used taxonomies and entities relationships. Schema.org is shining for content-driven web sites where SEO is crucial (but that’s just an excuse). While still in its infancy, JSON/LD is already bringing HATEOS concepts into real-life applications, step-by-step, organically. Regardless, feature-rich widgets are democratizing, and data crawling between third-parties is becoming more insightful.
OpenAPI 3 UI (Swagger)
The endgoal is to make Paper CMS a non-deterministic data ingestion / organization / retrieval
system.
At the end, an hypermedia API should be auto-discoverable.
Still, it’s useful to rely on Swagger niceties for on-boarding an API.
Moreover, the OpenAPI 3 specs is adding links
, a notable concept for Hypermedia minded APIs.
Wysiwyg HTML Editor
richt-text-editor.mp4
under the hood. Basic additional HTML sanitization is done server-side.
Custom fields and widgets
…
? Why?
Inspirations
We are seeing the emergence of different patterns in the content management world like:
- Shared entities vocabularies
- Automatic web form generation
- Isomorphic user input runtime validation,
- Entity / Collection oriented information architecture
- Headless non-opinionated CMS APIs for JAMStack consumption
- Hypermedia for non-deterministic data fetching via refs. | links | URIs…
- Plain files data storage for operations convenience (with some trade-offs)
- Conventions over configuration, with extendabilities (models, widgets…)
Goals
All these concepts are explored at different levels of implementations in Paper CMS. While it’s still an experiment, the end-goal is to provide a lightweight solution suitable for projects which:
- Has ten-ish max. editors in charge
- Needs moderate authoring concurrency with silo-ed document edits
- Might needs frequent content updates
- Low needs for user-land data input
- Are in an eco-system of focused services where caching / CDNs / whatever are dedicated
To sum up: Paper CMS is good for editors-driven web sites, but is not a good fit for users-driven web apps.
ℹ️ Project insights
⚠️ Work in progress: NOT FOR PRODUCTION ⚠️
Structure
Mono-repo. glued with PNPM recursive modules installation.
Major dependencies
- Node.js
- ESBuild
- React
- MUI
- React Quill
- JSON Schema React
- AJV
- Express
- Sharp
Work in progress
- Single media management
- Batch media management
- JSON/LD API output conformance
- OpenAPI conformance
- Swagger integration
- Wider Schema.org support for stock definitions
- Basic users account management
To do
- Media metadata with EXIF + IPTC support
- API collections’ pagination
- Automatic bi-directional relationships (“Is part of many” <=> “Has many”)
- Custom data fetching and population widgets for APIs / social networks content retrieval
Features ideas
- Might propose fully dynamic OpenAPI GUI builder right inside the back office, instead OR alongside YAML config.
- Might propose MongoDB/pSQL/S3 alternative to bare file storage, for increased mass and/or concurrency needs, but decreased portability.
- Might propose an option for storing media binaries in an S3 bucket.
,ggggggggggg,
dP""88""""""Y8,
Yb, 88 `8b
`" 88 ,8P
88aaaad8P"
88""""",gggg,gg gg,gggg, ,ggg, ,gggggg,
88 dP" "Y8I I8P" "Yb i8" "8i dP""""8I
88 i8' ,8I I8' ,8i I8, ,8I ,8' 8I
88 ,d8, ,d8b,,I8 _ ,d8' `YbadP' ,dP Y8,
88 P"Y8888P"`Y8PI8 YY88888P888P"Y8888P `Y8
I8
I8 ,gggg, ,ggg, ,ggg,_,ggg, ,gg,
I8 ,88"""Y8b,dP""Y8dP""Y88P""Y8b i8""8i
I8 d8" `Y8Yb, `88' `88' `88 `8,,8'
I8 d8' 8b d8 `" 88 88 88 `88'
I8 ,8I "Y88P' 88 88 88 dP"8,
I8' 88 88 88 dP' `8a
d8 88 88 88 dP' `Yb
Y8, 88 88 88 _ ,dP' I8
`Yba,,_____, 88 88 Y8,"888,,____,dP
`"Y8888888 88 88 `Y8a8P"Y88888P"