VRPlatformVRPlatform

VRI Migration

Migrate a legacy non-GL team to a GL-enabled team and import historical owner statements

VRI Migration

Legacy (VRI) teams run without a general ledger. Migrating one to a GL-enabled (VRT) team is a staged flow: bootstrap the new team, initialize its chart of accounts, map legacy statement accounts onto the new chart, then import the historical owner statements.

  1. POST /teams/migrate-vri-to-vrt — create the GL team from the legacy source.
  2. Initialize the target team with accounts and statement layouts.
  3. GET /teams/migrate-vri-to-vrt/statements/account-mappings — see which legacy accounts need mapping.
  4. POST /teams/migrate-vri-to-vrt/statements — import historical statements with explicit mappings.

Concepts

Effective cutover

glStartAt on the bootstrap request is the minimum requested cutover. The migration pushes the effective cutover forward to the first day of the month after the source team's last posted/published owner statement, so live GL accounting never overlaps months the legacy team already settled.

Historical ledger

Imported statements and their journal entries land on ledger = historical. They preserve the owner-facing history (balances, statement PDFs/views) without mixing into the live general ledger that starts at the cutover.

Account mappings

Legacy statements reference VRI accounts that do not exist on the new chart. Each legacy account found on importable statement lines must resolve to one target account. A hardcoded mapper covers the common cases; everything else needs an explicit mapping — the same fetch-then-post pattern as PMS migration listing mappings.

1. Bootstrap the GL team

POST /teams/migrate-vri-to-vrt
{
  "sourceTenantId": "legacy-team-uuid",
  "targetPartnerId": "optional-partner-uuid",
  "targetName": "Mountain Papa",
  "glStartAt": "2025-01-01",
  "moveConnectionCredentials": false
}

Copies only the narrow bootstrap state:

  • tenant shell, listings, and owner identities (as contacts);
  • connection shells — credentials stripped and disabled = true unless moveConnectionCredentials is true, which moves credentials over and clears them on the source so OAuth/token integrations are never live twice;
  • derived ownership periods, preferring historical statement-owner snapshots from glStartAt forward and falling back to current listing owners.

No statements are imported yet, and the target chart/layouts are not provisioned — that is the follow-up flow below.

2. Initialize accounts and layouts

Initialize the target team with its chart of accounts and statement layouts (PATCH /teams/{id}/init). The mapping preview requires the target chart to exist.

3. Review account mappings

GET /teams/migrate-vri-to-vrt/statements/account-mappings
  ?sourceTenantId=...&targetTenantId=...

Returns the legacy accounts that the current migration plan would import, with a suggestion per account and the target account pool:

{
  "effectiveGlStartAt": "2025-02-01",
  "oldAccounts": [
    {
      "legacyAccount": {
        "key": "legacy-ref:341",
        "ref": "341",
        "name": "Rental Income",
        "classification": "Revenue"
      },
      "sources": ["line", "template"],
      "suggestedTargetAccount": { "id": "rents-uuid", "title": "Rents" },
      "currentTargetAccount": null
    }
  ],
  "newAccounts": [
    {
      "id": "rents-uuid",
      "title": "Rents",
      "category": {
        "id": "category-uuid",
        "name": "Revenue",
        "classification": "revenue"
      },
      "type": "ledger",
      "status": "active"
    }
  ]
}
  • suggestedTargetAccount is the hardcoded mapper's pick; null means the account needs an explicit user choice.
  • currentTargetAccount reflects mappings stored by a previous import run, so reopening the mapping screen shows what is already resolved.
  • Only legacy accounts on imported, non-zero, non-payout statement lines are listed; template-only accounts are skipped.

4. Import historical statements

POST /teams/migrate-vri-to-vrt/statements
{
  "sourceTenantId": "legacy-team-uuid",
  "targetTenantId": "migrated-team-uuid",
  "accountMappings": [
    {
      "legacyAccountKey": "legacy-ref:341",
      "targetAccountId": "rents-uuid"
    }
  ]
}
  • Each accountMappings[] entry binds one oldAccounts[].legacyAccount.key from the preview to one target account id. Explicit mappings win over the hardcoded mapper.
  • Resolved mappings are stored on the target team, so the import can be rerun and the preview returns them as currentTargetAccount.
  • The import brings over pre-cutover owner statements, their provenance rows, attached historical journal entries, and statement templates rewritten onto the target chart. Only statements that attach to derived ownership periods are imported.
  • On success, the target team's statementStartAt moves to the effective cutover and historicalStatementsImportedAt records the run.

On this page