Skip to main content

Account Type System Guide

Understanding Types, Subtypes, and Calculations for Plaid & SnapTrade

Last Updated: 2025-10-22
Related Docs: SNAPTRADE-ACCOUNTS-TABLE.md, SNAPTRADE-TYPE-MIGRATION.md

📚 Table of Contents

  1. Overview
  2. Core Concepts
  3. Plaid Account Type System
  4. SnapTrade Account Type System
  5. Type Mapping & Translation
  6. User Overrides
  7. Calculations & Grouping
  8. The getEffectiveAccountType Function
  9. Data Flow Diagrams
  10. Common Pitfalls

Overview

Portfolio Tracker integrates with two main financial data providers:
  • Plaid: Bank accounts, credit cards, loans (traditional banking)
  • SnapTrade: Brokerage accounts (investment platforms like Fidelity)
Both use a two-tier categorization system (Type + Subtype), but they arrived at this system differently.

Core Concepts

Type vs Subtype

Type (Tier 1): Broad category
  • investment - Accounts with stocks, bonds, mutual funds
  • depository - Cash accounts (checking, savings)
  • credit - Credit cards
  • loan - Loans, mortgages
Subtype (Tier 2): Specific account detail
  • 401k, ira, roth - Retirement account types
  • brokerage - Taxable investment account
  • checking, savings - Bank account types
  • credit card - Credit card type

Why Two Tiers?

  • Type determines where money goes in calculations
    • Investment → Portfolio Value
    • Depository → Cash on Hand
    • Credit/Loan → Debts
  • Subtype determines how it’s displayed and grouped
    • 401k, IRA → Retirement group
    • Brokerage → Taxable Investments group

Plaid Account Type System

How Plaid Works

Plaid connects to banks and returns accounts with pre-assigned types and subtypes:

Plaid’s Type Hierarchy

Database Storage (Plaid)

Table: accounts Why both?
  • source_* = What Plaid said originally (never changes)
  • type/subtype = What user wants it to be (can be changed)

SnapTrade Account Type System

How SnapTrade Works

SnapTrade returns brokerage accounts with a single-tier type system:
Problem: SnapTrade’s "401K" is specific (like a subtype), but we need a broad category (type) for calculations.

Our Solution: Map to Plaid Format

We translate SnapTrade’s single-tier system to Plaid’s two-tier system:

Database Storage (SnapTrade)

Table: snaptrade_accounts Note: SnapTrade has 6 type-related columns (vs Plaid’s 4) because we need to preserve the original SnapTrade format.

Type Mapping & Translation

SnapTrade → Plaid Conversion

When: During account creation (process-connection/route.ts)

Why This Matters

Before mapping:
After mapping:

User Overrides

Why Allow Overrides?

Sometimes categorizations are wrong:
  • Plaid might mark a brokerage account as “depository”
  • User might want to categorize differently for personal reasons
  • Institution might not provide accurate account types

How Overrides Work

1. User Changes Type:
2. Detection:
3. Reset to Default:

Override Detection Example


Calculations & Grouping

How Accounts Are Categorized

Primary Rule: Use the type field to determine category

Net Worth Calculation

Account Grouping in UI

By Type:
  • Retirement: subtype includes retirement keywords (401k, ira, roth, etc.)
  • Investments: type = 'investment' AND not retirement
  • Cash: type = 'depository'
  • Credit Cards: type = 'credit'
  • Loans: type = 'loan'
Example Code:

The getEffectiveAccountType Function

Purpose

Determines the actual type to use for calculations, handling:
  1. User overrides (always respected)
  2. Edge cases (depository with investments → treat as investment)
  3. Backward compatibility

Location

lib/account-type-utils.ts

Logic Flow

Why This Matters

Without getEffectiveAccountType():
With getEffectiveAccountType():

Usage Across Codebase

Daily Snapshots:
Real-Time Calculations:

Data Flow Diagrams

Plaid Account Creation

SnapTrade Account Creation

User Override Flow


Common Pitfalls

❌ Pitfall 1: Hardcoding SnapTrade Types

❌ Pitfall 2: Forgetting Fallbacks

❌ Pitfall 3: Not Using getEffectiveAccountType

❌ Pitfall 4: Comparing Type to source_account_type

❌ Pitfall 5: Ignoring Hidden Accounts


Quick Reference

Key Files

Key Database Tables

Type Values (Tier 1)

  • investment - Investment accounts
  • depository - Cash/bank accounts
  • credit - Credit cards
  • loan - Loans, mortgages
  • other - Other account types

Common Subtypes (Tier 2)

Investments:
  • 401k, 403b, 457b - Employer retirement plans
  • ira, roth, sep - Individual retirement accounts
  • brokerage - Taxable investment account
  • 529 - Education savings
Depository:
  • checking - Checking account
  • savings - Savings account
  • money market - Money market account
  • hsa - Health savings account
Loans:
  • mortgage - Home mortgage
  • auto - Car loan
  • student - Student loan

Testing Your Understanding

Quiz 1: What type/subtype would these be?

  1. Fidelity 401(k) (SnapTrade) → ?
  2. Chase Checking (Plaid) → ?
  3. Vanguard Roth IRA (SnapTrade) → ?
  4. Capital One Credit Card (Plaid) → ?
Answers:
  1. type: "investment", subtype: "401k"
  2. type: "depository", subtype: "checking"
  3. type: "investment", subtype: "roth"
  4. type: "credit", subtype: "credit card"

Quiz 2: Will this account be in the retirement group?

Answer: YES (subtype is “401k”, which is in retirement subtypes list)

Quiz 3: Does this account have a user override?

Answer: YES (type !== source_type)

Migration History

Before Migration (Old System)

SnapTrade accounts:
Problems:
  • Can’t easily group by category
  • Hardcoded type checks everywhere
  • No user override support
  • Inconsistent with Plaid

After Migration (New System)

SnapTrade accounts:
Benefits:
  • ✅ Unified with Plaid
  • ✅ Easy category grouping (type === 'investment')
  • ✅ User override support
  • ✅ Historical tracking (snapshots save type/subtype)
  • ✅ Backward compatible (old code still works with fallbacks)

Summary

  1. Both Plaid and SnapTrade use a two-tier system (Type + Subtype)
  2. Type determines calculations, Subtype determines display
  3. source_* columns are immutable (what provider said)
  4. type/subtype columns are mutable (user can override)
  5. Always use getEffectiveAccountType() for calculations
  6. User overrides are detected by comparing type to source_type
  7. SnapTrade accounts get mapped from SnapTrade format → Plaid format
  8. Backward compatibility via fallbacks: account.type || account.account_type

Questions? See:
  • SNAPTRADE-ACCOUNTS-TABLE.md - Detailed SnapTrade column reference
  • CRITICAL-VERIFICATION-CHECKLIST.md - Calculation path audit
  • lib/account-type-mappings.ts - Full mapping table