Skip to main content

Data inventory — v1

Status: v1 — first issue. Scope: every data element processed by the ZeroAuth platform (docs/compliance/compliance-roadmap-v1.md §1.1 in-scope union). Companion documents:


1. Purpose

This inventory establishes the canonical catalogue of every data element ZeroAuth processes, classified by sensitivity under DPDP §17, with the lawful basis (DPDP §6), the retention period, and the cross-border transfer status named per element. It is used as the input to every Privacy Impact Assessment (PIA-template-v0) and as the source of truth for the tests/schema-purity.test.ts column allowlist.

When an engineering change introduces a new field, log line, or API surface, the PIA author looks up the element in this inventory. If the element is missing, a row must be added in the same PR that introduces the field, signed off by Agent #39 (Privacy) and Agent #41 (DPO). New rows that propose a new classification value (beyond the five enumerated below) require an ADR.

The five classification values used throughout are:

  • NON-PII — opaque IDs (UUIDs), system-generated counters, configuration values, timestamps not bound to a single natural person.
  • PII — data that identifies, or is reasonably likely to identify, a natural person under DPDP §2(t). Examples: name, email, phone, employee code, IP address paired with a session.
  • SENSITIVE-PII — the DPDP §17 category for elevated-obligation personal data. Biometric data is the canonical example. ZeroAuth never holds raw biometric data centrally; SENSITIVE-PII rows in this inventory describe the on-device-only artefacts within ZeroAuth code paths (see Q6 in dpdp-2t-commitments-memo-v0.md §7).
  • SECRET — credentials and key material whose disclosure to an unintended party degrades the system's authentication or integrity guarantees. Examples: password hashes, API-key SHA-256 hashes, JWT signing secret, session-bind cookie value, contract owner private key.
  • OPAQUE-CRYPTOGRAPHIC — artefacts that have been constructed under a hiding-and-binding commitment scheme or a one-way function such that they do not identify a natural person under §2(t) by the argument in dpdp-2t-commitments-memo-v0.md §5. Examples: Poseidon commitment, DID, did_sha256 in audit metadata.
  • TRANSIENT-SECRET — secret material that exists only in RAM on the customer's own device for the duration of a single proof-generation operation and is then garbage-collected. The SHA-256 of the biometric template is the canonical example. ZeroAuth ships the code path that produces this material; the bank's tenant database never holds it.

Cross-border status is named per element: Indian-only (lives on the Mumbai VPS + Hyderabad DR replica only) or shipped-out (replicated to a non-Indian region or processed by a non-Indian processor, with destination named).


2. Methodology

