CodamAIDocs
Topicdone

The database

CRMS uses the same database layer as CDMS: the same variables, the same routing to system and tenant database, the schema from the entities, and tables that are only appended to.

Variants
embedded: the CDMS databaseseparate service: its own databaseSINGLEMULTI

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 and as a separate service
embeddedseparate service
Databasethe database of the CDMS applicationa database of its own
Variablesthose of the application, nothing extraCODAMAI_PERSISTENCE_*, required
Transactionthe same as the application's, the same poolsits own
Tablesnext to the tables of the applicationonly 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:

WhatWhere
system templates (scope SYSTEM)system database
templates of a tenant and of a userdatabase of the caller’s tenant
final documentsdatabase of the caller’s tenant, without a tenant the system database

With SINGLE, this is the same database.

The variables of the separate service

VariableMeaningDefault
CODAMAI_PERSISTENCE_TENANT_MODESINGLE or MULTIrequired
CODAMAI_PERSISTENCE_DATABASE_DRIVERJDBC driver class, e.g. com.mysql.cj.jdbc.Driverrequired
CODAMAI_PERSISTENCE_DATABASE_URLJDBC URL with the placeholder {tenant}. It becomes single, system or the key of a tenantrequired
CODAMAI_PERSISTENCE_DATABASE_USER, _PASSWORDthe database accountrequired
CODAMAI_PERSISTENCE_DATABASE_POOL_SIZEsize of a connection pool20
CODAMAI_PERSISTENCE_DATABASE_AUTO_UPDATEHibernate adjusts the schema at starttrue
CODAMAI_PERSISTENCE_DATABASE_AUTO_CREATE_TENANT_DATABASEcreate a missing tenant database on first accessfalse
CODAMAI_PERSISTENCE_DATABASE_SHOW_SQLwrite SQL to the logfalse

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 VARCHAR columns, not as a database-specific ENUM type. 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_…:

AreaTables
template managementcrms_template_edition, crms_template_variant, crms_template_entry, crms_template_content, crms_template_asset, crms_template_blob, crms_template_draft
evidencecrms_journal_entry, crms_journal_head, crms_anchor, crms_anchor_proof, crms_document_key
document archivecrms_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:

TableWhat changes
crms_template_draftthe draft of a template, when the draft is saved
crms_journal_headthe head of a journal. It is locked while an entry is appended, so writers take turns
crms_document_keyonly the destruction of a document key. The row stays as a tombstone
crms_document_retentionthe 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.

Pitfalls

Next

Search