diff --git a/docs/superpowers/specs/2026-03-25-settings-phase1-design.md b/docs/superpowers/specs/2026-03-25-settings-phase1-design.md new file mode 100644 index 00000000..89dcf48c --- /dev/null +++ b/docs/superpowers/specs/2026-03-25-settings-phase1-design.md @@ -0,0 +1,200 @@ +# Settings Phase 1 — Admin Control Panel + +Inspired by Stirling-PDF's settings system, this phase adds five features to the existing settings dialog to make Stirling-Image feel like a serious self-hosted product. + +## Decisions + +- Extend existing settings dialog (no separate admin panel route) +- Teams are organizational labels only — no per-team permissions +- Tool disabling and feature flags require server restart +- Temp file management is minimal (max age + startup cleanup) +- Custom branding is app name + logo (no favicon, no custom theme colors) + +## 1. Teams Management + +**New "Teams" tab in settings dialog.** + +Simple CRUD for teams. Users are assigned to teams from the existing People section. + +### Database + +New `teams` table: + +| Column | Type | Notes | +|---|---|---| +| id | text | Primary key (UUID) | +| name | text | Unique, not null | +| createdAt | integer (timestamp) | Auto-set | + +Migration steps (single Drizzle migration file): +1. Create `teams` table +2. Insert a "Default" team with a known UUID +3. Collect all distinct `users.team` string values; for each non-"Default" value, insert a new team row +4. Update `users.team` from the string value to the corresponding team UUID +5. Keep `users.team` as a plain `text` column (no DB-level FK — SQLite doesn't support adding FK constraints via ALTER TABLE). Enforce the relationship at the application level. + +Note: The existing `0003_add_team_to_users.sql` migration added the `team` column as free text. This new migration extends that by creating the `teams` table and converting values. + +### Team Name Validation + +- 1-50 characters +- Trimmed (no leading/trailing whitespace) +- Unique (case-insensitive) +- The "Default" team cannot be deleted (it's the fallback for new users) + +### API Routes + +| Method | Path | Auth | Description | +|---|---|---|---| +| GET | /api/v1/teams | auth | List all teams with member count | +| POST | /api/v1/teams | admin | Create team (body: `{ name }`) | +| PUT | /api/v1/teams/:id | admin | Rename team (body: `{ name }`) | +| DELETE | /api/v1/teams/:id | admin | Delete team (fails if team has members or is "Default") | + +### UI + +- Table with columns: Team Name, Total Members, actions (three-dot menu: Rename, Delete) +- "+ Create New Team" button +- Delete blocked with message if team has assigned members or is the Default team +- People section's team assignment dropdown pulls from teams table + +## 2. Tool Disabling + +**New "Tools" tab in settings dialog.** + +Admin can globally disable specific tools. Disabled tools are hidden from all users. + +### Settings Key + +`disabledTools` — JSON array of tool IDs. Default: `"[]"` + +### Behavior + +- On save, shows "Restart required for changes to take effect" banner +- On API startup, server reads `disabledTools` and skips registering those tool routes (server-side enforcement) +- Frontend also filters disabled tools from the tool panel for immediate visual feedback after save, but API routes remain active until restart +- Pipelines containing disabled tools: step renders but shows "tool unavailable" badge + +### UI + +- Searchable list of all registered tools +- Each tool has a toggle (on = enabled, off = disabled) +- Search/filter bar at top +- Tools grouped by category for easier scanning +- "Restart required" banner appears after any change is saved + +## 3. Feature Flags + +**Added to existing "System Settings" section.** + +Single toggle controlling visibility of experimental tools. + +### Settings Key + +`enableExperimentalTools` — `"true"` or `"false"`. Default: `"false"` + +### Tool Registry Change + +Reuse the existing `alpha?: boolean` field on the `Tool` type in `packages/shared/src/types.ts`. Rename it to `experimental?: boolean` for clarity (update all references). Tools marked experimental are hidden unless the flag is enabled. + +### Behavior + +- Works independently of tool disabling (a tool can be both experimental AND manually disabled) +- On save, shows "Restart required" banner +- When flag is off, experimental tools are excluded from: tool panel, fullscreen grid, pipeline step picker + +### UI + +- Single toggle row in System Settings: "Enable Experimental Tools" with description "Show tools that are still in development. These may be unstable." + +## 4. Temp File Management + +**Added to existing "System Settings" section under "File Management" sub-heading.** + +Admin controls how long processed files persist and whether to clean on startup. + +### Settings Keys + +| Key | Default | Description | +|---|---|---| +| tempFileMaxAgeHours | "24" | Hours before temp files are eligible for cleanup | +| startupCleanup | "true" | Whether to run cleanup on server boot | + +### Behavior + +- The cleanup function re-reads `tempFileMaxAgeHours` from the settings DB on every cycle (not cached at startup). If the setting is not set, falls back to the `FILE_MAX_AGE_HOURS` env var (default 24). DB setting takes precedence over env var. +- On startup, if `startupCleanup` is true, cleanup runs asynchronously (does not block server startup — matches current behavior where `startCleanupCron()` is non-blocking) +- Changes take effect on next cleanup cycle (no restart required) + +### UI + +- Number input: "Max File Age (hours)" with description "How long processed files are kept before automatic cleanup" +- Toggle: "Startup Cleanup" with description "Clean up old temporary files when the server starts" + +## 5. Custom Branding — Logo Upload + +**Added to existing "System Settings" section, below App Name.** + +Admin uploads a custom logo displayed in the sidebar/navbar. + +### API Routes + +| Method | Path | Auth | Description | +|---|---|---|---| +| POST | /api/v1/settings/logo | admin | Upload logo (PNG/SVG/JPEG, max 500KB) | +| GET | /api/v1/settings/logo | public | Serve custom logo (404 if none) | +| DELETE | /api/v1/settings/logo | admin | Remove custom logo | + +### Settings Key + +`customLogo` — `"true"` or `"false"`. Default: `"false"` + +### Behavior + +- All uploaded logos are converted to PNG and stored to `data/branding/logo.png` (SVGs are rasterized, JPEGs are re-encoded) +- Server resizes to max 128x128 via Sharp on upload +- `GET /api/v1/settings/logo` serves with `Content-Type: image/png`. This route must be added to `PUBLIC_PATHS` in `auth.ts` so the logo is accessible on the login page. +- Sidebar/navbar checks `customLogo` on mount — if true, loads from logo endpoint; otherwise uses built-in SVG +- No restart required — logo change is immediate + +### UI + +- Logo upload area with drag-and-drop, preview thumbnail +- "Remove" button to revert to default logo +- Accepts PNG, SVG, JPEG. Max 500KB. +- Shows current logo preview if one is set + +## 6. Settings Dialog Navigation + +### Current Sections +General, System Settings, Security, People, API Keys, About + +### New Sections +General, System Settings, Security, People, **Teams**, API Keys, **Tools**, About + +### Section Contents + +| Section | What's new | +|---|---| +| System Settings | Feature flags toggle, temp file management controls, logo upload area (all added to existing section) | +| Teams | Entirely new — team CRUD table | +| Tools | Entirely new — tool enable/disable list | + +### Frontend Type Changes + +- Add `"teams" | "tools"` to the `Section` type union in `settings-dialog.tsx` +- Add corresponding entries to `NAV_ITEMS` array + +### i18n + +Add translation keys to `packages/shared/src/i18n/en.ts` under `settings` for the new sections (teams, tools) and their UI strings. + +## Summary + +| Feature | UI Location | New DB/API | Restart Required | +|---|---|---|---| +| Teams CRUD | New "Teams" tab | `teams` table, 4 CRUD routes | No | +| Tool disabling | New "Tools" tab | `disabledTools` setting key | Yes | +| Feature flags | System Settings | `enableExperimentalTools` setting key | Yes | +| Temp file management | System Settings | 2 setting keys | No | +| Logo upload | System Settings | 3 routes, `customLogo` key, `data/branding/` | No |