-
Mahmoud Aglan authored
Three P1 items, and a latent bug each of them depended on. SetLocale was registered nowhere. The middleware has existed since early on and no middleware group ever included it, so `app()->getLocale()` returned the config default on every request and the bilingual half of an Arabic-first product was dead code. Worse, that default was 'en' — so every page announced `lang="en"` while being marked `dir="rtl"`, telling a screen reader two contradictory things about the same text. The default is now 'ar', the middleware runs, and the portal's direction follows the locale instead of being hardcoded. notification_preferences had per-event, per-channel columns and no interface anywhere: it was written to by the deleted API and by nothing else, so every member received everything on every channel with no way to say otherwise. The preferences screen defaults an unset choice to ON — the member has not asked for less, and silently defaulting to off means a missed instalment nobody was told about. The device list is on the same screen, because push is the one channel whose recipients a member cannot otherwise see: an old phone, a browser at work, a device someone else now owns, all receiving silently until the token rotates. Transfer reconciliation is the control that makes proof approval honest. A screenshot is not evidence; matching the day's total against the academy's own statement is. The report is per branch per day with deliberately blank statement and signature columns, because a report that cannot be signed is not a control. It also surfaces ageing proofs — a member told "we will check" who heard nothing — and transfers recorded with no proof behind them, which are legitimate but which a reconciler needs to expect. One column asserts a database constraint rather than a number: an approved proof with no payment is made unrepresentable by payment_proofs_approved_payment_check, so a non-zero count there means the constraint is gone, and the screen says exactly that. A constraint nobody ever looks at is one you find out about the hard way. notification_preferences.academy_id added to the model's fillable — S1 added the column and the model was still writing rows that belonged to no tenant. Verified on the restored tenant: 12 portal screens and 6 staff screens render 200; suite 76 pass on SQLite. Co-Authored-By:Claude Opus 5 (1M context) <noreply@anthropic.com>
8d392c04