Files
EnvelopeGenerator/DATABASE_STRUCTURE_CONTEXT.md
TekH 780277d656 Add DATABASE_STRUCTURE_CONTEXT.md for DB documentation
Added `DATABASE_STRUCTURE_CONTEXT.md` to provide detailed
documentation of the database structure for the envelope
domain. This includes entity-to-table mappings, schema
snapshots, EF relationships, constraints, stored procedure
behavior, and trigger wiring paths.

Highlighted model-to-database drift risks, trigger mismatch
alerts, and provided migration-safe operating rules. Added a
refresh checklist to validate metadata consistency before and
after database migrations.
2026-10-20 10:07:25 +02:00

15 KiB

Database Structure Context

Why this file exists

This is the deep-dive DB reference for migration work when schema can change and old DB knowledge may be lost.

  • Scope: EnvelopeGenerator.Domain entities + EnvelopeGenerator.Infrastructure/EGDbContext.cs + live DB metadata snapshot from DD_ECM.
  • Goal: make schema transitions predictable (what exists, how it is linked, where logic executes).
  • Safety: all DB checks used read-only SELECT metadata queries; no data mutation.

Snapshot metadata

  • Source DB: DD_ECM on SDD-VHP04-SQL19\DD_TESTING01
  • Snapshot date: 2026-10-20
  • App context: EnvelopeGenerator.Infrastructure/EGDbContext.cs

Fast navigation

  • High-level aggregate map: AGENTS.md -> Database section
  • EF model config source: EnvelopeGenerator.Infrastructure/EGDbContext.cs
  • Stored procedure wrappers:
    • EnvelopeGenerator.Application/Common/SQL/EnvelopeCreateReadSQL.cs
    • EnvelopeGenerator.Application/Common/SQL/EnvelopeReceiverAddReadSQL.cs
    • EnvelopeGenerator.Application/Common/SQL/DocumentCreateReadSQL.cs
  • Direct SQL execution in controller:
    • EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/EnvelopeReceiverController.cs

Core data model (ER-level)

  • Envelope (TBSIG_ENVELOPE) is root aggregate.
  • Envelope (1) -> (N) Document via TBSIG_ENVELOPE_DOCUMENT.ENVELOPE_ID.
  • Envelope (1) -> (N) History via TBSIG_ENVELOPE_HISTORY.ENVELOPE_ID.
  • Envelope (N) <-> (N) Receiver through EnvelopeReceiver (TBSIG_ENVELOPE_RECEIVER, composite PK {ENVELOPE_ID, RECEIVER_ID}).
  • Document (1) -> (N) DocReceiverElement via TBSIG_DOCUMENT_RECEIVER_ELEMENT.DOCUMENT_ID.
  • DocReceiverElement (1) -> (N) ElementAnnotation via TBSIG_DOCUMENT_RECEIVER_ELEMENT_ANNOTATION.ELEMENT_ID.
  • DocumentStatus links Envelope + Receiver state in TBSIG_DOCUMENT_STATUS.

Entity <-> table mapping (code-level)

Entity Table PK in code PK in DB Important relation notes
Envelope TBSIG_ENVELOPE Id GUID Has Documents, Histories, EnvelopeReceivers; unique index on Uuid configured in EF
EnvelopeReceiver TBSIG_ENVELOPE_RECEIVER {EnvelopeId, ReceiverId} {ENVELOPE_ID, RECEIVER_ID} DB also has GUID identity (not modeled as entity PK)
Document TBSIG_ENVELOPE_DOCUMENT Id GUID FK ENVELOPE_ID
DocReceiverElement TBSIG_DOCUMENT_RECEIVER_ELEMENT Id GUID Coordinates persisted here (POSITION_X/Y, WIDTH, HEIGHT, PAGE)
ElementAnnotation TBSIG_DOCUMENT_RECEIVER_ELEMENT_ANNOTATION Id GUID FK ELEMENT_ID
DocumentStatus TBSIG_DOCUMENT_STATUS Id GUID FK ENVELOPE_ID, RECEIVER_ID
History TBSIG_ENVELOPE_HISTORY Id GUID USER_REFERENCE maps to Receiver.EmailAddress and User.Email when IsMigration == false
Receiver TBSIG_RECEIVER Id GUID Unique indexes in code: Signature, EmailAddress
EnvelopeReceiverReadOnly TBSIG_ENVELOPE_RECEIVER_READ_ONLY Id GUID AddedWho is FK-like mapping to Receiver.EmailAddress
EnvelopeType TBSIG_ENVELOPE_TYPE Id GUID Used as optional envelope defaults/template
EmailTemplate TBSIG_EMAIL_TEMPLATE Id GUID Trigger-managed CHANGED_WHEN
EmailOut (legacy/bridge) TBEMLP_EMAIL_OUT Id GUID Internal/obsolete domain class, still registered for DB access

