fix(loyalty): resolve critical production readiness issues
Some checks failed
Some checks failed
- Add pessimistic locking (SELECT FOR UPDATE) on card write operations to prevent race conditions in stamp_service and points_service - Replace 16 console.log/error/warn calls with LogConfig.createLogger() in 3 storefront JS files (dashboard, history, enroll) - Delete all stale lu.json locale files across 8 modules (lb is the correct ISO 639-1 code for Luxembourgish) - Update architecture rules and docs to reference lb.json not lu.json - Add production-readiness.md report for loyalty module Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
134
app/modules/loyalty/docs/production-readiness.md
Normal file
134
app/modules/loyalty/docs/production-readiness.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# Loyalty Module — Production Readiness Report
|
||||
|
||||
**Date:** 2026-03-13
|
||||
**Tests:** 213 passing | **Languages:** en, fr, de, lb (complete)
|
||||
|
||||
---
|
||||
|
||||
## Overall Assessment: READY WITH RESERVATIONS
|
||||
|
||||
The module has strong fundamentals — clean architecture, comprehensive tests, proper exception handling, full i18n (4 languages), wallet integration, and anti-fraud controls. All critical issues have been resolved.
|
||||
|
||||
---
|
||||
|
||||
## CRITICAL — Must Fix Before Launch
|
||||
|
||||
### ~~1. Race Conditions on Card Operations~~ — RESOLVED
|
||||
Added `get_card_for_update()` method to `card_service.py` using `SELECT ... FOR UPDATE`. All 7 write methods in `stamp_service.py` (3) and `points_service.py` (4) now re-fetch the card with a row-level lock before modifying fields.
|
||||
|
||||
### ~~2. Stale Locale File `lu.json`~~ — RESOLVED
|
||||
All `lu.json` files deleted across the codebase. `lb` is the canonical Luxembourgish code (ISO 639-1). Architecture rules and docs updated.
|
||||
|
||||
### ~~3. Console.log Statements in Storefront JS~~ — RESOLVED
|
||||
All 16 `console.log/error/warn` calls replaced with `LogConfig.createLogger()` in 3 storefront JS files (dashboard, history, enroll).
|
||||
|
||||
---
|
||||
|
||||
## HIGH — Should Fix Before Launch
|
||||
|
||||
### 4. Rate Limiting on Public Endpoints
|
||||
**Status:** Rate limiter middleware exists (`middleware/rate_limiter.py`) but is NOT applied to loyalty endpoints.
|
||||
|
||||
**Vulnerable endpoints:**
|
||||
- `POST /loyalty/enroll` — public, no auth required
|
||||
- `POST /pins/{pin_id}/verify` — PIN lockout helps but doesn't prevent request flooding
|
||||
|
||||
**Fix:** Apply `@rate_limit()` decorator to public loyalty routes.
|
||||
|
||||
**Effort:** 1 hour
|
||||
|
||||
### 5. T&C Strategy Unresolved
|
||||
**Location:** `storefront/enroll.html` line 140 — TODO comment noting current approach (small text field on program model) won't scale for full legal T&C.
|
||||
|
||||
**Options:**
|
||||
- (A) Leverage CMS module to host T&C pages
|
||||
- (B) Create dedicated T&C page within loyalty module
|
||||
- (C) Accept current approach for MVP, plan post-launch
|
||||
|
||||
**Effort:** Depends on option chosen
|
||||
|
||||
### 6. Accessibility (ARIA Labels)
|
||||
**Status:** Zero `aria-label` attributes across all loyalty templates. Icon-only buttons, modals, and form inputs lack screen reader support.
|
||||
|
||||
**Priority areas:**
|
||||
- PIN entry modal (terminal) — security-critical, needs aria-modal
|
||||
- Icon-only action buttons (view, edit, delete in tables)
|
||||
- Modal dialogs (delete confirmation, terms, barcode)
|
||||
|
||||
**Effort:** 2-3 hours
|
||||
|
||||
---
|
||||
|
||||
## MEDIUM — Address Post-Launch
|
||||
|
||||
### 7. Point Expiration Task Performance
|
||||
`point_expiration.py` processes cards one-by-one. With large card volumes, this could cause long-running DB locks.
|
||||
|
||||
**Fix:** Batch processing with `LIMIT` and chunked commits.
|
||||
|
||||
### 8. Wallet Sync Retry Logic
|
||||
Wallet sync task doesn't retry failed individual cards. A transient API error skips the card until next hourly run.
|
||||
|
||||
**Fix:** Add retry with exponential backoff per card.
|
||||
|
||||
### 9. Audit Logging Enhancement
|
||||
Current: LoyaltyTransaction captures operations but not all operations create transaction records (e.g., program config changes, PIN management).
|
||||
|
||||
**Fix:** Add structured audit logging for admin/management operations.
|
||||
|
||||
### 10. Test Coverage Metrics
|
||||
Tests pass (213) but no coverage measurement. Unknown blind spots.
|
||||
|
||||
**Fix:** Add `pytest-cov` and target >80% line coverage.
|
||||
|
||||
---
|
||||
|
||||
## LOW / Nice-to-Have
|
||||
|
||||
### 11. Field-Level Validation Errors
|
||||
Current: Generic toast notifications for form errors. No field-specific error highlighting.
|
||||
|
||||
### 12. Session Storage in Enroll-Success
|
||||
`enroll-success.html` stores wallet URLs in sessionStorage. Fragile if user navigates away before page loads.
|
||||
|
||||
### 13. Tier System (Future)
|
||||
Model has `tier_config` field (Bronze/Silver/Gold) but no business logic implementation. Properly marked as future.
|
||||
|
||||
---
|
||||
|
||||
## What's Already Solid
|
||||
|
||||
| Area | Status | Details |
|
||||
|------|--------|---------|
|
||||
| Architecture | Excellent | Clean service layer, proper separation of concerns |
|
||||
| Exception Handling | Excellent | 30+ custom exceptions, no bare except clauses |
|
||||
| Authentication | Strong | All routes protected, role-based access |
|
||||
| PIN Security | Strong | bcrypt hashing, lockout mechanism, timing-safe comparison |
|
||||
| Wallet Security | Strong | JWT/PKCS#7 signing, env-based secrets, token validation |
|
||||
| SQL Injection | Safe | SQLAlchemy ORM throughout, no raw SQL |
|
||||
| Input Validation | Good | Pydantic schemas on all endpoints |
|
||||
| Database Design | Excellent | Proper indexes, FKs, cascades, composite indexes |
|
||||
| Tests | Good | 213 tests, unit + integration coverage |
|
||||
| i18n | Complete | 4 languages (en/fr/de/lb), ~300 keys each |
|
||||
| Dark Mode | Excellent | Consistent dark: variants on all elements |
|
||||
| Responsive Design | Excellent | Mobile-first with proper breakpoints |
|
||||
| Empty States | Excellent | All list views have proper empty states |
|
||||
| Loading States | Excellent | Spinners and loading indicators everywhere |
|
||||
| Confirmation Dialogs | Good | All destructive actions have modals |
|
||||
| Pagination | Excellent | Full pagination on all list views |
|
||||
| Documentation | Good | 5 docs (business logic, data model, user journeys, UI design, analysis) |
|
||||
|
||||
---
|
||||
|
||||
## Pre-Launch Checklist
|
||||
|
||||
- [x] ~~Fix race conditions with `with_for_update()` on card operations~~ — DONE
|
||||
- [x] ~~Resolve `lu.json` vs `lb.json` locale situation~~ — DONE
|
||||
- [x] ~~Replace console.log with LogConfig in 3 storefront JS files~~ — DONE
|
||||
- [ ] Apply rate limiting to public enrollment endpoint
|
||||
- [ ] Decide on T&C strategy (or accept current for MVP)
|
||||
- [ ] Add basic ARIA labels to modals and icon-only buttons
|
||||
- [ ] Manual QA: Walk through all 8 user journeys in `docs/user-journeys.md`
|
||||
- [ ] Verify Google Wallet configuration in production environment
|
||||
- [ ] Configure Apple Wallet (if needed for launch) or gracefully disable
|
||||
- [ ] Review `LOYALTY_*` environment variables in production config
|
||||
Reference in New Issue
Block a user