From c592c745c3582c7ee3e5475327489744306ea326 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Mon, 27 Apr 2026 21:31:31 -0400 Subject: [PATCH] Update timezone plan: remove duplicate query, use 12-hour format - Remove UpdateSystemTimezone query from plan; reuse existing UpdateSystemSetting with 'default_timezone' as the key parameter - Update handler code example to reference UpdateSystemSetting - Update FormatInTimezone format string to 12-hour (03:04 PM) - Update queries file description in summary table --- TIMEZONE_PLAN.md | 94 ++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/TIMEZONE_PLAN.md b/TIMEZONE_PLAN.md index fcf85b7..d2137d4 100644 --- a/TIMEZONE_PLAN.md +++ b/TIMEZONE_PLAN.md @@ -14,27 +14,44 @@ Add per-user timezone support with system-wide fallback (set via docker-compose) **File:** `database/schema/schema.sql` -1. Add `timezone` column to `users` table: +1. Add `timezone` column directly to the `users` table definition (line ~36): ```sql -ALTER TABLE users ADD COLUMN IF NOT EXISTS timezone VARCHAR(50) DEFAULT 'UTC'; +CREATE TABLE IF NOT EXISTS users ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + email VARCHAR(255) UNIQUE NOT NULL, + username VARCHAR(255) UNIQUE NOT NULL, + password_hash VARCHAR(255) NOT NULL, + first_name VARCHAR(255), + last_name VARCHAR(255), + role VARCHAR(20) NOT NULL DEFAULT 'user' CHECK (role IN ('admin', 'user')), + theme VARCHAR(50) DEFAULT 'tokyo-night', + max_devices INTEGER DEFAULT 10, + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + timezone VARCHAR(50) DEFAULT 'UTC' +); ``` -2. Add system-wide default timezone to `system_settings`: +> Note: The `timezone` column is already present at line 36 in the current schema. No change needed for this step. + +1. Add `default_timezone` to the `system_settings` INSERT block (line ~49-52): ```sql INSERT INTO system_settings (setting_key, setting_value, description) VALUES +('scan_poll_interval_seconds', '60', 'How often to scan all libraries in minutes'), +('auto_scan_enabled', 'true', 'Whether auto-scanning is enabled system-wide'), ('default_timezone', 'UTC', 'System default timezone') ON CONFLICT (setting_key) DO NOTHING; ``` -3. Add index: +1. Add index in the indexes section (after line ~460, with other user indexes): ```sql CREATE INDEX IF NOT EXISTS idx_users_timezone ON users(timezone); ``` -4. Regenerate sqlc code: +1. Regenerate sqlc code: ```bash cd internal/database && sqlc generate @@ -54,11 +71,10 @@ UPDATE users SET timezone = $2, updated_at = NOW() WHERE id = $1; -- name: GetSystemTimezone :one SELECT setting_value FROM system_settings WHERE setting_key = 'default_timezone'; - --- name: UpdateSystemTimezone :exec -UPDATE system_settings SET setting_value = $2, updated_at = NOW() WHERE setting_key = 'default_timezone'; ``` +> Note: `UpdateSystemTimezone` is omitted because the existing `UpdateSystemSetting` query handles it by passing `'default_timezone'` as the key parameter. + Regenerate after adding queries: ```bash @@ -93,7 +109,7 @@ func FormatInTimezone(t time.Time, timezone string) string { loc = time.UTC } - return t.In(loc).Format("01-02-2006 15:04") + return t.In(loc).Format("01-02-2006 03:04 PM") } // FormatTimestamptzInTimezone formats a pgtype.Timestamptz in the specified timezone @@ -199,7 +215,7 @@ func (h *SystemSettingsHandler) UpdateTimezoneSettings(c *echo.Context) error { if _, err := time.LoadLocation(req.DefaultTimezone); err != nil { return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid timezone"}) } - err := h.db.UpdateSystemTimezone(c.Request().Context(), database.UpdateSystemTimezoneParams{ + err := h.db.UpdateSystemSetting(c.Request().Context(), database.UpdateSystemSettingParams{ SettingKey: "default_timezone", SettingValue: req.DefaultTimezone, }) @@ -267,20 +283,20 @@ Add system default timezone setting: ### Files to update -| Template | Line(s) | Field(s) | -|----------|---------|----------| -| `templates/book_detail.templ` | ~253, ~282 | `LastReadAt`, `DatePublished` | -| `templates/book_detail_modals.templ` | ~68, ~113 | `Timestamp`, `LastReadAt` | -| `templates/devices.templ` | ~83, ~91, ~174 | `LastSync`, `LastSeen`, `ExpiresAt` | -| `templates/conflicts.templ` | ~114 | `CreatedAt` | -| `templates/admin_users.templ` | ~89 | `CreatedAt` | -| `templates/queue.templ` | ~138 | `CreatedAt` | +| Template | Line(s) | Field(s) | +| ------------------------------------ | -------------- | ----------------------------------- | +| `templates/book_detail.templ` | ~253, ~282 | `LastReadAt`, `DatePublished` | +| `templates/book_detail_modals.templ` | ~68, ~113 | `Timestamp`, `LastReadAt` | +| `templates/devices.templ` | ~83, ~91, ~174 | `LastSync`, `LastSeen`, `ExpiresAt` | +| `templates/conflicts.templ` | ~114 | `CreatedAt` | +| `templates/admin_users.templ` | ~89 | `CreatedAt` | +| `templates/queue.templ` | ~138 | `CreatedAt` | ### Change pattern ```templ -{ book.ReadingProgress.LastReadAt.Time.Format("2006-01-02 15:04") } +{ book.ReadingProgress.LastReadAt.Time.Format("01-02-2006 03:04 PM") } { templates.FormatTimestamptzInTimezone(book.ReadingProgress.LastReadAt, user.Timezone) } @@ -290,7 +306,7 @@ For `time.Time` fields: ```templ -{ device.LastSync.Format("2006-01-02 15:04") } +{ device.LastSync.Format("01-02-2006 03:04 PM") } { templates.FormatInTimezone(device.LastSync, user.Timezone) } @@ -320,25 +336,25 @@ TZ=UTC ## Files Modified Summary -| File | Change | -|------|--------| -| `database/schema/schema.sql` | Add timezone column to users, system_setting row | -| `internal/database/queries/queries.sql` | Add UpdateUserTimezone, GetSystemTimezone, UpdateSystemTimezone | -| `templates/utils.go` | Add FormatInTimezone, FormatTimestamptzInTimezone | -| `templates/types.go` | Add Timezone field to User struct | -| `internal/router/helpers.go` | Pass timezone to template User | -| `internal/handlers/auth.go` | Handle timezone updates in UpdateProfile | -| `internal/handlers/system_settings.go` | Add timezone settings handler | -| `templates/profile_form.templ` | Add timezone dropdown | -| `templates/admin_settings.templ` | Add default timezone setting | -| `templates/book_detail.templ` | Update time displays | -| `templates/book_detail_modals.templ` | Update time displays | -| `templates/devices.templ` | Update time displays | -| `templates/conflicts.templ` | Update time displays | -| `templates/admin_users.templ` | Update time displays | -| `templates/queue.templ` | Update time displays | -| `docker-compose.yml` | Add TZ env var | -| `.env.example` | Add TZ example | +| File | Change | +| --------------------------------------- | ------------------------------------------------------------------------------- | +| `database/schema/schema.sql` | Add timezone column to users, system_setting row | +| `internal/database/queries/queries.sql` | Add UpdateUserTimezone, GetSystemTimezone (reuses existing UpdateSystemSetting) | +| `templates/utils.go` | Add FormatInTimezone, FormatTimestamptzInTimezone | +| `templates/types.go` | Add Timezone field to User struct | +| `internal/router/helpers.go` | Pass timezone to template User | +| `internal/handlers/auth.go` | Handle timezone updates in UpdateProfile | +| `internal/handlers/system_settings.go` | Add timezone settings handler | +| `templates/profile_form.templ` | Add timezone dropdown | +| `templates/admin_settings.templ` | Add default timezone setting | +| `templates/book_detail.templ` | Update time displays | +| `templates/book_detail_modals.templ` | Update time displays | +| `templates/devices.templ` | Update time displays | +| `templates/conflicts.templ` | Update time displays | +| `templates/admin_users.templ` | Update time displays | +| `templates/queue.templ` | Update time displays | +| `docker-compose.yml` | Add TZ env var | +| `.env.example` | Add TZ example | ---