# Project Guidelines

Detailed context is split into focused documents under `.claude/docs/`. Read the relevant file when working in that area.

| Area | File | Key rules |
| --- | --- | --- |
| Dev servers & credentials | [dev-servers.md](.claude/docs/dev-servers.md) | **MUST restart backend after code changes**; frontend restart on request |
| Frontend architecture | [frontend-architecture.md](.claude/docs/frontend-architecture.md) | Svelte 5 runes, overlays, entity cache system, i18n, auth flow |
| Backend architecture | [backend-architecture.md](.claude/docs/backend-architecture.md) | SQLAlchemy async constraints, Jinja2 sandbox, route ordering |
| Entity relationships | [entity-relationships.md](.claude/docs/entity-relationships.md) | Full entity graph and DB conventions |
| Template system | [template-system.md](.claude/docs/template-system.md) | **6-file sync rule** for template variables |

## Critical Rules (always apply)

1. **Restart backend** after ANY change to `packages/server/` or `packages/core/` — see [dev-servers.md](.claude/docs/dev-servers.md) for the one-liner.
2. **Overlays** MUST use `position: fixed` with inline styles and `z-index: 9999` — see [frontend-architecture.md](.claude/docs/frontend-architecture.md).
3. **Template variables** must be updated in 6 files simultaneously — see [template-system.md](.claude/docs/template-system.md).
4. **Entity cache** — shared entities use `$state`-based caches in `frontend/src/lib/stores/caches.svelte.ts`. Always use cache for cross-page data; invalidate after mutations — see [frontend-architecture.md](.claude/docs/frontend-architecture.md).
5. **Selector placeholders** — use plain text without decorative dashes. `Select provider...` not `— Select provider —` — see [frontend-architecture.md](.claude/docs/frontend-architecture.md).
6. **Telegram API** — ALL Telegram Bot API calls (sendMessage, sendPhoto, sendMediaGroup, etc.) MUST go through `TelegramClient` in `packages/core/src/notify_bridge_core/notifications/telegram/client.py`. NEVER duplicate sending logic in command handlers, API routes, or services. If `TelegramClient` lacks a method you need, add it there.
7. **Service provider defaults** — when implementing a new service provider, ALWAYS create default notification and command templates and configs. This requires changes across all of these locations:
   - Jinja2 notification templates for each locale in `packages/core/src/notify_bridge_core/templates/defaults/{en,ru}/`
   - Jinja2 command templates for each locale in `packages/core/src/notify_bridge_core/templates/command_defaults/{en,ru}/{provider}/`
   - Notification slot mapping in `packages/core/src/notify_bridge_core/templates/defaults/loader.py` (`PROVIDER_SLOT_FILE_MAP`)
   - Command slot mapping in `packages/core/src/notify_bridge_core/templates/command_defaults/loader.py` (`PROVIDER_COMMAND_SLOTS`)
   - Provider capabilities in `packages/core/src/notify_bridge_core/providers/capabilities.py`
   - Seed functions in `packages/server/src/notify_bridge_server/database/seeds.py` (notification templates, command templates, tracking configs, command configs)
   - Template variable definitions in `packages/server/src/notify_bridge_server/api/template_configs.py` (`get_template_variables()`)
8. **No provider-specific hardcoding** — ALL provider-specific UI logic lives in **provider descriptors** (`frontend/src/lib/providers/`). NEVER add `if (type === 'xyz')` in components.
   - Form fields, validation, config building → defined in the descriptor's `configFields` / `buildConfig` / `hasConfigChanged`
   - Event tracking checkboxes → `eventFields`; extra controls → `extraTrackingFields`; feature sections (periodic/scheduled/memory) → `featureSections`
   - Collection labels/icons → `collectionMeta`; webhook URL display → `webhookUrlPattern`
   - Pre-save hooks (e.g. shared-link validation) → `onBeforeSave`
   - Components use `getDescriptor(type)` and render dynamically from the descriptor
   - Feature gating: check `capabilities.notification_slots` or `capabilities.commands`, not `provider.type === 'immich'`
   - Template variable helpers: ALL provider types must have entries in `get_template_variables()`
