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
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
Methods
Apply(BowireUserMigrationPlan)
Carry out plan and record it.
public static BowireUserMigrationReceipt Apply(BowireUserMigrationPlan plan)
Parameters
Returns
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
Returns
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
storageRootstringThe data root holding the legacy flat layout.
subjectstringThe authenticated subject.
modeBowireUserMigrationModeWhat the install has said it wants.
Returns
ReadReceipt(string)
The decision on record for the slot at slot, or
null when there is none.
public static BowireUserMigrationReceipt? ReadReceipt(string slot)
Parameters
slotstring
Returns
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
Returns
- string
Where the slot was moved, or
nullwhen 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.