refactor(store): single account name on users; rename profile/laps tables

users.display_name becomes users.name and is now the only human-facing
name -- profiles.name is dropped (it duplicated the account name; the
Profile page's Name field now edits users.name through PUT /api/profile,
which carries Name alongside the profiles columns). The profile table
becomes profiles and laps becomes activity_laps, homogeneous with
activity_samples. Onboarding pre-fills the display name from the OIDC
claim's name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 16:11:23 +02:00
parent e2b2bf9611
commit 042579a396
19 changed files with 109 additions and 79 deletions

View File

@@ -715,7 +715,7 @@ func itoa(v int64) string {
}
func TestProfile_GetDefaultsThenUpdate(t *testing.T) {
s, _, _ := newTestServer(t)
s, db, _ := newTestServer(t)
router := s.Router()
rec := doJSON(t, router, http.MethodGet, "/api/profile", nil)
@@ -733,10 +733,18 @@ func TestProfile_GetDefaultsThenUpdate(t *testing.T) {
got.GarminEmail = "runner@example.com"
got.GarminPassword = "hunter2"
got.RollingWindowDays = 120
rec = doJSON(t, router, http.MethodPut, "/api/profile", got)
// Name rides along in the profile payload but lives on the users row.
rec = doJSON(t, router, http.MethodPut, "/api/profile", struct {
store.Profile
Name string
}{got, "Renamed Runner"})
if rec.Code != http.StatusOK {
t.Fatalf("put status = %d, body = %s", rec.Code, rec.Body.String())
}
u, found, err := db.GetUserBySub(newCtx(), "test-user")
if err != nil || !found || u.Name != "Renamed Runner" {
t.Fatalf("users.name after profile PUT = %q (found=%v err=%v), want Renamed Runner", u.Name, found, err)
}
rec = doJSON(t, router, http.MethodGet, "/api/profile", nil)
var updated store.Profile
@@ -1146,7 +1154,7 @@ func TestRequestLoggingMiddleware_LogsMethodPathStatusDuration(t *testing.T) {
if err := json.Unmarshal(buf.Bytes(), &entry); err != nil {
t.Fatalf("log output is not valid JSON: %v (%q)", err, buf.String())
}
if entry["msg"] != "http request" {
if entry["msg"] != "HTTP request" {
t.Errorf("msg = %v, want \"http request\"", entry["msg"])
}
if entry["method"] != "GET" || entry["path"] != "/api/health" {