SurfSense/surfsense_backend/app/schemas/site_configuration.py
Claude 2a2a909ef4
Implement dynamic site appearance configuration system
This commit implements a comprehensive database-driven site configuration
system that allows administrators to control the visibility and behavior
of homepage elements, navigation links, footer sections, and route
availability without code changes.

Backend Changes:
- Added SiteConfiguration model with singleton pattern (id=1)
- Created migration 38_add_site_configuration_table.py
- Implemented site_configuration_routes.py with public + admin endpoints
- Added Pydantic schemas for validation (Base, Update, Read, Public)
- Registered routes in main app

Frontend Changes:
- Created SiteConfigContext.tsx for global state management
- Updated app/layout.tsx to wrap app in SiteConfigProvider
- Implemented RouteGuard component for disabled routes
- Updated navbar with conditional rendering (pricing, docs, github, signin)
- Updated hero-section with conditional buttons (get started, talk to us)
- Updated footer with conditional sections and custom copyright
- Applied route guards to pricing, contact, terms, privacy pages

Admin Panel:
- Created /dashboard/site-settings page with full UI
- Visual toggle switches for all configuration options
- Real-time updates via API with toast notifications
- Organized by section (Header, Homepage, Footer, Routes, Text)
- Dark mode support and responsive design

Configuration Options:
Header: show_pricing_link, show_docs_link, show_github_link, show_sign_in
Homepage: show_get_started_button, show_talk_to_us_button
Footer: show_pages_section, show_legal_section, show_register_section
Routes: disable_pricing/docs/contact/terms/privacy_route
Custom: custom_copyright text (max 200 chars)

Security:
- Superuser-only admin endpoints with JWT validation
- Public read-only endpoint for frontend consumption
- Input validation via Pydantic schemas
- Singleton pattern with database constraints
- Client-side route guards for disabled routes

Documentation:
- Added comprehensive section to claude.md
- Includes API docs, migration guide, testing checklist
- Example code snippets and configuration tables
- Security considerations and future enhancements

All configuration defaults to minimal/privacy-focused state (most
features disabled by default). Administrators can enable features
as needed via the admin panel.

Files Changed: 16 files (6 backend, 10 frontend, 1 documentation)
2025-11-18 10:58:31 +00:00

58 lines
1.8 KiB
Python

from pydantic import BaseModel, Field
class SiteConfigurationBase(BaseModel):
# Header/Navbar toggles
show_pricing_link: bool = False
show_docs_link: bool = False
show_github_link: bool = False
show_sign_in: bool = True
# Homepage toggles
show_get_started_button: bool = False
show_talk_to_us_button: bool = False
# Footer toggles
show_pages_section: bool = False
show_legal_section: bool = False
show_register_section: bool = False
# Route disabling
disable_pricing_route: bool = True
disable_docs_route: bool = True
disable_contact_route: bool = True
disable_terms_route: bool = True
disable_privacy_route: bool = True
# Custom text
custom_copyright: str | None = Field(default="SurfSense 2025", max_length=200)
class SiteConfigurationUpdate(SiteConfigurationBase):
"""Schema for updating site configuration (all fields optional)"""
show_pricing_link: bool | None = None
show_docs_link: bool | None = None
show_github_link: bool | None = None
show_sign_in: bool | None = None
show_get_started_button: bool | None = None
show_talk_to_us_button: bool | None = None
show_pages_section: bool | None = None
show_legal_section: bool | None = None
show_register_section: bool | None = None
disable_pricing_route: bool | None = None
disable_docs_route: bool | None = None
disable_contact_route: bool | None = None
disable_terms_route: bool | None = None
disable_privacy_route: bool | None = None
custom_copyright: str | None = None
class SiteConfigurationRead(SiteConfigurationBase):
id: int
model_config = {"from_attributes": True}
class SiteConfigurationPublic(SiteConfigurationBase):
"""Public-facing schema (same as base, but explicitly named for clarity)"""
pass