Class BowireUserMigrator

Namespace
Kuestenlogik.Bowire.Auth
Assembly
Kuestenlogik.Bowire.dll

Moves a single-user install's state into an identity's slot when the install becomes multi-tenant (#97, #28 Phase E).

public static class BowireUserMigrator
Inheritance
BowireUserMigrator
Inherited Members

Remarks

The day an operator turns on an identity provider, everything already on disk becomes invisible: the stores stop resolving to the flat storage root and start resolving under users/<slot>/, so the newly signed-in person sees an empty workbench and their collections appear to be gone. They are not gone, but nothing in the product says so, and the obvious conclusion — that turning on auth cost them their work — is the one people draw.

Copy, never move. The legacy files stay exactly where they are. That costs disk and buys two things worth more than the disk: the install can be switched back to single-user without a second migration, and a migration that lands the data in the wrong slot is recoverable by declining it in the right one. The operator deletes the originals when they are satisfied, which is a decision only they can time.

Excluding, not including. The set below names what is not a person's state; everything else is copied. An inclusion list would have to be extended by every future store, and the failure mode of forgetting is silent data loss for whoever used that feature. Forgetting to exclude something merely copies a cache.

Fields

ReceiptFileName

The decision record, written inside the slot it concerns.

public const string ReceiptFileName = ".migration.json"

Field Value

string

Properties

NotPersonalState

Top-level names under the storage root that belong to the machine or the install rather than to a person, and are therefore not migrated.

public static IReadOnlySet<string> NotPersonalState { get; }

Property Value

IReadOnlySet<string>

Methods

Apply(BowireUserMigrationPlan)

Carry out plan and record it.

public static BowireUserMigrationReceipt Apply(BowireUserMigrationPlan plan)

Parameters

plan BowireUserMigrationPlan

Returns

BowireUserMigrationReceipt

Remarks

Copies into a staging directory beside the slot and moves it into place at the end. A file-by-file copy straight into the slot would, if it failed halfway, leave a slot that holds state — which the next Plan(string, string, BowireUserMigrationMode) reads as SlotNotEmpty and never offers again. Half the data, no receipt, and no way back through the product is a worse outcome than an error.

Exceptions

InvalidOperationException

The plan is not on offer.

Decline(BowireUserMigrationPlan)

Record that plan was refused, so it is not offered again.

public static BowireUserMigrationReceipt Decline(BowireUserMigrationPlan plan)

Parameters

plan BowireUserMigrationPlan

Returns

BowireUserMigrationReceipt

Plan(string, string, BowireUserMigrationMode)

What migrating into subject's slot would do. Reads the disk; changes nothing.

public static BowireUserMigrationPlan Plan(string storageRoot, string subject, BowireUserMigrationMode mode = BowireUserMigrationMode.Prompt)

Parameters

storageRoot string

The data root holding the legacy flat layout.

subject string

The authenticated subject.

mode BowireUserMigrationMode

What the install has said it wants.

Returns

BowireUserMigrationPlan

ReadReceipt(string)

The decision on record for the slot at slot, or null when there is none.

public static BowireUserMigrationReceipt? ReadReceipt(string slot)

Parameters

slot string

Returns

BowireUserMigrationReceipt

Remarks

An unreadable receipt reads as no receipt: the alternative is an identity that can never be offered a migration and never be told why, and re-offering is recoverable while that is not.

Undo(BowireUserMigrationPlan)

Take back a decision, so the offer can be made again.

public static string? Undo(BowireUserMigrationPlan plan)

Parameters

plan BowireUserMigrationPlan

Returns

string

Where the slot was moved, or null when only a receipt was removed.

Remarks

The case this exists for is accepting in the wrong account — the operator's admin identity signs in first, takes the data, and the person it belongs to is then told there is nothing to migrate.

Accepted moves the whole slot aside rather than deleting what was copied. Deleting would have to know which files came from the migration and which the person made afterwards, and the receipt records counts rather than a manifest — so the safe answer is to destroy nothing and hand back where it went.

Declined only removes the receipt. The slot itself may hold work done since, and moving that aside would hide the very thing the person is looking at. With the receipt gone the next plan reads the slot: empty means the offer returns, and anything else means it correctly does not.

Exceptions

InvalidOperationException

Nothing has been decided yet.