Physical schema snapshot (table/column level)

Notes:

  • Format per column: COLUMN_NAME TYPE NULLABLE.
  • This section reflects live DB metadata at snapshot time.

TBSIG_ENVELOPE

  • GUID int NOT NULL
  • USER_ID int NOT NULL
  • STATUS int NOT NULL
  • ENVELOPE_UUID nvarchar(36) NOT NULL
  • MESSAGE nvarchar(max) NOT NULL
  • EXPIRES_WHEN datetime NULL
  • EXPIRES_WARNING_WHEN datetime NULL
  • VERIFICATION_TYPE tinyint NOT NULL
  • TITLE nvarchar(128) NULL
  • CONTRACT_TYPE int NULL
  • LANGUAGE nvarchar(5) NULL
  • SEND_REMINDER_EMAILS bit NULL
  • FIRST_REMINDER_DAYS int NULL
  • REMINDER_INTERVAL_DAYS int NULL
  • ENVELOPE_TYPE int NULL
  • CERTIFICATION_TYPE int NULL
  • USE_ACCESS_CODE bit NULL
  • FINAL_EMAIL_TO_CREATOR int NULL
  • FINAL_EMAIL_TO_RECEIVERS int NULL
  • EXPIRES_WHEN_DAYS int NULL
  • EXPIRES_WARNING_WHEN_DAYS int NULL
  • TFA_ENABLED bit NOT NULL
  • DOC_RESULT varbinary(max) NULL
  • LANG_CODE varchar(5) NOT NULL
  • SOURCE varchar(10) NOT NULL
  • COMMENT varchar(128) NULL
  • ADDED_WHEN datetime NOT NULL
  • CHANGED_WHEN datetime NULL

TBSIG_ENVELOPE_RECEIVER

  • ENVELOPE_ID int NOT NULL
  • RECEIVER_ID int NOT NULL
  • SEQUENCE int NOT NULL
  • NAME nvarchar(128) NULL
  • JOB_TITLE nvarchar(128) NULL
  • COMPANY_NAME nvarchar(128) NULL
  • PRIVATE_MESSAGE nvarchar(max) NULL
  • ACCESS_CODE nvarchar(64) NULL
  • ADDED_WHEN datetime NOT NULL
  • CHANGED_WHEN datetime NULL
  • GUID bigint NOT NULL
  • PHONE_NUMBER varchar(20) NULL
  • PARENT_ENVELOPE_RECEIVER_ID int NOT NULL

TBSIG_ENVELOPE_DOCUMENT

  • GUID int NOT NULL
  • ENVELOPE_ID int NOT NULL
  • FILENAME nvarchar(256) NOT NULL
  • FILEPATH nvarchar(256) NOT NULL
  • ADDED_WHEN datetime NOT NULL
  • FILENAME_ORIGINAL nvarchar(256) NULL
  • BYTE_DATA varbinary(max) NULL

TBSIG_DOCUMENT_RECEIVER_ELEMENT

  • GUID int NOT NULL
  • DOCUMENT_ID int NOT NULL
  • RECEIVER_ID int NOT NULL
  • ELEMENT_TYPE int NOT NULL
  • POSITION_X float NOT NULL
  • POSITION_Y float NOT NULL
  • WIDTH float NOT NULL
  • HEIGHT float NOT NULL
  • PAGE int NOT NULL
  • REQUIRED bit NOT NULL
  • TOOLTIP nvarchar(512) NULL
  • READ_ONLY bit NOT NULL
  • ANNOTATION_INDEX int NOT NULL
  • ADDED_WHEN datetime NOT NULL
  • CHANGED_WHEN datetime NULL
  • CHANGED_WHO nvarchar(100) NULL
  • FULL_NAME nvarchar(100) NULL
  • POSITION nvarchar(100) NULL
  • PLACE nvarchar(100) NULL
  • INK varbinary(max) NULL

