docs: add settings page design (app-wide DB-backed)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,112 @@
|
|||||||
|
Title: App-wide Settings Page — Design
|
||||||
|
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Add an admin-only Settings page where operators can change app-wide configuration that affects server functions and runtime behavior (feature flags, execution modes, thresholds, API keys for integrations). Settings are persisted in the database and reflected immediately via an in-process cache + event broadcaster so server functions read updated values without restart.
|
||||||
|
|
||||||
|
Goals
|
||||||
|
|
||||||
|
- Provide a single UI for operators to view and change app-wide settings.
|
||||||
|
- Persist settings reliably and safely (DB-backed) and version/track changes.
|
||||||
|
- Ensure changes propagate to server functions quickly and predictably.
|
||||||
|
- Secure the UI and APIs (admin-only).
|
||||||
|
- Test coverage (unit + E2E).
|
||||||
|
|
||||||
|
Chosen approach (Recommended)
|
||||||
|
|
||||||
|
DB-backed settings with a Settings Service:
|
||||||
|
- Persist settings in a new Prisma model/table (AppSetting).
|
||||||
|
- Expose server-side SettingsService with get/set/getAll, an in-memory cache, and an EventEmitter to notify subscribers on change.
|
||||||
|
- Admin UI: route at /settings (app/routes/settings.tsx) with a guarded admin page to edit values.
|
||||||
|
- Server functions import SettingsService.get("key") or subscribe to change events when they need dynamic behavior.
|
||||||
|
|
||||||
|
Why DB-backed
|
||||||
|
|
||||||
|
- Atomic persistence, multi-instance safe when coupled with a small invalidation strategy (see below).
|
||||||
|
- Auditable (store updatedAt, updatedBy, description).
|
||||||
|
- Fits existing repo (prisma/ exists).
|
||||||
|
|
||||||
|
Data model (Prisma example)
|
||||||
|
|
||||||
|
model AppSetting {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
key String @unique
|
||||||
|
value Json
|
||||||
|
description String?
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
updatedBy String? // optional admin id/email
|
||||||
|
}
|
||||||
|
|
||||||
|
Backend: SettingsService
|
||||||
|
|
||||||
|
- File: app/lib/settings.server.ts
|
||||||
|
- Exports:
|
||||||
|
- async getSetting(key: string): Promise<any>
|
||||||
|
- async setSetting(key: string, value: any, opts?: { updatedBy?: string })
|
||||||
|
- async getAllSettings(): Promise<Record<string, any>>
|
||||||
|
- subscribe(cb: (key,value)=>void) => unsubscribe
|
||||||
|
|
||||||
|
Implementation notes:
|
||||||
|
- On startup, load all settings into an in-memory Map cache.
|
||||||
|
- getSetting reads from cache (fast). setSetting updates DB then cache and emits event.
|
||||||
|
- To support multiple instances, setSetting also writes a lightweight "manifest" or uses DB trigger; for now plan: setSetting updates DB and callers of getSetting should tolerate eventual consistency, or a periodic poll (1s) or Redis pub/sub can be added later.
|
||||||
|
|
||||||
|
API endpoints
|
||||||
|
|
||||||
|
- GET /api/admin/settings -> list all settings (admin-only)
|
||||||
|
- PUT /api/admin/settings/:key -> update a single setting (admin-only)
|
||||||
|
- POST /api/admin/settings -> create/replace settings (admin-only)
|
||||||
|
|
||||||
|
Server route files: app/routes/api/admin/settings/index.ts (GET, POST), app/routes/api/admin/settings/[key].ts (PUT)
|
||||||
|
|
||||||
|
Frontend: Settings page
|
||||||
|
|
||||||
|
- File: app/routes/settings.tsx (route available only to admins).
|
||||||
|
- UI: table/list of settings (key, value editor (text/json/toggle), description, last updated, updatedBy) and a Save button.
|
||||||
|
- Support types: boolean toggles, numeric inputs, string inputs, JSON editor for advanced values.
|
||||||
|
- Client calls API endpoints and displays toasts on success/failure.
|
||||||
|
- When updated, UI will optimistically update local state; eventual confirmation comes from API.
|
||||||
|
|
||||||
|
Security
|
||||||
|
|
||||||
|
- Protect API endpoints and the /settings route with admin guard. If the app has user sessions with roles, require isAdmin. Otherwise gate with an env-based ADMIN_TOKEN for now.
|
||||||
|
- Validate input server-side: schema for known keys; generic JSON allowed for advanced keys but validated.
|
||||||
|
|
||||||
|
Testing
|
||||||
|
|
||||||
|
- Unit tests for SettingsService (get/set/cache behavior). New tests under app/lib/__tests__.
|
||||||
|
- Integration test for API endpoints (app/routes/api/admin/settings tests).
|
||||||
|
- E2E Playwright test: toggling a setting that affects behavior (e.g., feature flag that hides/shows a UI element) should reflect immediately.
|
||||||
|
|
||||||
|
Migration
|
||||||
|
|
||||||
|
- Add Prisma model and generate migration: `npx prisma migrate dev --name add_app_setting`
|
||||||
|
- Run `npx prisma generate` and deploy migration.
|
||||||
|
|
||||||
|
Rollout
|
||||||
|
|
||||||
|
- Start with critical settings (e.g., ENABLE_TRADING=false, ANALYSIS_BACKGROUND=true, PRICE_STREAM_URL).
|
||||||
|
- Add a feature flag toggle to hide advanced JSON edits behind "advanced" switch.
|
||||||
|
|
||||||
|
Next steps after approval
|
||||||
|
|
||||||
|
1) Write this spec file into docs (done). (current step)
|
||||||
|
2) Create PR: add Prisma model, SettingsService, API routes, UI route + components, tests.
|
||||||
|
3) Run migrations locally and in staging, verify behavior.
|
||||||
|
4) Add audit logging for changes.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
|
||||||
|
- Multi-instance real-time propagation: simple approach (polling or Redis pub/sub) is deferred to future work if needed.
|
||||||
|
- Keep settings small and typed where possible to avoid fragile JSON edits.
|
||||||
|
|
||||||
|
Files to create/change (implementation plan will enumerate exact edits)
|
||||||
|
|
||||||
|
- prisma/schema.prisma (add AppSetting model)
|
||||||
|
- app/lib/settings.server.ts (service)
|
||||||
|
- app/routes/api/admin/settings/index.ts
|
||||||
|
- app/routes/api/admin/settings/[key].ts
|
||||||
|
- app/routes/settings.tsx
|
||||||
|
- tests: unit + integration + e2e
|
||||||
|
|
||||||
|
Please review and confirm; after approval I'll: 1) commit this spec, 2) produce an implementation plan (writing-plans skill) and then implement if you ask.
|
||||||
Reference in New Issue
Block a user