Formbase 0.14.0
Pairs with MorphDB 0.14.x. A correction is a new append — and now it can say which record it corrects. Breaking for code that
implements IRawStore or reads StoredDocument.Body, and for callers that passed a cancellation token
positionally to AcceptAsync/AppendAsync.
Added
- Record identity. A document may name the record it belongs to with a
RecordKey(an opaque
string, compared exactly, scoped to the form type):FormbaseEngine.AcceptAsync(type, body, recordKey: key), over HTTPPOST /formtypes/{type}/documents?recordKey=…. The projection shows each
record once — the document with the latest watermark — so a corrected record is one row and a count
counts it once. Documents without a key are records of their own, exactly as before. - Retiring a record.
FormbaseEngine.RetireAsync(type, key), over HTTP
DELETE /formtypes/{type}/records?recordKey=…, appends a retirement: a document with no body that
takes the record out of the projection while its earlier documents stay in the raw stream. Appending
under the key again brings the record back. Idempotency keys work for retirements as for intake. - Record keys are compared exactly and are not Unicode-normalized: the same text in two normalization
forms (a file name from one system in NFC, from another in NFD) names two records. Normalize keys that
come from file names or user input before sending them. RecordFold.Latest— the fold the projector applies (latest per key, retired keys dropped), public so
any reader of the raw stream can get records rather than appends.- Raw reads carry
recordKeyandretired(StoredDocument.Key,StoredDocument.IsRetirement). A
retirement reads back with a null body; readretiredrather than testing the body, since a document
whose content is the JSON valuenullhas a null body too. - Projected tables gain the
fb_record_keybookkeeping column. Record reads still return the declared
fields only.
Changed
- A durable host refuses to start — exit code
78, naming the setting — when MorphDB answers that the
configuredFormbase:MorphDb:ProjectIddoes not exist. It used to report ready and fail its first
projection with an unhandled error. A MorphDB that cannot be reached at startup does not stop the
start, as before. - Breaking:
IRawStore.AppendAsync(type, id, body, key = null, cancellationToken)takes the record key
before the cancellation token, andIRawStore.RetireAsyncis new — a raw-store adapter implements both.
IIntakeService.AcceptAsynclikewise takesrecordKeybefore the token, andIIntakeService.RetireAsync
is new. A call that passed the token positionally names it (cancellationToken: ct). - Breaking:
StoredDocument.Bodyis nullable — null for a retirement.StoredDocumentResponse.Body
is nullable over HTTP for the same reason, next to the newrecordKeyandretired. - An idempotency key reused under another record key, or for a retirement where it named a document (or
the reverse), is refused like a key reused with a different body. - Schema intelligence skips retirements when sampling a form type's documents.
- SQLite and PostgreSQL files and schemas from 0.13.x are upgraded in place on first use: the raw
table gains its record-key column (and, on SQLite, a retirement column), and every document it holds
reads back as a record of its own. On PostgreSQL the check runs before any change, so an up-to-date
schema takes no table lock at startup. An existing projected table gainsfb_record_keythe next time
it is rebuilt; until then nothing in it is keyed, because nothing appended before the upgrade was.
The upgrade is one-way. Once a record has been retired, 0.13.x can no longer read the form type's
raw stream (it answers500), and a projection it runs leaves the table empty. Back up the database
before upgrading if you may need to go back. - A bound field's
target.keyField(EntityRef.KeyField) is documented for what it is: the field on
the target form type whose value the bound field carries, not a key for finding the target record.
The API reference had shown it one way and nothing said which; nothing about its behaviour changes.
Dependencies
Microsoft.Extensions.AI.AbstractionsandMicrosoft.Extensions.AI.OpenAI10.10.1 (was 10.10.0), a patch.Formbase.MorphDbdepends onMorphDB.Client0.14.0 (was 0.13.1), and the live tests and the compose file
run theghcr.io/iyulab/morphdb:0.14.0image.