Portsie

Privacy Position and Policy

Last updated: February 25, 2026

1. Introduction

Portsie LLC ("Portsie," "we," "us," or "our") is a Texas limited liability company. This Privacy Policy describes how we collect, use, disclose, and protect your personal information when you use our website at www.portsie.com and related services (collectively, the "Service").

We've written this policy in plain language so anyone can understand how their data is handled. We also provide technical details and code references for transparency.

Our Privacy Philosophy

Portsie was built with a privacy-first architecture from the ground up — not bolted on after the fact. Our guiding principles:

  • Reduce breach impact. Even if our database were compromised, stored data should not directly identify you or reveal your financial details. Sensitive fields are encrypted and tokenized so raw database contents are useless without separate keys.
  • Minimize what we keep. We store only what is necessary for the product to function. Raw AI responses, plaintext account numbers, and other sensitive payloads are never persisted — columns that once held them have been permanently removed from the database.
  • Decrypt only when needed. Sensitive data is decrypted only in authorized server paths, never returned as raw blobs to the client, and never written to logs.
  • Build toward zero-knowledge. Our long-term goal is a Bring Your Own Backend (BYOB) mode where Portsie becomes a zero-knowledge client — your data lives entirely in your own cloud, encrypted with your own keys, and we cannot access it even if we wanted to.

Every privacy control described in this policy is implemented in code, validated by automated tests, and available for inspection in our open-source repository. We believe transparency is the strongest form of trust.

2. What Portsie Does

Portsie is a portfolio investment tracker. You can connect your brokerage account (like Charles Schwab) or upload financial documents (PDFs, CSVs, spreadsheets, images) and Portsie will extract and organize your holdings, balances, and transactions into a single dashboard.

3. Information We Collect

We may collect the following types of information:

  • Account Information: Email address, used for login and account recovery.
  • Brokerage Connection: If you connect Charles Schwab, we store OAuth tokens (encrypted) to access your account data on your behalf.
  • Financial Data: Positions (symbol, quantity, market value), balances (cash, equity, buying power), transactions (buy/sell/dividend history), and account details (account number stored encrypted, institution name, account type).
  • Uploaded Documents: Financial statements, reports, and other documents you upload for data extraction, stored in isolated per-user storage.
  • Cookies and Similar Technologies: We use essential cookies to maintain your session and preferences.

What We Do NOT Collect

  • We do not collect your Social Security number, date of birth, or government ID.
  • We do not store your brokerage password — we use industry-standard OAuth.
  • We do not collect browsing history, device fingerprints, or analytics cookies.
  • We do not sell or share your data with advertisers.

4. How We Use Your Information

  • To provide, maintain, and improve the Service.
  • To process and display your portfolio data.
  • To extract financial data from uploaded documents using AI/LLM services.
  • To authenticate your identity and secure your account.
  • To communicate with you about the Service.
  • To comply with legal obligations.

5. How We Process Your Documents

When you upload a financial document, here's what happens:

  1. Upload — Your file is stored in encrypted, per-user cloud storage.
  2. AI Extraction — The file is sent to an AI model to read and extract the financial data (positions, balances, transactions).
  3. Data Storage — Only the structured output is saved. The raw AI response is discarded immediately and replaced with a minimal diagnostic summary (model used, processing time, token count).
  4. Confirmation — Data is written to your portfolio after extraction.

Which AI Models Process Your Data?

By default, Portsie uses Google Gemini for document extraction. If Gemini is unavailable, it falls back to Claude (by Anthropic). You can also configure your own Anthropic API key in Settings.

What the AI model sees: The content of your uploaded document (text, images, or tables). This is sent via API and processed in real-time — it is not stored by the AI provider for training purposes.

What we keep: Only the structured output (positions, balances, transactions) plus a small diagnostic summary called debug_context (which model was used, processing time, token count). We do not store the full AI response, the raw extraction output, or any intermediate processing data.

What we removed: As part of our privacy hardening, we dropped database columns that previously stored raw AI responses (raw_llm_response, verification_raw_response, detected_account_info). These fields no longer exist in our database.

6. How We Protect Your Data

Privacy is built into the foundation of Portsie, not bolted on as an afterthought. We implemented a dedicated privacy layer with field-level encryption, tokenization, data minimization, and automatic log redaction — validated by a 42-test suite.

Field-Level Encryption

