iron-cms 0.17.2 → 0.18.0

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.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +88 -4
  3. data/app/assets/builds/iron.css +255 -106
  4. data/app/assets/tailwind/iron/application.css +1 -0
  5. data/app/assets/tailwind/iron/components/file-upload.css +26 -0
  6. data/app/assets/tailwind/iron/lexxy.css +111 -87
  7. data/app/controllers/concerns/iron/schema_editing.rb +19 -0
  8. data/app/controllers/iron/api/schema/base_controller.rb +25 -0
  9. data/app/controllers/iron/api/schema/block_definitions_controller.rb +49 -0
  10. data/app/controllers/iron/api/schema/content_types_controller.rb +64 -0
  11. data/app/controllers/iron/api/schema/field_definitions_controller.rb +88 -0
  12. data/app/controllers/iron/api/schema/locales_controller.rb +52 -0
  13. data/app/controllers/iron/application_controller.rb +1 -1
  14. data/app/controllers/iron/block_definitions_controller.rb +1 -0
  15. data/app/controllers/iron/content_types_controller.rb +1 -0
  16. data/app/controllers/iron/field_definitions_controller.rb +2 -1
  17. data/app/controllers/iron/first_runs_controller.rb +1 -1
  18. data/app/controllers/iron/locales_controller.rb +1 -0
  19. data/app/controllers/iron/sessions_controller.rb +1 -1
  20. data/app/helpers/iron/avatar_helper.rb +24 -2
  21. data/app/javascript/iron/controllers/file_upload_controller.js +38 -7
  22. data/app/models/iron/account.rb +1 -1
  23. data/app/models/iron/api/openapi_spec.rb +37 -15
  24. data/app/models/iron/block_definition/exportable.rb +1 -1
  25. data/app/models/iron/block_definition.rb +3 -1
  26. data/app/models/iron/content.rb +176 -0
  27. data/app/models/iron/content_type/exportable.rb +3 -1
  28. data/app/models/iron/content_type/importable.rb +1 -1
  29. data/app/models/iron/content_type.rb +6 -1
  30. data/app/models/iron/entry/content_assignable.rb +10 -2
  31. data/app/models/iron/exporter.rb +1 -26
  32. data/app/models/iron/field/length_constrained.rb +17 -0
  33. data/app/models/iron/field/validatable.rb +16 -0
  34. data/app/models/iron/field.rb +1 -1
  35. data/app/models/iron/field_definition/exportable.rb +3 -4
  36. data/app/models/iron/field_definition/importable.rb +16 -9
  37. data/app/models/iron/field_definition/ranked.rb +1 -1
  38. data/app/models/iron/field_definition/searchable.rb +2 -0
  39. data/app/models/iron/field_definition/validatable.rb +40 -0
  40. data/app/models/iron/field_definition/validations.rb +175 -0
  41. data/app/models/iron/field_definition.rb +1 -1
  42. data/app/models/iron/field_definitions/date.rb +2 -0
  43. data/app/models/iron/field_definitions/file.rb +3 -11
  44. data/app/models/iron/field_definitions/number.rb +2 -0
  45. data/app/models/iron/field_definitions/reference.rb +2 -0
  46. data/app/models/iron/field_definitions/rich_text_area.rb +1 -0
  47. data/app/models/iron/field_definitions/text_area.rb +2 -0
  48. data/app/models/iron/field_definitions/text_field.rb +1 -9
  49. data/app/models/iron/fields/block.rb +5 -1
  50. data/app/models/iron/fields/block_list.rb +5 -1
  51. data/app/models/iron/fields/date.rb +19 -2
  52. data/app/models/iron/fields/file.rb +5 -3
  53. data/app/models/iron/fields/number.rb +28 -1
  54. data/app/models/iron/fields/reference.rb +2 -0
  55. data/app/models/iron/fields/rich_text_area.rb +2 -0
  56. data/app/models/iron/fields/text_area.rb +4 -0
  57. data/app/models/iron/fields/text_field.rb +9 -5
  58. data/app/models/iron/importer.rb +1 -54
  59. data/app/models/iron/locale.rb +2 -0
  60. data/app/models/iron/schema/auto_dumpable.rb +26 -0
  61. data/app/models/iron/schema/diff.rb +194 -0
  62. data/app/models/iron/schema/validation.rb +214 -0
  63. data/app/models/iron/schema.rb +282 -0
  64. data/app/models/iron/seed.rb +5 -3
  65. data/app/models/iron/system.rb +7 -0
  66. data/app/models/iron/user/deactivatable.rb +5 -0
  67. data/app/models/iron/user.rb +18 -1
  68. data/app/views/iron/api/fields/_rich_text_area.json.jbuilder +2 -2
  69. data/app/views/iron/api/schema/block_definitions/_block_definition.json.jbuilder +4 -0
  70. data/app/views/iron/api/schema/block_definitions/index.json.jbuilder +1 -0
  71. data/app/views/iron/api/schema/block_definitions/show.json.jbuilder +1 -0
  72. data/app/views/iron/api/schema/content_types/_content_type.json.jbuilder +5 -0
  73. data/app/views/iron/api/schema/content_types/index.json.jbuilder +1 -0
  74. data/app/views/iron/api/schema/content_types/show.json.jbuilder +1 -0
  75. data/app/views/iron/api/schema/field_definitions/_field_definition.json.jbuilder +7 -0
  76. data/app/views/iron/api/schema/field_definitions/show.json.jbuilder +1 -0
  77. data/app/views/iron/api/schema/locales/_locale.json.jbuilder +4 -0
  78. data/app/views/iron/api/schema/locales/index.json.jbuilder +1 -0
  79. data/app/views/iron/api/schema/locales/show.json.jbuilder +1 -0
  80. data/app/views/iron/block_definitions/_empty_state.html.erb +5 -3
  81. data/app/views/iron/block_definitions/_form.html.erb +3 -1
  82. data/app/views/iron/block_definitions/edit.html.erb +19 -17
  83. data/app/views/iron/block_definitions/index.html.erb +7 -3
  84. data/app/views/iron/block_definitions/show.html.erb +14 -8
  85. data/app/views/iron/content_types/_content_type.html.erb +1 -1
  86. data/app/views/iron/content_types/_empty_state.html.erb +5 -3
  87. data/app/views/iron/content_types/_form.html.erb +12 -8
  88. data/app/views/iron/content_types/edit.html.erb +19 -17
  89. data/app/views/iron/content_types/index.html.erb +7 -3
  90. data/app/views/iron/content_types/show.html.erb +14 -8
  91. data/app/views/iron/entries/_empty_state.html.erb +1 -1
  92. data/app/views/iron/entries/edit.html.erb +1 -1
  93. data/app/views/iron/entries/entry.html.erb +1 -1
  94. data/app/views/iron/entries/fields/_block.html.erb +4 -0
  95. data/app/views/iron/entries/fields/_block_list.html.erb +2 -0
  96. data/app/views/iron/entries/fields/_boolean.html.erb +1 -0
  97. data/app/views/iron/entries/fields/_date.html.erb +3 -2
  98. data/app/views/iron/entries/fields/_field_errors.html.erb +7 -0
  99. data/app/views/iron/entries/fields/_field_label.html.erb +8 -0
  100. data/app/views/iron/entries/fields/_file.html.erb +11 -19
  101. data/app/views/iron/entries/fields/_number.html.erb +6 -2
  102. data/app/views/iron/entries/fields/_reference.html.erb +2 -1
  103. data/app/views/iron/entries/fields/_reference_list.html.erb +2 -0
  104. data/app/views/iron/entries/fields/_rich_text_area.html.erb +2 -1
  105. data/app/views/iron/entries/fields/_text_area.html.erb +6 -2
  106. data/app/views/iron/entries/fields/_text_field.html.erb +5 -12
  107. data/app/views/iron/field_definitions/_field_definition.html.erb +51 -29
  108. data/app/views/iron/field_definitions/date/_form.html.erb +5 -1
  109. data/app/views/iron/field_definitions/edit.html.erb +10 -8
  110. data/app/views/iron/field_definitions/file/_form.html.erb +6 -0
  111. data/app/views/iron/field_definitions/new.html.erb +5 -3
  112. data/app/views/iron/field_definitions/number/_form.html.erb +23 -1
  113. data/app/views/iron/field_definitions/reference/_form.html.erb +5 -0
  114. data/app/views/iron/field_definitions/rich_text_area/_form.html.erb +5 -0
  115. data/app/views/iron/field_definitions/text_area/_form.html.erb +23 -0
  116. data/app/views/iron/field_definitions/text_field/_form.html.erb +20 -1
  117. data/app/views/iron/home/_content_types.html.erb +1 -1
  118. data/app/views/iron/locales/_form.html.erb +5 -3
  119. data/app/views/iron/locales/edit.html.erb +1 -1
  120. data/app/views/iron/locales/index.html.erb +12 -6
  121. data/app/views/iron/shared/_schema_lock_badge.html.erb +19 -0
  122. data/config/locales/en.yml +13 -1
  123. data/config/locales/it.yml +18 -1
  124. data/config/routes.rb +11 -0
  125. data/db/migrate/20260612131538_create_iron_systems.rb +9 -0
  126. data/exe/iron +5 -0
  127. data/lib/generators/iron/agents/agents_generator.rb +52 -0
  128. data/lib/generators/iron/agents/templates/AGENTS.md +24 -0
  129. data/lib/generators/iron/agents/templates/SKILL.md +423 -0
  130. data/lib/generators/iron/install/install_generator.rb +118 -0
  131. data/lib/generators/iron/install/templates/iron_release.rake +5 -0
  132. data/lib/generators/iron/install/templates/schema.json +12 -0
  133. data/lib/generators/iron/install/templates/seeds.rb +13 -0
  134. data/lib/generators/iron/pages/pages_generator.rb +5 -0
  135. data/lib/generators/iron/pages/templates/pages_controller.rb +1 -1
  136. data/lib/generators/iron/pages/templates/show.html.erb +1 -1
  137. data/lib/install/template.rb +9 -0
  138. data/lib/iron/cli.rb +43 -0
  139. data/lib/iron/version.rb +1 -1
  140. data/lib/tasks/iron_content.rake +82 -0
  141. data/lib/tasks/iron_schema.rake +45 -0
  142. metadata +62 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7441460ff6c611510525a11808f5fe2deb724574380f91b5ffab5edbb1c571a0
