# Workforce tenant-import JSON package

The current **Settings → Migration Tools → Download Workforce package** action creates an `axima-workforce-migration-<timestamp>.json` file for Workforce's `/platform/migrations/axima-v2` wizard.

This is the implemented `axima-workforce-legacy-export`, schema version `1`, contract. The `.axima` archive described in `AXIMA_WORKFORCE_BUNDLE_V1.md` is a separate proposed bundle contract and is not accepted by this JSON wizard. Do not rename SQL dumps, ZIP archives, or other exports to `.json`.

## Export behavior

- Only a signed-in SuperAdmin can download a package. Export does not modify source records or send emails.
- The complete compact JSON is written to private temporary storage before download begins. Rows are queried in primary-key order in pages of at most 250. The response streams the completed file and prevents browser/proxy caching. Temporary storage is closed and removed after sending or when export fails.
- Export reads run in one transaction with explicit repeatable-read isolation on MySQL/PostgreSQL; SQLite uses its transactional snapshot. This keeps pages consistent if the server default is read-committed. Pause source writes for the final cutover export so later operational changes are not left behind, and do not change the source schema during export. Nontransactional legacy database tables cannot provide a consistent snapshot while writes continue.
- Database/schema/query and JSON-encoding errors stop the export. The download is not produced with silently missing data. A source `users` table is required; genuinely missing optional tables remain empty arrays with names listed in `manifest.missing_optional_entities` and explanatory `manifest.warnings`.
- `manifest.entity_counts` records rows actually written, not a separate earlier count. The screen's pre-export count is informational.
- Passwords and reusable authentication secrets are stripped. Active QR/shift/access-token entities are excluded. File/image binaries are not included; their record paths remain for follow-up migration. The JSON contains confidential operational/care information and must be handled accordingly.

## Compatibility

The root contains `format`, `schema_version`, `source_application`, `source_timezone`, `exported_at`, `exported_by`, `data`, `manifest`, and `integrity`. `source_timezone` and `manifest.missing_optional_entities` are additive metadata; existing schema-1 readers can ignore them. Source columns retain their database names and values, including legacy attendance `user_id` and availability `available_start`/`available_end`.

`integrity.data_sha256` is the lowercase SHA-256 digest of `data` encoded with PHP `JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR`. The exporter hashes those same compact bytes while writing them. Root field order and whitespace outside `data` do not matter to the Workforce verifier. This checksum detects corruption; it is not a cryptographic signature.

Select the original JSON download in the destination wizard. Compact export reduces transferred bytes; the Workforce upload path still needs to support the resulting file size. A failed upload occurs before package mapping and must be resolved on the destination. Export again if a download was interrupted or altered.

## Regression tests

With Composer dependencies and PDO SQLite installed:

```sh
php vendor/bin/phpunit --bootstrap tests/_bootstrap.php tests/unit/services/WorkforceMigrationExportServiceTest.php
```

Tests use only synthetic SQLite data and cover checksum round trips, credential removal, the actual response stream, complete pagination, optional tables, required users, database failures, invalid UTF-8, and authorization. `tests/_support/WorkforceMigrationFixture.php` can seed the actual exporter for a cross-application fixture; never commit a real migration download.