All sensitive fields are encrypted before storage using AES-256-GCM, the same encryption standard used by banks and governments. Each encrypted value uses a versioned ciphertext format (v1.[iv].[tag].[ciphertext]) with a unique initialization vector, making every ciphertext unique even for identical inputs. The versioned format enables future key rotation without re-encrypting all data at once.

DataProtection
Brokerage OAuth tokensAES-256-GCM encryption
Brokerage app credentialsAES-256-GCM encryption
Account numbersAES-256-GCM encryption + HMAC-SHA256 token for lookups
LLM API keys (if you provide one)AES-256-GCM encryption

Implementation: src/lib/privacy/crypto.ts

Account Number Tokenization

Account numbers receive additional protection through HMAC-SHA256 tokenization with domain separation. This creates a one-way token that lets us match "does this uploaded account number correspond to an existing account?" without ever storing the plaintext number in a searchable field. The domain separation ensures tokens generated for different purposes (e.g., account matching vs. deduplication) cannot be cross-referenced. Only a last-4-digit hint (account_number_hint) is stored in plaintext for display in the UI.

Implementation: src/lib/privacy/crypto.ts (tokenization), src/lib/privacy/mappers/accounts.ts (account number mapping)

Type-Safe Privacy

Encrypted and tokenized values use branded types in our codebase (EncryptedField, TokenizedField). This means the TypeScript compiler prevents developers from accidentally storing plaintext where ciphertext is expected, or mixing up encrypted values with tokens. Privacy violations are caught at build time, not at runtime.

Implementation: src/lib/privacy/types.ts

Data Minimization

We actively minimize data at every stage:

  • Raw AI responses are never stored. After extraction, only the structured output and a minimal debug_context (model name, timing, token count) are kept.
  • Plaintext account numbers are never stored. The original schwab_account_number column was dropped and replaced with encrypted + tokenized fields.
  • Uploaded source files have a configurable retention period (default 30 days in strict mode) and can be deleted at any time.

Implementation: src/lib/privacy/mappers/uploads.ts (extraction sanitization), src/lib/privacy/config.ts (privacy modes)

Data Isolation

  • Every database table uses Row-Level Security (RLS) — you can only access your own data, enforced at the database level.
  • Uploaded files are stored in per-user folders with access policies.
  • Admin views show redacted emails and exclude sensitive fields.

Automatic Log Redaction

All server-side logging uses a safe logging function that automatically redacts sensitive fields before they reach any log output. Account numbers, OAuth tokens, API keys, and email addresses are never written to logs. This applies across the entire pipeline: the extraction route, database writer, LLM dispatcher, data writer, and all admin endpoints.

Implementation: src/lib/privacy/redaction.ts safeLog(), redactForLog(), redactAccountNumber(), redactEmail()

Admin Endpoint Hardening

Admin API endpoints are hardened to prevent data leakage even for privileged users:

  • Quality-checks endpoints exclude raw JSONB data and mask email addresses.
  • User listing endpoints mask emails using redactEmail() (e.g., "j***@example.com").
  • No admin endpoint returns encrypted fields, tokens, or API keys.

Pipeline Hardening

The document extraction pipeline was hardened to minimize sensitive data at every step:

  • The extract route stores only debug_context — never the raw AI response.
  • Account creation stores encrypted account numbers and HMAC tokens — never plaintext.
  • Account matching uses account_number_hint (last 4 digits) instead of plaintext numbers for comparison.

Privacy Modes

Portsie supports two privacy modes controlled by server configuration:

  • Strict mode (default in production) — 30-day source file retention, maximum data minimization.
  • Standard mode (development) — relaxed retention for debugging.

Implementation: src/lib/privacy/config.ts

Transit Security

All data is transmitted over HTTPS. Communications with AI providers and brokerage APIs use encrypted connections.

Automated Testing

Our privacy protections are validated by a 42-test suite covering:

  • Encryption round-trip (encrypt → decrypt produces original value)
  • Tokenization determinism (same input always produces same token)
  • Domain separation (tokens for different purposes cannot be cross-referenced)
  • Log redaction (sensitive fields never appear in log output)
  • Privacy mode configuration

7. Data Retention

DataRetention
Account and portfolio dataKept until you delete your account
Uploaded source files30 days after processing (strict mode); configurable
Raw AI responsesNever stored (columns removed from database)
AI diagnostic contextKept with upload metadata (model name, timing only)
Brokerage tokensKept until you disconnect; auto-expire
Account numbers (plaintext)Never stored (column removed from database)

