Skip to main content

audit_signatures

One row per sign-off collected on an audit. An audit can require multiple signatures (e.g. inspector + project lead + client), and each sign-off captures the signer's name and the timestamp.

Source Mapping

CouchDB document type: an "audit" document — rows are produced by asyncconvert.py's audits_signatures(obj) handler iterating obj.signature[*] (note the singular field name in source).

ColumnCouchDB sourceNotes
auditobj.idThe audits.id this row belongs to.
signeeobj.signature[i].nameThe signer's display name — not their email. See Pitfalls.
date_signedobj.signature[i].signedDateParsed via parseDate(...).
couchdbidobj.couchDbIdLegacy CouchDB document identifier (the audit's).

Column Reference

ColumnTypeNullableDescription
auditVARCHAR(255)yesForeign-key reference to audits.id.
signeeVARCHAR(255)yesThe signer's display name (free text — see Pitfalls).
date_signedDATETIMEyesWhen the sign-off was captured.
couchdbidVARCHAR(255)yesLegacy CouchDB identifier of the audit document.

Keys

  • No primary key, no unique constraint. A signer can sign once per audit (in practice), but the schema does not enforce it. Identity in practice is (audit, signee, date_signed).

Indexes

  • idx_parent on audit

There is no index on signee or date_signed. Queries that find "all audits this person signed" will scan the table.

Relationships

DirectionOther tableJoinCardinality
outgoingauditsaudit_signatures.audit = audits.idmany sign-offs → one audit

There is no projectid column on this table — to filter by project, join through audits first. There is also no reliable join to users because signee is a name, not an email.

No FK constraints in MariaDB; joins are by string match.

Refresh Semantics

audit_signatures is rebuilt per audit document. On each observation of an audit, the converter:

  1. Issues DELETE FROM audit_signatures WHERE audit = <audit_id> (when delete tracking is enabled).
  2. Iterates obj.signature[*] and inserts one row per sign-off.

Reading during an in-flight reindex of an audit may briefly return zero rows for that audit.

A reindex with type=audit (or a full reindex) rebuilds this table as part of the audit reindex.

Common Queries

All signatures on an audit

SELECT signee, date_signed
FROM audit_signatures
WHERE audit = 'your_audit_id'
ORDER BY date_signed;

Audits signed by a given person (by name)

SELECT
a.id,
a.name,
s.date_signed
FROM audit_signatures s
JOIN audits a ON a.id = s.audit
WHERE s.signee = 'Jane Doe'
ORDER BY s.date_signed DESC;

Names are free text — see Pitfalls.

Sign-off latency from completion to first signature

SELECT
a.id,
a.name,
a.completiondate,
MIN(s.date_signed) AS first_signature,
TIMESTAMPDIFF(HOUR, a.completiondate, MIN(s.date_signed)) AS hours_to_first_sign
FROM audits a
JOIN audit_signatures s ON s.audit = a.id
WHERE a.projectid = 'your_project_id'
AND a.completiondate IS NOT NULL
GROUP BY a.id, a.name, a.completiondate
ORDER BY hours_to_first_sign DESC;

Pitfalls

  • signee is a name, not an email. Unlike every other "user" reference in the schema (audits.author, audits.responsible, audit_roles.email, tickets.responsible, etc.), this column stores signature[i].name — a free-text display name. There is no reliable join to users.email from here. If you need the user account, look up the email separately or by name + project.
  • No projectid column. Filter by project requires joining through audits first. Don't try to use this table standalone for project-scoped queries.
  • No primary key, no unique constraint. A duplicate signature (e.g. the same name signing twice with different timestamps) is preserved as two rows. Reading during an in-flight reindex may briefly return zero rows for that audit.
  • date_signed is whatever the source said. No clamping or reconciliation against audits.completiondate — it can occasionally predate completion (e.g. when an inspector pre-signs in the field).
  • No FK constraint. Joins to audits.id are by string match.