Data Handling & Privacy

This page is the honest inventory: what personal data AVA stores, where it
lives, which third parties it reaches and why, what retention levers exist
today, and what that means for GDPR-style obligations. It describes the
shipping v1.6.3 codebase. How the system is built and secured is covered in
architecture-security.md.

The one-sentence summary: AVA is single-tenant and self-hosted — every byte
lives on infrastructure the deploying MSP controls
, and data leaves that
host only for the integrations the MSP itself configures (AutoTask, an AI
provider, email, reCAPTCHA, optionally NinjaOne).


Where data lives

LocationWhat's thereWho controls it
SQLite database (Docker volume, e.g. ava-data)Sessions, transcripts, survey ratings, engineer accounts, canned responsesYou (the deploying MSP)
Uploads directory (Docker volume, e.g. ava-uploads)Chat file attachments, per-session, under UUID filenamesYou
Host-side env file (mounted read-only)All credentials and configurationYou
Your AutoTask instanceTickets, contacts, notes, transcripts, time entries, attachmentsYou, under your existing AutoTask agreement
Your AI provider (Anthropic / OpenAI / Google / OpenRouter — your choice, your key)Transcript-derived text at specific call sites (detailed below)You, under your provider agreement
SMTP2GO (or your SMTP relay)Outbound emails in transitYou, under your SMTP agreement
Google reCAPTCHABot-detection signals from the public chat pageGoogle, per reCAPTCHA terms
NinjaOne (optional)Hostname/username lookup queries; device telemetry read backYou, under your NinjaOne agreement

There is no vendor-operated backend in any path: the product vendor (Aixtek
Automation Labs) receives no telemetry, no analytics, and no customer data
from your deployment.


What AVA stores locally

Chat sessions (SQLite, Session table)

