plum-cms 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +51 -0
- data/README.md +81 -3
- data/app/assets/builds/tailwind.css +1 -1
- data/app/assets/stylesheets/plum/control_panel.css +1 -1
- data/app/assets/tailwind/application.css +42 -0
- data/app/controllers/plum/api/v1/entries_controller.rb +48 -0
- data/app/controllers/plum/cp/assets_controller.rb +4 -1
- data/app/controllers/plum/cp/content_types_controller.rb +25 -2
- data/app/controllers/plum/cp/entries_controller.rb +119 -9
- data/app/controllers/plum/cp/entry_revisions_controller.rb +27 -0
- data/app/controllers/plum/cp/fieldsets_controller.rb +37 -0
- data/app/controllers/plum/cp/site_settings_controller.rb +20 -1
- data/app/controllers/plum/pages_controller.rb +26 -1
- data/app/javascript/controllers/plum/asset_collection_controller.js +18 -0
- data/app/javascript/controllers/plum/blueprint_controller.js +202 -25
- data/app/javascript/controllers/plum/conditional_fields_controller.js +43 -0
- data/app/javascript/controllers/plum/focal_point_controller.js +16 -0
- data/app/javascript/controllers/plum/structured_field_controller.js +133 -0
- data/app/models/plum/asset.rb +5 -1
- data/app/models/plum/content_type.rb +63 -1
- data/app/models/plum/entry.rb +225 -1
- data/app/models/plum/entry_revision.rb +14 -0
- data/app/models/plum/fieldset.rb +17 -0
- data/app/models/plum/site.rb +15 -0
- data/app/models/plum/user.rb +1 -0
- data/app/services/plum/entry_serializer.rb +36 -0
- data/app/services/plum/field_expander.rb +12 -1
- data/app/services/plum/field_options.rb +21 -0
- data/app/services/plum/field_type_registry.rb +88 -0
- data/app/services/plum/liquid_context.rb +7 -1
- data/app/services/plum/site_archive.rb +367 -0
- data/app/views/layouts/plum/cp.html.erb +2 -0
- data/app/views/plum/cp/assets/_form.html.erb +13 -1
- data/app/views/plum/cp/content_types/_form.html.erb +81 -24
- data/app/views/plum/cp/custom_fields/_input.html.erb +5 -0
- data/app/views/plum/cp/entries/_form.html.erb +108 -31
- data/app/views/plum/cp/entries/edit.html.erb +16 -0
- data/app/views/plum/cp/entry_revisions/index.html.erb +25 -0
- data/app/views/plum/cp/fieldsets/index.html.erb +30 -0
- data/app/views/plum/cp/site_settings/edit.html.erb +12 -0
- data/config/plum_routes.rb +15 -0
- data/db/engine_migrate/20260807130000_create_plum_entry_revisions.rb +16 -0
- data/db/engine_migrate/20260807140000_create_plum_fieldsets.rb +13 -0
- data/db/engine_migrate/20260807150000_add_focal_point_to_plum_assets.rb +6 -0
- data/db/engine_migrate/20260807160000_add_localization_to_plum_entries.rb +9 -0
- data/docs/blueprint-fields.md +55 -0
- data/docs/extensions.md +32 -0
- data/docs/portability.md +40 -0
- data/docs/product-principles.md +73 -0
- data/docs/roadmap.md +100 -0
- data/docs/site/homepage.md +104 -0
- data/docs/site/information-architecture.md +176 -0
- data/docs/statamic-parity.md +28 -0
- data/docs/vision.md +82 -0
- data/lib/plum/engine.rb +3 -1
- data/lib/plum/version.rb +1 -1
- data/lib/plum.rb +4 -0
- data/lib/tasks/plum_portability.rake +37 -0
- data/lib/tasks/plum_styles.rake +12 -0
- metadata +36 -8
data/docs/roadmap.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Roadmap
|
|
2
|
+
|
|
3
|
+
Plum's roadmap is organized by outcomes rather than promised dates. Priorities
|
|
4
|
+
move as the product is exercised in real Rails applications.
|
|
5
|
+
|
|
6
|
+
## Shipped: Plum 0.2.0 — Authoring Foundation
|
|
7
|
+
|
|
8
|
+
Plum 0.2.0 established the practical authoring surface:
|
|
9
|
+
|
|
10
|
+
- a visual blueprint builder with 21 field types, reusable fieldsets, nested
|
|
11
|
+
structures, validation, field widths, sections, and conditions;
|
|
12
|
+
- assets with single and multiple image fields, metadata, focal points, and
|
|
13
|
+
responsive variants;
|
|
14
|
+
- relationships, taxonomies, navigation, globals, forms, and Liquid themes;
|
|
15
|
+
- drafts, scheduled publishing, immutable revisions, and rollback;
|
|
16
|
+
- localized entries, locale-aware public routes, and a live-only content API;
|
|
17
|
+
- registry-backed custom field types and packaged Tailwind control-panel styles.
|
|
18
|
+
|
|
19
|
+
See [the Statamic parity matrix](statamic-parity.md) for the supported surface.
|
|
20
|
+
|
|
21
|
+
## Now: Plum 0.3.0 — Production Readiness
|
|
22
|
+
|
|
23
|
+
The 0.3.0 milestone makes Plum safe to adopt, move, recover, and operate outside
|
|
24
|
+
its development repository.
|
|
25
|
+
|
|
26
|
+
### 1. Portability and recovery
|
|
27
|
+
|
|
28
|
+
- Versioned site export/import covering schemas, entries, relationships,
|
|
29
|
+
taxonomies, navigation, globals, forms, settings, and assets.
|
|
30
|
+
- Tested backup and restore commands with integrity checks and clear failure
|
|
31
|
+
behavior.
|
|
32
|
+
- A documented archive format that remains readable across compatible releases.
|
|
33
|
+
|
|
34
|
+
### 2. Real-world installation
|
|
35
|
+
|
|
36
|
+
- Build `plumcms.org` as a standalone Rails application using the released gem.
|
|
37
|
+
- Test fresh external installations and 0.2.x upgrades in CI.
|
|
38
|
+
- Publish a production Docker contract and SQLite deployment example.
|
|
39
|
+
- Exercise health checks, upgrades, persistence, backup, and restore on a VM.
|
|
40
|
+
|
|
41
|
+
### 3. Publishing and discovery
|
|
42
|
+
|
|
43
|
+
- SEO metadata, canonical URLs, redirects, XML sitemaps, and feeds.
|
|
44
|
+
- Document hierarchy, breadcrumbs, generated tables of contents, and site search.
|
|
45
|
+
- Secure, shareable preview links for draft and scheduled content.
|
|
46
|
+
|
|
47
|
+
### 4. Editorial operations
|
|
48
|
+
|
|
49
|
+
- Asset folders, search, replacement, cropping, and richer transformations.
|
|
50
|
+
- Granular editorial roles, approvals, and publish permissions.
|
|
51
|
+
- Form spam protection and improved submission review/export workflows.
|
|
52
|
+
|
|
53
|
+
### 5. Documentation
|
|
54
|
+
|
|
55
|
+
- Complete installation and first-page guides.
|
|
56
|
+
- Document every supported field and content primitive.
|
|
57
|
+
- Document standalone SQLite and embedded PostgreSQL operation.
|
|
58
|
+
- Publish configuration, troubleshooting, extension, upgrade, backup, and
|
|
59
|
+
restore references.
|
|
60
|
+
|
|
61
|
+
## Next: Plum 0.4.0 — Repeatable Adoption
|
|
62
|
+
|
|
63
|
+
- A thin `plum` CLI for diagnostics, export/import, backup/restore, upgrades,
|
|
64
|
+
themes, and packaging.
|
|
65
|
+
- Starter applications for common publishing use cases.
|
|
66
|
+
- Theme scaffolding, validation, packaging, and distribution tools.
|
|
67
|
+
- A collection of high-quality open themes and blocks.
|
|
68
|
+
- Importers for common CMS and structured-data formats.
|
|
69
|
+
- Addon discovery and a documented compatibility contract.
|
|
70
|
+
|
|
71
|
+
## Later: The Rails Content Ecosystem
|
|
72
|
+
|
|
73
|
+
- Translation-service integrations and richer localization workflows.
|
|
74
|
+
- Agency-oriented multisite operations and reusable project recipes.
|
|
75
|
+
- Community examples, case studies, talks, and contribution programs.
|
|
76
|
+
- Broader content APIs where real applications demonstrate the need.
|
|
77
|
+
|
|
78
|
+
## Plum 1.0
|
|
79
|
+
|
|
80
|
+
Plum 1.0 means another Rails developer can reproduce what powers
|
|
81
|
+
`plumcms.org` without private knowledge or site-specific patches.
|
|
82
|
+
|
|
83
|
+
It requires:
|
|
84
|
+
|
|
85
|
+
- a published, versioned gem;
|
|
86
|
+
- an editable page within ten minutes of installation;
|
|
87
|
+
- dependable standalone and embedded installation paths;
|
|
88
|
+
- a documented SQLite production deployment;
|
|
89
|
+
- clean host authentication, authorization, and tenancy integration;
|
|
90
|
+
- preview, revisions, export, backup, and restore;
|
|
91
|
+
- complete documentation for the supported public surface;
|
|
92
|
+
- a tested upgrade path;
|
|
93
|
+
- at least one production standalone site and one production embedded use; and
|
|
94
|
+
- a public example application that agencies can study and adapt.
|
|
95
|
+
|
|
96
|
+
## Not on the Near-Term Roadmap
|
|
97
|
+
|
|
98
|
+
Plum is not trying to become a general-purpose admin framework, a freeform
|
|
99
|
+
visual design tool, an ecommerce platform, or a hosted headless CMS. Plum's
|
|
100
|
+
focus is managed content that belongs inside Rails.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Homepage Copy
|
|
2
|
+
|
|
3
|
+
## Hero
|
|
4
|
+
|
|
5
|
+
### Plum
|
|
6
|
+
|
|
7
|
+
**The Rails-native CMS.**
|
|
8
|
+
|
|
9
|
+
Add managed content to an existing Rails application or build a complete
|
|
10
|
+
content-first site—without leaving the Rails stack.
|
|
11
|
+
|
|
12
|
+
Primary action: **Get started**
|
|
13
|
+
|
|
14
|
+
Secondary action: **View on GitHub**
|
|
15
|
+
|
|
16
|
+
Supporting note: Open source. Self-hosted. SQLite and PostgreSQL.
|
|
17
|
+
|
|
18
|
+
## One Stack, Complete Control
|
|
19
|
+
|
|
20
|
+
Plum uses the Rails application you already understand: its database, users,
|
|
21
|
+
authorization, jobs, mail, storage, and deployment. There is no external CMS to
|
|
22
|
+
synchronize and no second frontend to maintain.
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
gem "plum"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
bin/rails generate plum:install --mount-path=/website
|
|
30
|
+
bin/rails db:migrate
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Two Ways to Use Plum
|
|
34
|
+
|
|
35
|
+
### Add content to your application
|
|
36
|
+
|
|
37
|
+
Mount Plum in an existing Rails product. Let customers or editors manage pages,
|
|
38
|
+
navigation, documentation, announcements, and structured content while the host
|
|
39
|
+
application continues to own identity and business data.
|
|
40
|
+
|
|
41
|
+
Action: **Embed Plum**
|
|
42
|
+
|
|
43
|
+
### Build the whole site with Plum
|
|
44
|
+
|
|
45
|
+
Start with Rails, SQLite, and a Plum theme. Ship a fast, portable content site
|
|
46
|
+
that can grow into a custom Rails application whenever the project demands it.
|
|
47
|
+
|
|
48
|
+
Action: **Build a Plum site**
|
|
49
|
+
|
|
50
|
+
## Application Data Meets Editorial Content
|
|
51
|
+
|
|
52
|
+
Expose host application data safely to Plum templates without copying it into a
|
|
53
|
+
remote CMS.
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
Plum.configure do |config|
|
|
57
|
+
config.current_site_resolver = ->(_) { Current.account.plum_site }
|
|
58
|
+
config.current_user_resolver = ->(_) { Current.user }
|
|
59
|
+
|
|
60
|
+
config.register_content_source :products do |context|
|
|
61
|
+
context.owner.products.published
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Editors manage the story. Rails remains the source of truth for the application.
|
|
67
|
+
|
|
68
|
+
## Familiar Rails Foundations
|
|
69
|
+
|
|
70
|
+
- Rails 8 engine
|
|
71
|
+
- Hotwire control panel
|
|
72
|
+
- Active Record content
|
|
73
|
+
- Active Storage assets
|
|
74
|
+
- Active Job notifications
|
|
75
|
+
- Liquid themes
|
|
76
|
+
- SQLite and PostgreSQL
|
|
77
|
+
- Host-owned authentication and authorization
|
|
78
|
+
|
|
79
|
+
## For Independent Developers and Agencies
|
|
80
|
+
|
|
81
|
+
Package each client site as an independent Rails application with its own
|
|
82
|
+
SQLite database, assets, domain, and backup. Run several sites economically on
|
|
83
|
+
one VM with an ONCE-compatible container, and move any client without untangling
|
|
84
|
+
a shared CMS installation.
|
|
85
|
+
|
|
86
|
+
Action: **See the agency model**
|
|
87
|
+
|
|
88
|
+
## Built in Public, Used for Real
|
|
89
|
+
|
|
90
|
+
This website is a Rails application powered by Plum and SQLite. The same public
|
|
91
|
+
engine, theme system, and deployment path are available to every Plum project.
|
|
92
|
+
|
|
93
|
+
Action: **How this site works**
|
|
94
|
+
|
|
95
|
+
## Closing Call to Action
|
|
96
|
+
|
|
97
|
+
### Keep content in Rails.
|
|
98
|
+
|
|
99
|
+
Give editors the tools they need without giving up the application stack you
|
|
100
|
+
want.
|
|
101
|
+
|
|
102
|
+
Primary action: **Read the getting-started guide**
|
|
103
|
+
|
|
104
|
+
Secondary action: **Explore the roadmap**
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# plumcms.org Information Architecture
|
|
2
|
+
|
|
3
|
+
The site serves three audiences: developers adding content to an existing Rails
|
|
4
|
+
application, developers building a content-first site, and agencies operating
|
|
5
|
+
multiple client sites.
|
|
6
|
+
|
|
7
|
+
## Primary Navigation
|
|
8
|
+
|
|
9
|
+
- Why Plum
|
|
10
|
+
- Use Cases
|
|
11
|
+
- Documentation
|
|
12
|
+
- Roadmap
|
|
13
|
+
- GitHub
|
|
14
|
+
|
|
15
|
+
The persistent primary action is **Get started**.
|
|
16
|
+
|
|
17
|
+
## Routes
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
/
|
|
21
|
+
/why-plum
|
|
22
|
+
/features
|
|
23
|
+
/use-cases
|
|
24
|
+
/existing-rails-apps
|
|
25
|
+
/content-sites
|
|
26
|
+
/agencies
|
|
27
|
+
/docs
|
|
28
|
+
/getting-started
|
|
29
|
+
/concepts
|
|
30
|
+
/content-modeling
|
|
31
|
+
/themes
|
|
32
|
+
/embedding
|
|
33
|
+
/deployment
|
|
34
|
+
/reference
|
|
35
|
+
/roadmap
|
|
36
|
+
/changelog
|
|
37
|
+
/demo
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Homepage Story
|
|
41
|
+
|
|
42
|
+
The homepage should answer five questions in order:
|
|
43
|
+
|
|
44
|
+
1. What is Plum?
|
|
45
|
+
2. Why would a Rails developer use it instead of another CMS?
|
|
46
|
+
3. Can it work in my kind of project?
|
|
47
|
+
4. What does the code and editing experience look like?
|
|
48
|
+
5. Can I trust and try it?
|
|
49
|
+
|
|
50
|
+
## Documentation Structure
|
|
51
|
+
|
|
52
|
+
### Start
|
|
53
|
+
|
|
54
|
+
- Introduction
|
|
55
|
+
- Installation
|
|
56
|
+
- Your first editable page
|
|
57
|
+
- Build a small content site
|
|
58
|
+
|
|
59
|
+
### Core concepts
|
|
60
|
+
|
|
61
|
+
- Sites
|
|
62
|
+
- Content types and blueprints
|
|
63
|
+
- Entries and publishing
|
|
64
|
+
- Fields
|
|
65
|
+
- Liquid rendering
|
|
66
|
+
|
|
67
|
+
### Content features
|
|
68
|
+
|
|
69
|
+
- Blocks
|
|
70
|
+
- Rich text
|
|
71
|
+
- Assets and images
|
|
72
|
+
- Relationships
|
|
73
|
+
- Taxonomies
|
|
74
|
+
- Navigation
|
|
75
|
+
- Globals
|
|
76
|
+
- Forms
|
|
77
|
+
|
|
78
|
+
### Themes
|
|
79
|
+
|
|
80
|
+
- Theme anatomy
|
|
81
|
+
- Templates and layouts
|
|
82
|
+
- Theme manifests
|
|
83
|
+
- Settings
|
|
84
|
+
- Assets
|
|
85
|
+
- Blocks
|
|
86
|
+
- Packaging and installation
|
|
87
|
+
|
|
88
|
+
### Embed Plum
|
|
89
|
+
|
|
90
|
+
- Mounting the engine
|
|
91
|
+
- Host authentication
|
|
92
|
+
- Authorization
|
|
93
|
+
- Site resolution and tenancy
|
|
94
|
+
- Host content sources
|
|
95
|
+
- Routes and URLs
|
|
96
|
+
- White labelling
|
|
97
|
+
|
|
98
|
+
### Operate
|
|
99
|
+
|
|
100
|
+
- SQLite deployment
|
|
101
|
+
- PostgreSQL deployment
|
|
102
|
+
- Active Storage
|
|
103
|
+
- Jobs and email
|
|
104
|
+
- Docker and ONCE
|
|
105
|
+
- Backups and restore
|
|
106
|
+
- Upgrading
|
|
107
|
+
|
|
108
|
+
### Reference
|
|
109
|
+
|
|
110
|
+
- Configuration
|
|
111
|
+
- Blueprint field contracts
|
|
112
|
+
- Liquid objects and filters
|
|
113
|
+
- Theme manifest
|
|
114
|
+
- Generators
|
|
115
|
+
- Troubleshooting
|
|
116
|
+
|
|
117
|
+
## Content Types
|
|
118
|
+
|
|
119
|
+
### Pages
|
|
120
|
+
|
|
121
|
+
- Title
|
|
122
|
+
- Slug
|
|
123
|
+
- Summary
|
|
124
|
+
- Sections (`blocks`)
|
|
125
|
+
- SEO title
|
|
126
|
+
- SEO description
|
|
127
|
+
|
|
128
|
+
### Documentation pages
|
|
129
|
+
|
|
130
|
+
- Title
|
|
131
|
+
- Slug
|
|
132
|
+
- Section taxonomy
|
|
133
|
+
- Parent relationship
|
|
134
|
+
- Position
|
|
135
|
+
- Summary
|
|
136
|
+
- Body
|
|
137
|
+
|
|
138
|
+
### Releases
|
|
139
|
+
|
|
140
|
+
- Version
|
|
141
|
+
- Published date
|
|
142
|
+
- Summary
|
|
143
|
+
- Body
|
|
144
|
+
|
|
145
|
+
### Roadmap items
|
|
146
|
+
|
|
147
|
+
- Title
|
|
148
|
+
- Horizon (`now`, `next`, or `later`)
|
|
149
|
+
- Status
|
|
150
|
+
- Problem
|
|
151
|
+
- Intended outcome
|
|
152
|
+
|
|
153
|
+
## Initial Blocks
|
|
154
|
+
|
|
155
|
+
- Hero
|
|
156
|
+
- Prose
|
|
157
|
+
- Code example
|
|
158
|
+
- Feature grid
|
|
159
|
+
- Use-case cards
|
|
160
|
+
- Steps
|
|
161
|
+
- Comparison
|
|
162
|
+
- Quote
|
|
163
|
+
- Call to action
|
|
164
|
+
|
|
165
|
+
Blocks should be general enough to ship as examples or reusable base blocks.
|
|
166
|
+
Site-specific styling belongs in the plumcms.org theme.
|
|
167
|
+
|
|
168
|
+
## Proof the Site Must Provide
|
|
169
|
+
|
|
170
|
+
- The homepage is editable through Plum.
|
|
171
|
+
- Documentation is navigable and pleasant to read.
|
|
172
|
+
- A visitor can see real installation code immediately.
|
|
173
|
+
- The public roadmap distinguishes current capability from future intent.
|
|
174
|
+
- The application runs on Rails and SQLite in production.
|
|
175
|
+
- Its container, persistence, backup, and restore approach are documented.
|
|
176
|
+
- No private Plum features or site-specific engine patches are required.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Statamic capability parity
|
|
2
|
+
|
|
3
|
+
This matrix tracks practical authoring parity rather than matching Statamic's
|
|
4
|
+
internal architecture or naming.
|
|
5
|
+
|
|
6
|
+
| Capability | Plum status | Notes |
|
|
7
|
+
|---|---|---|
|
|
8
|
+
| Blueprint field builder | Supported | Visual, nested, typed configuration |
|
|
9
|
+
| Reusable fieldsets | Supported | Site-scoped snapshots with collision-safe insertion |
|
|
10
|
+
| Field instructions/defaults/required | Supported | Client and server validation |
|
|
11
|
+
| Field widths and sections | Supported | Twelve-column responsive editor |
|
|
12
|
+
| Conditional fields | Supported | Five common operators |
|
|
13
|
+
| Text, rich text, numbers, dates | Supported | Bounds and modes included |
|
|
14
|
+
| Choice controls | Supported | Select, radio, buttons, checkboxes |
|
|
15
|
+
| Assets | Supported | Single/multi-image fields, metadata, focal points, variants |
|
|
16
|
+
| Relationships | Supported | Single/multiple, type-filtered, site-scoped |
|
|
17
|
+
| Structured content | Supported | Lists, groups, repeaters, blocks |
|
|
18
|
+
| Taxonomies | Supported | Managed terms and public archives |
|
|
19
|
+
| Globals and navigation | Supported | Liquid-accessible content |
|
|
20
|
+
| Forms | Supported | Definitions, submissions, notifications |
|
|
21
|
+
| Themes | Supported | Liquid packages, settings, blocks |
|
|
22
|
+
| Revisions and publishing workflow | Supported | Attributed snapshots, restoration, drafts, scheduling |
|
|
23
|
+
| Localization/multisite | Supported | Site locales, translation groups, localized URLs/API |
|
|
24
|
+
| Content API | Supported | Public, site-scoped, live-only JSON collections |
|
|
25
|
+
| Addon field types | Supported | Registry-backed editor and value pipeline |
|
|
26
|
+
|
|
27
|
+
Longer-term ecosystem work can add commercial-style addon discovery, more
|
|
28
|
+
workflow roles, and translation services without changing these authoring APIs.
|
data/docs/vision.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Plum's Vision
|
|
2
|
+
|
|
3
|
+
Plum is the Rails-native CMS.
|
|
4
|
+
|
|
5
|
+
It gives Rails developers a default way to add managed content to an existing
|
|
6
|
+
application or build a complete content-first site without introducing another
|
|
7
|
+
application stack.
|
|
8
|
+
|
|
9
|
+
## Why Plum Exists
|
|
10
|
+
|
|
11
|
+
Rails is excellent at building applications, but content management is still
|
|
12
|
+
usually assembled from bespoke admin screens, delegated to a remote headless
|
|
13
|
+
CMS, or moved into a separate publishing platform. Each choice adds work or
|
|
14
|
+
pulls content away from the application that uses it.
|
|
15
|
+
|
|
16
|
+
Plum makes content a native part of Rails. It uses the application's database,
|
|
17
|
+
models, users, authorization, jobs, mail, storage, and deployment environment.
|
|
18
|
+
Developers keep the flexibility of Ruby and Rails. Editors get a focused,
|
|
19
|
+
polished place to manage content.
|
|
20
|
+
|
|
21
|
+
## Who Plum Is For
|
|
22
|
+
|
|
23
|
+
### Rails application teams
|
|
24
|
+
|
|
25
|
+
Mount Plum inside an existing application to manage marketing pages,
|
|
26
|
+
documentation, announcements, navigation, help content, and other editorial
|
|
27
|
+
material. Application records can be exposed safely alongside managed content
|
|
28
|
+
without copying them into an external CMS.
|
|
29
|
+
|
|
30
|
+
### Independent developers and agencies
|
|
31
|
+
|
|
32
|
+
Use Plum as the foundation of a complete client site. Start with Rails, SQLite,
|
|
33
|
+
a Plum theme, and one deployable container. Retain the ability to add ordinary
|
|
34
|
+
Rails features when the project grows beyond a brochure site.
|
|
35
|
+
|
|
36
|
+
### SaaS products
|
|
37
|
+
|
|
38
|
+
Give each account a site-scoped, white-labelled editing experience while the
|
|
39
|
+
host application continues to own identity, authorization, tenancy, and
|
|
40
|
+
business data.
|
|
41
|
+
|
|
42
|
+
## The Promise
|
|
43
|
+
|
|
44
|
+
A developer should be able to add Plum to a Rails application and publish an
|
|
45
|
+
editable page in less than ten minutes.
|
|
46
|
+
|
|
47
|
+
A small content site should be able to run as one Rails application with SQLite
|
|
48
|
+
and persistent storage. An agency should be able to operate several independent
|
|
49
|
+
Plum sites on one VM as portable containers. A larger application should be
|
|
50
|
+
able to use PostgreSQL and embed Plum without changing its content model.
|
|
51
|
+
|
|
52
|
+
Content must remain portable. Plum should never require a hosted Plum account,
|
|
53
|
+
a proprietary runtime, or a second frontend application.
|
|
54
|
+
|
|
55
|
+
## What Makes Plum Different
|
|
56
|
+
|
|
57
|
+
- It is Rails infrastructure, not a remote content service.
|
|
58
|
+
- It works both as a mountable engine and as the center of a standalone site.
|
|
59
|
+
- It lets editorial content and host application data participate in the same
|
|
60
|
+
rendering context.
|
|
61
|
+
- It follows the Rails approach: strong conventions, ordinary Ruby extension
|
|
62
|
+
points, and ownership of the complete application.
|
|
63
|
+
- It supports a low-operations SQLite path without limiting applications that
|
|
64
|
+
need PostgreSQL.
|
|
65
|
+
- It treats themes, content, assets, backups, and deployments as portable parts
|
|
66
|
+
of a site rather than features of a vendor account.
|
|
67
|
+
|
|
68
|
+
## The Long-Term Goal
|
|
69
|
+
|
|
70
|
+
When a Rails developer asks, "How do I let someone edit this content?", Plum
|
|
71
|
+
should be the obvious answer.
|
|
72
|
+
|
|
73
|
+
Plum succeeds when it becomes normal to:
|
|
74
|
+
|
|
75
|
+
- mount Plum in a Rails product;
|
|
76
|
+
- start a client content site with Plum;
|
|
77
|
+
- publish and share Plum themes and blocks;
|
|
78
|
+
- run a collection of independent Plum sites economically; and
|
|
79
|
+
- extend content workflows with familiar Rails code.
|
|
80
|
+
|
|
81
|
+
The goal is not to reproduce every feature of every CMS. The goal is to make
|
|
82
|
+
content management feel like it has always belonged in Rails.
|
data/lib/plum/engine.rb
CHANGED
|
@@ -8,7 +8,9 @@ module Plum
|
|
|
8
8
|
|
|
9
9
|
initializer "plum.assets" do |app|
|
|
10
10
|
app.config.assets.paths << root.join("app/assets/javascripts")
|
|
11
|
-
|
|
11
|
+
# Importmap exposes these files as `plum/*`, so Propshaft must resolve
|
|
12
|
+
# them relative to the parent controllers directory.
|
|
13
|
+
app.config.assets.paths << root.join("app/javascript/controllers")
|
|
12
14
|
app.config.assets.paths << root.join("vendor/javascript")
|
|
13
15
|
|
|
14
16
|
lexxy_spec = Gem.loaded_specs["lexxy"]
|
data/lib/plum/version.rb
CHANGED
data/lib/plum.rb
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
namespace :plum do
|
|
2
|
+
namespace :site do
|
|
3
|
+
desc "Export a complete Plum site archive (SITE_ID or first site; ARCHIVE required)"
|
|
4
|
+
task export: :environment do
|
|
5
|
+
path = ENV.fetch("ARCHIVE") { abort "ARCHIVE is required" }
|
|
6
|
+
site = ENV["SITE_ID"].present? ? Plum::Site.find(ENV["SITE_ID"]) : Plum::Site.first
|
|
7
|
+
abort "No Plum site exists" unless site
|
|
8
|
+
|
|
9
|
+
archive = Plum::SiteArchive.dump(site: site, path: path)
|
|
10
|
+
puts "Exported #{site.name} to #{archive}"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
desc "Import a Plum site archive as a new site (ARCHIVE required; NAME and DOMAIN optional)"
|
|
14
|
+
task import: :environment do
|
|
15
|
+
path = ENV.fetch("ARCHIVE") { abort "ARCHIVE is required" }
|
|
16
|
+
site = Plum::SiteArchive.load(path: path, name: ENV["NAME"], domain: ENV["DOMAIN"])
|
|
17
|
+
puts "Imported #{site.name} as site #{site.id}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
namespace :backup do
|
|
22
|
+
desc "Create a timestamped Plum site backup (SITE_ID optional; DIRECTORY defaults to backups/plum)"
|
|
23
|
+
task create: :environment do
|
|
24
|
+
site = ENV["SITE_ID"].present? ? Plum::Site.find(ENV["SITE_ID"]) : Plum::Site.first
|
|
25
|
+
abort "No Plum site exists" unless site
|
|
26
|
+
directory = Rails.root.join(ENV.fetch("DIRECTORY", "backups/plum"))
|
|
27
|
+
filename = "plum-site-#{site.id}-#{Time.current.utc.strftime('%Y%m%d%H%M%S')}.plum.zip"
|
|
28
|
+
archive = Plum::SiteArchive.dump(site: site, path: directory.join(filename))
|
|
29
|
+
puts "Backed up #{site.name} to #{archive}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
desc "Restore a Plum backup as a new site (ARCHIVE required; NAME and DOMAIN optional)"
|
|
33
|
+
task restore: :environment do
|
|
34
|
+
Rake::Task["plum:site:import"].invoke
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require "fileutils"
|
|
2
|
+
|
|
3
|
+
namespace :plum do
|
|
4
|
+
desc "Build Tailwind and copy the result into Plum's packaged stylesheet"
|
|
5
|
+
task build_styles: :environment do
|
|
6
|
+
system(Rails.root.join("bin/rails").to_s, "tailwindcss:build", exception: true)
|
|
7
|
+
source = Rails.root.join("app/assets/builds/tailwind.css")
|
|
8
|
+
destination = Rails.root.join("app/assets/stylesheets/plum/control_panel.css")
|
|
9
|
+
FileUtils.cp(source, destination)
|
|
10
|
+
puts "Packaged #{destination.relative_path_from(Rails.root)}"
|
|
11
|
+
end
|
|
12
|
+
end
|