9. **Nav tree & entity types** — when adding a new entity type (target type, bot type, etc.), update the sidebar nav in `frontend/src/routes/+layout.svelte`. Target types need: `{ href: '/targets?type={type}', key: 'nav.target{PascalName}', icon: '...', countKey: 'targets_{type}' }` in the `children` array under `nav.targets`, plus i18n keys `nav.target{PascalName}` in both locale files. Also add the counter entry `targets_{type}: targets.filter(t => t.type === '{type}').length` to the `counts` derived block in `+layout.svelte`.
10. **Template consistency** (IMPORTANT) — notification templates and command templates for the same provider MUST use the same formatting patterns. If notification templates wrap URLs in `<a href>`, show type icons, location, and favorite status for assets, command templates must do the same. The reference pattern is the `assets_added` notification template. Command handlers must pass rich asset dicts (`public_url`, `city`, `country`, `is_favorite`, `type`) to templates — not just `id` and `originalFileName`.
11. **New provider descriptor checklist** — when adding a new service provider, create a descriptor file in `frontend/src/lib/providers/{name}.ts` and register it in `index.ts`. The descriptor must define: `type`, `defaultName`, `icon`, `hasUrl`, `configFields`, `buildConfig()`, `hasConfigChanged()`, `eventFields`, `collectionMeta` (or `null`). Optional: `extraTrackingFields`, `featureSections`, `webhookUrlPattern`, `webhookBased`, `onBeforeSave`. Also add i18n keys: `providers.type{PascalName}` and `gridDesc.provider{PascalName}` in both `en.json` and `ru.json`.
12. **Template context variables** (IMPORTANT) — when adding new variables to templates, update ALL of these in sync:
    - Runtime context builder: `packages/core/src/notify_bridge_core/templates/context.py`
    - Variable docs: `packages/server/src/notify_bridge_server/api/template_configs.py` (`get_template_variables()`)
    - Notification preview sample: `packages/server/src/notify_bridge_server/services/sample_context.py` (`_SAMPLE_CONTEXT`)
    - Command preview sample: `packages/server/src/notify_bridge_server/api/command_template_configs.py` (`sample_ctx` in `preview_raw`)
    - Runtime validator whitelist: `packages/core/src/notify_bridge_core/templates/validator.py`

<!-- code-review-graph MCP tools -->
## MCP Tools: code-review-graph

**IMPORTANT: This project has a knowledge graph. ALWAYS use the
code-review-graph MCP tools BEFORE using Grep/Glob/Read to explore
the codebase.** The graph is faster, cheaper (fewer tokens), and gives
you structural context (callers, dependents, test coverage) that file
scanning cannot.

### When to use graph tools FIRST

- **Exploring code**: `semantic_search_nodes` or `query_graph` instead of Grep
- **Understanding impact**: `get_impact_radius` instead of manually tracing imports
- **Code review**: `detect_changes` + `get_review_context` instead of reading entire files
- **Finding relationships**: `query_graph` with callers_of/callees_of/imports_of/tests_for
- **Architecture questions**: `get_architecture_overview` + `list_communities`

Fall back to Grep/Glob/Read **only** when the graph doesn't cover what you need.

### Key Tools

| Tool | Use when |
|------|----------|
| `detect_changes` | Reviewing code changes — gives risk-scored analysis |
| `get_review_context` | Need source snippets for review — token-efficient |
| `get_impact_radius` | Understanding blast radius of a change |
| `get_affected_flows` | Finding which execution paths are impacted |
| `query_graph` | Tracing callers, callees, imports, tests, dependencies |
| `semantic_search_nodes` | Finding functions/classes by name or keyword |
| `get_architecture_overview` | Understanding high-level codebase structure |
| `refactor_tool` | Planning renames, finding dead code |

### Workflow

1. The graph auto-updates on file changes (via hooks).
2. Use `detect_changes` for code review.
3. Use `get_affected_flows` to understand impact.
4. Use `query_graph` pattern="tests_for" to check coverage.
