From c62ad3cc08bf6b2f7c19f1b4e9bc65654dad97a6 Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 1 May 2026 14:02:05 +0800 Subject: [PATCH] feat(backend): finish Module 13 sub-modules + flow fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Notifications: notification_preferences + Laravel notifications inbox. SmsChannel adapter. RoutesByPreferences trait reads per-user toggles. HouseholdApproved/Rejected, QrBalanceLow, CodesPurchased notifications wired via auto-discovered listeners or direct dispatch. Payments: payments table + PaymentDriver interface. ManualPaymentDriver works out of the box; PayMongoDriver activates when PAYMONGO_SECRET_KEY is set, falls back to manual otherwise. Resident initiates code purchase, admin can mark paid manually, webhook applies real provider events. Fulfillment runs StoreOperations::sellToHousehold. Live tracking (HTTP polling): truck_location_history with SPATIAL INDEX. Driver POST writes history, updates trucks.last_known_coordinates, caches in Redis, flags geofence-trigger when entering active trip dumpsite. Admin GET /admin/live/trucks returns active positions. Reverb broadcast deferred. Flow fixes: - QrAllocator now idempotent — re-approving a household won't re-dispense free codes. - arrive-dumpsite enforces dumpsite geofence via ST_Contains; can be bypassed with override_geofence: true. 171 feature tests passing. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 6ddb35b..4ad4c55 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -266,7 +266,47 @@ bind `FakeSmsService` via `$this->app->instance(SmsService::class, ...)` in `GET /admin/reports/compliance.csv?from=&to=` streams a DENR-style dumpsite-release export, `POST /admin/reports/rebuild` triggers aggregation on demand. -- All 164 feature tests passing +- [x] Module 13b: Notifications — complete + - `notification_preferences` table + `notifications` (Laravel inbox). + - `App\Notifications\Channels\SmsChannel` adapts our SmsService. + - `RoutesByPreferences` trait routes via database + sms based on + per-user toggles. Notifications: `HouseholdApproved`, + `HouseholdRejected`, `QrBalanceLowNotification`, `CodesPurchased`. + Listeners auto-route via Laravel 11 discovery; rejection + + purchase notifications dispatched directly from the controller / + `StoreOperations`. + - `GET/PATCH /me/notification-preferences`. Defaults seeded on + register. +- [x] Module 13c: Payments — scaffolded (PayMongo + Manual) + - `payments` table. + - `PaymentDriver` interface with `ManualPaymentDriver` (admin marks + paid; default) and `PayMongoDriver` (activates when + `PAYMONGO_SECRET_KEY` is set; HMAC-SHA256 webhook verification). + - Resident `POST /me/payments/code-purchase` → driver returns + checkout URL. Webhook `POST /api/v1/webhooks/paymongo` applies + paid/failed events. Admin `POST /admin/live/payments/{uuid}/mark-paid` + forces fulfillment for cash-paid or stuck payments. + - Fulfillment runs `StoreOperations::sellToHousehold()` — codes + allocated → active for the household + `CodesPurchased` notification. +- [x] Module 13d: Live Tracking (HTTP polling) — complete + - `truck_location_history` (POINT 4326 + SPATIAL INDEX). + - `TruckTracker::record()` writes history, updates + `trucks.last_known_coordinates`, Redis-caches latest position, + flags geofence-trigger when entering the active trip's dumpsite. + - Driver `POST /driver/trucks/{uuid}/location` (15-second cadence; + only the assigned-team driver may post). + - Admin `GET /admin/live/trucks` returns positions for active trucks + updated within the last hour. + - Reverb broadcast deferred — polling is the data source for now. +- Flow corrections from this batch: + - `QrAllocator::allocateFreeToHousehold()` is now **idempotent** — + if the household already has any QR codes assigned, the listener + skips. Re-approving a rejected→approved cycle no longer dispenses + a second free batch. + - `arrive-dumpsite` validates the GPS is **inside** the dumpsite + boundary via `Dumpsite::containsPoint`. `override_geofence: true` + bypasses for known-bad GPS — admin can audit later. +- All 171 feature tests passing - [ ] Deferred sub-modules: PayMongo payments, FCM notifications, Reverb live tracking