4.6 KiB
Feedback Reward Account Detail Design
Goal
Show users which submitted feedback earned points, how many points were awarded, and why.
The first implementation focuses on account-page visibility. The later ops workflow for automatic reward issuance should reuse the same fields and display contract.
Current Context
user_feedbackalready stores each submitted feedback item withstatus,message,user_id,user_email, timestamps, and context JSON./api/feedbackalready returns the current user's feedback list.AccountFeedbackPanelalready renders the current user's feedback in the account page.- Current points balance is shown through
/api/auth/me, but account UI has no per-feedback reward source detail. - Existing points grant helpers update
users.points; feedback-specific rewards are not yet linked back to a feedback row.
Scope
In scope:
- Add feedback reward metadata to feedback rows.
- Return reward metadata through the existing current-user feedback API.
- Display feedback reward details in the account page next to the matching feedback item.
- Keep the data contract ready for future ops automation: a processed feedback item can carry reward points and a human-readable reason.
Out of scope for this phase:
- Building the ops action that decides and grants points.
- Sending push/email/Telegram notifications after ops processing.
- Rebuilding a general points ledger for all point sources.
- Merging historical Supabase referral ledger entries into the account page.
Data Model
Extend user_feedback with nullable columns:
reward_points INTEGER DEFAULT 0reward_reason TEXT DEFAULT ''rewarded_at TIMESTAMPreward_status TEXT DEFAULT ''
Recommended reward_status values:
- empty string: no reward decision recorded
granted: points were awarded for this feedbackskipped: reviewed but no points awardedpending: reward decision is queued or awaiting processing
The display should treat reward_points > 0 as the strongest signal that the user earned points.
API Contract
DBManager._feedback_row_to_dict() should include:
reward_pointsreward_reasonrewarded_atreward_status
GET /api/feedback should continue using the same response shape:
{
"feedback": [
{
"id": 123,
"status": "resolved",
"message": "Hong Kong COWIN reading looked stale",
"reward_points": 300,
"reward_reason": "Valid data freshness report",
"rewarded_at": "2026-06-08T12:00:00",
"reward_status": "granted"
}
]
}
The frontend proxy does not need a new route if it transparently forwards the existing payload.
Account UI
AccountFeedbackPanel should show reward detail inside each feedback row:
- Granted reward:
+300 pointsplus reward reason. - Skipped reward: a muted note that no points were awarded, with reason if available.
- Pending reward: a small pending label.
- No reward metadata: render nothing extra to avoid noise.
The account page should remain dense and scannable. Reward content belongs inside the existing feedback row, not in a separate marketing-style card.
Future Ops Workflow
The later feedback-processing feature can use a single backend operation:
- Update feedback status.
- Grant points to the matching user.
- Write
reward_points,reward_reason,rewarded_at, andreward_status = grantedback to the same feedback row.
If the grant fails, the operation should not mark the feedback as granted. It should either keep reward_status = pending or return a clear ops error.
Error Handling
- Missing reward fields should default to zero or empty strings in API responses.
- If old SQLite databases do not have the new columns,
DBManagermigration should add them with_ensure_column. - Account UI should tolerate partial payloads without crashing.
- Reward reason should be bounded in storage and display to avoid oversized rows.
Testing
Backend tests:
- Existing feedback rows serialize reward fields with defaults.
- Updating reward metadata for a feedback row returns the fields in
/api/feedback. - Old rows without rewards still list normally.
Frontend tests:
- Account feedback panel displays
+N pointsand reason for rewarded feedback. - Skipped and pending reward states render without implying points were granted.
- Rows without reward metadata do not show an empty reward block.
Rollout
This is a backward-compatible schema and UI change. Existing feedback rows keep working with empty reward metadata. The account page can ship before the ops reward action; it will simply show reward details once rows carry those fields.