- `aggregateResults` ingests rating maps, tallies per-option counts +
histogram (1-5 buckets) + running sum, then `finalise` computes per-option
means and sorts options by mean desc with tiebreaks (count of 5s, then
4s, then total count, then id). Question-level `count` reflects
submissions that rated at least one option.
- Out-of-range, fractional, and non-integer ratings are silently dropped —
the aggregator never trusts user data, schema validates it on submit.
- CSV export expands a date_ranked_choice question into one column per
option named `<qid>[<optid>]`. JSON export is unchanged (it serialises
the rating map directly).
- New `results.test.ts` covers: per-option counts and means, histogram
tallying, mean-with-tiebreak ordering, ignoring bad ratings, and missing
answers. Wires the file into the `bun test` script.
Refs m/fdbck#1.
Migration: + fdbck.feedback_instances.live_results_enabled bool default false
+ fdbck.feedback_submissions.form_snapshot jsonb (frozen form per submission)
Schemas (moved $lib/server/schemas.ts → $lib/schemas.ts so the form-validation
Zod runtime can be reused on the client):
- form_definition.version: "0.YYMMDD" (today = 0.260505) with .b/.c suffix
for same-day re-edits when older snapshots already use that day
- live_results_enabled on Create + Update DTOs
Server:
- submit/+server: writes the parsed form_definition into form_snapshot so
results stay queryable after the form is later edited
- admin POST: stamps todayVersion() on first save
- admin PATCH: stampVersion() keeps current version while no submission has
it yet; otherwise advances to today (or .b/.c)
- new $lib/server/results.ts: pure aggregation + version helpers
(scale → histogram + mean, choices → counts + other_count for vanished
options, boolean → yes/no, text → list of free-text answers)
- new GET /api/public/feedback/<slug>/results: gated on live_results_enabled,
strips free-text answers (count-only) for participant-side display
- admin GET + page loader return aggregated results alongside submissions
UI:
- Results.svelte component (shared admin/participant) — CSS bar charts,
no external lib
- FormBuilder.svelte — add/remove/reorder/edit questions, type switch,
options/scale config; visual ↔ JSON toggle in admin Edit tab keeps both
views in sync
- admin detail: new "Ergebnisse" tab with version stamp, "live_results"
checkbox in Edit tab, info banner about version bumps when submissions exist
- /f/<slug>: after submit (and only if live_results_enabled), polls
/results every 5s and renders <Results /> below the form