Privacy & PII Configuration
What data VetRx Ledger stores, how sensitive fields are encrypted, and how to operate in minimal-PII mode to protect staff and patient privacy.
What data VetRx Ledger stores
| Field | Type | Encrypted at rest | Notes |
|---|---|---|---|
email | Account / waitlist | ✅ AES-256-GCM | Never shared with third parties |
dea_number | Org/clinic record | ✅ AES-256-GCM | Required for DEA-106 draft generation |
dvm_id, tech_id | Ledger events | No (indexed for query) | Can be badge numbers, initials, or role codes — not required to be real names |
org_name, clinic_name | Organisation record | No | Not PII unless the name contains a personal name (e.g. "Dr. Smith's Animal Clinic") |
drug, lot, expiry, qty | Vial / event record | No | Drug inventory data only — not PII |
| Patient name / client name | — | — | Not collected — intentionally out of scope |
AES-256-GCM field-level encryption
Sensitive fields are encrypted before they reach the data store using AES-256-GCM (Galois/Counter Mode), which provides both confidentiality and authenticated integrity. The implementation lives in lib/encrypt.ts.
- Key: 256-bit (32-byte) key stored as a 64-character hex string in the
FIELD_ENCRYPTION_KEYenvironment variable on the server. - IV: A random 12-byte initialisation vector is generated per encryption operation and prepended to the ciphertext.
- Authentication tag: A 16-byte GCM authentication tag is included — any tampering with the ciphertext causes decryption to fail with an explicit error.
- Storage format:
base64(iv[12] + tag[16] + ciphertext) - Idempotent:
encryptFielddetects already-encrypted values and skips re-encryption, preventing double-encryption bugs.
FIELD_ENCRYPTION_KEY. Store the key securely (password manager, secret management service) and back it up. Rotation requires re-encrypting all stored values.Generating a production key
openssl rand -hex 32
# Example output: a3f8d2...64 hex characters total
# Set this as FIELD_ENCRYPTION_KEY in your Vercel environment:
vercel env add FIELD_ENCRYPTION_KEYMinimal-PII mode
VetRx Ledger does not enforce real names anywhere in the system. To operate in maximum-privacy mode:
- Use badge numbers or role codes for
dvm_idandtech_idon every event (e.g.DVM-04,TECH-11). Maintain a separate, access-controlled roster that maps badge numbers to real identities — VetRx Ledger never needs it. - Use a functional email address for the account rather than a personal one (e.g.
compliance@yourclinic.com). - Use a clinic identifier rather than a personal name for the DEA registrant field (e.g. "Riverside Animal Hospital — Unit 2"rather than a DVM's personal name, where the registration permits it).
- Review your state board requirements — some jurisdictions require the individual practitioner name on DEA records. VetRx Ledger supports either approach.
Data retention
VetRx Ledger uses two storage layers depending on your deployment:
- Serverless ephemeral storage (
/tmp/vetrx-*.jsonl): File-backed stores that live on the Vercel Lambda instance. These are cleared on cold starts and are suitable for demo and evaluation use. Not recommended for production record-keeping. - Supabase (production): Persistent PostgreSQL database with row-level security. Each organisation can only read its own records. See
supabase/migrations/for the full schema and RLS policies.
Audit log retention
The audit log (audit_log table) is append-only by design — RLS policies block DELETE and UPDATE operations on audit entries for all roles, including the record owner. This matches the DEA requirement for tamper-evident records under 21 CFR § 1304.04(f) (2-year minimum retention).
Ledger events themselves also use an append-only model — a "deletion" is recorded as a REVERSAL event with a corresponding negative quantity, preserving the full history.
Export and deletion requests
Exporting your data
- Navigate to /ledger/verify and click Export JSON — this downloads all ledger events with the full verification manifest.
- Navigate to /audit-log and click Export CSV or Export JSON for the complete audit trail.
- From /reconcile, download the monthly reconciliation PDF for each period.
Account deletion
To delete your account and all associated data, email hello@grantshelf.com with your organisation ID. We will purge all records within 30 days.
Third-party data sharing
- PostHog: Anonymised product analytics — page views and feature usage only. No email, no PII, no event content is sent to PostHog. You can opt out by blocking
app.posthog.comin your network policy. - Stripe:Payment processing under Stripe's Privacy Policy. VetRx Ledger never sees raw card numbers. Stripe stores your billing email and subscription status; we store your Stripe Customer ID.
- Vercel: Hosting and edge compute. Request metadata (IP, headers, response times) is retained by Vercel per their data processing agreement.
- No data brokers. No ad networks. No data sales. VetRx Ledger does not sell, share, or transfer your data to any third party beyond the three service providers above.