Conversation
…rity, Privacy, Activity Log)
…d POS system Login & MFA: - Fix LoginWithMfaAsync never issuing a token after successful code verification - Fix WebAuthn rpId hardcoded to "localhost", breaking passkeys off-localhost - Fix passkey credentialJson double-JSON-encoding on register-complete - Add passkey transports (USB/NFC/BLE/hybrid) with device-type detection and labels - Add two-step MFA UI to the login page (code entry or passkey fallback) - Fix roleGuard trusting a partially-loaded currentUser (missing roles) on refresh Settings & error pages: - Redesign MFA setup, passkey management, and recovery codes UI in user-settings - Consolidate /auth/access and /auth/error into a single /error route module - Restyle 404 page to match the new auth/settings visual language POS system: - New POS terminal, inventory, customers, shifts, analytics, payment logs, and operators management pages - Backend: categories, products, customers, orders, shifts, payment/donation logging, analytics - Link orders to shifts via ShiftId (was inferred from timestamps), decrement stock on sale, enforce an open shift server-side, and fix an IDOR that let any user end another operator's shift Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Fix roleGuard double-navigating (to both /auth/login and /notfound) when a stale/expired token is present on a role-protected page — the second navigate was racing the logout() redirect and could strand the user on a misleading "Not Found" instead of sending them to log back in - Wire roleGuard's "authenticated but wrong role" cases to /error/access (a fully-built page that was never actually linked to) instead of the generic /notfound page - Remove dead publicRoutes allowlist in authGuard — it can never match since authGuard is only ever attached to /dashboard and /landing Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Members can request to buy something (item name, reason, link, price, quantity, needed-by date); Admin/Leader board members approve or reject with an optional rejection reason. Backend: - PurchaseRequest entity + PurchaseRequestStatus enum (Pending/Approved/ Rejected), EF config, AddPurchaseRequests migration - IPurchaseRequestService/PurchaseRequestService (submit, list-own, board queue, approve, reject) with status guards - PurchaseRequestsController: create + view-own for any authenticated user; list/approve/reject gated to Admin,Leader - Consolidated per-feature domain events + notification handlers under DomainEvents/Purchasing/ (reuses the shared INotificationService): board notified on submit, submitter notified on approve/reject - 3 new NotificationType cases; DI wired in Program.cs Frontend: - purchase-requests.service.ts (thin HttpClient wrapper) - Purchase Requests page (submit + my requests) for everyone - Purchase Approvals page (approval queue) gated to board - Routes + Purchasing menu section (approvals hidden from non-board) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Every p-dialog in the app used a hardcoded pixel/rem width (400px-70rem)
with no breakpoints, so on phones they overflowed the viewport and caused
horizontal scrolling.
- Added [breakpoints] to all 40 fixed-width dialogs, following the
existing house convention ({ '575px': '95vw' }); wider dialogs
(>=780px: project/announcement/profile editors) also get an
intermediate { '1199px': '75vw' } step
- Stacked the side-by-side Price/Quantity and Price/Stock field rows
in the purchase-request and POS product forms on mobile
(flex-col sm:flex-row)
Verified at 375x812: dialog renders 356px wide with even margins and
document scrollWidth stays at 375 (no horizontal overflow).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
p-datepicker without appendTo="body" renders its calendar overlay inline within the dialog's DOM, where the dialog's own scroll/overflow/stacking context interferes with the overlay's touch handling — scrolling inside the calendar to pick a date gets misread as an outside-click and closes the whole dialog. Affected the new "Needed By" field (purchase-requests.ts) and the pre-existing "Add Transaction" date field (expenses.ts). Fixed both with appendTo="body", the same convention already used correctly for every other in-dialog datepicker in the app (projects.ts, project-details.ts, course-portal.ts, dashboard.ts, elections.ts — all audited, all clean). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
20260716000000_UpdatePosSystem shipped without a [Migration] attribute (and no Designer file), so EF Core never ran it: PosCustomers kept its old Name/Phone columns while the model expected FirstName/LastName, and every POS customer / analytics query threw "42703: column p.FirstName does not exist". Add [DbContext] + [Migration] the same way the other inline-attribute migrations declare themselves. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Access control (extends the existing RFID card feature): - Doors, ESP32 lock controllers (IP allow-list + shared secret + optional source-IP enforcement), NFC-card and Aliro / Apple Home Key credentials. - Credential lifecycle Pending -> Active -> Declined / Disabled / Revoked; the door only opens for an Active credential, and a Home Key must be provisioned to the member's device before it can be accepted. - Webhook for the lock: POST /api/access/verify and /api/access/event, authenticated by the device's X-Device-Key header. - IAccessProvisioningService is the single seam for real lock integration (Matter/Aliro SetUser + SetCredential); the default impl fans out to the registered devices over HTTP and is fully tolerant of unreachable hardware. - Dedicated AccessLog for every unlock, denial, credential change and provisioning attempt, plus the generic audit log for admin actions. - Admin API: /api/AccessDoors, /api/AccessDevices, /api/AccessLogs, and new endpoints on /api/RfidCards (assign / accept / decline / disable / enable / provision-homekey / doors / logs). Angular: Access Control section with Credentials, Doors, ESP32 Devices and Access Logs pages. Member badge codes: - Every member gets a stable random code like FOSS-K7M2QX9P (unambiguous alphabet). Assigned on insert by a SaveChanges interceptor (covers every creation path); DbSeeder back-fills existing members on startup. - Surfaced on the profile page, the sortable Users list, each credential row, a memberCode JWT claim, and the user DTOs. Full reference in docs/ACCESS_CONTROL.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- app.menu.ts: flat always-open sections become labelled groups (Menu / Admin) of collapsible category dropdowns built from small helpers; empty categories are dropped. Auto-expands the category holding the current route, accordion behaviour otherwise. - app.menuitem.ts: drop the stray `providers: [LayoutService]` — it gave every menu item its own LayoutService instance, breaking the shared menuSource$ bus so nested submenus could never auto-expand. LayoutService is providedIn:'root'. - Add a root README; remove the stale DOCKER.md (wrong ports/commands, now covered by the README). Add docker-compose.local.yml for host port mappings. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Door access control + member badge codes + sidebar redesign
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Login & MFA
LoginWithMfaAsyncnever issuing a JWT after a correct MFA code — the two-step MFA login flow was silently broken end-to-end.rpIdhardcoded to"localhost"for passkey registration/login, which would break passkeys on any real deployment domain.credentialJsondouble-JSON-encoding bug on register-complete that would corrupt stored credentials.roleGuardtrusting acurrentUserthat was loaded without roles yet on page refresh.roleGuarddouble-navigation race where an expired/invalid token on a role-protected page could strand the user on "Not Found" instead of sending them to log back in.roleGuard's "authenticated but wrong role" case to the/error/accesspage (previously built but never actually linked to anywhere) instead of the generic/notfound.publicRoutesallowlist code inauthGuardthat could never match.Settings & error pages
/auth/accessand/auth/errorinto a single/errorroute module.New POS system
ShiftId(previously inferred from timestamps), stock is decremented on sale, an open shift is enforced server-side before a sale can be completed, and a fixed an IDOR that let any authenticated user end another operator's shift by guessing its ID.Responsive & polish fixes
95vwon mobile instead of overflowing the viewport at a hardcoded pixel/rem width.p-datepickerinside dialogs closing the whole dialog instead of letting you scroll/select a date — missingappendTo="body"caused the calendar overlay to fight the dialog's own scroll handling.Test plan
dotnet build), new EF Core migrations (AddShiftIdToPosOrder, etc.) generated and reviewedng build), all POS routes compile as separate lazy chunks🤖 Generated with Claude Code