feat: add JSON serialization, urgency field, and snake_case API contract

Fix latent API bug where multi-word fields (RecurrenceDuration, ParentUUID,
CreatedAt) serialized as PascalCase, breaking the frontend. Add explicit
snake_case json tags and custom MarshalJSON/UnmarshalJSON on Task, Status,
and APIKey to emit unix timestamps and string status codes.

Add Urgency float64 as a derived field on Task, populated via
PopulateUrgency helper in all handlers before serialization. The report
engine's sortByUrgency now also retains the computed score.

Frontend updated with urgency type, color-coded badge in TaskItem, and
mock data values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 14:58:34 +01:00
parent 924b66bc64
commit 3bb2ef2759
9 changed files with 581 additions and 51 deletions
+8 -4
View File
@@ -420,7 +420,8 @@ func mergeFilters(base, user *Filter) *Filter {
return merged
}
// sortByUrgency is a helper function to sort tasks by urgency (descending)
// sortByUrgency is a helper function to sort tasks by urgency (descending).
// It also populates the Urgency field on each task so the score is available in responses.
func sortByUrgency(tasks []*Task) []*Task {
cfg, _ := GetConfig()
coeffs := BuildUrgencyCoefficients(cfg)
@@ -428,11 +429,14 @@ func sortByUrgency(tasks []*Task) []*Task {
sorted := make([]*Task, len(tasks))
copy(sorted, tasks)
// Calculate and store urgency on each task
for _, t := range sorted {
t.Urgency = t.CalculateUrgency(coeffs)
}
for i := 0; i < len(sorted)-1; i++ {
for j := i + 1; j < len(sorted); j++ {
urgI := sorted[i].CalculateUrgency(coeffs)
urgJ := sorted[j].CalculateUrgency(coeffs)
if urgI < urgJ {
if sorted[i].Urgency < sorted[j].Urgency {
sorted[i], sorted[j] = sorted[j], sorted[i]
}
}