This inventory was produced by walking every surface that handles data:

  1. Every table in src/services/db.ts — twelve table definitions enumerated below. Every column captured.
  2. Every audit-event metadata field — by inspecting src/services/audit.ts and the call sites that build the metadata JSONB. The canonical fields are did_sha256, actor_email, ip_address, user_agent, requested_scope, failure_reason, verification_id, device_id, session_id and free-form per-event extensions.
  3. Every API payload field — by inspecting the request and response interfaces in src/types/ and the route handlers under src/routes/. The inventory captures the fields that cross the network boundary.
  4. Every Winston log field — by inspecting src/services/usage.ts (request logger), src/middleware/error-handler.ts (error logger), and the structured-logging conventions across services. Winston records requestId, path, tenantId, apiKeyId, status code, response time. Body content is not logged (A-22 mitigation).
  5. Every Caddy access-log field — by inspecting Caddyfile. Caddy records source IP, method, path (no query string under the C-005 closure for /api/console/*), user agent, response status, bytes, duration.
  6. On-device, transient elements — the SHA-256 of the biometric template that lives in RAM on the customer's phone during proof generation. Captured here because ZeroAuth ships the code that computes it, even though it never leaves the device (Q6 in dpdp-2t-commitments-memo-v0.md §7).
  7. The OPAQUE-CRYPTOGRAPHIC artefacts — the Poseidon commitment and the DID, classified per the §2(t) memo argument.

The walk is committed to source so the audit trail is reviewable. Every PR that touches src/services/db.ts, audit metadata fields, log fields, or API surfaces must update this inventory in the same commit; CI lints for column drift against the allowlist locked into tests/schema-purity.test.ts.


3. Inventory table

The columns:

  • Element name<surface>.<column> for DB columns; <service>.<field> for log fields; <endpoint>.<field> for API payloads.
  • Source surface — DB table / log type / API endpoint / cache.
  • Classification — one of the five values defined in §1.
  • Lawful basis — DPDP §6 ground: consent / legitimate-interest / legal-obligation / not-personal-data (where the §2(t) memo argument applies) / other (specify).
  • Retention (days) — number of days; 0 = transient (must be GC'd within request lifetime); -1 = bound to a sliding window from last contact (resolved per the retention policy).
  • Cross-borderIndian-only or shipped-out:<destination>.
  • Notes — observations, mitigations, special handling.

3.1 leads table (marketing capture)

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
leads.idDBNON-PIInot-personal-data1095Indian-onlySurrogate PK; SERIAL counter.
leads.typeDBNON-PIInot-personal-data1095Indian-onlyEnum: pilot / whitepaper.
leads.nameDBPIIconsent-1Indian-onlyCaptured via marketing form; consent text shown at point of capture.
leads.companyDBPIIconsent-1Indian-onlyCompany name; may identify a natural person at small firms.
leads.emailDBPIIconsent-1Indian-onlyPrimary identifier for follow-up; subject to DPDP §13 erasure on request.
leads.sizeDBNON-PIIconsent1095Indian-onlyCompany-size bucket (1-10, 11-50, …).
leads.created_atDBNON-PIIlegitimate-interest1095Indian-onlyTimestamp; not bound to an identified individual on its own.

3.2 tenants table (developer accounts)

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
tenants.idDBNON-PIInot-personal-data-1Indian-onlyUUID; surrogate PK.
tenants.emailDBPIIconsent-1Indian-onlyAccount owner email; consent captured at signup. Subject to §11 erasure (cascades to api_keys via FK).
tenants.password_hashDBSECRETlegitimate-interest-1Indian-onlybcrypt hash; never displayed; rotated on password reset.
tenants.company_nameDBPIIconsent-1Indian-onlyMay identify a natural person at single-founder firms.
tenants.planDBNON-PIInot-personal-data-1Indian-onlyEnum: free/starter/growth/enterprise.
tenants.statusDBNON-PIInot-personal-data-1Indian-onlyEnum: active/suspended/deactivated.
tenants.rate_limitDBNON-PIInot-personal-data-1Indian-onlyPer-tenant requests / 15 min.
tenants.monthly_quotaDBNON-PIInot-personal-data-1Indian-only-1 = unlimited.
tenants.metadataDBPIIconsent-1Indian-onlyJSONB; may contain free-form bank-side identifiers.
tenants.security_policyDBNON-PIInot-personal-data-1Indian-onlyJSONB; per-tenant security knobs (Play Integrity gate, etc.).
tenants.created_atDBNON-PIInot-personal-data-1Indian-onlyTimestamp.
tenants.updated_atDBNON-PIInot-personal-data-1Indian-onlyTimestamp.

3.3 pending_signups table (24-hour signup verification)

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
pending_signups.idDBNON-PIInot-personal-data1Indian-onlyUUID.
pending_signups.emailDBPIIconsent1Indian-only24h TTL; deleted on consume or expiry.
pending_signups.password_hashDBSECRETconsent1Indian-onlybcrypt; 24h TTL.
pending_signups.company_nameDBPIIconsent1Indian-only24h TTL.
pending_signups.token_hashDBSECRETconsent1Indian-onlySHA-256 of the single-use verify token.
pending_signups.expires_atDBNON-PIInot-personal-data1Indian-onlyTimestamp.
pending_signups.created_atDBNON-PIInot-personal-data1Indian-onlyTimestamp.
pending_signups.consumed_atDBNON-PIInot-personal-data1Indian-onlyTimestamp.

3.4 api_keys table (tenant API credentials)

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
api_keys.idDBNON-PIInot-personal-data-1Indian-onlyUUID.
api_keys.tenant_idDBNON-PIInot-personal-data-1Indian-onlyFK → tenants.
api_keys.nameDBNON-PIInot-personal-data-1Indian-onlyFree-form label.
api_keys.key_prefixDBNON-PIInot-personal-data-1Indian-onlyFirst 13 chars (e.g. za_live_a1b2c3); identification only.
api_keys.key_hashDBSECRETlegitimate-interest-1Indian-onlySHA-256 of full key; raw key shown once at creation.
api_keys.scopesDBNON-PIInot-personal-data-1Indian-onlyTEXT[] of scope strings.
api_keys.environmentDBNON-PIInot-personal-data-1Indian-onlylive/test.
api_keys.statusDBNON-PIInot-personal-data-1Indian-onlyactive/revoked.
api_keys.last_used_atDBNON-PIIlegitimate-interest-1Indian-onlyTimestamp.
api_keys.expires_atDBNON-PIInot-personal-data-1Indian-onlyOptional expiry timestamp.
api_keys.created_atDBNON-PIInot-personal-data-1Indian-onlyTimestamp.
api_keys.revoked_atDBNON-PIInot-personal-data-1Indian-onlyTimestamp.

3.5 devices table (registered devices)

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
devices.idDBNON-PIInot-personal-data-1Indian-onlyUUID.
devices.tenant_idDBNON-PIInot-personal-data-1Indian-onlyFK.
devices.environmentDBNON-PIInot-personal-data-1Indian-onlylive/test.
devices.external_idDBPIIlegitimate-interest-1Indian-onlyTenant-supplied device identifier; may be derived from MAC / serial.
devices.nameDBNON-PIInot-personal-data-1Indian-onlyHuman-readable name (e.g. Branch-12-Counter-3).
devices.location_idDBNON-PIInot-personal-data-1Indian-onlyTenant-side location code.
devices.statusDBNON-PIInot-personal-data-1Indian-onlyactive/inactive/retired.
devices.battery_levelDBNON-PIInot-personal-data-1Indian-only0-100.
devices.metadataDBPIIlegitimate-interest-1Indian-onlyJSONB; may carry Play Integrity verdict, cert-chain hash.
devices.last_seen_atDBNON-PIIlegitimate-interest-1Indian-onlyTimestamp.
devices.created_atDBNON-PIInot-personal-data-1Indian-onlyTimestamp.
devices.updated_atDBNON-PIInot-personal-data-1Indian-onlyTimestamp.

3.6 tenant_users table (enrolled identities — PII columns scheduled for Phase 1 PII-strip)

The columns marked PII (scheduled-for-removal) are removed in the Phase 1 PII-strip migration (the follow-on to C-121). Until that migration lands, tests/schema-purity.test.ts allowlists them for the current state.

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
tenant_users.idDBNON-PIInot-personal-data-1Indian-onlyUUID.
tenant_users.tenant_idDBNON-PIInot-personal-data-1Indian-onlyFK.
tenant_users.environmentDBNON-PIInot-personal-data-1Indian-onlylive/test.
tenant_users.external_idDBPIIconsent-1Indian-onlyTenant-supplied user identifier; may be Aadhaar fragment, employee code, phone.
tenant_users.full_nameDBPII (scheduled-for-removal)consent-1Indian-onlyDirect identifier. Removed in Phase 1 PII-strip.
tenant_users.emailDBPII (scheduled-for-removal)consent-1Indian-onlyDirect identifier. Removed in Phase 1 PII-strip.
tenant_users.phoneDBPII (scheduled-for-removal)consent-1Indian-onlyDirect identifier. Removed in Phase 1 PII-strip.
tenant_users.employee_codeDBPII (scheduled-for-removal)consent-1Indian-onlyMay be re-identifying when joined with HR system. Removed in Phase 1 PII-strip.
tenant_users.statusDBNON-PIInot-personal-data-1Indian-onlyactive/inactive.
tenant_users.primary_device_idDBNON-PIInot-personal-data-1Indian-onlyFK → devices.
tenant_users.metadataDBPIIconsent-1Indian-onlyJSONB; tenant-side metadata may include identifying data.
tenant_users.last_verified_atDBNON-PIIlegitimate-interest-1Indian-onlyTimestamp.
tenant_users.created_atDBNON-PIInot-personal-data-1Indian-onlyTimestamp.
tenant_users.updated_atDBNON-PIInot-personal-data-1Indian-onlyTimestamp.

3.7 verification_events table

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
verification_events.idDBNON-PIInot-personal-data2555Indian-onlyUUID. Retention 7 years (audit baseline).
verification_events.tenant_idDBNON-PIInot-personal-data2555Indian-onlyFK.
verification_events.environmentDBNON-PIInot-personal-data2555Indian-onlylive/test.
verification_events.user_idDBNON-PIInot-personal-data2555Indian-onlyFK → tenant_users; UUID.
verification_events.device_idDBNON-PIInot-personal-data2555Indian-onlyFK → devices; UUID.
verification_events.api_key_idDBNON-PIInot-personal-data2555Indian-onlyFK → api_keys.
verification_events.methodDBNON-PIInot-personal-data2555Indian-onlyEnum: zkp/fingerprint/face/depth/saml/oidc/manual.
verification_events.resultDBNON-PIInot-personal-data2555Indian-onlypass/fail/challenge.
verification_events.reasonDBNON-PIInot-personal-data2555Indian-onlyFree-form short string; must not contain PII.
verification_events.confidence_scoreDBNON-PIInot-personal-data2555Indian-onlyNumeric.
verification_events.reference_idDBPIIlegitimate-interest2555Indian-onlyTenant-supplied transaction reference; may be re-identifying.
verification_events.metadataDBPIIlegitimate-interest2555Indian-onlyJSONB; reviewed at PR time.
verification_events.occurred_atDBNON-PIInot-personal-data2555Indian-onlyTimestamp.
verification_events.created_atDBNON-PIInot-personal-data2555Indian-onlyTimestamp.

3.8 attendance_events table

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
attendance_events.idDBNON-PIInot-personal-data2555Indian-onlyUUID.
attendance_events.tenant_idDBNON-PIInot-personal-data2555Indian-onlyFK.
attendance_events.environmentDBNON-PIInot-personal-data2555Indian-onlylive/test.
attendance_events.user_idDBNON-PIInot-personal-data2555Indian-onlyFK; UUID.
attendance_events.device_idDBNON-PIInot-personal-data2555Indian-onlyFK.
attendance_events.verification_idDBNON-PIInot-personal-data2555Indian-onlyFK.
attendance_events.event_typeDBNON-PIInot-personal-data2555Indian-onlycheck_in/check_out.
attendance_events.resultDBNON-PIInot-personal-data2555Indian-onlyaccepted/rejected.
attendance_events.metadataDBPIIlegitimate-interest2555Indian-onlyJSONB.
attendance_events.occurred_atDBNON-PIInot-personal-data2555Indian-onlyTimestamp.
attendance_events.created_atDBNON-PIInot-personal-data2555Indian-onlyTimestamp.

3.9 proof_pairing_sessions table (W3, 5-minute TTL)

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
proof_pairing_sessions.idDBNON-PIInot-personal-data30Indian-onlyUUID; rows TTL-deleted by cleanup job.
proof_pairing_sessions.tenant_idDBNON-PIInot-personal-data30Indian-onlyFK.
proof_pairing_sessions.environmentDBNON-PIInot-personal-data30Indian-onlylive/test.
proof_pairing_sessions.api_key_idDBNON-PIInot-personal-data30Indian-onlyFK.
proof_pairing_sessions.nonce_hexDBNON-PIInot-personal-data30Indian-only31-byte random nonce.
proof_pairing_sessions.session_bind_token_hashDBSECRETlegitimate-interest30Indian-onlySHA-256 of session-bind cookie (A-13).
proof_pairing_sessions.stateDBNON-PIInot-personal-data30Indian-onlyEnum.
proof_pairing_sessions.consumed_user_idDBNON-PIInot-personal-data30Indian-onlyFK; UUID.
proof_pairing_sessions.consumed_verification_idDBNON-PIInot-personal-data30Indian-onlyFK.
proof_pairing_sessions.proof_hashDBNON-PIInot-personal-data30Indian-onlySHA-256 of submitted Groth16 proof bytes; for replay defence.
proof_pairing_sessions.last_error_codeDBNON-PIInot-personal-data30Indian-onlyMachine code.
proof_pairing_sessions.desktop_ipDBPIIlegitimate-interest30Indian-onlyIPv4/IPv6 of desktop client; abuse-defence signal.
proof_pairing_sessions.desktop_user_agentDBPIIlegitimate-interest30Indian-onlyUA string.
proof_pairing_sessions.failure_countDBNON-PIInot-personal-data30Indian-onlySMALLINT.
proof_pairing_sessions.expires_atDBNON-PIInot-personal-data30Indian-only5-min TTL.
proof_pairing_sessions.consumed_atDBNON-PIInot-personal-data30Indian-onlyTimestamp.
proof_pairing_sessions.created_atDBNON-PIInot-personal-data30Indian-onlyTimestamp.

3.10 audit_events table (append-only, hash-chained per ADR 0013)

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
audit_events.idDBNON-PIInot-personal-data2555Indian-onlyBIGSERIAL. 7-year retention.
audit_events.tenant_idDBNON-PIInot-personal-data2555Indian-onlyFK.
audit_events.environmentDBNON-PIInot-personal-data2555Indian-onlylive/test.
audit_events.actor_typeDBNON-PIInot-personal-data2555Indian-onlyapi_key/console/device/system.
audit_events.actor_idDBPIIlegal-obligation2555Indian-onlyUUID of api_key, console user, or device.
audit_events.actionDBNON-PIInot-personal-data2555Indian-onlyVerb (e.g. verify, revoke_key).
audit_events.entity_typeDBNON-PIInot-personal-data2555Indian-onlyNoun (e.g. tenant_user).
audit_events.entity_idDBNON-PIInot-personal-data2555Indian-onlyUUID.
audit_events.statusDBNON-PIInot-personal-data2555Indian-onlysuccess/failure.
audit_events.summaryDBNON-PIInot-personal-data2555Indian-onlyShort human string. Must not contain PII.
audit_events.metadataDBPIIlegal-obligation2555Indian-onlyJSONB; field-by-field rows below.
audit_events.metadata.did_sha256DB JSONBOPAQUE-CRYPTOGRAPHICnot-personal-data2555Indian-onlySHA-256 of DID; per §2(t) memo argument.
audit_events.metadata.actor_emailDB JSONBPIIlegal-obligation2555Indian-onlyConsole-user email when actor_type=console.
audit_events.metadata.ip_addressDB JSONBPIIlegal-obligation2555Indian-onlySource IPv4/IPv6.
audit_events.metadata.user_agentDB JSONBPIIlegal-obligation2555Indian-onlyUA string.
audit_events.metadata.requested_scopeDB JSONBNON-PIInot-personal-data2555Indian-onlyFree-form scope name.
audit_events.metadata.failure_reasonDB JSONBNON-PIInot-personal-data2555Indian-onlyShort machine code.
audit_events.metadata.verification_idDB JSONBNON-PIInot-personal-data2555Indian-onlyUUID.
audit_events.metadata.device_idDB JSONBNON-PIInot-personal-data2555Indian-onlyUUID.
audit_events.metadata.session_idDB JSONBNON-PIInot-personal-data2555Indian-onlyUUID.
audit_events.previous_hashDBNON-PIInot-personal-data2555Indian-onlySHA-256 hash chain link (ADR 0013).
audit_events.event_hashDBNON-PIInot-personal-data2555Indian-onlySHA-256 of canonical event payload (ADR 0013).
audit_events.created_atDBNON-PIInot-personal-data2555Indian-onlyTimestamp.

3.11 audit_anchors table (Phase 1 C-016 backfill — anchored daily to Base Sepolia)

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
audit_anchors.idDBNON-PIInot-personal-data2555shipped-out:Base SepoliaBIGSERIAL.
audit_anchors.tenant_idDBNON-PIInot-personal-data2555shipped-out:Base SepoliaFK.
audit_anchors.dayDBNON-PIInot-personal-data2555shipped-out:Base SepoliaDATE of anchored window.
audit_anchors.terminal_hashDBNON-PIInot-personal-data2555shipped-out:Base SepoliaFinal event_hash for the day.
audit_anchors.tx_hashDBNON-PIInot-personal-data2555shipped-out:Base SepoliaOn-chain anchor transaction; Ethereum-format.
audit_anchors.block_numberDBNON-PIInot-personal-data2555shipped-out:Base SepoliaL2 block.
audit_anchors.created_atDBNON-PIInot-personal-data2555shipped-out:Base SepoliaTimestamp.

Cross-border note. The anchor payload contains only tenant_id + day + terminal_hash. None of these identify a natural person; the §13 transfer-impact assessment in dpdp-2t-commitments-memo-v0.md §7 Q3 treats the on-chain anchor as a not-personal-data export under Argument-A.

3.12 usage_logs table (per-API-call billing log)

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
usage_logs.idDBNON-PIInot-personal-data540Indian-onlyBIGSERIAL. 18 months for billing.
usage_logs.tenant_idDBNON-PIInot-personal-data540Indian-onlyFK.
usage_logs.api_key_idDBNON-PIInot-personal-data540Indian-onlyFK.
usage_logs.endpointDBNON-PIInot-personal-data540Indian-onlyURL path only (no query string).
usage_logs.methodDBNON-PIInot-personal-data540Indian-onlyHTTP verb.
usage_logs.status_codeDBNON-PIInot-personal-data540Indian-onlyHTTP status.
usage_logs.response_time_msDBNON-PIInot-personal-data540Indian-onlyINT.
usage_logs.ip_addressDBPIIlegitimate-interest540Indian-onlySource IP.
usage_logs.user_agentDBPIIlegitimate-interest540Indian-onlyUA string.
usage_logs.created_atDBNON-PIInot-personal-data540Indian-onlyTimestamp.

3.13 usage_monthly table (billing roll-up)

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
usage_monthly.idDBNON-PIInot-personal-data2555Indian-onlyBIGSERIAL.
usage_monthly.tenant_idDBNON-PIInot-personal-data2555Indian-onlyFK.
usage_monthly.monthDBNON-PIInot-personal-data2555Indian-onlyDATE.
usage_monthly.total_requestsDBNON-PIInot-personal-data2555Indian-onlyCounter.
usage_monthly.zkp_verificationsDBNON-PIInot-personal-data2555Indian-onlyCounter.
usage_monthly.zkp_registrationsDBNON-PIInot-personal-data2555Indian-onlyCounter.
usage_monthly.saml_authsDBNON-PIInot-personal-data2555Indian-onlyCounter.
usage_monthly.oidc_authsDBNON-PIInot-personal-data2555Indian-onlyCounter.

3.14 On-device transient secrets

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
device.sha256_biometric_templateCustomer-device RAMTRANSIENT-SECRETconsent0Indian-only (never transmitted)Computed on customer device during proof generation; consumed by fuzzy extractor; input buffer GC'd. Q6 in §2(t) memo asks counsel to confirm standard of care.
device.fuzzy_extractor_secretCustomer-device RAMTRANSIENT-SECRETconsent0Indian-only (never transmitted)Derived from biometric capture; never leaves the device.
device.poseidon_saltCustomer StrongBox-wrappedSECRETconsent-1Indian-only (never transmitted)Per-user salt bound to hardware key; survives across sessions on the customer's device only.

3.15 OPAQUE-CRYPTOGRAPHIC artefacts (commitments + DIDs)

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
user.poseidon_commitmentBank-tenant DB (per §2(t) memo)OPAQUE-CRYPTOGRAPHICnot-personal-data-1Indian-only (Phase 0); may ship out per Q3 of §2(t) memoSingle Fr field element; hiding+binding under DL on BN128.
user.didBank-tenant DBOPAQUE-CRYPTOGRAPHICnot-personal-data-1Indian-only (Phase 0); may ship out per Q3 of §2(t) memodid:zeroauth:<40 hex>. Leading 20 bytes of keccak256(commitment).
user.did_sha256audit_events.metadata.did_sha256OPAQUE-CRYPTOGRAPHICnot-personal-data2555Indian-onlyUsed in audit metadata (A-22 mitigation) to avoid raw DID in audit rows.
onchain.tx_hashBase Sepolia / Base mainnetNON-PIInot-personal-data-1shipped-out:Base L2Public Ethereum-format transaction hash.
onchain.commitment_anchorBase Sepolia DIDRegistryOPAQUE-CRYPTOGRAPHICnot-personal-data-1shipped-out:Base L2Commitment value emitted as on-chain event (no PII).

3.16 Winston log fields (structured-JSON application logs)

The Winston logger lives in src/services/logger.ts; the request logger in src/services/usage.ts and error logger in src/middleware/error-handler.ts. Body content is not logged. The fields below could carry PII if a future change is not reviewed; the inventory captures the risk per field.

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
winston.timestampWinston logNON-PIInot-personal-data90shipped-out:Sentry (scrubbed) on error path onlyISO-8601.
winston.levelWinston logNON-PIInot-personal-data90shipped-out:Sentryinfo/warn/error.
winston.messageWinston logNON-PII (could carry PII if developer is careless)legitimate-interest90shipped-out:SentryReviewed at PR time.
winston.requestIdWinston logNON-PIInot-personal-data90shipped-out:SentryUUID per request.
winston.pathWinston logNON-PII (could carry PII if a path embeds an identifier)legitimate-interest90shipped-out:SentryURL path; query string omitted.
winston.tenantIdWinston logNON-PIInot-personal-data90shipped-out:SentryUUID.
winston.apiKeyIdWinston logNON-PIInot-personal-data90shipped-out:SentryUUID.
winston.statusCodeWinston logNON-PIInot-personal-data90shipped-out:SentryHTTP status.
winston.responseTimeMsWinston logNON-PIInot-personal-data90shipped-out:SentryNumeric.
winston.error.stackWinston logNON-PII (could carry PII in error context)legitimate-interest90shipped-out:SentryReviewed at PR time; Sentry beforeSend scrubber strips known PII keys.

3.17 Caddy access-log fields (reverse-proxy edge log)

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
caddy.tsCaddy access logNON-PIInot-personal-data90Indian-onlyTimestamp.
caddy.remote_ipCaddy access logPIIlegitimate-interest90Indian-onlySource IP; retained for abuse defence.
caddy.methodCaddy access logNON-PIInot-personal-data90Indian-onlyHTTP verb.
caddy.urlCaddy access logPIIlegitimate-interest90Indian-onlyPath; query string stripped on /api/console/* per C-005 closure (A-28).
caddy.user_agentCaddy access logPIIlegitimate-interest90Indian-onlyUA string.
caddy.statusCaddy access logNON-PIInot-personal-data90Indian-onlyHTTP status.
caddy.sizeCaddy access logNON-PIInot-personal-data90Indian-onlyBytes returned.
caddy.durationCaddy access logNON-PIInot-personal-data90Indian-onlyNumeric.
caddy.request_idCaddy access logNON-PIInot-personal-data90Indian-onlyUUID.

3.18 Caches and ephemeral surfaces

Element nameSource surfaceClassificationLawful basisRetention (days)Cross-borderNotes
session-store.tenantContextIn-memory cacheNON-PIInot-personal-data0Indian-onlyPer-request; never persisted.
rate-limiter.bucketIn-memory cacheNON-PIInot-personal-data0Indian-onlyPer IP + tenant; 15-min sliding window.
jwt.signing_secretenv var → process memorySECRETlegitimate-interest-1Indian-onlyHS256 secret; rotated quarterly.
cookie.zeroauth_console_jwtBrowser cookie (HttpOnly, SameSite=Strict)SECRETlegitimate-interest-1Indian-onlyConsole session JWT; A-28 closure.

4. Cross-references to threat-model rows

The following threat-model rows in docs/threat_model.md reference this inventory:

  • A-15 (Camera spoofing) — references session_bind_token_hash + nonce_hex in proof_pairing_sessions.
  • A-22 (PII in pairing logs and responses) — references audit_events.metadata.did_sha256 (in lieu of raw did) and the desktop_ip / desktop_user_agent columns.
  • A-27 (Demo-DID prover bypass, CLOSED) — references the did field on the prover submit body, which is no longer privileged by prefix.
  • A-28 (JWT-in-URL log leak, CLOSED) — references caddy.url (the closure removed the query-string fallback that put JWTs into this field).

5. Open inventory questions

The following questions are referred forward to PIA-current-state (Agent #39's A39-W2-Tue deliverable) and to counsel via the §2(t) memo's §7:

  • Q-INV-01. Does tenant_users.metadata need a structural schema (JSON Schema, migrations/) to keep tenant-supplied PII out of free-form text? Owner: Agent #6 + Agent #39. Target: Phase 1 sprint 2.
  • Q-INV-02. Is the 90-day Winston-log retention defensible for Sentry shipping, given Sentry's US-region tenancy? Counsel referred via §13 cross-border opinion (D-Q1-05 dependency).
  • Q-INV-03. Does the pending_signups table need column-level encryption at rest, or is the 24-hour TTL sufficient mitigation? Owner: Agent #39 + Agent #6. Decision Phase 1 sprint 3.
  • Q-INV-04. Should the audit_events.metadata.actor_email field be moved to a did_sha256-style hash to align with the rest of the metadata? Defers to Agent #41 (DPO) — the actor_email is operationally useful for incident response; the trade-off is captured in PIA-current-state.

LAST_UPDATED: 2026-05-28 OWNER: Agent #39 (Privacy) + Agent #41 (DPO)