TBSIG_DOCUMENT_RECEIVER_ELEMENT_ANNOTATION

  • GUID bigint NOT NULL
  • ELEMENT_ID int NOT NULL
  • NAME nvarchar(100) NOT NULL
  • VALUE nvarchar(max) NOT NULL
  • ADDED_WHEN datetime NOT NULL
  • CHANGED_WHEN datetime NULL
  • CHANGED_WHO nvarchar(100) NULL
  • TYPE nvarchar(50) NOT NULL
  • POSITION_X float NULL
  • POSITION_Y float NULL
  • WIDTH float NULL
  • HEIGHT float NULL

TBSIG_DOCUMENT_STATUS

  • GUID int NOT NULL
  • ENVELOPE_ID int NOT NULL
  • RECEIVER_ID int NOT NULL
  • STATUS int NOT NULL
  • STATUS_CHANGED_WHEN datetime NULL
  • VALUE nvarchar(max) NULL
  • ADDED_WHEN datetime NOT NULL
  • CHANGED_WHEN datetime NULL

TBSIG_ENVELOPE_HISTORY

  • GUID bigint NOT NULL
  • ENVELOPE_ID int NOT NULL
  • USER_REFERENCE nvarchar(128) NOT NULL
  • STATUS int NOT NULL
  • ADDED_WHEN datetime NOT NULL
  • ACTION_DATE datetime NULL
  • COMMENT nvarchar(max) NULL

TBSIG_RECEIVER

  • GUID int NOT NULL
  • EMAIL_ADDRESS nvarchar(128) NOT NULL
  • SIGNATURE nvarchar(64) NOT NULL
  • ADDED_WHEN datetime NOT NULL
  • TOTP_SECRET_KEY nvarchar(max) NULL
  • TFA_REG_DEADLINE datetime NULL
  • CULTURE nvarchar(10) NULL

TBSIG_ENVELOPE_RECEIVER_READ_ONLY

  • GUID bigint NOT NULL
  • ENVELOPE_ID bigint NOT NULL
  • RECEIVER_MAIL nvarchar(250) NOT NULL
  • DATE_VALID date NOT NULL
  • ADDED_WHO varchar(100) NOT NULL
  • ADDED_WHEN datetime NULL
  • CHANGED_WHO varchar(100) NULL
  • CHANGED_WHEN datetime NULL

TBSIG_ENVELOPE_TYPE

  • GUID int NOT NULL
  • TITLE nvarchar(128) NOT NULL
  • LANGUAGE nvarchar(5) NOT NULL
  • EXPIRES_DAYS int NULL
  • CERTIFICATION_TYPE int NULL
  • USE_ACCESS_CODE bit NULL
  • FINAL_EMAIL_TO_CREATOR int NULL
  • FINAL_EMAIL_TO_RECEIVERS int NULL
  • ADDED_WHEN datetime NOT NULL
  • CHANGED_WHEN datetime NULL
  • EXPIRES_WARNING_DAYS int NULL
  • SEND_REMINDER_EMAILS bit NULL
  • FIRST_REMINDER_DAYS int NULL
  • REMINDER_INTERVAL_DAYS int NULL
  • CONTRACT_TYPE int NULL

TBSIG_EMAIL_TEMPLATE

  • GUID int NOT NULL
  • NAME nvarchar(64) NULL
  • BODY nvarchar(max) NULL
  • SUBJECT nvarchar(512) NULL
  • ADDED_WHEN datetime NOT NULL
  • CHANGED_WHEN datetime NULL
  • LANG_CODE varchar(5) NOT NULL

TBEMLP_EMAIL_OUT

  • GUID int NOT NULL
  • REMINDER_TYPE_ID int NOT NULL
  • SENDING_PROFILE int NOT NULL
  • REFERENCE_ID int NOT NULL
  • REFERENCE_STRING varchar(200) NULL
  • ENTITY_ID int NULL
  • WF_ID int NOT NULL
  • WF_REFERENCE varchar(200) NULL
  • EMAIL_ADRESS varchar(1000) NOT NULL
  • EMAIL_SUBJ varchar(500) NOT NULL
  • EMAIL_BODY varchar(max) NOT NULL
  • EMAIL_ATTMT1 varchar(512) NULL
  • EMAIL_SENT datetime NULL
  • COMMENT varchar(500) NULL
  • ADDED_WHO varchar(50) NOT NULL
  • ADDED_WHEN datetime NULL
  • CHANGED_WHO varchar(50) NULL
  • CHANGED_WHEN datetime NULL
  • ERROR_TIMESTAMP datetime NULL
  • ERROR_MSG varchar(900) NULL
  • ATTACHMENT1_BYTES varbinary(max) NULL
  • ATT1_RELATED_ID bigint NULL
  • ATT1_REL_TYPE varchar(20) NULL