4
- data.tar.gz: 157944fd97ba5e0b6aba79409fd0b456bd6bef4cb802ed836eba2dc9b693de15
3
+ metadata.gz: fdbdcd75d63988db324f7cd3520ff66b7327aa366a8316e82ca0a48fc02f5830
4
+ data.tar.gz: 55f750ec5c956ea41834df8c10fec16aa12e99e01224ab6c9fc142f2c76843d0
5
5
  SHA512:
6
- metadata.gz: 5fd0f51df8afd88331e30b3349eee6e1dfb6df988ab1f17b5a5362d2e94f71d6fbabfb2e62001c8627c6e2a2c5c0a0ad998c4ae9b192319b6cf37d392ef13fe2
7
- data.tar.gz: a6a1b3169c158dae96b9190b0553b0e83eaf450df510cefcc70915aca31087284d495fc28269c271a9827f3a59f2d04cca87657b00e22e0e392cd3eedbec8ae7
6
+ metadata.gz: 0b5f6d0e3e5c7114cea52af8687af60ef66afd906025c5fc4a394fa6c5a3ecdbc029117028a1c938c6f02fe6e9a4530083cf36c281e2b37723395604e7aea274
7
+ data.tar.gz: 9437328b4b67b083d7c57938acfcb8b5f5d7a082e831b21890eff4afd2c3dc2b051dadb1b0def5eaa26b5192fbc8aadff9f1cc60e5fafc99b79033a63ca57eac
data/README.md CHANGED
@@ -35,7 +35,7 @@ Iron CMS allows you to publish content types to your website. To set this up:
35
35
 
