Dev updates

Changelog

What changed in Zedi and when, written from the commit log by the one person who writes the commits. Each entry lists work that is merged on the dev branch as of that date. Production trails dev by a bit, so promotions are called out on their own line.

Found a bug or want something moved up? Email [email protected].

  1. Mobile menu, this page, and small fixes

    • The marketing site has a mobile menu. Below the desktop breakpoint the section links moved into a slide-out sheet behind a hamburger, so phone visitors can reach Product, Compare, Pricing and FAQ.
    • This changelog. Entries live in the repo next to the code, and this page is where dev updates get posted from now on.
    • Import: when a PDF extraction succeeds but the automatic commit fails, the extracted preview is kept so you can review and commit it by hand instead of losing the work.
    • People: the person detail page links back to the People list.
    • Landing page copy corrected: forward-by-email gives you one inbound address for your whole account, not one per bank.
    • CI now runs on every push and pull request to the dev branch, and the Docker build contexts got a .dockerignore.
  2. Import overhaul: PDF extraction runs in the background

    • PDF statement extraction is a background job. Upload returns right away and the import page polls the statement until the preview is ready, so a long statement no longer times out behind the web proxy. The copy no longer promises a 30 second extraction.
    • Stuck and abandoned statements are swept automatically: an extraction that never finished is marked failed, and a preview nobody committed expires.
    • QFX rows now carry the same fingerprint as CSV rows, so a transaction imported once as CSV and again as QFX is deduplicated across formats.
    • Reconciliation counts interest lines, and the extraction request keeps its schema key order, which cut extraction latency by a wide margin.
    • The import page was split into smaller components: the PDF panel with polling, the statements table, and the import history table.
  3. Every feature branch merged onto dev

    • Investments, in development and not yet in production: Schwab brokerage CSV exports (activity history and positions snapshots) import into a dedicated investments domain instead of the transactions table, with a new Investments page showing holdings, activity, allocation and value over time. The net position card buckets investment balances separately from cash.
    • People: Venmo and Zelle counterparties are tagged during CSV import, each person shows a net balance, unmatched names land in a review tray on the import page, and receipt splits get a Request via Venmo button. Venmo exports are detected by header and there is a Venmo account type.
    • Forward-by-email ingest, prototype: a private inbound address per account, an approved-sender list, and an activity log under Settings, Connections. The inbound worker is not deployed yet, and the card hides itself until an ingest domain is configured.
    • Settings, Connections: connect and disconnect Google and Apple sign-in on an existing account.
    • New signups must verify their email address before reaching the dashboard, with a dedicated page explaining the wait.
    • Theme: an info status color joins success, warning and danger across all 14 themes, and the import page stopped using raw palette classes.
    • A Yahoo Finance client and an internal-secret middleware are in place for the upcoming daily price refresh; the refresh route itself is still being rebuilt on the investments tables. Nothing prices holdings yet.
  4. Hotfix: intermittent 500s on ordinary requests

    • Fixed bursts of 500 errors that could hit any signed-in request, including PDF imports that failed with "internal server" and no log line. The backend fetched the signing keys for session tokens once per concurrent request when its cache expired and tripped the auth rate limit. Refreshes are now single-flight, a failed refresh serves the last good key set for 15 seconds, and the keys endpoint gets the same rate-limit rule as session checks.
    • Deleting an account that had PDF statements no longer fails: the migration that cascades import runs on statement delete existed on disk but was never registered with the migration runner. It is now.
    • The receipt library is paginated, 20 receipts per page, with the total counted under the same filters as the page.
    • Receipts: the store name input no longer stretches the card while editing.
    • Shipped to production the same evening.
  5. Filter-aware overview and analytics filters

    • Transactions: the Overview tiles follow whatever filter is active (category, search, type, amount, hidden, review flags) and are labeled Filtered when they do.
    • Analytics: a category filter including Uncategorized, plus include and exclude modes on both the category and account dimensions, applied to the KPIs, spending mix, trends, merchants and the pivot card. Choices persist locally and mirror into the mobile filter sheet.
    • Analytics: the spending donut labels its slices and wraps its legend instead of clipping it.
    • Import: the PDF statements table shows which account each statement targets.
  6. Rendering sweep

    • Dashboard KPI sparkline tooltips are no longer clipped by their card.
    • The Uncategorized filter on transactions works again.
    • Assorted rendering fixes across the signed-in app.
  7. Email verification, durable Stripe webhooks, rate limits

    • Email verification is enforced for new accounts.
    • Stripe webhooks are recorded before they are processed, so a failure during processing can be retried instead of losing a subscription change.
    • Auth rate limiting works as configured, and the API has its own rate limits.
    • Error boundaries around the signed-in app, and database pool sizing tuned for the hosted environment.