Constraints and indexes (relevant)

From EF + DB metadata snapshot:

  • TBSIG_ENVELOPE: PK PK_TBSIG_ENVELOPE (GUID).
  • TBSIG_ENVELOPE_RECEIVER: composite PK PK_TBSIG_ENVELOPE_RECEIVER (ENVELOPE_ID, RECEIVER_ID).
  • TBSIG_DOCUMENT_RECEIVER_ELEMENT: PK GUID, plus unique key UQTBSIG_DOCUMENT_RECEIVER_ELEMENT_DocID_PosX_PosY (DOCUMENT_ID, POSITION_X, POSITION_Y).
  • TBSIG_RECEIVER: PK GUID, unique key UQTBSIG_RECEIVER (EMAIL_ADDRESS).
  • TBEMLP_EMAIL_OUT: PK GUID, FK FK_TBEMLP_EMAIL_OUT_SENDING_PROFILE.

Stored procedures: behavior and code call sites

Active in .NET code path

  1. PRSIG_API_CREATE_ENVELOPE
  • Purpose: creates envelope row (STATUS=1002, SOURCE='API', defaults) and returns ENVELOPE_UUID via output.
  • DB writes: TBSIG_ENVELOPE.
  • Called by:
    • SQL template EnvelopeGenerator.Application/Common/SQL/EnvelopeCreateReadSQL.cs
    • executor EnvelopeGenerator.Infrastructure/Executor/EnvelopeExecutor.cs
    • used in EnvelopeReceiverController.CreateAsync and CreateEnvelopeReceiverCommandHandler.
  1. PRSIG_API_CREATE_RECEIVER
  • Purpose: upserts TBSIG_RECEIVER by email, adds envelope assignment row with generated access code.
  • DB writes: TBSIG_RECEIVER, TBSIG_ENVELOPE_RECEIVER.
  • Called by:
    • SQL template EnvelopeGenerator.Application/Common/SQL/EnvelopeReceiverAddReadSQL.cs
    • executor EnvelopeGenerator.Infrastructure/Executor/EnvelopeReceiverExecutor.cs
    • used in EnvelopeReceiverController.CreateAsync and CreateEnvelopeReceiverCommandHandler.
  1. PRSIG_API_ADD_DOC
  • Purpose: stores one document for envelope if absent; returns doc id.
  • DB writes: TBSIG_ENVELOPE_DOCUMENT.
  • Called by:
    • SQL template EnvelopeGenerator.Application/Common/SQL/DocumentCreateReadSQL.cs
    • executor EnvelopeGenerator.Infrastructure/Executor/DocumentExecutor.cs
    • used in EnvelopeReceiverController.CreateAsync.
  1. PRSIG_API_ADD_DOC_RECEIVER_ELEM
  • Purpose: inserts signature element record if (DOC_ID, RECEIVER_ID) pair does not exist.
  • DB writes: TBSIG_DOCUMENT_RECEIVER_ELEMENT.
  • Called directly by:
    • EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/EnvelopeReceiverController.cs
  1. PRSIG_API_ADD_HISTORY_STATE
  • Purpose: appends history row with status and user reference.
  • DB writes: TBSIG_ENVELOPE_HISTORY.
  • Called directly by:
    • EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/EnvelopeReceiverController.cs

Legacy/other path references in repo

  • PRSIG_GET_ENVELOPES_FOR_USER and PRSIG_GET_CLOSED_ENVELOPES_FOR_USER are called in legacy VB path:

    • EnvelopeGenerator.CommonServices/Models/EnvelopeModel.vb
  • PRSIG_API_WITHDRAW_ENVELOPE exists in DB snapshot but no active .cs call site found in current server flow.

Trigger behavior and where they are wired

How trigger names are wired in app

  • Config source: EnvelopeGenerator.Server/EnvelopeGenerator.Server/appsettings.json -> DbTriggerParams.
  • DI binding: EnvelopeGenerator.Infrastructure/DependencyInjection.cs (AddDbTriggerParams).
  • Model binding: EnvelopeGenerator.Infrastructure/EGDbContext.cs -> AddTrigger<T>() -> ToTable(tb => tb.HasTrigger(triggerName)).

