Commit Graph

16 Commits

Author SHA1 Message Date
Spencer Twaddle da6eb547ce Phase 3+4: Wire react-hook-form+zod into all form pages; disable buttons during submit 2026-05-02 17:09:31 -05:00
Spencer Twaddle 95665e5baa Phase 2: Create zod schemas in src/schemas/index.ts 2026-05-02 17:01:55 -05:00
Spencer Twaddle afeff4b308 Phase 1: Install react-hook-form, zod, @hookform/resolvers 2026-05-02 17:01:21 -05:00
Spencer Twaddle ae28abdb3e Phase 12: Add TanStack React Query
- Install @tanstack/react-query
- Create queryClient with MutationCache for global toast on success/error
- QueryToastBridge component bridges module-level handlers to ToastProvider
- Wrap App in QueryClientProvider
- Create domain hook files: budgets, incomes, outgos, shares, summary
- Update all 5 pages to use hooks; remove inline useEffect/useState fetch logic
- DnD reorder pages use local displayItems state synced from query data
2026-05-02 16:48:00 -05:00
Spencer Twaddle b33ff5079c Replace custom AuthContext with react-oidc-context
Deletes the hand-rolled AuthContext/UserManager setup and replaces it
with AuthProvider from react-oidc-context. onSigninCallback clears the
OIDC code params from the URL (unless an error is present). TokenSync
bridges the library token into the existing api/client setTokenProvider
pattern. AuthGuard updated to use auth.isLoading/isAuthenticated/
signinRedirect from the library. CallbackPage simplified to a passive
error renderer — react-oidc-context processes the OIDC exchange itself.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:38:12 -05:00
Spencer Twaddle 65701cbdb8 Add react-oidc-context dependency
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:37:01 -05:00
Spencer Twaddle 4dc5ad4910 Rework client OIDC env vars: rename to VITE_OIDC_*, add committed .env
Renames VITE_AUTH_* to VITE_OIDC_* to match the stack convention.
Adds a dedicated VITE_OIDC_POST_LOGOUT_REDIRECT_URI instead of deriving
it from the redirect URI via string replace. Switches from Dockerfile
ARG/ENV to a committed src/Budget.Client/.env so Vite picks up
production values at build time without needing build-arg overrides.
.env.local is gitignored for localhost dev overrides.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 15:57:52 -05:00
Spencer Twaddle 71bd88ace9 Fixed some critical bugs 2026-05-02 15:50:03 -05:00
Spencer Twaddle 6d1bc2ce2c Security hardening
- Remove OwnerUserId from BudgetDto: OIDC sub of the budget owner was
  being returned to all collaborators (including View-only users)
- Remove SharedWithUserId from ShareDto: other users' internal OIDC subs
  were visible to anyone with read access to a budget
- Delete MeController: scaffolding endpoint that returned sub to the
  browser; no legitimate frontend use case
- Restrict /healthz to require authorization: prevents unauthenticated
  probing of database connectivity
- Add input validation annotations to all request DTOs: [Required],
  [MaxLength], [Range(0,0.9999)] on EffectiveTaxRate, [EmailAddress] on
  share email — [ApiController] now returns 400 instead of 500 for
  invalid input hitting DB constraints
- Replace User.FindFirst("sub")!.Value with GetUserId() extension across
  all controllers: returns 401 instead of NullReferenceException (500)
  if a token lacks a sub claim

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 09:00:33 -05:00
Spencer Twaddle 45f921bb71 Phase 8: Polish and production readiness
- Add ErrorBoundary component wrapping the whole app
- Add ToastProvider with showError/showInfo; Income and Outgo pages use it for API errors
- Add LoadingSkeleton component with shimmer animation; Income and Outgo show it while loading
- Add confirm-on-delete dialogs for income and outgo rows
- Apply EF migrations automatically on startup via MigrateAsync()
- Add /healthz health check endpoint using DbContext check
- Add Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore package

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 08:03:05 -05:00
Spencer Twaddle 64203606a6 Phase 7: Budget list, settings, and sharing UI
- Implement BudgetsPage: list all budgets, create new budget, navigate to income view
- Implement SettingsPage: rename budget, edit tax rate, manage shares table
- Shares table shows permission dropdowns, pending status badge, revoke button
- Add share form: email input, permission selector, add button
- BudgetNav component used across all budget pages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 07:59:40 -05:00
Spencer Twaddle 69d6ac0bea Phase 6: Summary API and page
- Add SummaryController: computes monthly income, breakdown by type (Need/Want/Save/Unspent), and pre-tax income
- Need/Want/Save get target% (50/30/20), maxAmount, and remaining; Unspent shows totals only
- PUT /summary/tax-rate updates EffectiveTaxRate on the budget (no new migration needed)
- Add SummaryDto, SummaryBreakdownItem, PreTaxIncomeDto DTOs
- Add Summary page: income header cards, type breakdown table with ⓘ tooltip for target%,
  pre-tax section with editable tax rate field

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 07:58:54 -05:00
Spencer Twaddle 38296bc22a Phase 5: Outgo API and page
- Add OutgosController: list, create, update, delete, reorder, categories, payment-sources endpoints
- Outgo DTOs with computed Monthly, Annually, MonthlyPercent fields
- Add AutocompleteInput component with filtered suggestion dropdown
- Add Outgo page: full table with all columns, inline editing, add/delete, drag-to-reorder
- Autocomplete wired to categories and payment-sources API endpoints

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 07:57:52 -05:00
Spencer Twaddle f429a747d8 Phase 4: Income API and page
- Add FrequencyCalculator static utility (all 9 frequency multipliers)
- Add IncomesController: list, create, update, delete, reorder
- Add Income DTOs with computed Monthly/Annually fields
- Add shared TypeScript types (IncomeDto, OutgoDto, BudgetDto, ShareDto, SummaryDto)
- Add API client with Bearer token injection via setTokenProvider
- Add FrequencySelect, MoneyDisplay, BudgetNav shared components
- Add Income page: sortable table with inline editing, add/delete rows, drag-to-reorder via dnd-kit
- Wire TokenWirer in App.tsx to keep API client in sync with auth state

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 07:56:42 -05:00
Spencer Twaddle ae21da6a81 Phase 2: Authentication scaffolding
- Add JWT Bearer auth to ASP.NET (authority/audience from AUTH__AUTHORITY / AUTH__AUDIENCE config)
- Add KnownUserMiddleware: upserts KnownUser and resolves pending shares on each authenticated request
- Add MeController as a guarded test endpoint (/api/me)
- Add oidc-client-ts + react-router-dom to client
- Create AuthContext/AuthProvider with login, logout, token storage
- Create AuthGuard component protecting all budget routes
- Add stub /callback page for OIDC redirect handling
- Wire up all routes in App.tsx with SPA routing structure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 07:54:21 -05:00
Spencer Twaddle d788dfea03 Phase 1: Project scaffolding and infrastructure
- Scaffold Budget.Api (ASP.NET Core Web API, net10.0) with EF Core + Npgsql
- Scaffold Budget.Client (Vite + React + TypeScript) with /api proxy to localhost:5000
- Define all entity models: Budget, Income, Outgo, KnownUser, BudgetShare
- Configure AppDbContext with EF mappings and cascade deletes
- Add InitialCreate migration
- Configure SPA static file serving + fallback in Program.cs
- Add Dockerfile (multi-stage: node + dotnet sdk + aspnet runtime)
- Add .env.example with all required environment variables

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 07:37:28 -05:00