Implement classification redesign

This commit is contained in:
Lars Nolden
2026-09-11 22:46:17 +02:00
parent cc43a2f9a7
commit 87f052a3ea
23 changed files with 1602 additions and 296 deletions
+27
View File
@@ -18,6 +18,7 @@ import (
"finance-duck/internal/analytics"
"finance-duck/internal/app"
"finance-duck/internal/banking"
"finance-duck/internal/classification"
"finance-duck/internal/domain"
)
@@ -69,6 +70,8 @@ func New(a *app.App, assets fs.FS, publicURL string) (http.Handler, error) {
s.mux.HandleFunc("POST /api/reclassify/preview", s.preview)
s.mux.HandleFunc("POST /api/reclassify/apply", s.apply)
s.mux.HandleFunc("POST /api/reclassify/cancel", s.cancel)
s.mux.HandleFunc("POST /api/taxonomy/propose", s.taxonomyPropose)
s.mux.HandleFunc("POST /api/taxonomy/apply", s.taxonomyApply)
s.mux.HandleFunc("GET /api/health", func(w http.ResponseWriter, r *http.Request) {
_, err := a.Snapshot(r.Context())
if err != nil {
@@ -319,6 +322,9 @@ func (s *Server) transaction(w http.ResponseWriter, r *http.Request) {
}
b.Enrichment.Classification = domain.Provenance{Source: "manual", Timestamp: time.Now().UTC().Format(time.RFC3339)}
d.Transactions[i].Enrichment = b.Enrichment
if b.Enrichment.MerchantID != "" {
app.LearnAlias(d, t.Facts, b.Enrichment.MerchantID)
}
return nil
}
}
@@ -509,3 +515,24 @@ func (s *Server) cancel(w http.ResponseWriter, r *http.Request) {
s.app.CancelPreview(b.ID)
respond(w, map[string]bool{"ok": true}, nil)
}
func (s *Server) taxonomyPropose(w http.ResponseWriter, r *http.Request) {
var b app.TaxonomyProposalRequest
if !decode(w, r, &b) {
return
}
v, e := s.app.ProposeTaxonomy(r.Context(), b)
respond(w, v, e)
}
func (s *Server) taxonomyApply(w http.ResponseWriter, r *http.Request) {
var b struct {
ID string `json:"id"`
Revision string `json:"revision"`
Approved classification.TaxonomyProposal `json:"approved"`
}
if !decode(w, r, &b) {
return
}
v, e := s.app.ApplyTaxonomy(r.Context(), b.ID, b.Revision, b.Approved)
respond(w, v, e)
}