Concepts

Markdown

Schema changes

Renaming fields, changing field types, or toggling the translatable flag on collections with existing content requires careful handling to avoid data loss. This page documents behaviour as of externa-core 1.2.1+, the repair command for older drafts, and the type-change risks that remain open.

Upgrading from 1.2.0 or earlier

Field renames are safe from externa-core 1.2.1 (#218, #223). If you renamed fields on an older version, run the repair command in Repairing older drafts right after upgrading, before the scheduler runs or anyone publishes.


Renaming fields

Current behaviour

Field values are stored internally by field ID, not by name (app/Services/Collections/CollectionItemValuesWriter.php in externa-core). This means:

  • Rename without pending drafts: Content is preserved. The published API immediately reflects the new field name.
  • Rename with pending drafts (versioned collections): From 1.2.1, pending drafts and older revisions keep the renamed field's value, so publishing (manual or scheduled) and restoring revisions preserve content. On 1.2.0 and earlier, the value was dropped because drafts and revisions stored a snapshot keyed by the old field name.

Fixed in v1.2.1 (#218, #223).

Repairing older drafts

Drafts and revisions created before 1.2.1 may still hold a pre-rename field key. Right after deploying 1.2.1, before the scheduler runs or anyone publishes:

  1. Dry run (default, no writes): php artisan externa:repair-renamed-field-drafts
  2. Apply: php artisan externa:repair-renamed-field-drafts --apply

Mappings come from the CollectionField activity-log rename history. For orphaned keys with no history, pass --map=collection:old=new (collection slug or id; repeatable). The command never overwrites a value already stored under the new key, and publish-time behaviour is unchanged. Keys reported as unmappable belong to deleted fields and can be ignored.

If values were already lost by publishing on an older version, restore from a database backup taken before the rename, or re-enter them via the admin UI or Collections API.

API breaking change

Renaming a field is a breaking change for API consumers. The Public CMS API, Collections API, and GraphQL all use the current field name as the key. Update your frontend or client code after renaming.


Changing field types

Current behaviour

Changing a field's type does not convert stored values. Until core#219 ships:

  • The admin UI prevents type changes once a field exists (the type dropdown is disabled).
  • The server endpoint and AI assistant (ManageCollections.updateField) can still change it, leaving values unconverted and potentially breaking validation or rendering.

Do not change field types if the field has content, unless you are prepared to manually convert all values.

Safe path

  1. Create a new field with the desired type.
  2. Migrate content from the old field to the new field:
    • Export the collection, transform the values, and re-import; or
    • Use the Collections API or Admin API to update each item programmatically.
  3. Delete the old field after verifying the migration.

Planned fix

qiick-io/externa-core#219 will reject type changes on fields with stored values (admin + AI tool), returning a validation error. Type conversion tooling is tracked separately in core#220.


Toggling the translatable flag

Current behaviour

Toggling translatable on a field with existing content does not convert stored values. Values keep their original shape:

  • Non-translatable → translatable: Values remain scalars (e.g., "Hello"). The API will not return a locale map until you re-save the item.
  • Translatable → non-translatable: Values remain locale maps (e.g., { "en": "Hello", "it": "Ciao" }). The API and admin UI may break or show the raw map.

This is the same root cause as type changes: no automatic conversion.

Safe path

Follow the same migration strategy as type changes above:

  1. Create a new field with the desired translatable setting.
  2. Migrate and transform values (flatten or expand locale maps as needed).
  3. Delete the old field.

Planned fix

qiick-io/externa-core#219 will reject translatable changes on fields with stored values.


Rename/convert tooling

qiick-io/externa-core#220 tracks safe type conversion with dry run for fields with existing content (e.g., text → textarea, string → number, translatable toggle with automatic map creation/flattening). This is planned for externa-core 1.4.0.

Until then, follow the manual migration paths above.