Commit Graph

41 Commits

Author SHA1 Message Date
Chris Chen 8cb6245560 feat(1099): add 1099 Copy B + filing CSV download endpoints
Injects I1099FormService into Form1099ReportController and adds two
Read-gated GET endpoints: recipient/{payeeId}/copy-b (Copy B PDF) and
export-csv (filing-data CSV). Registers Form1099FormService in DI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 17:21:14 -07:00
Chris Chen 7c5348969b feat(1099): add recipient and report controllers
Payee1099Controller (api/payee-1099): CRUD + TIN reveal, class-level
Read gate, method-level Write/Delete overrides — mirrors the
HasPermission class+method stacking pattern from ExpensesController.
Form1099ReportController (api/form1099-report): boxes, annual summary,
and per-recipient detail; read-only, no method-level overrides needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 17:06:49 -07:00
Chris Chen 4877fec1da feat(expense-snapshot): REST controller + DI registration 2026-06-25 15:01:38 -07:00
Chris Chen 73077295a4 feat(expense-categories): AI 建議 for group/sub name + 990 line
ci-cd-vm / ci-cd (push) Successful in 2m25s
Add an AI assist button to the Edit/New Group (大項) and Subcategory
(小項) dialogs: the user enters a Chinese name, and the model refines
the Chinese, translates it to English, and suggests the matching IRS
Form 990 Part IX line. Suggestions surface in a confirm card; Apply
fills the Chinese name, English name, and 990 line fields.

Backend mirrors the existing expense-classification AI family but over
the Form 990 line catalog: IExpenseCategoryAiService + base (catalog
load, prompt, id validation) + Claude/Gemini providers + factory that
picks the provider from ChurchProfile.AiProvider. New write-gated
POST api/expense-categories/ai-suggest endpoint; sub-category requests
pass the parent group + its 990 line to bias the choice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 14:18:34 -07:00
Chris Chen 120240ad0c feat(ai): DB-only config + runtime provider selection via factory 2026-06-25 13:23:13 -07:00
Chris Chen a89e936f4d Implement AI 2026-06-25 11:11:26 -07:00
Chris Chen 1a03a1cbba feat(finance): expose Form 990 line catalog endpoint
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 19:36:01 -07:00
Chris Chen b41297f972 feat(finance): Form 990 functional-expenses report endpoint 2026-06-24 19:30:33 -07:00
Chris Chen 9dbb1d38d8 WIP 2026-06-24 18:45:22 -07:00
Chris Chen b0e2e112fc feat(giving): add sundayAttendanceCount model field and attendance setCounts API
ci-cd-vm / ci-cd (push) Successful in 2m21s
2026-06-24 11:35:34 -07:00
Chris Chen 7eb6a4db78 feat(attendance): add PUT /api/meal-attendance/{date} to overwrite a Sunday's counts 2026-06-24 11:18:27 -07:00
Chris Chen e53cea7a82 Add init link. 2026-06-24 10:53:13 -07:00
Chris Chen e88ea7917f add church profile.
ci-cd-vm / ci-cd (push) Successful in 2m31s
2026-06-24 08:21:31 -07:00
Chris Chen b0deb62c82 update sunday 2026-06-23 20:20:12 -07:00
Chris Chen 8f18166dbf feat(auth): add POST /api/auth/change-password endpoint 2026-06-23 19:54:20 -07:00
Chris Chen 5a915ebdd1 Harden notifications: bump MailKit, bound webhook body, share truncation, skip soft-deleted members 2026-06-23 19:29:23 -07:00
Chris Chen 39432ac588 Add admin NotificationsController for binding, groups, history, and send 2026-06-23 19:20:28 -07:00
Chris Chen 4c22cfaf19 Add Line webhook controller with signature verification and dispatch
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 19:18:50 -07:00
Chris Chen 62592c29ae Add audit logs.
ci-cd-vm / ci-cd (push) Successful in 4m2s
2026-06-23 12:13:47 -07:00
Chris Chen 870eeec82a Add role control 2026-06-23 07:19:08 -07:00
Chris Chen deff2264a6 Create HealthController.cs
ci-cd-vm / ci-cd (push) Failing after 1m41s
2026-06-22 17:57:20 -07:00
Chris Chen ddced87dc6 Update
ci-cd-nas / build-push (push) Failing after 27s
ci-cd-nas / deploy (push) Has been skipped
2026-06-20 22:26:52 -07:00
Chris Chen 7ab8e9703b WIP 2026-06-20 21:06:24 -07:00
Chris Chen 8061a60fe5 add quick add entry. 2026-06-20 20:42:06 -07:00
Chris Chen 87425b3276 add attendance 2026-06-20 19:43:15 -07:00
Chris Chen 3558c67fd7 WIP 2026-06-20 17:51:33 -07:00
Chris Chen f55807fa7d wip 2026-06-20 15:13:23 -07:00
Chris Chen 769597d769 refactor finance. 2026-05-29 23:56:29 -07:00
Chris Chen 95fa37ebdf fix(expense): open category read to all authed users; statement lookups via FirstOrDefaultAsync
Final-review findings:
- ExpenseCategoriesController was finance-only at the class level, but the member
  self-service reimbursement form reads the category list to populate its dropdown,
  so members got 403 and could not submit. Open GET to any authenticated user;
  keep group/subcategory writes finance-only (mirrors MinistriesController).
  Verified live with a member-role account: reads 200, writes 403, self-submit 200.
