# social-home Cursor rules

You are working on Social Home — a privacy-first federated social platform for Home Assistant.
Read spec_work.md before making any changes. The spec is the source of truth.

ARCHITECTURE:
- Route handlers are `BaseView` subclasses (routes/base.py), one class per REST
  resource, dispatched by HTTP method (get/post/patch/delete). No function-based
  handlers. No per-handler try/except — BaseView._iter maps exceptions centrally.
- Repository pattern: services depend on Abstract*Repo Protocols, never on
  Sqlite*Repo concretes. Services don't take `db: AsyncDatabase` when a repo
  already covers the operation.
- Domain dataclasses in domain/ are pure — no I/O, frozen, slots=True.
  Row-shaped dataclasses live in domain/, not in repositories/.
- Platform adapters: SOCIAL_HOME_MODE=ha|standalone. HA-specific code only in ha_adapter.py.
- create_app() only orchestrates. Wiring goes in _build_repos / _build_services /
  _build_middleware factories.
- Background loops use _stop: asyncio.Event + while not self._stop.is_set()
  (template: replay_cache_scheduler.py). No _running: bool flags.
- Federation transports satisfy TransportStrategy; envelope crypto satisfies
  EncryptionStrategy (federation/strategies.py).

MUST ALWAYS:
- Use async/await for all I/O
- Type-hint all public methods
- Run Ed25519 validation before any federation event processing
- Truncate GPS to 4dp: round(float(lat), 4)
- Use AsyncDatabase.enqueue() for writes, fetchall/fetchone for reads —
  but only inside the repo, never inside a service or route
- Check _require_space_admin() / _require_space_member() before privileged operations
- For multi-write handlers needing atomic event publish: async with UnitOfWork(db, bus=bus)
- For composable list/search reads: build a Spec and call repo.find(spec)
- New inbound federation validation steps: append to InboundPipeline chain
  (federation/inbound_validator.py) — never edit handle_inbound_envelope directly

MUST NEVER:
- Import inside a function or method — all imports at the top of the file
  (only exception: TYPE_CHECKING blocks for circular deps)
- Env-var-gated stubs or dual code paths in production to simplify testing —
  tests mock at the test boundary (sys.modules or unittest.mock.patch)
- Add *Addendum or *Extension subclasses — merge into original class
- Store email, phone, GPS, or DOB in federation message payloads
- Put user-generated content in push notification bodies
- Use print() — use logging.getLogger(__name__)
- Write SQL in route handlers or service methods (exceptions:
  backup_service, data_export_service — whole-table dumps)
- Declare a row-shaped @dataclass in repositories/ — move it to domain/
  and re-export from the repo module so existing imports keep working
- Inline a Sqlite*Repo or service constructor in create_app — extend the
  matching _build_* factory instead

TESTS:
- tests/protocol/ are a release blocker — run them before every push on federation/presence code
- 90% branch coverage required (pytest --cov-fail-under=90)
