Files
notify-bridge/CLAUDE.md
T
alexei.dolgolyov 03ec9b3c86 feat: telegram commands, app settings, bot polling, webhook handling, UI improvements
Adds telegram bot command system with 13 commands (search, latest, random, etc.),
webhook/polling handlers, rate limiting, app settings page, and various UI/UX
improvements across all entity pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 23:11:42 +03:00

4.9 KiB

Project Guidelines

Development Servers

IMPORTANT: When the user requests it OR when backend code changes are made (files in packages/server/), you MUST restart the standalone server using this one-liner:

PID=$(netstat -ano 2>/dev/null | grep ':8420.*LISTENING' | awk '{print $5}' | head -1) && [ -n "$PID" ] && taskkill //F //PID $PID 2>/dev/null; sleep 1 && cd packages/server && pip install -e . 2>&1 | tail -1 && cd ../.. && NOTIFY_BRIDGE_DATA_DIR=./test-data NOTIFY_BRIDGE_SECRET_KEY=test-secret-key-minimum-32chars nohup python -m uvicorn notify_bridge_server.main:app --host 0.0.0.0 --port 8420 > /dev/null 2>&1 & sleep 3 && curl -s http://localhost:8420/api/health

IMPORTANT: Overlays (modals, dropdowns, pickers) MUST use position: fixed with inline styles and z-index: 9999. Tailwind CSS v4 fixed/absolute classes do NOT work reliably inside flex/overflow containers in this project. Always calculate position from getBoundingClientRect() for dropdowns, or use top:0;left:0;right:0;bottom:0 for full-screen backdrops.

IMPORTANT: When the user requests it, restart the frontend dev server using this one-liner:

PID=$(netstat -ano 2>/dev/null | grep ':5173.*LISTENING' | awk '{print $5}' | head -1) && [ -n "$PID" ] && taskkill //F //PID $PID 2>/dev/null; sleep 1 && cd frontend && npx vite dev --port 5173 --host > /dev/null 2>&1 & sleep 4 && curl -s -o /dev/null -w "Frontend: %{http_code}" http://localhost:5173/

Test Credentials

Default test account: username admin, password admin1.

Frontend Architecture Notes

  • i18n: Uses $state rune in .svelte.ts file. Locale auto-detects from localStorage. t() is reactive via $state. setLocale() updates immediately without page reload.
  • Svelte 5 runes: $state only works in .svelte and .svelte.ts files. Regular .ts files cannot use runes -- use plain variables instead.
  • Static adapter: Frontend uses @sveltejs/adapter-static with SPA fallback. API calls proxied via Vite dev server config.
  • Auth flow: After login/setup, use window.location.href = '/' (hard redirect), NOT goto('/').
  • Tailwind CSS v4: Uses @theme directive in app.css for CSS variables.

Backend Architecture Notes

  • SQLAlchemy async + aiohttp: Cannot nest async with aiohttp.ClientSession() inside a route that has an active SQLAlchemy async session -- greenlet context breaks. Eagerly load all DB data before entering aiohttp context.
  • Jinja2 SandboxedEnvironment: All template rendering MUST use from jinja2.sandbox import SandboxedEnvironment.
  • System-owned entities: user_id=0 means system-owned (e.g. default templates).
  • FastAPI route ordering: Static path routes MUST be registered BEFORE parameterized routes.
  • __pycache__: Add to .gitignore. Never commit.

Project Structure (Phase 1)

  • packages/core (notify_bridge_core): Shared library — providers, models, notifications, templates. No DB dependency.
  • packages/server (notify_bridge_server): FastAPI REST API + SQLite. Depends on core.
  • frontend: SvelteKit 2 + Svelte 5 + Tailwind CSS v4. Static adapter with SPA fallback. Dev proxy to :8420.
  • Environment vars: NOTIFY_BRIDGE_DATA_DIR, NOTIFY_BRIDGE_SECRET_KEY, NOTIFY_BRIDGE_DATABASE_URL
  • Core package includes jinja2 dependency (template rendering lives in core, not server).

Entity Relationships (Phase 6)

ServiceProvider → type: "immich", config: JSON (url, api_key, external_domain)
Tracker → provider_id, tracking_config_id, target_ids: JSON list, collection_ids: JSON list
TrackingConfig → provider_type (must match provider), event flags, scheduling
TemplateConfig → provider_type (must match provider), Jinja2 slots per event type
NotificationTarget → template_config_id, type: "telegram"/"webhook", config: JSON
  • TrackingConfig owned by Tracker (what to watch), TemplateConfig owned by Target (how to format)
  • user_id=0 on TemplateConfig = system default (EN/RU seeded on first startup)
  • DB: SQLite + async SQLAlchemy via sqlmodel, auto-created on startup
  • API: All CRUD routes under /api/, auth via JWT Bearer, NOTIFY_BRIDGE_ env prefix

Template System Sync Rules

IMPORTANT: When adding or changing template context variables, you MUST update ALL of these in sync:

  1. packages/core/.../templates/context.pybuild_template_context() where variables are computed
  2. packages/server/.../api/template_configs.py_SAMPLE_CONTEXT dict (for preview rendering)
  3. packages/server/.../api/template_configs.pyget_template_variables() endpoint (event_vars, asset_fields, album_fields, scheduled_vars, per-slot variable dicts)
  4. packages/core/.../templates/defaults/{en,ru}/*.jinja2 — default template files using the new variables
  5. packages/core/.../providers/immich/provider.pyIMMICH_VARIABLES list (provider-specific variable definitions)