Swift DMS — Security & Compliance

Last reviewed: 2026-05-21

Independent dealers handle three classes of sensitive data: customer

personally identifiable information (PII), financial records (purchase /

sale prices, banking), and vehicle history reports (VIN, accident

history). This document is the high-level overview of how Swift DMS

protects each.

Data classes + handling

Class Examples Storage At-rest encryption In-transit encryption
Customer PII Name, address, phone, DOB, DL Dealer-scoped garage_register.json, customers.json Render disk encrypted at rest by Render TLS 1.2+ on every API call
Driver's licence images DL photos Dealer's own Google Drive (per-vehicle folder) Google Drive's at-rest encryption TLS 1.2+ to Drive
Banking / financial Purchase price, sale price, financing terms Dealer-scoped garage_register.json Render disk encrypted TLS 1.2+
Vehicle history (Carfax) VHR PDFs Dealer's own Google Drive Drive at-rest TLS to Carfax + Drive
OAuth refresh tokens Google, QuickBooks Online Dealer-scoped config.json Render disk encrypted; tokens rotate; revocable via Connections sheet TLS to Intuit / Google
Passwords Dealer login config.users[].password hashed with PBKDF2-SHA256 (600k iterations) Hash, not plaintext TLS 1.2+

Tenancy model

Swift DMS is multi-tenant by Render-deployed Flask app + per-dealer

directory isolation (dealers/<dealer_id>/). Tenant scoping happens at

every request via session["dealer_id"]; no API call is allowed to

read another tenant's data. Multi-rooftop dealer groups

(groups/<group_id>/config.json) opt in to cross-rooftop reads through

the explicit location switcher; the user must be a member of the group

to switch.

Authentication & authorization

per-user salt). Brute-force protection via flask-limiter (10/min on

login, 5/hr on registration).

when served over HTTPS (always true on Render production).

nonces in OAuth flows (Google, QuickBooks) and Flask's request-scoped

session.

consume-once semantics (replay attempts log to security_audit.log),

PBKDF2-hashed token store at rest.

password match. Production refuses to serve admin routes if the

default credentials from the public repo are still in place.

OAuth integrations

Per-dealer OAuth means each dealer connects their own Google + Intuit

accounts. Swift DMS never stores access tokens (always derived from

refresh tokens at request time); refresh tokens are stored encrypted at

rest by Render's disk encryption and are revocable by the dealer from

the Connections sheet.

storage, wholesale tracking sheet sync. Tokens rotate every ~6

months; Swift re-prompts on expiry.

scope only. Used for Customer + Item + Invoice + Attachable sync on

BOS generation. Refresh tokens rotate every ~100 days; Swift detects

rotations on every refresh and persists the new token.

Compliance

Act (Canada federal). Compliance via per-dealer data isolation,

Principle 9 access right (/api/data/export returns full dealer

data as a JSON zip), retention controlled by the dealer's own

schedule.

Quebec sales. Swift DMS renders BOS PDFs in French (Pro+ tier) for QC

dealers. The dashboard UI is bilingual on the Pro+ tier.

language for the four MVDA-mandated statements (Sales Final,

Compensation Fund, As-Is, CAMVAP) from bos_template/province_rules.py

and the regulator-issued reference documents. Tests pin canonical

wording so accidental rewordings fail CI.

Backup & restore

daily snapshots.

the dealer's own Sheet (Sheets-as-backup pattern), so a Render disk

loss doesn't lose the dealer's deal history.

their full data at any time.

sheet-driven restore against an empty dealer dir; fails CI if the

restore-from-sheets round-trip breaks.

Audit logging

Security-relevant events write to a JSONL append-only log at

<DATA_ROOT>/security_audit.log:

application log)

Incident response

send_default_pii=False + a before_send PII redactor that strips

email, phone, dl_number, dob from breadcrumbs.

session expired, push delivery health amber/red).

What Swift DMS does not do

revenue. No third-party data sales, no marketing analytics that

identify your customers.

no-training data-use headers where supported. AI inbox replies are

drafted from each prospect's individual message + your replies, not

pooled across dealers.

membership controls; one rooftop's data is never visible to another

without the dealer-group owner's consent.

Reporting a vulnerability

Email security@swiftdms.ca with the issue. We acknowledge inside one

business day and aim for a fix within 7 days for critical issues

(authentication bypass, data leak across tenants, remote code

execution). Coordinated disclosure preferred; we credit reporters in

release notes unless asked not to.

Open audit findings

The Phase J audit (AUDIT.md at the repo root) tracks remaining

hardening work. As of this writing, the largest open items are:

Render disk encryption; planning per-token AES envelope encryption)