Skip to content

Implement Settings Infrastructure with Supabase Sync #681

@hellno

Description

@hellno

Summary

Create a clean, extensible settings infrastructure that:

  • Stores user preferences in Supabase (synced across devices)
  • Provides sensible defaults without requiring user configuration
  • Redesigns the settings page with sectioned navigation
  • Makes it trivial to add new settings in the future

Background

Current state:

  • Settings are fragmented (localStorage, next-themes, IndexedDB)
  • No central user preferences table in Supabase
  • Settings page is minimal and unorganized

Architecture Decisions

These decisions are already made - implementer should follow them:

Decision Choice Rationale
Storage Supabase user_settings table Sync across devices/browsers
Schema Columns with defaults (not JSONB) Type safety, easy to add new settings
Scope User-level only (not per-account) Simplicity; per-account can be added later
Defaults TypeScript constants + DB defaults Dual-layer fallback
Row creation Lazy (on first settings change) Use defaults until user customizes
Migration Reset all users to new defaults Clean slate, no legacy migration

Database Schema

-- Migration: create_user_settings

create table public.user_settings (
  id uuid primary key default gen_random_uuid(),
  user_id uuid references auth.users(id) on delete cascade not null unique,
  
  -- Appearance
  theme text default 'system' check (theme in ('light', 'dark', 'system')),
  
  -- Navigation  
  default_view text default 'following' check (default_view in ('following', 'trending', 'inbox', 'dms')),
  
  -- Timestamps
  created_at timestamptz default now(),
  updated_at timestamptz default now()
);

-- RLS Policies
alter table public.user_settings enable row level security;

create policy "Users can view own settings"
  on public.user_settings for select
  using (auth.uid() = user_id);

create policy "Users can insert own settings"
  on public.user_settings for insert
  with check (auth.uid() = user_id);

create policy "Users can update own settings"
  on public.user_settings for update
  using (auth.uid() = user_id);

-- Auto-update updated_at
create trigger update_user_settings_updated_at
  before update on public.user_settings
  for each row execute function update_updated_at_column();

Implementation Tasks

1. Database & Types

  • Create Supabase migration for user_settings table
  • Run pnpm supabase gen types to update TypeScript types
  • Create src/common/constants/settings.ts with defaults:
export const DEFAULT_SETTINGS = {
  theme: 'system',
  default_view: 'following',
} as const;

export type Theme = 'light' | 'dark' | 'system';
export type DefaultView = 'following' | 'trending' | 'inbox' | 'dms';

export interface UserSettings {
  theme: Theme;
  default_view: DefaultView;
}

2. Settings Store

  • Create src/stores/useSettingsStore.ts:
    • State: settings, isLoaded, isUpdating
    • Actions: loadSettings(), updateSetting(key, value)
    • Load from Supabase on auth, merge with defaults
    • Upsert to Supabase on change (creates row if doesn't exist)
    • Optimistic updates for snappy UI

3. Settings Page Redesign

  • Redesign app/(app)/settings/page.tsx with sectioned layout
  • Create section components in src/common/components/Settings/:
    • GeneralSettings.tsx - Default view dropdown
    • AppearanceSettings.tsx - Theme toggle (migrate from ThemeToggle)
    • SidebarSettings.tsx - Links to channels/lists pages
    • ShortcutsSettings.tsx - View-only hotkey reference

Settings Page Layout:

┌────────────────────────────────────────────────┐
│ Settings                                       │
├─────────────┬──────────────────────────────────┤
│ General     │ [Content for selected section]   │
│ Appearance  │                                  │
│ Sidebar     │                                  │
│ Shortcuts   │                                  │
└─────────────┴──────────────────────────────────┘

4. Integration

  • Initialize settings store in app startup (initializeStores)
  • Apply default_view setting on app load (navigate to chosen page)
  • Connect theme setting to next-themes (settings store becomes source of truth)
  • Remove old theme localStorage usage

5. Section Details

General:

Setting UI Options
Default view Dropdown Following, Trending, Inbox, DMs

Appearance:

Setting UI Options
Theme Icon buttons (sun/moon/system) Light, Dark, System

Sidebar:

Item Action
Manage Channels Link to /channels
Manage Lists Link to /lists (or relevant page)

Shortcuts:

  • Render hotkeyDefinitions as a reference table
  • Group by category if applicable
  • View-only (no customization)

Adding New Settings (Future Reference)

To add a new setting:

  1. Add column to user_settings with DEFAULT value (1 migration)
  2. Add to DEFAULT_SETTINGS constant and UserSettings type
  3. Add UI control in appropriate section

No data backfill needed - existing rows get default automatically.

Out of Scope

  • ❌ Email preferences (no email system yet)
  • ❌ Notification settings (none exist)
  • ❌ Per-account settings (separate future work)
  • ❌ Billing settings (already handled elsewhere)
  • ❌ Account management (lives on /accounts)
  • ❌ List configuration (has dedicated pages)
  • ❌ Custom keyboard shortcuts (view-only for now)
  • ❌ Settings search

Acceptance Criteria

  • User can change theme and it persists across sessions/devices
  • User can set default view and app opens to that page
  • Settings page has clear sectioned navigation
  • New users see sensible defaults without touching settings
  • Adding a new setting requires minimal code changes
  • Works on both web and desktop (Tauri)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions