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
This commit is contained in:
2026-04-27 21:31:31 -04:00
parent e5726e12be
commit c592c745c3
+55 -39
View File
@@ -14,27 +14,44 @@ Add per-user timezone support with system-wide fallback (set via docker-compose)
**File:** `database/schema/schema.sql` **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 ```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 ```sql
INSERT INTO system_settings (setting_key, setting_value, description) VALUES 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') ('default_timezone', 'UTC', 'System default timezone')
ON CONFLICT (setting_key) DO NOTHING; ON CONFLICT (setting_key) DO NOTHING;
``` ```
3. Add index: 1. Add index in the indexes section (after line ~460, with other user indexes):
```sql ```sql
CREATE INDEX IF NOT EXISTS idx_users_timezone ON users(timezone); CREATE INDEX IF NOT EXISTS idx_users_timezone ON users(timezone);
``` ```
4. Regenerate sqlc code: 1. Regenerate sqlc code:
```bash ```bash
cd internal/database && sqlc generate cd internal/database && sqlc generate
@@ -54,11 +71,10 @@ UPDATE users SET timezone = $2, updated_at = NOW() WHERE id = $1;
-- name: GetSystemTimezone :one -- name: GetSystemTimezone :one
SELECT setting_value FROM system_settings WHERE setting_key = 'default_timezone'; 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: Regenerate after adding queries:
```bash ```bash
@@ -93,7 +109,7 @@ func FormatInTimezone(t time.Time, timezone string) string {
loc = time.UTC 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 // 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 { if _, err := time.LoadLocation(req.DefaultTimezone); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid timezone"}) 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", SettingKey: "default_timezone",
SettingValue: req.DefaultTimezone, SettingValue: req.DefaultTimezone,
}) })
@@ -267,20 +283,20 @@ Add system default timezone setting:
### Files to update ### Files to update
| Template | Line(s) | Field(s) | | Template | Line(s) | Field(s) |
|----------|---------|----------| | ------------------------------------ | -------------- | ----------------------------------- |
| `templates/book_detail.templ` | ~253, ~282 | `LastReadAt`, `DatePublished` | | `templates/book_detail.templ` | ~253, ~282 | `LastReadAt`, `DatePublished` |
| `templates/book_detail_modals.templ` | ~68, ~113 | `Timestamp`, `LastReadAt` | | `templates/book_detail_modals.templ` | ~68, ~113 | `Timestamp`, `LastReadAt` |
| `templates/devices.templ` | ~83, ~91, ~174 | `LastSync`, `LastSeen`, `ExpiresAt` | | `templates/devices.templ` | ~83, ~91, ~174 | `LastSync`, `LastSeen`, `ExpiresAt` |
| `templates/conflicts.templ` | ~114 | `CreatedAt` | | `templates/conflicts.templ` | ~114 | `CreatedAt` |
| `templates/admin_users.templ` | ~89 | `CreatedAt` | | `templates/admin_users.templ` | ~89 | `CreatedAt` |
| `templates/queue.templ` | ~138 | `CreatedAt` | | `templates/queue.templ` | ~138 | `CreatedAt` |
### Change pattern ### Change pattern
```templ ```templ
<!-- Before --> <!-- Before -->
{ book.ReadingProgress.LastReadAt.Time.Format("2006-01-02 15:04") } { book.ReadingProgress.LastReadAt.Time.Format("01-02-2006 03:04 PM") }
<!-- After --> <!-- After -->
{ templates.FormatTimestamptzInTimezone(book.ReadingProgress.LastReadAt, user.Timezone) } { templates.FormatTimestamptzInTimezone(book.ReadingProgress.LastReadAt, user.Timezone) }
@@ -290,7 +306,7 @@ For `time.Time` fields:
```templ ```templ
<!-- Before --> <!-- Before -->
{ device.LastSync.Format("2006-01-02 15:04") } { device.LastSync.Format("01-02-2006 03:04 PM") }
<!-- After --> <!-- After -->
{ templates.FormatInTimezone(device.LastSync, user.Timezone) } { templates.FormatInTimezone(device.LastSync, user.Timezone) }
@@ -320,25 +336,25 @@ TZ=UTC
## Files Modified Summary ## Files Modified Summary
| File | Change | | File | Change |
|------|--------| | --------------------------------------- | ------------------------------------------------------------------------------- |
| `database/schema/schema.sql` | Add timezone column to users, system_setting row | | `database/schema/schema.sql` | Add timezone column to users, system_setting row |
| `internal/database/queries/queries.sql` | Add UpdateUserTimezone, GetSystemTimezone, UpdateSystemTimezone | | `internal/database/queries/queries.sql` | Add UpdateUserTimezone, GetSystemTimezone (reuses existing UpdateSystemSetting) |
| `templates/utils.go` | Add FormatInTimezone, FormatTimestamptzInTimezone | | `templates/utils.go` | Add FormatInTimezone, FormatTimestamptzInTimezone |
| `templates/types.go` | Add Timezone field to User struct | | `templates/types.go` | Add Timezone field to User struct |
| `internal/router/helpers.go` | Pass timezone to template User | | `internal/router/helpers.go` | Pass timezone to template User |
| `internal/handlers/auth.go` | Handle timezone updates in UpdateProfile | | `internal/handlers/auth.go` | Handle timezone updates in UpdateProfile |
| `internal/handlers/system_settings.go` | Add timezone settings handler | | `internal/handlers/system_settings.go` | Add timezone settings handler |
| `templates/profile_form.templ` | Add timezone dropdown | | `templates/profile_form.templ` | Add timezone dropdown |
| `templates/admin_settings.templ` | Add default timezone setting | | `templates/admin_settings.templ` | Add default timezone setting |
| `templates/book_detail.templ` | Update time displays | | `templates/book_detail.templ` | Update time displays |
| `templates/book_detail_modals.templ` | Update time displays | | `templates/book_detail_modals.templ` | Update time displays |
| `templates/devices.templ` | Update time displays | | `templates/devices.templ` | Update time displays |
| `templates/conflicts.templ` | Update time displays | | `templates/conflicts.templ` | Update time displays |
| `templates/admin_users.templ` | Update time displays | | `templates/admin_users.templ` | Update time displays |
| `templates/queue.templ` | Update time displays | | `templates/queue.templ` | Update time displays |
| `docker-compose.yml` | Add TZ env var | | `docker-compose.yml` | Add TZ env var |
| `.env.example` | Add TZ example | | `.env.example` | Add TZ example |
--- ---