Data migration

Version 2 has three more fields. Your customer has a year of data.

This is the part nobody demonstrates and everybody runs into — usually at nine on a Monday, at a customer's, with the old version already uninstalled. It is the reason the schema is drawn rather than typed.

The database migrates itself

Your application carries the schema it was built with. On the first start after an update it compares that against the new one and does what is needed — add a column, add a table, add an index — before a single window opens. Nobody writes a migration script, because there is nothing a script would know that the comparison does not.

A rename stays a rename

Tables and fields are matched by identity, not by name. Rename kunde to auftraggeber and the column keeps its data. Match by name and the same change reads as “one field vanished and an empty one appeared” — which is a year of somebody's work, gone, with the update reporting success.

A changed formula recalculates itself

Change netto = menge * preis to take a discount off, and every existing row is worked out again on the next start — in the right order, so a total is never built from figures that have not been updated yet. Only the tables whose formulas actually moved: a release that shifted a button does not recompute a million rows.

A safety copy first, every time

Before any of it runs, the database is copied. If a migration cannot be finished, nothing has happened — the copy is the answer, not an apology.

Ship data with the first installation

An application starts empty, which is right for invoices and wrong for the postcode table, the VAT rates, the standard categories and the first administrator. In the build dialog you tick which tables travel with it — so a fresh installation is empty, not broken.

And it is remembered by identity too

The tick is on the table itself, not on its name — rename it and it still ships. “Everything” means everything, including tables you add next year; with “only these”, a new table starts unticked and the build sheet says so rather than silently leaving it out.