Confidentiality Declaration
Data Entity
Description
Formal signed record of a peer mentor or driver's confidentiality obligation, required for specific expense claim types (e.g. driver honoraria) before a claim can be submitted. Captures the declaration content, digital signature, validity period, and linkage to the associated expense claim.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Surrogate primary key, generated server-side on creation | PKrequiredunique |
expense_claim_id |
uuid |
Foreign key to the expense_claims row this declaration is attached to. A single expense claim may have at most one active declaration at a time. | required |
user_id |
uuid |
Foreign key to the users row of the peer mentor or driver who signed the declaration. Denormalized for fast audit queries independent of the expense claim. | required |
organization_id |
uuid |
Tenant scoping key. All queries are filtered by organization_id to enforce tenant isolation. | required |
declaration_type |
enum |
Category of confidentiality obligation. 'driver_confidentiality' covers peer mentors acting as drivers who handle sensitive personal information about contacts. 'general_confidentiality' is a catch-all for other organization-defined cases. | required |
declaration_text |
text |
Full canonical text of the confidentiality obligation at the time of signing. Stored verbatim so the signed content is immutable even if the organization later changes its template. | required |
status |
enum |
Lifecycle state of the declaration. 'pending' = presented to user but not yet signed. 'signed' = user accepted and signature recorded. 'expired' = valid_until passed. 'revoked' = administratively invalidated. | required |
signature_method |
enum |
How the user confirmed acceptance. 'in_app_tap' = tapped 'I agree' button. 'biometric' = biometric confirmation used as signing gesture. Recorded for audit purposes. | required |
signed_at |
datetime |
UTC timestamp of when the user completed the signing gesture. Null while status is 'pending'. | - |
valid_from |
datetime |
UTC datetime from which this declaration is considered active. Defaults to signed_at. Allows organizations to backdate declarations to the start of a claim period. | - |
valid_until |
datetime |
UTC datetime after which the declaration expires. Null means the declaration does not expire by time (only by revocation). Organizations may configure a rolling validity window (e.g. calendar year). | - |
device_fingerprint |
string |
Hashed identifier of the device on which the declaration was signed (Flutter device_info_plus output, SHA-256). Used in audit trail to confirm signing was performed on a known device. | - |
ip_address |
string |
IP address of the client at time of signing, recorded for audit. May be absent in offline-first scenarios where signing happens while disconnected; populated on first successful sync. | - |
revocation_reason |
text |
Free-text reason provided by an administrator when revoking the declaration. Null unless status is 'revoked'. | - |
revoked_by |
uuid |
user_id of the administrator who revoked the declaration. Null unless status is 'revoked'. | - |
created_at |
datetime |
UTC timestamp of row insertion. Set by the database on INSERT, never updated. | required |
updated_at |
datetime |
UTC timestamp of last modification. Updated by trigger or application on every UPDATE. | required |
Database Indexes
idx_declarations_expense_claim_id
Columns: expense_claim_id
idx_declarations_user_id_status
Columns: user_id, status
idx_declarations_organization_id_created_at
Columns: organization_id, created_at
idx_declarations_status_valid_until
Columns: status, valid_until
Validation Rules
declaration_text_not_empty
error
Validation failed
valid_until_after_valid_from
error
Validation failed
signed_at_required_when_signed
error
Validation failed
revocation_reason_required_when_revoked
error
Validation failed
expense_claim_must_exist
error
Validation failed
organization_tenant_match
error
Validation failed
Business Rules
declaration_required_before_claim_submission
An expense claim of type 'driver_honoraria' or any type flagged as requiring a declaration by the organization's expense type configuration cannot transition from 'draft' to 'submitted' unless a linked declaration row exists with status 'signed'.
declaration_immutable_after_signing
Once status transitions to 'signed', the fields declaration_text, signature_method, signed_at, and valid_from become read-only. Any UPDATE attempt on these columns for a signed row must be rejected.
single_active_declaration_per_claim
At most one declaration with status 'pending' or 'signed' may exist for a given expense_claim_id at any time. Attempting to create a second active declaration for the same claim must be rejected unless the previous one is first revoked or expired.
revocation_requires_admin_role
Only users with role 'coordinator', 'org_admin', or 'global_admin' may set status to 'revoked'. Peer mentors cannot revoke their own declarations.
expiry_auto_transition
A scheduled job evaluates all signed declarations where valid_until < NOW() and transitions their status from 'signed' to 'expired'. Affected expense claims that are still in 'draft' are flagged, triggering a notification to the peer mentor.
audit_log_on_all_state_changes
Every status transition (pending→signed, signed→expired, signed→revoked) must produce an audit_logs entry referencing the declaration id, the actor user_id, the old and new status, and a UTC timestamp.
offline_signing_sync_integrity
Declarations signed while the device is offline are held in the mutation outbox. On sync, the server validates that the associated expense_claim_id still exists and has not been cancelled before persisting the declaration. If validation fails, the mutation is rejected and the peer mentor is notified.