36
36
  4. **Access your content** on the web:
37
37
  - Entries will be available at their generated routes
38
- - Use the `iron_entry_path(@entry)` helper to generate URLs
38
+ - Use the `iron_entry_path(@entry.attributes)` helper to generate URLs
39
39
  - Multi-locale support is built-in with URL prefixes
40
40
 
41
41
  ### Responsive Images
@@ -127,6 +127,40 @@ The seed creates a default admin user during loading. Configure via environment
127
127
  - `IRON_SEED_EMAIL` (default: `admin@example.com`)
128
128
  - `IRON_SEED_PASSWORD` (default: `password`)
129
129
 
130
+ ### Building with AI Agents
131
+
132
+ Iron is built for agent-driven development: the CMS schema lives in a declarative file and content is managed through rake tasks, so a coding agent can take a site from brief to working CMS without clicking through the admin.
133
+
134
+ Install the knowledge package:
135
+
136
+ ```bash
137
+ bin/rails g iron:agents
138
+ ```
139
+
140
+ This creates `.claude/skills/iron-cms/SKILL.md` — a Claude Code skill teaching agents the full workflow (schema file format, field types, payload formats) — and adds an `## Iron CMS` command crib sheet to your `AGENTS.md` (created if missing).
141
+
142
+ The schema lives in `db/cms/schema.json` and declares locales, block definitions and content types:
143
+
144
+ ```bash
145
+ bin/rails iron:schema:dump # write the current schema to db/cms/schema.json
146
+ bin/rails iron:schema:diff # preview what apply would change
147
+ bin/rails iron:schema:apply # upsert the file into the database (PRUNE=1 also deletes)
148
+ ```
149
+
150
+ Apply upserts by handle and is additive by default. In development, schema edits made in the admin UI are dumped back to the file automatically, so it stays current either way.
151
+
152
+ Content is managed imperatively:
153
+
154
+ ```bash
155
+ bin/rails iron:content:list HANDLE=post
156
+ bin/rails iron:content:get HANDLE=post ROUTE=hello-world
157
+ bin/rails iron:content:create HANDLE=post PAYLOAD='{"title": "Hello"}'
158
+ bin/rails iron:content:update HANDLE=post ID=12 PAYLOAD='{"title": "Hi"}'
159
+ bin/rails iron:content:delete HANDLE=post ID=12
160
+ ```
161
+
162
+ Payloads are JSON objects of field handles to values — inline via `PAYLOAD=`, from a file via `FILE=`, or piped on stdin. Results print as JSON on stdout; validation errors as JSON on stderr. See the generated skill for payload semantics per field type, file ingestion, and the end-to-end loop.
163
+
130
164
  ## System Requirements
