# AximaApp v2 → Axima Workforce Migration Bundle v1

## Purpose

This contract defines a portable, auditable source package for moving one AximaApp v2 installation into Axima Workforce as a new organization. It is intentionally independent of the Yii and Laravel database schemas. A raw SQL dump is **not** a valid migration bundle.

PR1 establishes the contract and a read-only preflight. It does not export, delete, update, or transmit production data.

## Required package layout

```text
aximaapp-v2-export-<bundle-id>.axima
├── manifest.json
├── checksums.sha256
├── preflight.json
├── data/
│   ├── organization.json
│   ├── users.jsonl
│   ├── locations.jsonl
│   ├── facilities.jsonl
│   ├── clients.jsonl
│   ├── contracts.jsonl
│   ├── shifts.jsonl
│   ├── attendance.jsonl
│   ├── clock_entries.jsonl
│   ├── timesheets.jsonl
│   ├── availability.jsonl
│   ├── credentials.jsonl
│   ├── shift_notes.jsonl
│   ├── notes.jsonl
│   ├── care_plans.jsonl
│   ├── adls.jsonl
│   ├── accommodations.jsonl
│   └── mileage_entries.jsonl
├── files/
│   └── <sha256>.<extension>
└── reconciliation/
    ├── entity-counts.json
    ├── time-summary.json
    ├── payroll-source-summary.json
    └── billing-source-summary.json
```

Optional entity files may be omitted when the source table does not exist. Every omitted entity remains listed in `manifest.json` with `status: "missing"` or `status: "not_applicable"`.

## Record envelope

Every JSONL record uses a stable source envelope:

```json
{
  "source_id": "123",
  "source_created_at": "2026-08-01T15:00:00-04:00",
  "source_updated_at": "2026-08-10T12:00:00-04:00",
  "source_hash": "<sha256 of canonical data object>",
  "data": {}
}
```

Source IDs are strings so integer and UUID sources can share the same contract. Target IDs are never written into the source package.

## Manifest requirements

`manifest.json` must validate against `docs/migration/schema/manifest-v1.schema.json` and contain:

- contract name and schema version;
- bundle UUID and generation timestamp;
- source application, source version, timezone and currency;
- entity file names, row counts and SHA-256 checksums;
- attachment inventory and checksum file location;
- preflight status and issue counts;
- explicit excluded secret classes.

## Security rules

The following values must never be exported:

- password hashes or plaintext passwords;
- authentication keys, access tokens and password-reset tokens;
- session records and cookies;
- SMTP, API, webhook or database credentials;
- active QR access tokens;
- private application encryption keys.

The completed package must be encrypted before it leaves the source server, stored in private storage, audited, and expired after a defined retention period. Attachments are addressed by SHA-256 rather than their original server path.

## Time, money and identity rules

- The manifest declares the source IANA timezone. Naive source timestamps are interpreted in that timezone.
- The manifest declares the source ISO 4217 currency. Decimal rates are converted to integer cents by the destination importer.
- Email addresses are normalized using trim plus lowercase for matching, but the original value remains available for audit.
- Existing Axima Workforce users are reused by normalized email and attached to the new organization.
- A source `Client` is a person receiving care and must not be silently converted to a commercial `ClientContract`.

## Preflight

Run:

```bash
php yii axima-workforce-migration/preflight \
  --output=@runtime/migration/preflight.json
```

The command is read-only and checks:

- required and optional source tables;
- duplicate normalized emails;
- orphaned staff, client, shift and contract references;
- invalid shift, attendance, clock-entry, timesheet and contract ranges;
- missing, external, unsupported or oversized attachments;
- source counts, scheduled/worked minutes, timesheet gross totals and estimated client billing.

An error means the package is not ready for automatic commit. Warnings may be accepted only when the destination reconciliation ledger records the exception.

## Versioning

Bundle v1 is immutable. Additive optional fields may be introduced without changing the version. Removing, renaming or changing the meaning of a required field requires a new schema version.
