refactor(config): mandatory app-config rows seeded in DB; rename to session.setup_timeout
All registry keys must exist as rows in the config table: main seeds missing keys with their defaults at startup, LoadApp fails fast on a missing key, and the code-side fallback const/helper for the onboarding setup timeout is gone -- the value rides in SessionConfig.SetupTimeout. The key is renamed session.idle_timeout -> session.setup_timeout, and the /config page's 'overridden' now means 'differs from the default'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -22,8 +22,8 @@
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/internal/store/migrations/0003_profile.sql`
|
||||
- Create: `backend/internal/store/profile.go`
|
||||
- Test: `backend/internal/store/profile_test.go`
|
||||
- Create: `../../../backend/internal/store/profiles.go`
|
||||
- Test: `../../../backend/internal/store/profiles_test.go`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: `store.Profile` struct, `(db *DB) GetProfile(ctx context.Context) (Profile, error)`, `(db *DB) UpdateProfile(ctx context.Context, p Profile) error`.
|
||||
@@ -72,7 +72,7 @@ INSERT INTO profile (id) VALUES (1);
|
||||
|
||||
- [ ] **Step 2: Write the failing test**
|
||||
|
||||
Create `backend/internal/store/profile_test.go`:
|
||||
Create `../../../backend/internal/store/profiles_test.go`:
|
||||
|
||||
```go
|
||||
package store
|
||||
@@ -130,9 +130,9 @@ func TestProfile_DefaultsThenUpdate(t *testing.T) {
|
||||
Run: `cd backend && go test ./internal/store/... -run TestProfile -v`
|
||||
Expected: FAIL — `db.GetProfile undefined` (compile error, `Profile` type/methods don't exist yet).
|
||||
|
||||
- [ ] **Step 4: Write `profile.go`**
|
||||
- [ ] **Step 4: Write `profiles.go`**
|
||||
|
||||
Create `backend/internal/store/profile.go`:
|
||||
Create `../../../backend/internal/store/profiles.go`:
|
||||
|
||||
```go
|
||||
package store
|
||||
@@ -253,7 +253,7 @@ Expected: PASS
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
cd backend && git add internal/store/migrations/0003_profile.sql internal/store/profile.go internal/store/profile_test.go
|
||||
cd backend && git add internal/store/migrations/0003_profile.sql internal/store/profiles.go internal/store/profiles_test.go
|
||||
git commit -m "feat: add single-profile settings table and store layer"
|
||||
```
|
||||
(If this is the first commit in the repo, run `git init` first and skip any `git add` of files outside `backend/` — later tasks add frontend files separately.)
|
||||
@@ -876,7 +876,7 @@ Expected: all PASS.
|
||||
- [ ] **Step 7: Commit**
|
||||
|
||||
```bash
|
||||
cd backend && git add internal/api/profile.go internal/api/server.go internal/api/api_test.go
|
||||
cd backend && git add internal/api/profiles.go internal/api/server.go internal/api/api_test.go
|
||||
git commit -m "feat: add profile REST endpoints with HR zone validation"
|
||||
```
|
||||
|
||||
|
||||
@@ -765,16 +765,16 @@ EOF
|
||||
|
||||
---
|
||||
|
||||
## Task 4: Scope `profile.go` to `user_id`
|
||||
## Task 4: Scope `profiles.go` to `user_id`
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/internal/store/profile.go`
|
||||
- Modify: `backend/internal/store/profile_test.go`
|
||||
- Modify: `../../../backend/internal/store/profiles.go`
|
||||
- Modify: `../../../backend/internal/store/profiles_test.go`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: `func (db *DB) GetProfile(ctx context.Context, userID int64) (Profile, error)`; `func (db *DB) UpdateProfile(ctx context.Context, userID int64, p Profile) error`. Every other task/caller of these two methods must pass `userID` as the second positional argument from here on.
|
||||
|
||||
- [ ] **Step 1: Update `GetProfile`/`UpdateProfile` in `backend/internal/store/profile.go`**
|
||||
- [ ] **Step 1: Update `GetProfile`/`UpdateProfile` in `../../../backend/internal/store/profiles.go`**
|
||||
|
||||
Replace the two function bodies (the `Profile` struct and `profileColumns` constant are unchanged):
|
||||
|
||||
@@ -832,7 +832,7 @@ func (db *DB) UpdateProfile(ctx context.Context, userID int64, p Profile) error
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Fix `backend/internal/store/profile_test.go`'s call sites**
|
||||
- [ ] **Step 2: Fix `../../../backend/internal/store/profiles_test.go`'s call sites**
|
||||
|
||||
The existing `TestProfile_DefaultsThenUpdate` calls `db.GetProfile(ctx)` and `db.UpdateProfile(ctx, p)` directly against a fresh DB with no provisioned user — since Task 1 made `profile` rows always belong to a user, this test must provision one first. Replace the test's opening two lines:
|
||||
|
||||
@@ -866,7 +866,7 @@ Run: `cd backend && gofmt -l internal/store/`
|
||||
Expected: no output.
|
||||
|
||||
```bash
|
||||
git add backend/internal/store/profile.go backend/internal/store/profile_test.go
|
||||
git add backend/internal/store/profiles.go backend/internal/store/profiles_test.go
|
||||
git commit -m "$(cat <<'EOF'
|
||||
store: scope GetProfile/UpdateProfile to a user_id
|
||||
|
||||
@@ -3302,7 +3302,7 @@ func TestSetup_RejectsEmptyDisplayName(t *testing.T) {
|
||||
- [ ] **Step 4: Build everything and fix remaining call sites**
|
||||
|
||||
Run: `cd backend && go build ./... 2>&1 | head -50`
|
||||
Expected: remaining errors are all inside `internal/api/*.go` handler files (`profile.go`, `activities.go`, `sync.go`, `kinds.go`, `review.go`, `reclassify.go`, `progression.go`, `garmin.go`) and `cmd/seedsample/main.go` — referencing `s.Garmin`/`s.Sync` (now removed) or store methods missing `userID`. These are fixed in Tasks 14/15/17; confirm no errors remain in `server.go`, `main.go`, or `api_test.go` itself.
|
||||
Expected: remaining errors are all inside `internal/api/*.go` handler files (`profiles.go`, `activities.go`, `sync.go`, `kinds.go`, `review.go`, `reclassify.go`, `progression.go`, `garmin.go`) and `cmd/seedsample/main.go` — referencing `s.Garmin`/`s.Sync` (now removed) or store methods missing `userID`. These are fixed in Tasks 14/15/17; confirm no errors remain in `server.go`, `main.go`, or `api_test.go` itself.
|
||||
|
||||
- [ ] **Step 5: `gofmt` and commit**
|
||||
|
||||
@@ -3325,7 +3325,7 @@ EOF
|
||||
|
||||
---
|
||||
|
||||
## Task 14: Thread `userID` into `profile.go`, `kinds.go`, `garmin.go`, `progression.go`
|
||||
## Task 14: Thread `userID` into `profiles.go`, `kinds.go`, `garmin.go`, `progression.go`
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/internal/api/profile.go`
|
||||
@@ -3636,7 +3636,7 @@ Run: `cd backend && gofmt -l internal/api/`
|
||||
Expected: no output.
|
||||
|
||||
```bash
|
||||
git add backend/internal/api/profile.go backend/internal/api/kinds.go backend/internal/api/garmin.go backend/internal/api/progression.go
|
||||
git add backend/internal/api/profiles.go backend/internal/api/kinds.go backend/internal/api/garmin.go backend/internal/api/progression.go
|
||||
git commit -m "$(cat <<'EOF'
|
||||
api: scope profile, workout-kind, Garmin auth, and progression handlers to userID
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/internal/store/schema.sql` (add column to the `profile` table)
|
||||
- Modify: `backend/internal/store/profile.go` (`Profile` struct, `profileColumns`, `GetProfile`, new `MarkGarminConnected`)
|
||||
- Modify: `backend/internal/store/profile_test.go` (new tests)
|
||||
- Modify: `../../../backend/internal/store/profiles.go` (`Profile` struct, `profileColumns`, `GetProfile`, new `MarkGarminConnected`)
|
||||
- Modify: `../../../backend/internal/store/profiles_test.go` (new tests)
|
||||
- Modify: `backend/internal/store/isolation_test.go` (new adversarial test)
|
||||
- Modify: `docs/DATABASE.md` (regenerated)
|
||||
- Modify (real DB, not version-controlled): `backend/geniusrun.db` — additive `ALTER TABLE`
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
Add to `backend/internal/store/profile_test.go`:
|
||||
Add to `../../../backend/internal/store/profiles_test.go`:
|
||||
|
||||
```go
|
||||
func TestMarkGarminConnected_SetsTimestampOnceOnFirstCall(t *testing.T) {
|
||||
@@ -139,7 +139,7 @@ to:
|
||||
rolling_window_days INTEGER NOT NULL DEFAULT 90,
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Update `Profile`, `profileColumns`, and `GetProfile` in `profile.go`**
|
||||
- [ ] **Step 4: Update `Profile`, `profileColumns`, and `GetProfile` in `profiles.go`**
|
||||
|
||||
Change the struct (add the field right after `GarminPassword`):
|
||||
|
||||
@@ -192,7 +192,7 @@ Do **not** touch `UpdateProfile` — `garmin_connected_at` must stay out of its
|
||||
|
||||
- [ ] **Step 5: Add `MarkGarminConnected`**
|
||||
|
||||
Append to `backend/internal/store/profile.go`:
|
||||
Append to `../../../backend/internal/store/profiles.go`:
|
||||
|
||||
```go
|
||||
|
||||
@@ -237,7 +237,7 @@ Confirm the backend isn't running before touching the file (`ps aux | grep geniu
|
||||
- [ ] **Step 10: Commit**
|
||||
|
||||
```bash
|
||||
git add backend/internal/store/schema.sql backend/internal/store/profile.go backend/internal/store/profile_test.go backend/internal/store/isolation_test.go docs/DATABASE.md
|
||||
git add backend/internal/store/schema.sql backend/internal/store/profiles.go backend/internal/store/profiles_test.go backend/internal/store/isolation_test.go docs/DATABASE.md
|
||||
git commit -m "feat(store): persist garmin_connected_at, set once on first successful auth"
|
||||
```
|
||||
|
||||
|
||||
@@ -508,7 +508,7 @@ to:
|
||||
})
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Add `handleDeleteProfile` to `profile.go`**
|
||||
- [ ] **Step 5: Add `handleDeleteProfile` to `profiles.go`**
|
||||
|
||||
Append to `backend/internal/api/profile.go`:
|
||||
|
||||
@@ -554,7 +554,7 @@ Expected: `gofmt -l .` prints nothing; `go build`/`go vet`/`go test` all succeed
|
||||
- [ ] **Step 8: Commit**
|
||||
|
||||
```bash
|
||||
git add backend/internal/api/server.go backend/internal/api/profile.go backend/internal/api/api_test.go backend/internal/api/isolation_test.go
|
||||
git add backend/internal/api/server.go backend/internal/api/profiles.go backend/internal/api/api_test.go backend/internal/api/isolation_test.go
|
||||
git commit -m "feat(api): add DELETE /api/profile with Garmin client/tokenstore teardown"
|
||||
```
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ hatch back to the login screen.
|
||||
nullable-TEXT-pointer pattern as `sync_state.EarliestSyncedDate`).
|
||||
|
||||
New store method (`internal/store/users.go` or a new small file, e.g.
|
||||
`profile.go` wherever `UpdateProfile`/`GetProfile` already live):
|
||||
`profiles.go` wherever `UpdateProfile`/`GetProfile` already live):
|
||||
|
||||
```go
|
||||
// MarkGarminConnected records the first time userID successfully
|
||||
|
||||
Reference in New Issue
Block a user