What this is about
CRMS stores templates, journals and the entries of final documents in a database. The files of the documents themselves are in the S3 bucket, not in the database.
CRMS has no database path of its own for this. It uses the shared CodamAI persistence layer, the same one as CDMS. Per request, it picks the entity manager of the system database or of the caller’s tenant database. An entity manager is the object through which JPA reads and writes rows.
Which database
| embedded | separate service | |
|---|---|---|
| Database | the database of the CDMS application | a database of its own |
| Variables | those of the application, nothing extra | CODAMAI_PERSISTENCE_*, required |
| Transaction | the same as the application's, the same pools | its own |
| Tables | next to the tables of the application | only the CRMS tables |
System and tenant
As with CDMS, there are two ways to run an installation (see SINGLE and MULTI):
SINGLE: one database holds everything.MULTI: one system database and one database of its own per tenant.
Every CRMS module creates the same tables in the system database and in every tenant database. Who a row belongs to decides where it goes:
| What | Where |
|---|---|
system templates (scope SYSTEM) | system database |
| templates of a tenant and of a user | database of the caller’s tenant |
| final documents | database of the caller’s tenant, without a tenant the system database |
With SINGLE, this is the same database.
The variables of the separate service
| Variable | Meaning | Default |
|---|---|---|
CODAMAI_PERSISTENCE_TENANT_MODE | SINGLE or MULTI | required |
CODAMAI_PERSISTENCE_DATABASE_DRIVER | JDBC driver class, e.g. com.mysql.cj.jdbc.Driver | required |
CODAMAI_PERSISTENCE_DATABASE_URL | JDBC URL with the placeholder {tenant}. It becomes single, system or the key of a tenant | required |
CODAMAI_PERSISTENCE_DATABASE_USER, _PASSWORD | the database account | required |
CODAMAI_PERSISTENCE_DATABASE_POOL_SIZE | size of a connection pool | 20 |
CODAMAI_PERSISTENCE_DATABASE_AUTO_UPDATE | Hibernate adjusts the schema at start | true |
CODAMAI_PERSISTENCE_DATABASE_AUTO_CREATE_TENANT_DATABASE | create a missing tenant database on first access | false |
CODAMAI_PERSISTENCE_DATABASE_SHOW_SQL | write SQL to the log | false |
Embedded, you set none of these in addition. CRMS uses what the application already has.
The schema
- From the entities. Hibernate builds the tables from the entity classes. CRMS ships no SQL scripts of its own.
- Portable. Enumerations are stored as text in
VARCHARcolumns, not as a database-specificENUMtype. There are no vendor-specific column definitions. That is why CRMS runs on every database the CDMS scaffold offers. - Queries through the Criteria API. No module writes SQL or JPQL as text.
The tables are all named crms_…:
| Area | Tables |
|---|---|
| template management | crms_template_edition, crms_template_variant, crms_template_entry, crms_template_content, crms_template_asset, crms_template_blob, crms_template_draft |
| evidence | crms_journal_entry, crms_journal_head, crms_anchor, crms_anchor_proof, crms_document_key |
| document archive | crms_document_entry, crms_document_payload, crms_document_retention |
Append only
What has been written once, CRMS does not change any more. The entities of these tables are @Immutable: Hibernate never writes an UPDATE for them. No module calls delete, merge or bulk changes on them. An architecture test per module requires this.
Only four tables are changed, each for a named reason:
| Table | What changes |
|---|---|
crms_template_draft | the draft of a template, when the draft is saved |
crms_journal_head | the head of a journal. It is locked while an entry is appended, so writers take turns |
crms_document_key | only the destruction of a document key. The row stays as a tombstone |
crms_document_retention | the work list of retention: done_at, once a document is removed |
What protects against changes is the hash chain: every entry contains the hash of the previous one, and the head of every journal gets a timestamp outside the database. Whoever changes a row with database access is detected on verification. See The hash chain.