Configure best-effort backups, restore preparation, and migration job orchestration.
+
Backup, Migrate & Restore
+
Protect SimpleChat data, move selected workspaces to another environment, and stage restore decisions with guided checks.
-
-
-
-
-
-
-
-
-
-
@@ -6216,29 +6251,29 @@
Selected
-
Choose transfer behavior
-
Set synchronization semantics, included services, retry behavior, and optional destination capacity.
+
Choose what happens at the destination
+
Choose whether to copy only missing items, catch up changes, or make migrated destination data match the source.
+
+
+
+
+
+
Backup, Migrate & Restore Configuration Guide
+
+
+
+
Configure backup, migration, and restore readiness before an incident or cutover window. The safest path is to first prove backups, then rehearse migration or restore decisions from completed backup records.
+
+
Use dedicated backup storage that is separate from Enhanced Citation source files.
+
Generate and protect the backup encryption key, preferably in Key Vault.
+
Run a manual full backup and inspect the Backup Inventory entry.
+
For migration, connect destination Cosmos, Search, and storage services before selecting scope.
+
For restore, open Backup Inventory and stage the selected backup through the Restore workflow.
+
+
+
+
+
+
+
+
+
+
+
Backup Setup Guide
+
+
+
+
Backups create durable artifacts and job records that later migration or restore workflows can inspect. Full backups capture a complete selected snapshot. Partial backups capture daily changes between full backups.
+
+
Storage: Use a dedicated backup account/container so restore and migration artifacts never overwrite source documents.
+
Encryption: Keep backup encryption enabled and store generated keys in Key Vault for production.
+
Scope: Leave Cosmos DB and AI Search enabled unless you are intentionally creating a limited backup.
+
Timing: Queue large backup jobs outside business hours because App Service workers perform the work.
+
+
+
+
+
+
+
+
+
+
+
Migration Guide
+
+
+
+
Migration moves selected SimpleChat users, groups, public workspaces, and their optional documents to another SimpleChat environment.
+
+
Copy missing items only: safest first run; existing destination records are not changed.
+
Catch up changed items: use after a previous completed migration to copy new items and update migration-owned changes.
+
Make destination match source: use only during cutover when migrated destination-only items should be removed.
+
AI Search freeze: freeze external destination writers before moving Search documents because SimpleChat cannot coordinate external writers.
+
+
+
+
+
+
+
+
+
+
+
RU Boost Permission Guide
+
+
+
+
RU Boost temporarily raises eligible Cosmos DB throughput up to 10,000 RU/s and then restores the original setting. It can increase Azure charges and requires Azure management-plane permissions.
+
+
Data copy permissions prove the identity can create, read, and delete probe records in destination Cosmos containers.
+
RU Boost permissions prove the identity can read and write Cosmos throughput settings through Azure Resource Manager.
+
Destination RU Boost also needs the destination subscription ID and resource group because those values are not part of the data-plane endpoint.
+
Use Test RU Boost before a cutover window; it validates capacity permissions separately from migration data access.
+
+
+
+
+
+
+
+
+
+
+
Restore Guide
+
+
+
+
Restore starts from Backup Inventory. The workflow helps admins confirm what is in the backup, what surfaces are safe to restore, and whether backend restore execution is available for the selected backup.
+
+
Prefer full backups for restore decisions because partial backups depend on earlier backup history.
+
Confirm the encryption key is still available before relying on encrypted artifacts.
+
Review warnings and missing surfaces before restoring AI Search or source document blobs.
+
Run restore only in a maintenance window because restored records can affect live users and search results.
+
+
+
+
+
diff --git a/docs/explanation/features/DATA_MANAGEMENT_BACKUP_MIGRATION.md b/docs/explanation/features/DATA_MANAGEMENT_BACKUP_MIGRATION.md
index 423ea2eb..dc13242c 100644
--- a/docs/explanation/features/DATA_MANAGEMENT_BACKUP_MIGRATION.md
+++ b/docs/explanation/features/DATA_MANAGEMENT_BACKUP_MIGRATION.md
@@ -1,11 +1,11 @@
# Data Management Backup and Migration
Implemented in version: **0.241.211**
-Updated in version: **0.250.106**
+Updated in version: **0.250.108**
## Overview
-The Data Management feature adds an admin-only portal section for SimpleChat-owned backup, restore preparation, and migration orchestration. It stores its configuration as a separate `backup_settings` document in the Cosmos `settings` container rather than mixing backup secrets and schedules into normal app settings.
+The Data Management feature adds an admin-only **Backup, Migrate & Restore** portal section for SimpleChat-owned backup, restore preparation, and migration orchestration. It stores its configuration as a separate `backup_settings` document in the Cosmos `settings` container rather than mixing backup secrets and schedules into normal app settings.
## Technical Specifications
@@ -41,10 +41,10 @@ Full and partial backups use the same Cosmos-backed durable job contract as resi
### Cosmos Backup Performance and Source Capacity
-The Backup card provides opt-in controls for Cosmos batch staging concurrency (1-16), retry attempts (1-10), a source capacity failure policy, and a temporary local/source Cosmos throughput boost capped at **10,000 RU/s**.
+The Backup card provides opt-in controls for Cosmos batch staging concurrency (1-16), retry attempts (1-10), a source RU Boost failure policy, and a temporary local/source Cosmos throughput boost capped at **10,000 RU/s**.
- Each queued backup records its concurrency, retry, boost, target RU, and failure policy in its immutable plan. Retrying the job uses that recorded plan rather than current settings.
-- Before a source boost, the job discovers whether the source has shared database throughput or dedicated container throughput and persists the exact original mode/value for every target before any mutation.
+- Before source RU Boost, the job discovers whether the source has shared database throughput or dedicated container throughput and persists the exact original mode/value for every target before any mutation.
- A boost applies only to eligible manual or autoscale database/container throughput at or below 10,000 RU/s. Serverless, shared/dedicated layouts without an eligible throughput resource, and capacity values already above the SimpleChat cap cannot be managed by the job.
- The `continue_without_boost` policy records a warning and runs the backup at current capacity when ARM capacity discovery or mutation is denied or unsupported. The `fail` policy stops before export so administrators can correct capacity permissions or topology first.
- Every applied boost records `restore_pending` before mutation. Completion, cancellation, worker failure, stale-worker recovery, and scheduler recovery attempt restoration in a fenced `finally` path. Restore writes only when the live capacity still equals this job's boosted value; an external post-boost change is preserved and reported instead of overwritten.
@@ -99,18 +99,16 @@ The Migration card uses a six-stage administrator workflow:
1. **Target** configures Target Cosmos DB, Target Search, and Target Enhanced Citation Storage without returning stored secrets to the browser.
2. **Scope** selects `none`, `selected`, or `all` for users, groups, and public workspaces. Selected mode keeps choices while searching or paging. All mode displays an exhaustive server-owned count rather than treating one catalog page as the full population.
-3. **Content & Options** chooses included documents, AI Search entries, source blobs, New only, Delta / upsert, or Mirror with deletions, plus retry/concurrency and optional destination capacity.
+3. **What Moves** chooses included documents, AI Search entries, source blobs, Copy missing items only, Catch up changed items, or Make destination match source, plus retry/concurrency and optional destination RU Boost.
4. **Review** runs a server-owned preflight snapshot. It reports authoritative principal/document counts, included and skipped surfaces, destination inventory changes, collisions, partition-key compatibility, source and target access, capacity policy, destination coordinator/write-gate readiness, and blockers or warnings.
-5. **Confirm** presents the normalized plan and requires a separate acknowledgement. Mirror mode also requires the exact `MIRROR WITH DELETIONS` phrase.
+5. **Confirm** presents the normalized plan and requires a separate acknowledgement. **Make destination match source** mode also requires the exact `MAKE DESTINATION MATCH SOURCE` phrase.
6. **Progress** follows the sanitized durable job record and exposes progress, throughput, failures, collisions, warnings, Cancel, Retry/Resume, and the full job log.
Catalog APIs use bounded page sizes, deterministic ID ordering, server-side search, authoritative filtered totals, and opaque continuation state bound to the current scope type and search. Invalid or mismatched continuation input fails safely. Explicit selected scope is bounded to 2,000 IDs and fails validation instead of silently truncating.
Any target, scope, or option change marks the review stale and prevents confirmation until preflight runs again. Ready reviews issue a short-lived, administrator-bound authorization that is atomically reserved before durable job creation and consumed by that exact job before work starts, so blocked, expired, replayed, or changed reviews cannot queue work. A failed job create releases the exact reservation for retry. Submission also has an explicit in-flight guard, and API validation errors return to the relevant workflow stage. The worker rejects execution if migration-relevant settings changed after queueing, then captures its own durable inventory and reruns authoritative preflight after it acquires the migration lease and destination coordinator. A terminal Progress view exposes **Start new migration** to deliberately reset the consumed confirmation.
-Migration execution currently copies selected SimpleChat Cosmos records, matching AI Search documents for selected document scopes, and source document blobs when Enhanced Citations source and destination storage are configured.
-
-For durable provenance, destination access probes, collision protection, checkpoint retries, transfer telemetry, and temporary destination Cosmos capacity controls, see [Data Management Migration Resilience](DATA_MANAGEMENT_MIGRATION_RESILIENCE.md).
+Migration execution currently copies selected SimpleChat Cosmos records, matching AI Search documents for selected document scopes, and source document blobs when Enhanced Citations source and destination storage are configured. The admin UI describes the modes as **Copy missing items only**, **Catch up changed items**, and **Make destination match source** while preserving the backend job values for compatibility.
### Restore Workflow
@@ -122,6 +120,8 @@ The Backup Inventory exposes a **Restore** action for completed backup jobs with
4. Run preflight review to validate the manifest, target access, partition-key compatibility, and destination collision policy.
5. Confirm the reviewed plan and queue a durable restore job.
+For durable provenance, destination access probes, collision protection, checkpoint retries, transfer telemetry, and temporary destination Cosmos capacity controls, see [Data Management Migration Resilience](DATA_MANAGEMENT_MIGRATION_RESILIENCE.md).
+
Create-only restore is the default and blocks existing destination collisions. Overwrite restore requires the exact `RESTORE WITH OVERWRITE` phrase. Running restores use durable checkpoints, sanitized progress, cancellation, retry, and Activity Log auditing. For implementation and recovery guidance, see [Data Management Restore](DATA_MANAGEMENT_RESTORE.md).
### Security
@@ -149,7 +149,8 @@ Create-only restore is the default and blocks existing destination collisions. O
- Source blob backup performance: concurrent file transfers (default 4, maximum
8), bounded chunk size in MiB (default 8, range 1-16), and independent retry
attempts (default 5, maximum 10).
-- Temporary local/source Cosmos capacity boost: disabled by default; capped at 10,000 RU/s and restored from a durable source capacity snapshot.
+- Source RU Boost for backups: disabled by default; capped at 10,000 RU/s and restored from a durable source capacity snapshot.
+- Destination RU Boost for migrations: disabled by default; configured near the migration performance options with destination subscription ID and resource group fields.
- Target Cosmos authentication: managed identity or account key.
- Target Cosmos database name: always `SimpleChat`.
- Target Search authentication: managed identity or admin key.
@@ -167,21 +168,22 @@ Data Management settings save through their own API and are excluded from the re
3. Use Test Storage to validate and create the backup container if needed.
4. Generate an encryption key or let the first encrypted backup generate one automatically.
5. Configure the full backup cadence and scheduled UTC time.
-6. Configure Cosmos Backup Performance when needed. Keep the default bounded concurrency for normal workloads; enable the source boost only when the cost, topology, and ARM permissions have been reviewed.
-7. Queue a full or partial backup, or use the restore/migration dry-run buttons to create durable orchestration records.
+6. Configure Cosmos Backup Performance when needed. Keep the default bounded concurrency for normal workloads; enable source RU Boost only when the cost, topology, and ARM permissions have been reviewed.
+7. Queue a full or partial backup, or use Migration and Restore workflow preflight to stage operational decisions.
8. In Migration, complete Target, Scope, and Content & Options. Use server-paginated search for selected principals or choose All to use the exhaustive count.
9. Run Preflight Review and resolve every blocker. Re-run it after changing any earlier-stage input.
-10. Continue to Confirm, acknowledge the normalized plan, and provide the exact destructive phrase for Mirror with deletions.
+10. Continue to Confirm, acknowledge the normalized plan, and provide the exact destructive phrase for Make destination match source.
11. Execute once, then use Progress or the full job log for live telemetry, Cancel, Retry/Resume, warnings, and remediation details.
12. Open Advanced backup scope only when you need to alter the default Cosmos DB, AI Search index, or source blob backup surfaces.
13. Use Backup Inventory to see available backups first, filter to full or partial backups, and open View Log for structured backup details.
-14. Use Job History to inspect active container, checkpoint position, records, bytes, RU, retries/throttles, rates, capacity restoration state, durable backup cutoff/checkpoint state, completed steps, reconciliation readiness, preview divergence, and artifact contents. Backup and migration detail both provide Retry/Resume and Cancel; migration detail also provides full or failure-only JSONL manifest downloads.
+14. Use Restore from Backup Inventory to select a completed backup, choose restore policy and surfaces, run preflight, confirm the reviewed plan, and queue a durable restore job.
+15. Use Job History to inspect active container, checkpoint position, records, bytes, RU, retries/throttles, rates, capacity restoration state, durable backup cutoff/checkpoint state, completed steps, reconciliation readiness, preview divergence, and artifact contents. Backup and migration detail both provide Retry/Resume and Cancel; migration detail also provides full or failure-only JSONL manifest downloads.
Migration is used when moving SimpleChat data into another SimpleChat environment, rehearsing a cutover, or preparing a controlled environment transfer. The target Cosmos account, authentication type, and optional account key are configurable. The target database name is fixed to `SimpleChat` so future migration apply jobs use the standard SimpleChat container layout.
For managed identity target Cosmos migration, assign this App Service identity Cosmos DB Data Contributor on the target Cosmos account and ensure network access from the application environment.
-For optional local/source Cosmos backup capacity management, assign the App Service managed identity only the management-plane actions needed to read Cosmos account/database/container throughput settings, read/write database/container `throughputSettings`, read throughput operation results, run `migrateToAutoscale` when applicable, and read Cosmos metrics. Bicep and Terraform provision the `SimpleChat Cosmos Throughput Operator` custom role with these actions. This role is distinct from Cosmos DB data-plane access and does not grant access to source record content.
+For optional local/source or destination RU Boost capacity management, assign the App Service managed identity only the management-plane actions needed to read Cosmos account/database/container throughput settings, read/write database/container `throughputSettings`, read throughput operation results, run `migrateToAutoscale` when applicable, and read Cosmos metrics. Bicep and Terraform provision the `SimpleChat Cosmos Throughput Operator` custom role with these actions. This role is distinct from Cosmos DB data-plane access and does not grant access to source or destination record content. The admin UI exposes separate **Validate Cosmos Access** and **Test RU Boost** actions because these permissions are intentionally different.
## Testing and Validation
@@ -196,20 +198,24 @@ For optional local/source Cosmos backup capacity management, assign the App Serv
- Source blob bounded transfer, encryption, resume, throttling, fencing, and
failure-isolation coverage:
`functional_tests/test_data_management_blob_backup_transfers.py`.
+- RU Boost permission separation coverage:
+ `functional_tests/test_data_management_destination_cosmos_capacity.py`.
+- Restore workflow coverage:
+ `functional_tests/test_data_management_restore_workflow.py`.
- UI/template coverage: `ui_tests/test_admin_data_management_settings_ui.py`.
- Scheduler/recovery, cancellation, retry, coordinator, provenance, and write-fence coverage remains in the focused `functional_tests/test_data_management_*` modules.
- Syntax validation: `python -m py_compile` for modified backend modules and `node --check` for the admin browser module.
## Limitations
-- Backup artifact export is implemented for Cosmos DB and AI Search, with optional source blob copying. Restore application remains a follow-up workflow and consumes the recorded non-destructive manifest contract.
+- Backup artifact export is implemented for Cosmos DB and AI Search, with optional source blob copying. Restore execution supports configured target Cosmos DB, AI Search, and Enhanced Citation blob targets after a passing preflight review.
- Bicep and Terraform deployments provision `data_management_jobs`, `data_management_job_items`, and `data_management_backup_item_states` so durable job and latest-state storage are available on either IaC path.
- Source capacity boosts are not available for serverless Cosmos, non-scalable shared/dedicated topology, or targets above 10,000 RU/s. Existing source capacity above the cap remains portal-managed and is never reduced by SimpleChat.
- Capacity operations can take time to apply and may be denied by network/RBAC policy. The documented failure policy determines whether the backup continues at existing capacity or fails before export; unresolved `restore_pending` state must be retried before another boost is applied.
-- Restore execution is documented separately. Migration apply supports selected SimpleChat Cosmos, Search, and Enhanced Citations Blob surfaces rather than arbitrary Azure resources.
+- Migration apply supports selected SimpleChat Cosmos, Search, and Enhanced Citations Blob surfaces rather than arbitrary Azure resources.
- Search page artifacts are restore-ready only after every page, schema fingerprint, and integrity result agrees. Concurrent writes or deletes inside an active Search window can cause an index to be marked unavailable and require a resume or new backup.
## Version References
-- Application version updated in `application/single_app/config.py` to `0.250.102`.
+- Application version updated in `application/single_app/config.py` to `0.250.108`.
- Functional and UI tests include the same implementation version.
\ No newline at end of file
diff --git a/docs/explanation/features/DATA_MANAGEMENT_MIGRATION_RESILIENCE.md b/docs/explanation/features/DATA_MANAGEMENT_MIGRATION_RESILIENCE.md
index 5bfc5b12..47bc98fe 100644
--- a/docs/explanation/features/DATA_MANAGEMENT_MIGRATION_RESILIENCE.md
+++ b/docs/explanation/features/DATA_MANAGEMENT_MIGRATION_RESILIENCE.md
@@ -1,13 +1,13 @@
# Data Management Migration Resilience
Implemented in version: **0.250.071**
-Updated in version: **0.250.105**
+Updated in version: **0.250.108**
GitHub issue: [#1043](https://github.com/microsoft/simplechat/issues/1043)
## Overview
-Data Management migrations use durable, job-scoped provenance and checkpoints across selected Cosmos DB records, Azure AI Search documents, and Enhanced Citations source blobs. A migration retry retains the original migration GUID and resumes from verified service checkpoints. Operators can run create-only, delta/upsert, or explicitly confirmed mirror migrations, preview estimated destination changes, and review final source/destination reconciliation plus preview divergence.
+Data Management migrations use durable, job-scoped provenance and checkpoints across selected Cosmos DB records, Azure AI Search documents, and Enhanced Citations source blobs. A migration retry retains the original migration GUID and resumes from verified service checkpoints. Operators can run Copy missing items only, Catch up changed items, or explicitly confirmed Make destination match source migrations, preview estimated destination changes, and review final source/destination reconciliation plus preview divergence.
## Dependencies
@@ -46,11 +46,11 @@ The migration state is stored on the existing Data Management job record. It con
Failed, canceled, or stale migration jobs can be retried from the existing job detail. Completed resource checkpoints and the migration GUID remain unchanged.
-### Incremental Modes And Watermarks
+### Incremental Modes And Previous Runs
-- **New only** is the default. It creates missing destination identities and never updates or deletes existing data.
-- **Delta / upsert** requires a compatible completed migration baseline. The backend uses an explicitly selected baseline job or pins the newest compatible completed job when the field is blank. It creates new items, updates changed migration-owned items, and retains destination-only data.
-- **Mirror with deletions** runs delta/upsert and then removes destination-only items only when they carry successful migration ownership. The exact phrase `MIRROR WITH DELETIONS` is required. Unowned destination data is retained and reported.
+- **Copy missing items only** is the default. It creates missing destination identities and never updates or deletes existing data.
+- **Catch up changed items** requires a compatible completed migration baseline. The backend uses an explicitly selected previous migration job or pins the newest compatible completed job when the field is blank. It creates new items, updates changed migration-owned items, and retains destination-only data.
+- **Make destination match source** catches up changed items and then removes destination-only items only when they carry successful migration ownership. The exact phrase `MAKE DESTINATION MATCH SOURCE` is required. Unowned destination data is retained and reported.
Each run captures a UTC cutoff for Cosmos and intentionally includes the baseline second again to avoid timestamp-resolution gaps. Cosmos combines `_ts` with a canonical content hash, so different revisions in the same second are still detected. AI Search has no shared modified-time field, so it uses the source version observed during resumable keyset enumeration plus a canonical source hash. Blob Storage uses the ETag observed immediately before transfer and verifies it again after upload. Search or Blob changes observed after inventory can therefore cause preview divergence or a retryable `not_ready` reconciliation; they are never represented as having a global timestamp cutoff.
@@ -87,7 +87,7 @@ Version 0.250.105 also exposes these checks through the staged browser workflow'
### Temporary Cosmos Capacity
-The optional **Temporarily increase destination Cosmos capacity during this migration** control raises eligible destination database or dedicated-container throughput to the configured target, capped at **10,000 RU/s**.
+The optional **destination RU Boost** control raises eligible destination database or dedicated-container throughput to the configured target, capped at **10,000 RU/s**. Version 0.250.108 separates **Validate Cosmos Access** from **Test RU Boost** because data-plane copy permissions and ARM throughput permissions are intentionally different.
- The original mode and RU/s value are persisted before every ARM capacity change.
- Only targets below the requested value are changed.
@@ -112,7 +112,7 @@ The optional **Temporarily increase destination Cosmos capacity during this migr
2. Keep the source active and run one or more **Delta / upsert** catch-up migrations.
3. Resolve preview conflicts and any reconciliation state that is `not_ready`.
4. Freeze source writes and external destination AI Search writers for the final cutover window. Confirm the destination Search writer freeze in the migration workflow.
-5. Run a final **Delta / upsert**, or a confirmed **Mirror with deletions** only when the destination must exactly follow source deletions.
+5. Run a final **Catch up changed items**, or a confirmed **Make destination match source** only when the destination must exactly follow source deletions.
6. Switch traffic only after final reconciliation is `ready` or its warnings are explicitly accepted.
## Testing And Validation
@@ -153,4 +153,5 @@ The focused coverage verifies provenance and source fingerprints, unowned collis
- Application version updated in `application/single_app/config.py` to `0.250.071`.
- The staged migration workflow and catalog/review contracts were updated in `application/single_app/config.py` version `0.250.105`.
+- Plain-language mode labels and separate RU Boost permission testing were updated in `application/single_app/config.py` version `0.250.108`.
- This documentation and the related functional tests use their corresponding implementation versions.
\ No newline at end of file
diff --git a/docs/explanation/release_notes.md b/docs/explanation/release_notes.md
index 9a236735..b4163139 100644
--- a/docs/explanation/release_notes.md
+++ b/docs/explanation/release_notes.md
@@ -2,6 +2,16 @@
For feature-focused and fix-focused drill-downs by version, see [Features by Version](/explanation/features/) and [Fixes by Version](/explanation/fixes/).
+### **(v0.250.108)**
+
+#### User Interface Enhancements
+
+* **Backup, Migrate & Restore Admin Refresh**
+ * Reworked the Admin Settings data-management tab into a clearer Backup, Migrate & Restore control center with start-here guidance, setup modals, and plain-language migration choices.
+ * Separated destination Cosmos **RU Boost** configuration and testing from Cosmos data-copy access validation so admins can verify the correct Azure management-plane permissions before migration.
+ * Aligned the refresh with the restore workflow from Backup Inventory so admins can review backup readiness, choose restore policy/surfaces, run preflight, and queue supported restore jobs.
+ * (Ref: #1140, `admin_settings.html`, `admin_data_management.js`, `functions_data_management.py`, Data Management docs and tests)
+
### **(v0.250.106)**
#### New Features
diff --git a/functional_tests/test_data_management_destination_cosmos_capacity.py b/functional_tests/test_data_management_destination_cosmos_capacity.py
index 5d185121..f5806bf7 100644
--- a/functional_tests/test_data_management_destination_cosmos_capacity.py
+++ b/functional_tests/test_data_management_destination_cosmos_capacity.py
@@ -1,11 +1,14 @@
# test_data_management_destination_cosmos_capacity.py
"""
Functional test for Data Management destination Cosmos migration controls.
-Version: 0.250.071
+Version: 0.250.108
Implemented in: 0.250.075
+Updated in: 0.250.106
+Updated in: 0.250.108
This test ensures preflight proves destination create/read/delete access and
an opt-in 10,000 RU migration boost restores the original capacity afterward.
+It also verifies RU Boost permission testing is separate from data-copy access.
"""
import copy
@@ -26,7 +29,21 @@
class FakeJobContainer:
"""Persist deep-copy job state for checkpoint assertions."""
+ def __init__(self):
+ self.items = {}
+
+ def create_item(self, body):
+ self.items[body["id"]] = copy.deepcopy(body)
+ return copy.deepcopy(body)
+
+ def read_item(self, item, partition_key):
+ del partition_key
+ if item in self.items:
+ return copy.deepcopy(self.items[item])
+ return {"id": item, "type": "data_management_settings"}
+
def upsert_item(self, body):
+ self.items[body["id"]] = copy.deepcopy(body)
return copy.deepcopy(body)
@@ -66,6 +83,9 @@ def __init__(self, target_container):
def create_container_if_not_exists(self, **_kwargs):
return self.target_container
+ def read(self):
+ return {"id": "SimpleChat"}
+
def load_data_management_module(monkeypatch, source_container, job_container):
"""Load Data Management with only the fake dependencies this test needs."""
@@ -212,6 +232,112 @@ def set_capacity(_settings, target_ru, **kwargs):
assert restored_state["capacity"]["targets"][1]["restore_status"] == "restored"
+def test_ru_boost_permission_test_is_separate_from_data_copy_access(monkeypatch):
+ """Validate RU Boost checks ARM capacity permissions without data-copy probes."""
+ job_container = FakeJobContainer()
+ module = load_data_management_module(monkeypatch, FakeSourceContainer(), job_container)
+ module.DATA_MANAGEMENT_MIGRATION_COSMOS_CONTAINERS = {
+ "users": [{
+ "name": "user_settings",
+ "container_attr": "source_container",
+ "container_name_attr": "target_container_name",
+ "partition_key_path": "/id",
+ "id_field": "id",
+ }],
+ "groups": [],
+ "public_workspaces": [],
+ }
+ monkeypatch.setattr(
+ module,
+ "_preflight_target_cosmos_migration_access",
+ lambda *_args, **_kwargs: (_ for _ in ()).throw(AssertionError("data copy probe should not run")),
+ )
+ monkeypatch.setattr(
+ module,
+ "_inspect_target_cosmos_migration_capacity",
+ lambda _settings, _plan: {
+ "target_ru": 10000,
+ "management_settings": {"target": "destination"},
+ "database_mode": "autoscale",
+ "database_current_ru": 4000,
+ "targets": [{
+ "scope": "database",
+ "container_name": "",
+ "mode": "autoscale",
+ "current_ru": 4000,
+ }],
+ },
+ )
+ capacity_calls = []
+
+ def validate_capacity(_settings, target_ru, **kwargs):
+ capacity_calls.append((target_ru, kwargs["reason"], kwargs["decision"]["scope"]))
+ return {"to_ru": target_ru}
+
+ monkeypatch.setattr(module, "set_database_throughput", validate_capacity)
+
+ result = module.test_target_cosmos_capacity_management(
+ settings={
+ "target_cosmos_endpoint": "https://target.documents.azure.com:443/",
+ "target_cosmos_subscription_id": "sub",
+ "target_cosmos_resource_group": "rg",
+ "migration_temporary_destination_ru": 10000,
+ },
+ migration_plan={
+ "users": {"mode": "all", "ids": [], "include_documents": False},
+ "groups": {"mode": "none", "ids": [], "include_documents": False},
+ "public_workspaces": {"mode": "none", "ids": [], "include_documents": False},
+ },
+ )
+
+ assert result["success"] is True
+ assert result["target"] == "cosmos_ru_boost"
+ assert result["targets"][0]["write_verified"] is True
+ assert capacity_calls == [(4000, "validate_data_management_ru_boost_permissions", "database")]
+
+
+def test_target_cosmos_connection_excludes_ru_boost_permissions(monkeypatch):
+ """Validate data-copy access testing does not require ARM capacity permissions."""
+ job_container = FakeJobContainer()
+ target_container = FakeTargetContainer()
+ module = load_data_management_module(monkeypatch, FakeSourceContainer(), job_container)
+ module.DATA_MANAGEMENT_MIGRATION_COSMOS_CONTAINERS = {
+ "users": [{
+ "name": "user_settings",
+ "container_attr": "source_container",
+ "container_name_attr": "target_container_name",
+ "partition_key_path": "/id",
+ "id_field": "id",
+ }],
+ "groups": [],
+ "public_workspaces": [],
+ }
+ monkeypatch.setattr(module, "_get_target_cosmos_database", lambda _settings: FakeTargetDatabase(target_container))
+ monkeypatch.setattr(
+ module,
+ "_inspect_target_cosmos_migration_capacity",
+ lambda *_args, **_kwargs: (_ for _ in ()).throw(AssertionError("RU Boost probe should not run")),
+ )
+
+ result = module.test_target_cosmos_connection(
+ settings={
+ "target_cosmos_endpoint": "https://target.documents.azure.com:443/",
+ "migration_temporary_destination_ru_enabled": True,
+ "target_cosmos_subscription_id": "",
+ "target_cosmos_resource_group": "",
+ },
+ migration_plan={
+ "users": {"mode": "all", "ids": [], "include_documents": False},
+ "groups": {"mode": "none", "ids": [], "include_documents": False},
+ "public_workspaces": {"mode": "none", "ids": [], "include_documents": False},
+ },
+ )
+
+ assert result["success"] is True
+ assert "capacity" not in result
+ assert result["migration_access"]["container_count"] == 1
+
+
def test_failed_capacity_restore_remains_pending_for_later_recovery(monkeypatch):
"""Validate a failed restore leaves its durable snapshot available for a retry."""
migration_id = "55555555-5555-5555-5555-555555555555"
diff --git a/functional_tests/test_data_management_incremental_migration_modes.py b/functional_tests/test_data_management_incremental_migration_modes.py
index c2653ae4..fa90d3ea 100644
--- a/functional_tests/test_data_management_incremental_migration_modes.py
+++ b/functional_tests/test_data_management_incremental_migration_modes.py
@@ -1,11 +1,13 @@
# test_data_management_incremental_migration_modes.py
"""
Functional test for explicit Data Management incremental migration modes.
-Version: 0.250.071
+Version: 0.250.108
Implemented in: 0.250.071
+Updated in: 0.250.106
+Updated in: 0.250.108
-This test ensures mode defaults, baseline lineage, and destructive mirror
-confirmation are normalized into the immutable migration plan.
+This test ensures mode defaults, baseline lineage, and destructive destination
+cleanup confirmation are normalized into the immutable migration plan.
"""
import importlib.util
@@ -118,7 +120,7 @@ def test_incremental_migration_mode_contract(monkeypatch):
with pytest.raises(module.DataManagementSettingsValidationError, match="exact confirmation phrase"):
module.normalize_data_management_migration_plan({"migration_plan": mirror_plan})
- mirror_plan["mirror_confirmation"] = "MIRROR WITH DELETIONS"
+ mirror_plan["mirror_confirmation"] = "MAKE DESTINATION MATCH SOURCE"
normalized_mirror = module.normalize_data_management_migration_plan({
"migration_plan": mirror_plan,
})
diff --git a/functional_tests/test_data_management_security_patterns.py b/functional_tests/test_data_management_security_patterns.py
index 082bcfc1..aeccc684 100644
--- a/functional_tests/test_data_management_security_patterns.py
+++ b/functional_tests/test_data_management_security_patterns.py
@@ -2,12 +2,14 @@
# test_data_management_security_patterns.py
"""
Functional test for Data Management security patterns.
-Version: 0.250.105
+Version: 0.250.108
Implemented in: 0.241.211
Updated in: 0.250.102
Updated in: 0.250.103
Updated in: 0.250.104
Updated in: 0.250.105
+Updated in: 0.250.106
+Updated in: 0.250.108
This test ensures Data Management admin routes require authenticated admin
access, secrets stay redacted in frontend responses, and the admin browser
@@ -74,7 +76,7 @@ def test_version_and_container_registration():
"""Validate the Data Management version and Cosmos job container registrations."""
config_source = read_text(CONFIG_FILE)
- assert 'VERSION = "0.250.105"' in config_source
+ assert 'VERSION = "0.250.108"' in config_source
assert 'cosmos_data_management_jobs_container_name = "data_management_jobs"' in config_source
assert 'partition_key=PartitionKey(path="/id")' in config_source
assert 'cosmos_data_management_job_items_container_name = "data_management_job_items"' in config_source
@@ -94,7 +96,7 @@ def test_version_and_container_registration():
def test_admin_routes_require_login_admin_and_swagger_security():
"""Validate every Data Management route has the required admin security stack."""
routes = route_functions_with_decorators()
- assert len(routes) == 24
+ assert len(routes) == 29
for function_name, decorators in routes:
assert "swagger_route" in decorators, f"{function_name} missing swagger_route"
@@ -227,7 +229,7 @@ def test_settings_secrets_are_redacted_for_frontend():
assert 'DATA_MANAGEMENT_MIGRATION_MAX_DESTINATION_RU = 10000' in source
assert 'DATA_MANAGEMENT_MIGRATION_MODE_DELTA_UPSERT = "delta_upsert"' in source
assert 'DATA_MANAGEMENT_MIGRATION_MODE_MIRROR = "mirror_with_deletions"' in source
- assert 'DATA_MANAGEMENT_MIRROR_CONFIRMATION = "MIRROR WITH DELETIONS"' in source
+ assert 'DATA_MANAGEMENT_MIRROR_CONFIRMATION = "MAKE DESTINATION MATCH SOURCE"' in source
assert 'DATA_MANAGEMENT_SEARCH_WRITE_FREEZE_CONFIRMATION_ERROR' in source
assert '_validate_target_ai_search_migration_write_safety' in source
assert '_get_target_data_management_search_write_gate_container' in source
@@ -527,17 +529,23 @@ def test_admin_ui_exposes_data_management_without_external_assets():
route_source = read_text(ROUTE_FILE)
assert 'continuation_token=continuation_token' in route_source
assert '@bp.route("/api/admin/data-management/migration/review", methods=["POST"])' in route_source
+ assert '@bp.route("/api/admin/data-management/target/cosmos/ru-boost/test", methods=["POST"])' in route_source
+ assert '@bp.route("/api/admin/data-management/restore/review", methods=["POST"])' in route_source
assert 'review_data_management_migration(' in route_source
+ assert 'review_data_management_restore(' in route_source
assert '"workflow_step": "review"' in route_source
assert 'hmac.compare_digest(' in route_source
assert 'get_data_management_migration_review_fingerprint(' in route_source
assert 'create_data_management_migration_review_authorization(' in route_source
assert 'reserve_data_management_migration_review_authorization(' in route_source
- assert 'release_data_management_migration_review_reservation(' in route_source
+ assert 'release_data_management_migration_review_reservation' in route_source
assert 'except DataManagementHistoryPaginationError:' in route_source
assert 'DATA_MANAGEMENT_HISTORY_VALIDATION_ERROR' in route_source
assert 'except DataManagementHistoryPaginationError as exc:' not in route_source
assert 'data-management-restore-dry-run-btn' not in template
+ assert 'id="data-management-restore-modal"' in template
+ assert 'id="data-management-test-target-cosmos-ru-boost-btn"' in template
+ assert 'MAKE DESTINATION MATCH SOURCE' in template
assert 'data-management-migration-dry-run-btn' not in template
admin_settings_js = read_text(APP_ROOT / "static" / "js" / "admin" / "admin_settings.js")
assert "closest('[data-ignore-settings-change=\"true\"]')" in admin_settings_js
@@ -545,8 +553,10 @@ def test_admin_ui_exposes_data_management_without_external_assets():
assert "window.updateAdminSettingsSaveButtonState = updateSaveButtonState;" in admin_settings_js
assert 'Target Cosmos' not in sidebar
assert 'Migration' in sidebar
+ assert 'Backup, Migrate & Restore' in sidebar
assert 'cdn.jsdelivr.net' not in read_text(ADMIN_JS)
assert 'data-tab="data-management"' in sidebar
+ assert 'data-section="data-management-readiness-section"' in sidebar
assert 'data-section="data-management-backup-section"' in sidebar
assert 'data-section="data-management-cosmos-editor-section"' in sidebar
assert 'data-section="data-management-backup-inventory-section"' in sidebar
diff --git a/ui_tests/test_admin_data_management_settings_ui.py b/ui_tests/test_admin_data_management_settings_ui.py
index 0f7b4012..f576bf45 100644
--- a/ui_tests/test_admin_data_management_settings_ui.py
+++ b/ui_tests/test_admin_data_management_settings_ui.py
@@ -1,7 +1,7 @@
# test_admin_data_management_settings_ui.py
"""
UI test for Admin Settings Data Management controls.
-Version: 0.250.106
+Version: 0.250.108
Implemented in: 0.241.211
Updated in: 0.241.221
Updated in: 0.250.102
@@ -9,10 +9,11 @@
Updated in: 0.250.104
Updated in: 0.250.105
Updated in: 0.250.106
+Updated in: 0.250.108
This test ensures admins can discover the Data Management tab, see the
operational-business-hours warning, and access the backup, encryption,
-migration, Cosmos DB JSON editor, backup inventory, and job-history controls without unsafe frontend rendering.
+migration, restore, Cosmos DB JSON editor, backup inventory, and job-history controls without unsafe frontend rendering.
Version 0.250.049 moves query results and document editing into a scrollable modal.
Version 0.250.050 keeps this coverage aligned with the Cosmos editor save-path fix.
Version 0.250.051 verifies the Cosmos editor results list scrolls independently.
@@ -22,7 +23,10 @@
Version 0.250.102 adds independently bounded source-blob transfer controls.
Version 0.250.103 adds the staged migration workflow, scalable catalogs,
server-owned review, confirmation gating, and inline durable job progress.
-Version 0.250.106 adds backup cleanup and unit-based retention controls.
+Version 0.250.106 adds backup cleanup, unit-based retention controls, and
+the restore workflow modal.
+Version 0.250.108 adds plain-language Backup, Migrate & Restore guidance and
+separate RU Boost testing.
"""
import json
@@ -59,6 +63,12 @@ def test_admin_data_management_controls_render_from_template():
"data-management",
"data-management-save-settings-btn",
"data-management-operational-warning",
+ "data-management-readiness-section",
+ "data-management-setup-guide-modal",
+ "data-management-backup-guide-modal",
+ "data-management-migration-guide-modal",
+ "data-management-ru-boost-guide-modal",
+ "data-management-restore-guide-modal",
"data-management-backup-section",
"data-management-schedule-section",
"data_management_enabled",
@@ -104,6 +114,7 @@ def test_admin_data_management_controls_render_from_template():
"data_management_target_cosmos_subscription_id",
"data_management_target_cosmos_resource_group",
"data-management-test-target-cosmos-btn",
+ "data-management-test-target-cosmos-ru-boost-btn",
"data-management-target-ai-search-section",
"data_management_target_ai_search_auth",
"data_management_target_ai_search_endpoint",
@@ -298,7 +309,7 @@ def test_admin_data_management_controls_render_from_template():
assert "Use a dedicated backup storage account" in template
assert "Open Key Vault settings" in template
assert "Cosmos Backup Performance" in template
- assert "Temporary source max RU/s" in template
+ assert "Source RU Boost target" in template
assert "continue_without_boost" in template
assert "Managed identity requires Cosmos DB Data Contributor" in template
assert "Paste a connection string to save or replace it" in template
@@ -306,8 +317,11 @@ def test_admin_data_management_controls_render_from_template():
assert 'id="data_management_target_cosmos_database" value="SimpleChat" readonly aria-readonly="true"' in template
assert 'max="10000"' in template
assert 'Validate Cosmos Access' in template
- assert 'role="radiogroup" aria-label="Migration synchronization mode"' in template
- assert "MIRROR WITH DELETIONS" in template
+ assert 'role="radiogroup" aria-label="Migration destination behavior"' in template
+ assert "MAKE DESTINATION MATCH SOURCE" in template
+ assert "Copy missing items only" in template
+ assert "Catch up changed items" in template
+ assert "Make destination match source" in template
assert "I confirm external destination AI Search writers are frozen" in template
assert 'data-migration-step-button="target"' in template
assert 'data-migration-step-button="scope"' in template
@@ -370,7 +384,12 @@ def test_admin_data_management_controls_render_from_template():
assert 'The edit was recorded in Activity Logs.' in js_source
assert 'closest("[data-ignore-data-management-change' in js_source
assert 'testTargetCosmos' in js_source
+ assert 'testTargetCosmosRuBoost' in js_source
+ assert '/api/admin/data-management/target/cosmos/ru-boost/test' in js_source
assert 'testMigrationAccess' in js_source
+ assert '/api/admin/data-management/restore/review' in js_source
+ assert 'openRestoreModal' in js_source
+ assert 'updateRestoreQueueButtonState' in js_source
assert 'retryDataManagementJob' in js_source
assert 'openDataManagementCancellationModal' in js_source
assert 'requestDataManagementCancellation' in js_source