feat: add partner interface, admin dashboard, and unit tests
Partner flow: QR scanner component (html5-qrcode) with camera permission/not-found handling, 3-step spend flow (scan → amount entry with auto-filled max → success/error result). Admin dashboard: stats overview, grant points with debounced student search, paginated transactions table with type filters, paginated students table. Tests: comprehensive unit tests for points and auth packages — service (all paths including error branches, RS256 wrong-method), handler (all HTTP status codes via httptest), JWT round-trip, repository constructors. Auth coverage: 72.9%, points service coverage: 100%. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
50b3c4198a
commit
be2260d259
@@ -32,6 +32,13 @@ type spendRequest struct {
|
||||
Amount int `json:"amount"`
|
||||
}
|
||||
|
||||
// spendResponse is returned on a successful spend; includes new balance for the partner UI.
|
||||
type spendResponse struct {
|
||||
Status string `json:"status"`
|
||||
Spent int `json:"spent"`
|
||||
NewBalance int `json:"new_balance"`
|
||||
}
|
||||
|
||||
// GenerateQR handles GET /api/v1/me/qr.
|
||||
// Returns a one-time QR JWT token with 5-minute TTL for the authenticated student.
|
||||
func (h *Handler) GenerateQR(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -67,7 +74,7 @@ func (h *Handler) Spend(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
partnerID := middleware.UserIDFromContext(r.Context())
|
||||
|
||||
err := h.service.SpendPoints(r.Context(), SpendRequest{
|
||||
newBalance, err := h.service.SpendPoints(r.Context(), SpendRequest{
|
||||
QRToken: req.QRToken,
|
||||
Amount: req.Amount,
|
||||
PartnerID: partnerID,
|
||||
@@ -87,5 +94,5 @@ func (h *Handler) Spend(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
response.JSON(w, http.StatusOK, map[string]string{"status": "ok"})
|
||||
response.JSON(w, http.StatusOK, spendResponse{Status: "ok", Spent: req.Amount, NewBalance: newBalance})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user