This document describes the PKI database model as of the current codebase.
Source of truth:
- Schema DDL:
backend/schema/pki_schema.sql - Runtime usage:
backend/db.py,backend/app.py
| Table | Notes |
|---|---|
organizations |
Created/read/listed by app. |
certificates |
Primary certificate metadata store; issuance + revocation state updates. |
certificate_audit_log |
Issuance, revocation, renewal, download, and password-view flows write audit records. |
subject_alternative_names |
Populated on cert creation; read by popup with PEM fallback for legacy certs. |
certificate_extensions |
Generic extension storage; populated on cert creation for audit trail. |
basic_constraints |
Normalized extension storage; populated on cert creation, read by popup. |
key_usage |
Normalized extension storage; populated on cert creation, read by popup. |
extended_key_usage |
Normalized extension storage; populated on cert creation, read by popup. |
crls |
Populated during revocation after CRL generation succeeds. |
revoked_certificates |
Populated during revocation; links CRL history to revoked certs. |
| View | Notes |
|---|---|
certificate_summary |
Used by dashboard statistics queries in backend/db.py. |
| Index Group | Notes |
|---|---|
certificates indexes |
Useful for current read paths by org/type/status/issuer. |
| Extension table indexes | Present for extension-related tables. |
| Audit table indexes | Present for audit-log access patterns. |
Stores organization identity and folder mapping.
- Used by:
- create organization
- list organizations
- fetch by id / by directory
Stores all issued cert metadata for:
rootintermediateserverclientemail
Actively used for:
- certificate listing and dashboard stats
- chain relation via
issuer_cert_id - revocation status (
status,revoked_at,revocation_reason) - expiring certificate queries
db.log_certificate_operation(...)is actively called by certificate lifecycle and download flows.- Current app flows record create, renew, revoke, artifact download, and PKCS#12 password view events.
The following extension and CRL tables are used by the current application:
subject_alternative_namesβ populated on cert creation; read by popup with PEM fallbackcertificate_extensionsβ generic extension audit trailbasic_constraintsβ normalized extension storagekey_usageβ normalized extension storageextended_key_usageβ normalized extension storage with OIDβname mappingcrlsβ CRL metadata including generation timestamp and next update timerevoked_certificatesβ per-CRL revocation history with linkage to revoked certs
Impact: Certificate extension details (SAN, KU, EKU, BasicConstraints) are now persisted to DB during issuance and retrieved preferentially by popup/metadata routes (with PEM parse fallback for legacy certs). CRL artifacts are now tracked relationally, not just on disk.
These examples reflect objects actively used today.
SELECT c.id, c.cert_name, c.cert_type, c.issuer_cert_id, c.status, c.not_after,
issuer.cert_type AS issuer_cert_type
FROM certificates c
LEFT JOIN certificates issuer ON c.issuer_cert_id = issuer.id
WHERE c.organization_id = :org_id
ORDER BY c.created_at DESC, c.id DESC;Note: The issuer_cert_type field is included to enable UI-level logic (e.g., showing password fields for root-issued certificates). This join is optional for filtering queries but recommended for dashboard/listing queries.
SELECT cert_type,
COUNT(*) AS total,
SUM(CASE WHEN issuer_cert_id IS NULL THEN 1 ELSE 0 END) AS missing_issuer
FROM certificates
GROUP BY cert_type;SELECT id, serial_number, revoked_at, revocation_reason
FROM certificates
WHERE issuer_cert_id = :issuer_cert_id
AND status = 'revoked'
ORDER BY revoked_at;SELECT (SELECT COUNT(*) FROM organizations) AS organizations,
(SELECT COUNT(*) FROM certificates) AS certificates;- If you add writes to new tables, update this document in the same PR.
- If you switch app logic to read from views, update the relevant section here.
- Keep this doc aligned with both
backend/schema/pki_schema.sqland runtime behavior inbackend/db.py/backend/app.py.