Trigger definitions observed in DB snapshot

  1. TBSIG_DOCUMENT_RECEIVER_ELEMENT_AFT_INS
  • Fires on insert of TBSIG_DOCUMENT_RECEIVER_ELEMENT.
  • Normalizes/rewrites POSITION_X, POSITION_Y and sets CHANGED_WHO='TBSIG_DOC_REC_EL_AFT_INS'.
  1. TBSIG_DOCUMENT_RECEIVER_ELEMENT_AFT_UPD
  • Fires on update of TBSIG_DOCUMENT_RECEIVER_ELEMENT.
  • Rewrites coordinates and CHANGED_WHO='TBSIG_DOC_REC_EL_AFT_UPD' except when CHANGED_WHO='OFFSET_Y_POS'.
  1. TBSIG_ENVELOPE_HISTORY_AFT_INS
  • Fires on history insert.
  • Central state machine side-effects:
    • syncs TBSIG_ENVELOPE.STATUS for selected 100x states,
    • on 1003 applies Y-offset update to receiver elements,
    • on 2005 calculates partial/fully signed and may insert follow-up 1006 history,
    • on 2007 (type-dependent reject path) writes rejection emails into TBEMLP_EMAIL_OUT and updates envelope rejected state,
    • on 3001 invitation-message counting can move envelope to 1004.
  1. TBSIG_EMAIL_TEMPLATE_AFT_UPD
  • Fires on update of TBSIG_EMAIL_TEMPLATE.
  • Sets CHANGED_WHEN = GETDATE().
  1. TBSIG_ENVELOPE_RECEIVER_READ_ONLY_UPD
  • Fires on update of TBSIG_ENVELOPE_RECEIVER_READ_ONLY.
  • Updates config timestamp row (TBSIG_CONFIG.GUID = 1).
  1. TBEMLP_EMAIL_OUT_AFT_UPD
  • Fires on update of TBEMLP_EMAIL_OUT.
  • When EMAIL_SENT changes and WF_ID in (3001..3005), writes corresponding history entries to TBSIG_ENVELOPE_HISTORY.

Trigger mismatch alert (important)

  • DbTriggerParams contains TBEMLP_EMAIL_OUT_AFT_INS, but this trigger was not found in the snapshot DB (ExistsInDb = 0).
  • TBEMLP_EMAIL_OUT_AFT_UPD exists and is active.

This should be treated as environment drift and validated before migrations.

Known model-vs-DB drift risks

These are not necessarily bugs, but they are migration risk hotspots:

  • Receiver.EmailAddress is [StringLength(250)] in entity, DB column is nvarchar(128).
  • EnvelopeReceiverReadOnly.AddedWho entity expects nvarchar(250), DB column is varchar(100).
  • EnvelopeReceiver entity does not model DB columns GUID and PARENT_ENVELOPE_RECEIVER_ID.
  • Envelope entity does not explicitly model some DB columns (VERIFICATION_TYPE, LANG_CODE, SOURCE).
  • EmailOut entity has [NotMapped] AddedWhen, while DB has ADDED_WHEN column.

Before schema changes, reconcile these deltas intentionally (either mapping update or documented accepted divergence).

Migration-safe operating rules

  • Do not rely on implicit trigger behavior; document expected side effects in feature code touching history/status flows.
  • Any change to TBSIG_ENVELOPE_HISTORY semantics requires trigger impact review first.
  • Keep DbTriggerParams synchronized with actual DB trigger inventory per environment.
  • For stored procedure changes, update both:
    • SQL wrapper templates (Application/Common/SQL/*)
    • direct SQL callers in controllers/executors.

Refresh checklist (read-only)

Run these metadata checks before/after DB migration:

  1. Column inventory per table (INFORMATION_SCHEMA.COLUMNS).
  2. Constraint inventory (INFORMATION_SCHEMA.TABLE_CONSTRAINTS + KEY_COLUMN_USAGE).
  3. Trigger inventory (sys.triggers) and definitions (OBJECT_DEFINITION).
  4. Stored procedure inventory (sys.procedures) and definitions (OBJECT_DEFINITION).
  5. Repo call-site grep for PRSIG_ names to detect dead or missing integration points.