- MonthlyStatementService Update/Finalize now use FirstOrDefaultAsync for
  convention consistency with the rest of the service layer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 19:14:18 -07:00
Chris Chen e1f99158aa fix(expense): resolve current user id from 'sub' JWT claim
Live verification revealed the JWT carries the user id in the 'sub' claim
(NameClaimType=sub, MapInboundClaims=false), so ClaimTypes.NameIdentifier is
null at runtime. This caused ExpensesController.GetMine/GetById to throw
NullReferenceException (500) on the '!.Value', and made the services fall back
to 'system' — silently defeating the self-ownership guard. Resolve via
NameIdentifier (unit tests) then 'sub' (real tokens). Adds a regression test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 19:08:21 -07:00
Chris Chen 9933c180b7 feat(expense): add controllers + register services
Adds ExpenseCategoriesController, ExpensesController, MonthlyStatementsController
and registers IExpenseCategoryService, IExpenseService, IMonthlyStatementService in DI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:37:25 -07:00
Chris Chen f6f06d841c feat(ministry): add Ministry entity, seed (10), and read endpoint 2026-05-29 18:03:28 -07:00
Chris Chen b5a15dd9f2 feat(giving): add offering-sessions controller 2026-05-28 16:54:24 -07:00
Chris Chen 586551aec0 feat(giving): add givings controller 2026-05-28 16:43:06 -07:00
Chris Chen 81efaedbc2 feat(giving): add giving-categories controller 2026-05-28 16:34:18 -07:00
Chris Chen a525c71baa WIP 2026-05-28 15:25:31 -07:00
Chris Chen 8249b3fe3e feat: add UsersController and register all services
Adds UsersController with CRUD endpoints (list, get, create, update,
deactivate, reset-password) restricted to super_admin role. Registers
IUserManagementService in Program.cs alongside existing services.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 14:10:46 -07:00
Chris Chen 0986233d9b feat: add MembersController (CRUD + paged list)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 14:03:23 -07:00
Chris Chen 2aa095c158 Task 11: Smoke test fixes (all 5 scenarios pass)
TokenService.GenerateRefreshToken():
  - Switched to URL-safe Base64 (RFC 4648 §5): +→-, /→_, no = padding.
  - Characters are unreserved per RFC 6265, so Response.Cookies.Append
    does NOT percent-encode the value.  Request.Cookies reads back exact value.

AuthController:
  - CookieOptions.Secure = !env.IsDevelopment()
    Plain HTTP in local dev works; HTTPS-only in staging/production.
  - Inject IWebHostEnvironment for environment-aware Secure flag.

TokenServiceTests:
  - Updated GenerateRefreshToken test: 86-char URL-safe Base64 instead
    of 64-byte standard Base64.  16/16 tests pass.

Smoke test results (http://localhost:5209):
  1. POST /api/auth/login       → 200 + rolac_rt cookie + JWT
  2. POST /api/auth/refresh     → 200 + new token (rotation)
  3. POST /api/auth/logout      → 204 + cookie cleared
  4. Refresh with revoked token → 401
  5. Wrong password             → 401

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 19:28:20 -07:00
Chris Chen 8b86bd573e Tasks 7-9: AuthController, appsettings, Program.cs
Task 7 – AuthController (POST /api/auth/login|refresh|logout)
  - Refresh token in HttpOnly; Secure; SameSite=Strict cookie (rolac_rt)
  - Cookie Path scoped to /api/auth; cleared on logout/invalid refresh

Task 8 – appsettings.json (non-secret JWT values + CORS origins)
  - appsettings.Development.json carries connection string + JWT secret
    (file is gitignored)

Task 9 – Program.cs wiring
  - EF Core + Npgsql, ASP.NET Core Identity, JWT Bearer auth
  - RoleClaimType=role matches the short JWT claim name written by TokenService
  - CORS: AllowCredentials for Angular app
  - Swagger UI with Bearer security definition
  - Startup: MigrateAsync + DbSeeder.SeedAsync (roles + dev admin)
  - DbSeeder: added SeedAsync(IServiceProvider) entry point

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 17:40:52 -07:00
Chris Chen 4da8806bfc Init API 2026-05-25 17:38:23 -07:00