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.
15 KiB
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.Domainentities +EnvelopeGenerator.Infrastructure/EGDbContext.cs+ live DB metadata snapshot fromDD_ECM. - Goal: make schema transitions predictable (what exists, how it is linked, where logic executes).
- Safety: all DB checks used read-only
SELECTmetadata queries; no data mutation.
Snapshot metadata
- Source DB:
DD_ECMonSDD-VHP04-SQL19\DD_TESTING01 - Snapshot date:
2026-10-20 - App context:
EnvelopeGenerator.Infrastructure/EGDbContext.cs
Fast navigation
- High-level aggregate map:
AGENTS.md->Databasesection - EF model config source:
EnvelopeGenerator.Infrastructure/EGDbContext.cs - Stored procedure wrappers:
EnvelopeGenerator.Application/Common/SQL/EnvelopeCreateReadSQL.csEnvelopeGenerator.Application/Common/SQL/EnvelopeReceiverAddReadSQL.csEnvelopeGenerator.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) DocumentviaTBSIG_ENVELOPE_DOCUMENT.ENVELOPE_ID.Envelope (1) -> (N) HistoryviaTBSIG_ENVELOPE_HISTORY.ENVELOPE_ID.Envelope (N) <-> (N) ReceiverthroughEnvelopeReceiver(TBSIG_ENVELOPE_RECEIVER, composite PK{ENVELOPE_ID, RECEIVER_ID}).Document (1) -> (N) DocReceiverElementviaTBSIG_DOCUMENT_RECEIVER_ELEMENT.DOCUMENT_ID.DocReceiverElement (1) -> (N) ElementAnnotationviaTBSIG_DOCUMENT_RECEIVER_ELEMENT_ANNOTATION.ELEMENT_ID.DocumentStatuslinksEnvelope + Receiverstate inTBSIG_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 NULLUSER_ID int NOT NULLSTATUS int NOT NULLENVELOPE_UUID nvarchar(36) NOT NULLMESSAGE nvarchar(max) NOT NULLEXPIRES_WHEN datetime NULLEXPIRES_WARNING_WHEN datetime NULLVERIFICATION_TYPE tinyint NOT NULLTITLE nvarchar(128) NULLCONTRACT_TYPE int NULLLANGUAGE nvarchar(5) NULLSEND_REMINDER_EMAILS bit NULLFIRST_REMINDER_DAYS int NULLREMINDER_INTERVAL_DAYS int NULLENVELOPE_TYPE int NULLCERTIFICATION_TYPE int NULLUSE_ACCESS_CODE bit NULLFINAL_EMAIL_TO_CREATOR int NULLFINAL_EMAIL_TO_RECEIVERS int NULLEXPIRES_WHEN_DAYS int NULLEXPIRES_WARNING_WHEN_DAYS int NULLTFA_ENABLED bit NOT NULLDOC_RESULT varbinary(max) NULLLANG_CODE varchar(5) NOT NULLSOURCE varchar(10) NOT NULLCOMMENT varchar(128) NULLADDED_WHEN datetime NOT NULLCHANGED_WHEN datetime NULL
TBSIG_ENVELOPE_RECEIVER
ENVELOPE_ID int NOT NULLRECEIVER_ID int NOT NULLSEQUENCE int NOT NULLNAME nvarchar(128) NULLJOB_TITLE nvarchar(128) NULLCOMPANY_NAME nvarchar(128) NULLPRIVATE_MESSAGE nvarchar(max) NULLACCESS_CODE nvarchar(64) NULLADDED_WHEN datetime NOT NULLCHANGED_WHEN datetime NULLGUID bigint NOT NULLPHONE_NUMBER varchar(20) NULLPARENT_ENVELOPE_RECEIVER_ID int NOT NULL
TBSIG_ENVELOPE_DOCUMENT
GUID int NOT NULLENVELOPE_ID int NOT NULLFILENAME nvarchar(256) NOT NULLFILEPATH nvarchar(256) NOT NULLADDED_WHEN datetime NOT NULLFILENAME_ORIGINAL nvarchar(256) NULLBYTE_DATA varbinary(max) NULL
TBSIG_DOCUMENT_RECEIVER_ELEMENT
GUID int NOT NULLDOCUMENT_ID int NOT NULLRECEIVER_ID int NOT NULLELEMENT_TYPE int NOT NULLPOSITION_X float NOT NULLPOSITION_Y float NOT NULLWIDTH float NOT NULLHEIGHT float NOT NULLPAGE int NOT NULLREQUIRED bit NOT NULLTOOLTIP nvarchar(512) NULLREAD_ONLY bit NOT NULLANNOTATION_INDEX int NOT NULLADDED_WHEN datetime NOT NULLCHANGED_WHEN datetime NULLCHANGED_WHO nvarchar(100) NULLFULL_NAME nvarchar(100) NULLPOSITION nvarchar(100) NULLPLACE nvarchar(100) NULLINK varbinary(max) NULL
TBSIG_DOCUMENT_RECEIVER_ELEMENT_ANNOTATION
GUID bigint NOT NULLELEMENT_ID int NOT NULLNAME nvarchar(100) NOT NULLVALUE nvarchar(max) NOT NULLADDED_WHEN datetime NOT NULLCHANGED_WHEN datetime NULLCHANGED_WHO nvarchar(100) NULLTYPE nvarchar(50) NOT NULLPOSITION_X float NULLPOSITION_Y float NULLWIDTH float NULLHEIGHT float NULL
TBSIG_DOCUMENT_STATUS
GUID int NOT NULLENVELOPE_ID int NOT NULLRECEIVER_ID int NOT NULLSTATUS int NOT NULLSTATUS_CHANGED_WHEN datetime NULLVALUE nvarchar(max) NULLADDED_WHEN datetime NOT NULLCHANGED_WHEN datetime NULL
TBSIG_ENVELOPE_HISTORY
GUID bigint NOT NULLENVELOPE_ID int NOT NULLUSER_REFERENCE nvarchar(128) NOT NULLSTATUS int NOT NULLADDED_WHEN datetime NOT NULLACTION_DATE datetime NULLCOMMENT nvarchar(max) NULL
TBSIG_RECEIVER
GUID int NOT NULLEMAIL_ADDRESS nvarchar(128) NOT NULLSIGNATURE nvarchar(64) NOT NULLADDED_WHEN datetime NOT NULLTOTP_SECRET_KEY nvarchar(max) NULLTFA_REG_DEADLINE datetime NULLCULTURE nvarchar(10) NULL
TBSIG_ENVELOPE_RECEIVER_READ_ONLY
GUID bigint NOT NULLENVELOPE_ID bigint NOT NULLRECEIVER_MAIL nvarchar(250) NOT NULLDATE_VALID date NOT NULLADDED_WHO varchar(100) NOT NULLADDED_WHEN datetime NULLCHANGED_WHO varchar(100) NULLCHANGED_WHEN datetime NULL
TBSIG_ENVELOPE_TYPE
GUID int NOT NULLTITLE nvarchar(128) NOT NULLLANGUAGE nvarchar(5) NOT NULLEXPIRES_DAYS int NULLCERTIFICATION_TYPE int NULLUSE_ACCESS_CODE bit NULLFINAL_EMAIL_TO_CREATOR int NULLFINAL_EMAIL_TO_RECEIVERS int NULLADDED_WHEN datetime NOT NULLCHANGED_WHEN datetime NULLEXPIRES_WARNING_DAYS int NULLSEND_REMINDER_EMAILS bit NULLFIRST_REMINDER_DAYS int NULLREMINDER_INTERVAL_DAYS int NULLCONTRACT_TYPE int NULL
TBSIG_EMAIL_TEMPLATE
GUID int NOT NULLNAME nvarchar(64) NULLBODY nvarchar(max) NULLSUBJECT nvarchar(512) NULLADDED_WHEN datetime NOT NULLCHANGED_WHEN datetime NULLLANG_CODE varchar(5) NOT NULL
TBEMLP_EMAIL_OUT
GUID int NOT NULLREMINDER_TYPE_ID int NOT NULLSENDING_PROFILE int NOT NULLREFERENCE_ID int NOT NULLREFERENCE_STRING varchar(200) NULLENTITY_ID int NULLWF_ID int NOT NULLWF_REFERENCE varchar(200) NULLEMAIL_ADRESS varchar(1000) NOT NULLEMAIL_SUBJ varchar(500) NOT NULLEMAIL_BODY varchar(max) NOT NULLEMAIL_ATTMT1 varchar(512) NULLEMAIL_SENT datetime NULLCOMMENT varchar(500) NULLADDED_WHO varchar(50) NOT NULLADDED_WHEN datetime NULLCHANGED_WHO varchar(50) NULLCHANGED_WHEN datetime NULLERROR_TIMESTAMP datetime NULLERROR_MSG varchar(900) NULLATTACHMENT1_BYTES varbinary(max) NULLATT1_RELATED_ID bigint NULLATT1_REL_TYPE varchar(20) NULL
Constraints and indexes (relevant)
From EF + DB metadata snapshot:
TBSIG_ENVELOPE: PKPK_TBSIG_ENVELOPE (GUID).TBSIG_ENVELOPE_RECEIVER: composite PKPK_TBSIG_ENVELOPE_RECEIVER (ENVELOPE_ID, RECEIVER_ID).TBSIG_DOCUMENT_RECEIVER_ELEMENT: PKGUID, plus unique keyUQTBSIG_DOCUMENT_RECEIVER_ELEMENT_DocID_PosX_PosY (DOCUMENT_ID, POSITION_X, POSITION_Y).TBSIG_RECEIVER: PKGUID, unique keyUQTBSIG_RECEIVER (EMAIL_ADDRESS).TBEMLP_EMAIL_OUT: PKGUID, FKFK_TBEMLP_EMAIL_OUT_SENDING_PROFILE.
Stored procedures: behavior and code call sites
Active in .NET code path
PRSIG_API_CREATE_ENVELOPE
- Purpose: creates envelope row (
STATUS=1002,SOURCE='API', defaults) and returnsENVELOPE_UUIDvia output. - DB writes:
TBSIG_ENVELOPE. - Called by:
- SQL template
EnvelopeGenerator.Application/Common/SQL/EnvelopeCreateReadSQL.cs - executor
EnvelopeGenerator.Infrastructure/Executor/EnvelopeExecutor.cs - used in
EnvelopeReceiverController.CreateAsyncandCreateEnvelopeReceiverCommandHandler.
- SQL template
PRSIG_API_CREATE_RECEIVER
- Purpose: upserts
TBSIG_RECEIVERby 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.CreateAsyncandCreateEnvelopeReceiverCommandHandler.
- SQL template
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.
- SQL template
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
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_USERandPRSIG_GET_CLOSED_ENVELOPES_FOR_USERare called in legacy VB path:EnvelopeGenerator.CommonServices/Models/EnvelopeModel.vb
-
PRSIG_API_WITHDRAW_ENVELOPEexists in DB snapshot but no active.cscall 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
TBSIG_DOCUMENT_RECEIVER_ELEMENT_AFT_INS
- Fires on insert of
TBSIG_DOCUMENT_RECEIVER_ELEMENT. - Normalizes/rewrites
POSITION_X,POSITION_Yand setsCHANGED_WHO='TBSIG_DOC_REC_EL_AFT_INS'.
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 whenCHANGED_WHO='OFFSET_Y_POS'.
TBSIG_ENVELOPE_HISTORY_AFT_INS
- Fires on history insert.
- Central state machine side-effects:
- syncs
TBSIG_ENVELOPE.STATUSfor selected100xstates, - on
1003applies Y-offset update to receiver elements, - on
2005calculates partial/fully signed and may insert follow-up1006history, - on
2007(type-dependent reject path) writes rejection emails intoTBEMLP_EMAIL_OUTand updates envelope rejected state, - on
3001invitation-message counting can move envelope to1004.
- syncs
TBSIG_EMAIL_TEMPLATE_AFT_UPD
- Fires on update of
TBSIG_EMAIL_TEMPLATE. - Sets
CHANGED_WHEN = GETDATE().
TBSIG_ENVELOPE_RECEIVER_READ_ONLY_UPD
- Fires on update of
TBSIG_ENVELOPE_RECEIVER_READ_ONLY. - Updates config timestamp row (
TBSIG_CONFIG.GUID = 1).
TBEMLP_EMAIL_OUT_AFT_UPD
- Fires on update of
TBEMLP_EMAIL_OUT. - When
EMAIL_SENTchanges andWF_ID in (3001..3005), writes corresponding history entries toTBSIG_ENVELOPE_HISTORY.
Trigger mismatch alert (important)
DbTriggerParamscontainsTBEMLP_EMAIL_OUT_AFT_INS, but this trigger was not found in the snapshot DB (ExistsInDb = 0).TBEMLP_EMAIL_OUT_AFT_UPDexists 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.EmailAddressis[StringLength(250)]in entity, DB column isnvarchar(128).EnvelopeReceiverReadOnly.AddedWhoentity expectsnvarchar(250), DB column isvarchar(100).EnvelopeReceiverentity does not model DB columnsGUIDandPARENT_ENVELOPE_RECEIVER_ID.Envelopeentity does not explicitly model some DB columns (VERIFICATION_TYPE,LANG_CODE,SOURCE).EmailOutentity has[NotMapped] AddedWhen, while DB hasADDED_WHENcolumn.
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_HISTORYsemantics requires trigger impact review first. - Keep
DbTriggerParamssynchronized 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.
- SQL wrapper templates (
Refresh checklist (read-only)
Run these metadata checks before/after DB migration:
- Column inventory per table (
INFORMATION_SCHEMA.COLUMNS). - Constraint inventory (
INFORMATION_SCHEMA.TABLE_CONSTRAINTS+KEY_COLUMN_USAGE). - Trigger inventory (
sys.triggers) and definitions (OBJECT_DEFINITION). - Stored procedure inventory (
sys.procedures) and definitions (OBJECT_DEFINITION). - Repo call-site grep for
PRSIG_names to detect dead or missing integration points.