131
165
 
132
166
  Iron requires `libvips` to be installed on your system for image processing and responsive image generation.
@@ -150,7 +184,52 @@ sudo pacman -S libvips
150
184
 
151
185
  ## Installation
152
186
 
153
- Add this line to your application's Gemfile:
187
+ ### Quickstart
188
+
189
+ Create a new Iron-powered site in two commands:
190
+
191
+ ```bash
192
+ gem install iron-cms
193
+ iron new mysite
194
+ ```
195
+
196
+ `iron new` scaffolds a fresh Rails app and runs `rails g iron:install` to wire Iron in. Then start it:
197
+
198
+ ```bash
199
+ cd mysite
200
+ bin/dev # open http://localhost:3000/admin
201
+ ```
202
+
203
+ When developing Iron itself, point the new app at a local checkout with `iron new mysite --path /path/to/iron`.
204
+
205
+ For an **existing** Rails app, add the gem and run the generator directly:
206
+
207
+ ```bash
208
+ bundle add iron-cms
209
+ bin/rails g iron:install
210
+ ```
211
+
212
+ `rails g iron:install` wires everything up and is safe to re-run:
213
+
214
+ - mounts `Iron::Engine` at `/admin`
215
+ - installs the Active Storage, Action Text, and Iron migrations
216
+ - drops a minimal `db/cms/schema.json` skeleton for the schema-as-code workflow
217
+ - appends an idempotent administrator-provisioning block to `db/seeds.rb` (the SKILL.md seed-zip workflow adds `Iron::Seed.load` below this block rather than re-provisioning the admin)
218
+ - emits `lib/tasks/iron_release.rake` so `db:prepare` also runs `iron:schema:apply`
219
+ - installs the `iron-cms` agent skill (`rails g iron:agents`) and the pages controller (`rails g iron:pages`)
220
+ - runs `db:prepare` then `db:seed` (migrate, apply the schema, and provision the first admin)
221
+
222
+ Provisioning credentials come from `IRON_SEED_EMAIL` / `IRON_SEED_PASSWORD` (defaulting to `admin@example.com` / `password` in local environments — development and test; **required in any non-local environment** like staging or production, where seeding fails fast without them).
223
+
224
+ The local agent workflow drives Iron through the `iron:schema` / `iron:content` rake tasks and needs no API token. If you later want to reach the REST API over HTTP, mint one explicitly with `bin/rails iron:integration:create NAME=agent ROLE=administrator` (it's shown once).
225
+
226
+ Because `db:prepare` now also applies the CMS schema, `bin/kamal deploy` converges migrations and the CMS schema on every deploy — its Docker entrypoint runs `db:prepare`, so no deploy-specific wiring is needed. The hook works under any deploy mechanism that runs `db:prepare`.
227
+
228
+ The `iron-cms` agent skill and an `## Iron CMS` section in `AGENTS.md` are now installed: open the new app in Claude Code and hand it a content brief — it will model `db/cms/schema.json`, apply it, and populate content using the `iron:schema` / `iron:content` tasks.
229
+
230
+ ### Manual installation
231
+
232
+ If you prefer to wire Iron up by hand, add this line to your application's Gemfile:
154
233
 
155
234
  ```ruby
156
235
  gem "iron-cms"
@@ -165,15 +244,20 @@ bundle
165
244
  Or install it yourself as:
166
245
 
167
246
  ```bash
168
- gem install iron
247
+ gem install iron-cms
169
248
  ```
170
249
 
171
- Then copy iron migrations:
250
+ Iron stores file uploads with Active Storage and rich text with Action Text. If your application doesn't have their tables yet, install them first, then copy the Iron migrations and migrate:
172
251
 
173
252
  ```bash
253
+ bin/rails active_storage:install
254
+ bin/rails action_text:install:migrations
174
255
  bin/rails iron:install:migrations
256
+ bin/rails db:migrate
175
257
  ```
176
258
 
259
+ (`action_text:install:migrations` copies just the table migration — Iron ships its own editor, so the full Action Text JavaScript setup isn't needed.)
260
+
177
261
  Configure the mailer sender address used for system emails (e.g. password resets):
178
262
 
179
263
  ```ruby