Resets LastSyncAt on all linked accounts so the next sync
re-fetches the full 90-day transaction window. Duplicate
detection prevents re-importing existing transactions.
- POST /api/bank-sync/connections/{id}/reset-sync endpoint
- Re-sync button shown only on SimpleFIN connection cards
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Npgsql requires DateTimeKind.Utc for timestamp with time zone
columns. This fixes errors in transaction create/edit, budgets,
reports, loans, scheduled transactions, and file imports.
Changes:
- TransactionService: SpecifyKind on request.Date for create,
update, and transfer
- BudgetService: UTC kind on all new DateTime(year, month, 1)
- ReportService: UTC kind on endOfMonth; rewrite spending-by-
category GroupBy to avoid untranslatable navigation properties
- LoanService: UTC kind on payoff scenario date construction
- ScheduledTransactionService: UTC kind on SemiMonthly date
- ImportService: SpecifyKind on parsed.Date when persisting
- OFX/CSV/QIF parsers: AssumeUniversal + AdjustToUniversal on
all date parsing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
EF Core cannot translate GroupBy with a navigation property
(Category.Name) joined via nullable FK into SQL. Split into two
queries: group by CategoryId server-side, then look up category
names in a separate query.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Math.Abs() inside a GroupBy().Select() cannot be translated to
SQL by EF Core. Since the query already filters for Amount < 0,
negating the sum produces the same result and translates cleanly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Track completion in a `data_migrations` table. On startup the
migration checks if it has already been applied and skips the
SimpleFIN API calls entirely, avoiding the slow startup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrap edit/delete buttons in a flex container so they render
side by side instead of stacking. Fix Dashboard DateTime to use
UTC kind, which Npgsql requires for timestamp comparisons.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Runs once at startup after DB migrations. For each SimpleFIN
connection, re-discovers accounts from the API, groups by
institution, and splits connections that contain accounts from
multiple banks. Existing sync state and account mappings are
preserved.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Group discovered SimpleFIN accounts by institution and create a
separate SyncConnection per institution so each bank appears as
its own card in the UI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
UpdateAccountRequest was missing the Type field, so changes to
account type were silently ignored. Add Type to the DTO and apply
it in the update service method.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of showing defaults as greyed-out placeholder text, populate
textareas with the actual default prompt text so users can directly
edit it. Add {categories}, {examples}, and {transactions} placeholders
so users control where dynamic data is inserted in the prompts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add SystemPrompt and UserPromptTemplate fields to AI categorization
settings so users can customize the prompts sent to Ollama without
code changes. Null/empty values fall back to built-in defaults.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds local LLM-based transaction categorization using Ollama:
- Settings UI to configure Ollama URL, model, confidence threshold
- Auto-categorization during bank sync and file import
- Manual "Classify Uncategorized" button on Transactions screen that respects active filters
- Payee default category learning loop for classified transactions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DateOnly.ToDateTime() produces Kind=Unspecified which Npgsql rejects
for timestamptz. Specify UTC kind on Plaid transaction dates and add
a safety net in BankSyncService for all parsed dates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Plaid ClientId/Secret are now stored per-user in the database
(encrypted) instead of in appsettings.json. Users enter their own
Plaid developer credentials in the Settings > Bank Connections tab.
- New BankSyncSettings model (1:1 with User) for encrypted credentials
- PlaidSyncProvider is now stateless, receives credentials per-call
- Settings UI shows a credentials card with save form
- Connect via Plaid button disabled until credentials are configured
- Removed Plaid section from appsettings.json
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add automated transaction syncing via Plaid and SimpleFIN providers,
a Settings page for managing connections and account mappings,
background scheduled syncing, and sync history logging.
New backend: BankSync plugin project with PlaidSyncProvider and
SimpleFinSyncProvider, SyncConnection/LinkedAccount/SyncLog models,
AES-256 encryption service, BankSyncService orchestration,
BankSyncBackgroundService (15-min tick), and BankSyncController
(13 endpoints). EF migration creates sync_connections,
linked_accounts, and sync_logs tables.
New frontend: Settings view with 3 tabs (Profile, Bank Connections,
Sync History), bankSync API service, BankSyncComplete SignalR
notifications, and Settings nav item in sidebar + avatar dropdown.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add full frontend UI for five backend features: bank reconciliation (3-step
stepper workflow), payee management (CRUD with alias chips), transaction splits
(expandable rows + split editor), plugins (card grid), and real-time SignalR
notifications (bell dropdown with badge). Fix backend PayeeResponse to expose
alias IDs for deletion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Complete the import flow from file upload through duplicate resolution
to transaction creation. Previously, ResolveDuplicatesAsync was a stub
that only incremented counters, FileWatcherService detected files but
didn't process them, and ImportsView.vue ignored the API response.
Backend:
- Add ParsedDataJson column to ImportBatch to persist parsed data
between upload and confirm steps
- Rewrite ImportService.ResolveDuplicatesAsync to deserialize parsed
transactions and create/merge/skip based on user decisions, with
payee matching, fingerprinting, and account balance updates
- Add GetBatchesAsync for import history
- Complete FileWatcherService: wait for file ready, resolve account by
filename, call UploadAsync, send SignalR notification, archive file
- Add GET /api/imports/batches endpoint
Frontend:
- Create imports API service (frontend/src/services/imports.ts)
- Add ImportBatch, DuplicateResolution types
- Rewrite ImportsView.vue with 3-step Vuetify stepper wizard:
upload, review with duplicate handling, completion summary,
plus import history table
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>