Captured from the public contact form and the chat lifecycle:

  • Client first name, last name, email address, phone number.
  • Company name/domain (derived from the email domain's AutoTask match).
  • The issue description as typed by the client.
  • AI triage output: priority (P1–P4), AutoTask issue-type classification, and
    a one-line topic summary derived from the issue description.
  • AutoTask linkage IDs (ticket, company, contact) — numeric references, not
    copies of AutoTask data.
  • Optional device-lookup hints (hostname, username, domain) if the client
    arrived via an RMM systray link that supplied them. These are sanitized,
    length-capped, used only as lookup keys, and scrubbed from the browser URL
    immediately after capture.
  • Wrap-up fields: the engineer's closure notes draft, resolution choice, and
    step-completion checkpoints.
  • Timestamps (created, closed, updated) and the assigned engineer.

Transcripts (Message table)

Every message in every chat — client, engineer, and system lines — with
sender, content, and timestamp. Anything a client types into the chat is
stored verbatim
, so transcripts can contain whatever personal data clients
choose to share. Attachment references are stored as message metadata.

Attachments (uploads volume)

Files uploaded by either side of a chat, stored under
uploads/<sessionId>/<uuid> — the client's original filename is kept only as
display metadata, never as a filesystem path. Subject to the retention job
described below.

Survey ratings (SurveyRating table)

An optional post-chat rating (1–5 stars) and free-text comment, at most one
per session, linked to the session.

Engineer accounts (Engineer table)

Work email, display name, role, an AutoTask resource-ID mapping, and an
offboarding timestamp. Populated from Entra ID sign-in — no passwords are
ever stored (authentication is delegated to Microsoft).

Client browser storage

The chat page keeps its state (session token, contact info for reconnect,
device hints) in the browser's sessionStorage/localStorage for the
duration of the visit. No third-party analytics or advertising trackers are
present on either the client page or the dashboard.


What is written to AutoTask

AutoTask is where a chat becomes a permanent operational record. On session
start, AVA:

  • Matches the client's email domain to one of your AutoTask Companies
    (falling back to your configured catchall company for personal domains).
  • Finds or creates a Contact — writing the client's name, email, and
    phone into your AutoTask instance if no contact exists yet.
  • Opens a Ticket carrying the client's issue description and the triage
    classification (priority, issue type, summary), using your configured
    default status/queue/source/type values.

On close (the engineer's wrap-up), AVA writes to the ticket:

  • A time entry (engineer-reviewed billed hours, attributed to the
    engineer's mapped AutoTask resource).
  • A client-facing note and an internal note, both engineer-authored
    (optionally AI-drafted, always engineer-reviewed before submit).
  • The full chat transcript as its own note — sender labels, timestamps,
    and message content verbatim.
  • Any chat attachments, uploaded to the ticket.
  • The resolution field and the final ticket status.

Once data is in AutoTask it is governed by your AutoTask instance's own
retention, access control, and data-processing terms — AVA does not manage it
further. If you handle an erasure request, remember the AutoTask copy exists
alongside the local one.


What reaches the AI provider

AI calls go to whichever provider you configure (LLM_FAST / LLM_QUALITY),
directly, using your API key — there is no intermediary. Prompts also include
your configured company name/descriptor/profile (branding, not client data).
The exact data scope per call site:

Call siteWhen it firesData sent to the model
TriageAutomatically, once per new chatClient's name, the email domain only (not the full address), the issue description, and your live AutoTask issue-type picklist labels
Field summarizer (wrap-up "draft with AI" buttons)Only when an engineer clicks itThe session transcript — sender roles + message content, capped at ~24k characters (most recent kept). No client contact fields are attached, but the transcript itself contains whatever was typed in chat
Transcript summarizer (quality tier)When a long-form summary is generatedSame transcript scope and cap as the field summarizer
Similar resolutionsEngineer's context panel during a chatThe current issue text plus titles, descriptions, and resolution notes of recently closed AutoTask tickets (count- and length-capped)
Ticket trendsEngineer's context panel during a chatMetadata of the client company's recent AutoTask tickets — number, title, capped description, status, type, dates

Honest notes:

  • Transcript-derived calls can carry any personal data a client typed into
    the conversation. If a client pastes a password into chat, that text is in
    the transcript, and the transcript is what gets summarized. (The default
    welcome message warns clients not to share passwords, and you can
    customize it.)
  • All inputs are length- and count-capped; model outputs are
    schema-validated where they drive ticket fields; failures degrade to
    non-AI fallbacks. See
    architecture-security.md.
  • Whether the provider retains or trains on API traffic is governed by
    your agreement with that provider — review your chosen provider's API
    data-use terms as part of your own compliance work. Switching providers is
    an env-var change, so you can standardize on whichever provider your
    privacy posture requires.

What reaches other services

  • Email (SMTP2GO or your relay). Three outbound paths, all
    operator-configured, all fail-closed when unconfigured (the send is
    skipped, never redirected to a default address): the after-hours
    email-a-ticket form (client name, email, phone, and message → your
    configured support mailbox), engineer feedback submissions
    (FEEDBACK_EMAIL), and the weekly survey report (REPORTS_EMAIL — note
    this report contains personal data: per-rating lines naming the client,
    their company, the engineer, the ticket number, and any comment text, plus
    the aggregates).
  • Google reCAPTCHA v3. The public chat page loads reCAPTCHA, so Google
    receives the bot-detection signals that service inherently collects from
    visitors; the server then verifies the token with Google. This is the only
    third-party script on the client page. Publish this in your own privacy
    notice.
  • Microsoft Entra ID. Engineer sign-in only. No client data flows to
    Microsoft.
  • NinjaOne (optional, off by default). When configured, AVA sends the
    session's hostname/username hints (and the client email's local part as a
    last-resort search key) to your NinjaOne tenant to find the device, and
    reads back telemetry for display. The credential you create is
    monitoring-scope (read-only). No chat content is ever sent to NinjaOne.

IP addresses

Client IPs are used for in-memory rate limiting (session starts, uploads) and
are not persisted to the database. The nginx access logs on your host do
record client IPs, subject to the built-in log rotation (10 MB × 3 files per
service); the provided log format omits URL query strings.


Retention & erasure levers

What exists today, honestly labeled:

DataMechanismDefault
AttachmentsAutomatic: an in-process retention job deletes each closed session's upload directory once closedAt is older than the window — regardless of whether the AutoTask upload succeededOn; 30 days (UPLOAD_RETENTION_ENABLED, UPLOAD_RETENTION_DAYS, UPLOAD_RETENTION_INTERVAL_HOURS — every 6 h)
Attachments (earlier)Automatic: on a fully successful wrap-up, local files are purged as soon as every attachment is confirmed uploaded to AutoTaskAlways on
Sessions, transcripts, survey ratingsOperator-managed: rows persist in SQLite indefinitely. There is no built-in retention window or self-service erasure UI today
AutoTask copiesGoverned by your AutoTask instance
BackupsWhatever your backup tooling retains

To honor an erasure request for the local copy, delete the session's rows
directly (children first — messages and any survey rating, then the session),
remove its upload directory if one still exists, and handle the AutoTask
ticket/contact side in AutoTask itself. For example, against the database
file with the sqlite3 CLI:

-- Replace :sid with the session id
DELETE FROM Message      WHERE sessionId = :sid;
DELETE FROM SurveyRating WHERE sessionId = :sid;
DELETE FROM Session      WHERE id = :sid;

Stop the container (or take the write briefly offline) before editing the
database file directly, and take a backup first.


Backup implications

The two Docker volumes — the SQLite database and the uploads directory — are
the complete local data set, and both contain personal data. Practical
consequences:

  • Backups of those volumes inherit every transcript and attachment; encrypt
    them at rest and give them a retention period consistent with your privacy
    commitments — an erasure performed on the live database does not reach
    last month's backup unless your process says it does.
  • The host-side env file contains all credentials. Back it up separately
    from and more restrictively than data backups (it is deliberately not in
    the repository or the image), and keep it chmod 600 — the app warns at
    boot if it is group- or world-readable.
  • A consistent SQLite backup is easiest taken while the container is
    stopped, or via SQLite's online-backup tooling; a plain file copy of a
    database under active write can be torn.

GDPR / privacy FAQ

Who is the data controller?
You, the deploying MSP. AVA is self-hosted, single-tenant software; the
product vendor operates no service in the data path and receives no personal
data from your deployment. You remain controller (or processor for your own
clients, per your MSA) exactly as you are for the rest of your stack.

Who are the sub-processors?
Only the services you configure: your AutoTask instance, your chosen AI
provider, your SMTP provider, Google (reCAPTCHA), Microsoft (engineer SSO),
and optionally your NinjaOne tenant. Most MSPs already have agreements with
most of this list. There are no hidden ones.

Where does the data physically reside?
Wherever you run the container. Nothing constrains hosting region — an
EU-resident deployment on an EU host keeps the local data set in the EU;
integration traffic goes wherever your configured providers operate.

Can I answer a data-subject access request?
Yes — everything local is in two well-defined places (the SQLite tables
described above, plus the session's upload directory), keyed by the client's
email address on the Session table. Remember the AutoTask copy.

Can I honor an erasure ("right to be forgotten") request?
Yes, but it is operator work today: SQL deletion for the local rows, file
deletion for any remaining uploads, and AutoTask-side cleanup — see
Retention & erasure levers. There is no
one-click erasure feature yet.

Is chat data used to train AI models?
AVA itself does no training and keeps no vendor-side copy. Whether your AI
provider retains or trains on API traffic is set by your agreement with that
provider — check its API data-use terms and pick your provider accordingly.

What cookies does it set?
The dashboard sets one first-party, HttpOnly session cookie for signed-in
engineers. The client chat page uses browser session storage (not cookies)
for its own state, plus whatever reCAPTCHA sets under Google's terms. There
are no advertising or cross-site tracking cookies.

How long are clients' IP addresses kept?
In the application: only in memory, for rate limiting — never written to the
database. On the host: in rotated nginx access logs (bounded at roughly
30 MB per service by the shipped log-rotation config).

What should my client-facing privacy notice cover?
At minimum: that chat contents become part of the support ticket in your PSA;
that AI assists triage and summarization (naming your provider if your
notice style requires it); reCAPTCHA's presence on the chat page; and your
retention periods for transcripts and attachments.


What to read next


Did this page help you?