diff --git a/content/guides/10.environment-sync/0.index.md b/content/guides/10.environment-sync/0.index.md index 5f82ed616..61589523d 100644 --- a/content/guides/10.environment-sync/0.index.md +++ b/content/guides/10.environment-sync/0.index.md @@ -19,7 +19,7 @@ The CLI is built to be safe to point at production: `diff` never applies anythin ## What syncs - **Schema**: every collection, field, and relation, including custom fields on system collections. -- **Configuration**: roles, policies, access, permissions, flows, operations, dashboards, panels, settings, media-library and flow folders, and custom Data Studio translation strings. +- **Configuration**: roles, policies, access, permissions, flows, operations, dashboards, panels, settings, global and role presets (bookmarks and default views), media-library and flow folders, and custom Data Studio translation strings. - **Opt-in**: user accounts, with every secret field stripped. Unlike a full schema snapshot, a pull is not all-or-nothing. `--collections posts` narrows which Schema files it overwrites, and resource flags like `--flows` or `--no-schema` choose which Configuration files it touches. That is how you promote finished work from a shared development instance while unfinished work stays out of the sync files entirely. Scope is by collection and resource type, not by individual record. See [Promote only the changes that are ready](/guides/environment-sync/common-workflows#promote-only-the-changes-that-are-ready). diff --git a/content/guides/10.environment-sync/5.secrets-and-limitations.md b/content/guides/10.environment-sync/5.secrets-and-limitations.md index 781ceb345..7b489eb8c 100644 --- a/content/guides/10.environment-sync/5.secrets-and-limitations.md +++ b/content/guides/10.environment-sync/5.secrets-and-limitations.md @@ -27,11 +27,11 @@ The server never hands out the real value for these fields: concealed fields rea ## System collections that do not sync -None of these sync today. Some are shared configuration that a future release could take on; the rest are per-instance state that a sync should never touch. +None of these sync today, apart from the shared presets noted below. Some are shared configuration that a future release could take on; the rest are per-instance state that a sync should never touch. | Collection | Why it doesn't sync | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `directus_presets` | Bookmarks, saved layouts, and Insights presets mix shared configuration with personal preference. A future release may sync the shared part. | +| `directus_presets` | Personal presets: the bookmarks and saved layouts that belong to one user. Global and role presets sync as the `presets` resource. | | `directus_extensions` | The enabled/disabled state of installed extensions is tied to what is physically deployed on each instance. Deploy extensions to the target before pushing schema or flows that depend on them; the push itself does not warn. | | `directus_files` | File-interface **fields** sync as Schema; file records and the binaries behind them are their own workstream. | | `directus_comments` | Content comments; per-instance state. | @@ -64,4 +64,7 @@ None of these sync today. Some are shared configuration that a future release co - **Users without an email address fail import.** The server's import validation rejects a user with no email, so a `--users` push containing one fails before any Configuration changes apply. Give the account an email on the source, or remove it, first. - **Panels can duplicate on a first sync into a look-alike target.** Panels have no name to match on, so pushing into a target that already holds equivalent panels (seeded from the same template) can create them a second time. The ID map prevents repeats after that first push. - **A mirror push of users does not protect your own account.** If users are in the sync files and the account the push authenticates with is absent from them, a `mirror` push orders its deletion like any other record; the CLI has no self-protection, and whether the server refuses is up to the server. When you sync users, make sure the sync files include the accounts your pushes run as. +- **Preset filters keep their source IDs.** A preset whose filter or layout names a specific user, role, or item by ID is copied as-is, so it may match nothing on the target. Dynamic values such as `$CURRENT_USER` work on any instance. +- **Role presets need their role linked.** A preset scoped to a role the target can't identify is skipped with a warning. That includes a role created by hand on the target with the same name, because a presets-only pull carries role IDs, not names. Pull with `--roles --no-deps` and push again: roles are matched by name, and their policies stay out. A matched role's icon, description, and parent are updated from the source. In `mirror` mode, roles that exist only on the target are deleted. +- **Presets can arrive before their collection.** Like permissions, a preset can be pushed for a collection the target doesn't have yet, for example with `"schema": false`. It's created without an error and takes effect once the collection exists. - **A Configuration diff can leave harmless gaps in PostgreSQL integer IDs.** The target server dry-runs the import and rolls it back, but PostgreSQL sequences do not roll back. No records are created or changed; only a sequence such as the one for `directus_permissions` can advance. diff --git a/content/guides/10.environment-sync/6.reference.md b/content/guides/10.environment-sync/6.reference.md index 6a53fea71..ed9d2caa9 100644 --- a/content/guides/10.environment-sync/6.reference.md +++ b/content/guides/10.environment-sync/6.reference.md @@ -112,9 +112,9 @@ d6s sync pull --from [scope flags] | `--no-deps` | Do not add prerequisites; resources owned by a selected parent remain included | | `--project ` | Project to sync (default: `default`) | -A bare pull includes every selectable resource except users. This means translations sync by default. Pass `--no-translations` to exclude them, or `--translations` to pull only translations. +A bare pull includes every selectable resource except users. This means translations and presets sync by default. Pass `--no-translations` or `--no-presets` to exclude either one, or `--translations` to pull only translations. -The selectable resources are `roles`, `policies`, `flows`, `dashboards`, `settings`, `folders`, `users`, and `translations`. The CLI automatically includes `access`, `permissions`, `operations`, and `panels` with their parent resources (see [the dependency table](#configuration-resources)). `--flows` also brings `folders`, because the folder a flow lives in is part of its identity. Folders differ from the automatic resources in one way: `folders` is selectable in its own right, so `--no-deps` drops it from a `--flows` selection while `operations` still comes. Positive selection (`--flows`) cannot be combined with `--all` or with `--no-` flags. An exclusion that a retained resource depends on is refused rather than silently overridden: `--no-policies` alone fails because `roles` requires policies and would pull them back, so pass `--no-roles` as well, or keep policies. `--no-folders` alone fails for the same reason, because `flows` requires folders. Resource selection never narrows the schema; the two axes are scoped independently. +The selectable resources are `roles`, `policies`, `flows`, `dashboards`, `settings`, `folders`, `presets`, `users`, and `translations`. The CLI automatically includes `access`, `permissions`, `operations`, and `panels` with their parent resources (see [the dependency table](#configuration-resources)). `--flows` also brings `folders`, because the folder a flow lives in is part of its identity. Folders differ from the automatic resources in one way: `folders` is selectable in its own right, so `--no-deps` drops it from a `--flows` selection while `operations` still comes. Positive selection (`--flows`) cannot be combined with `--all` or with `--no-` flags. An exclusion that a retained resource depends on is refused rather than silently overridden: `--no-policies` alone fails because `roles` requires policies and would pull them back, so pass `--no-roles` as well, or keep policies. `--no-folders` alone fails for the same reason, because `flows` requires folders. Resource selection never narrows the schema; the two axes are scoped independently. Two warnings a scoped pull can raise, neither of which widens the scope for you: @@ -232,6 +232,7 @@ Resource selection follows a dependency graph: selecting a resource pulls in wha | `settings` | Yes | `--settings` | — | A single record. License and AI credentials, branding images (logos, backgrounds, favicon), and the default storage folder are stripped. | | `folders` | Yes | `--folders` | — | Both folder trees. Media-library folders and flow folders share `directus_folders` and are told apart by their `type`. Distinct from collection folders (Data Studio sidebar groups), which sync as Schema. | | `translations` | Yes | `--translations` | — | Matched by `language` and `key`; on Directus 12.2.0 and later, `merge` and `mirror` can update existing strings. | +| `presets` | Yes | `--presets` | — | Global and role bookmarks and default views. Personal presets are never pulled; a `mirror` push keeps them on the target, along with presets of never-synced roles. A role preset is skipped with a warning until its role is linked. | | `users` | Opt-in | `--users` | `roles`, `policies` | Secret fields (`password`, `token`, `tfa_secret`, and others) are stripped. | ::callout{icon="i-lucide-triangle-alert" color="warning"} @@ -298,6 +299,7 @@ Records are matched across instances first by the ID map (`/ | Permissions | `policy`, `collection`, and `action` | | Operations | `flow` and `key` | | Translations | `language` and `key` | +| Presets | `collection`, `bookmark`, and `role` | | Settings | The single settings record | | Panels | Nothing; ID map only | @@ -346,6 +348,7 @@ With `--json`, stdout carries exactly one report per command; warnings still go "dashboards", "permissions", "policies", + "presets", "roles", "settings", "translations" @@ -359,13 +362,14 @@ With `--json`, stdout carries exactly one report per command; warnings still go "directus_dashboards", "directus_permissions", "directus_policies", + "directus_presets", "directus_roles", "directus_settings", "directus_translations" ], "recordCount": 57, - "collectionCount": 11, - "fileCount": 12, + "collectionCount": 12, + "fileCount": 13, "removed": [], "incomplete": [] } @@ -406,12 +410,13 @@ The Schema counters (`collections` through `files`) are `null` when the Schema p "dependent": 0 }, "unchanged": 0, - "incomplete": [] + "incomplete": [], + "skipped": 0 } } ``` -`changes` is `true` when a push would do anything, including when `data.reconciliation.ambiguous` is non-zero. `added`/`modified`/`deleted` count Schema items. `data.resultsByCollection` is the target server's own per-collection dry-run answer. Reconciliation separates records that matched, have no match, need a choice, or depend on a choice; `unchanged` counts matched records whose synced values already agree. +`changes` is `true` when a push would do anything, including when `data.reconciliation.ambiguous` is non-zero. `added`/`modified`/`deleted` count Schema items. `data.resultsByCollection` is the target server's own per-collection dry-run answer. Reconciliation separates records that matched, have no match, need a choice, or depend on a choice; `unchanged` counts matched records whose synced values already agree. `skipped` counts records left out because the target can't take them yet, such as role presets whose role doesn't exist there. `d6s sync push --to production --yes --json` reports the same top-level shape and adds `applied`, which is `true` when the push changed the target. Its `data.resultsByCollection` reflects what the import actually did; `data.reconciliation` and `data.unchanged` are `null` because push reports applied results rather than diff-only comparison counts.