docs(expense-snapshot): implementation plan + spec read-time creator-name refinement

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Chris Chen
2026-06-25 14:45:08 -07:00
parent d4c20df34f
commit 5d03e42302
2 changed files with 1365 additions and 5 deletions
File diff suppressed because it is too large Load Diff
@@ -29,7 +29,7 @@ Everything needed to refill the vendor-payment form **except `ExpenseDate`**.
| Label | `Name` (required, user-supplied, e.g. "Monthly Rent — Landlord X") | | Label | `Name` (required, user-supplied, e.g. "Monthly Rent — Landlord X") |
| Header | `MinistryId`, `Description`, `VendorName`, `CheckNumber`, `Notes` | | Header | `MinistryId`, `Description`, `VendorName`, `CheckNumber`, `Notes` |
| Lines (1..n) | `CategoryGroupId`, `SubCategoryId`, `Amount`, `FunctionalClass`, `Description` | | Lines (1..n) | `CategoryGroupId`, `SubCategoryId`, `Amount`, `FunctionalClass`, `Description` |
| Audit | `CreatedBy`, `CreatedByName`, `CreatedAt` (+ soft-delete / auditable fields) | | Audit | `CreatedBy` + `CreatedAt` (auto-stamped by `AuditSaveChangesInterceptor`); the creator display name is resolved at read time, not stored |
**Excluded:** `ExpenseDate` (always starts fresh / today), the receipt file, and `MemberId` **Excluded:** `ExpenseDate` (always starts fresh / today), the receipt file, and `MemberId`
(not used in vendor mode). (not used in vendor mode).
@@ -50,9 +50,10 @@ overwrites it. Captured value is shown editable in the form.
### Entities (`API/ROLAC.API/Entities/`) ### Entities (`API/ROLAC.API/Entities/`)
- **`ExpenseSnapshot`** — header. Fields: `Id`, `Name`, `MinistryId`, `Description`, - **`ExpenseSnapshot`** — header, extends `SoftDeleteEntity` (so it gets `CreatedBy`,
`VendorName`, `CheckNumber`, `Notes`, `CreatedBy`, `CreatedByName`, plus auditable `CreatedAt`, `UpdatedBy`, `UpdatedAt`, `IsDeleted` auto-stamped). Fields: `Id`, `Name`,
(`CreatedAt`, `UpdatedAt`, `UpdatedBy`) and soft-delete (`IsDeleted`). Owns `Lines`. `MinistryId`, `Description`, `VendorName`, `CheckNumber`, `Notes`. Owns `Lines`. The
creator's display name is resolved at read time (mirroring `ReviewedByName`), not stored.
- **`ExpenseSnapshotLine`** — mirrors `ExpenseLine`: `Id`, `SnapshotId` (cascade), - **`ExpenseSnapshotLine`** — mirrors `ExpenseLine`: `Id`, `SnapshotId` (cascade),
`CategoryGroupId`, `SubCategoryId`, `Amount`, `FunctionalClass`, `Description`. `CategoryGroupId`, `SubCategoryId`, `Amount`, `FunctionalClass`, `Description`.
Category FKs use `Restrict` delete (same as `ExpenseLine`). Category FKs use `Restrict` delete (same as `ExpenseLine`).
@@ -76,7 +77,7 @@ permission check used by `ExpensesController`.
|---|---|---| |---|---|---|
| GET | `/` | List all snapshots (shared), newest first, with `createdByName` + totals | | GET | `/` | List all snapshots (shared), newest first, with `createdByName` + totals |
| GET | `/{id}` | Full snapshot incl. lines (for apply / management edit) | | GET | `/{id}` | Full snapshot incl. lines (for apply / management edit) |
| POST | `/` | Create from form payload; stamps `CreatedBy`/`CreatedByName` from current user | | POST | `/` | Create from form payload (`CreatedBy`/`CreatedAt` auto-stamped by the interceptor) |
| PUT | `/{id}` | Update (rename and/or re-save fields from the management page) | | PUT | `/{id}` | Update (rename and/or re-save fields from the management page) |
| DELETE | `/{id}` | Soft-delete | | DELETE | `/{id}` | Soft-delete |