You can delete any upload and its associated data at any time from the dashboard. When an account is deleted, all associated data is permanently removed via cascading deletes.

8. Schema Changes for Privacy

We actively remove database columns that could store sensitive data unnecessarily. The following columns were dropped as part of our privacy hardening:

TableRemoved ColumnReplaced With
accountsschwab_account_numberEncrypted field + HMAC token + last-4-digit hint
uploaded_statementsraw_llm_responseMinimal debug_context
uploaded_statementsverification_raw_responseNot replaced (unnecessary)
uploaded_statementsdetected_account_infoNot replaced (unnecessary)
extraction_failuresraw_llm_responseNot replaced (unnecessary)

9. Third-Party Services

Cloud Infrastructure

Supabase (database, authentication, file storage) — hosted on AWS in Seoul (ap-northeast-2). Your data is encrypted at rest by Supabase/AWS. Supabase cannot read our application-level encrypted fields without our encryption keys.

AI Providers

  • Google (Gemini) — processes uploaded documents for data extraction. Google's API terms state that API data is not used for model training.
  • Anthropic (Claude) — fallback extraction engine and optional user-configured provider. Anthropic's API terms state that API data is not used for model training.

What Third Parties See

  • AI providers see the content of your uploaded documents during processing (not stored by them, not used for training).
  • Supabase/AWS stores your encrypted data (they cannot read application-encrypted fields without our encryption keys).
  • No other third parties receive your data.

10. Current Architecture: Managed Cloud

In the current managed cloud mode:

  • Portsie operates the infrastructure (Supabase project, encryption keys, AI API keys).
  • Your data is encrypted at rest and in transit.
  • Row-Level Security ensures each user's data is isolated at the database level.
  • Encryption keys are stored as server environment variables — the Portsie team has access to them for operational purposes.

What this means: While your data is strongly protected against external threats and other users, the Portsie team technically has the ability to decrypt sensitive fields using the server-side encryption keys. This is standard for managed cloud services (similar to how your bank can access your account data).

11. Future: Bring Your Own Backend (BYOB)

We are building a Bring Your Own Backend (BYOB) mode where you can:

  • Provide your own Supabase project — your data lives entirely in your own cloud account.
  • Provide your own encryption keys — Portsie never sees or stores them.
  • Provide your own AI API keys — documents are processed using your own accounts.

In BYOB mode, Portsie becomes a zero-knowledge client: the application code runs against your infrastructure, and we cannot access your data even if we wanted to. This is the strongest privacy guarantee possible for a cloud application.

BYOB mode is not yet available. When it launches, existing users will be able to migrate their data to their own backend.

12. Your Rights

Depending on your jurisdiction, you may have the right to:

  • Access — View all your data in the dashboard at any time.
  • Delete — Delete individual uploads, accounts, or your entire account.
  • Export — Your financial data is yours; we support data export.
  • Control — Choose which AI provider processes your documents and bring your own API key.
  • Request correction of inaccurate data.
  • Object to or restrict certain processing.

Texas residents may have additional rights under the Texas Data Privacy and Security Act (TDPSA). To exercise any of these rights, contact us using the information below.

13. Privacy Documentation

For full technical transparency, we maintain the following internal documentation that describes our privacy architecture in detail:

  • Privacy Architecture & Controls — Threat model, encryption scheme, data flow, trust boundaries.
  • Data Classification Matrix — Per-table, per-field classification (public, internal, confidential, restricted) with storage treatment.
  • Operations Runbook — Key generation/rotation procedures, retention enforcement, incident response checklist.

All code references in this policy point to files in our public GitHub repository: github.com/modern-investor/portsie. You can verify any implementation detail yourself.

Privacy implementation: src/lib/privacy/ — encryption, tokenization, redaction, privacy config, and field mappers. Privacy documentation: docs/ — architecture, data classification, and operations runbook.

14. Children's Privacy

The Service is not intended for individuals under the age of 18. We do not knowingly collect personal information from children.

15. Changes to This Policy

We may update this Privacy Policy from time to time. We will notify you of material changes by posting the updated policy on this page with a revised "Last updated" date.

16. Contact Us

If you have questions about this Privacy Policy or how your data is handled, please contact us at: privacy@portsie.com