From 420614c49036900546581b68e2b7d9f110cb71af Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Wed, 11 Mar 2026 10:49:41 +0000 Subject: [PATCH] Update architecture and project conventions docs --- docs/architecture.md | 5 +++-- docs/project-conventions.md | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index 7aecacf7..f23f6c81 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -127,8 +127,9 @@ Last.fm schemas (separate, not Ecto-persisted to main DB): | `RecordChat` | Chat implementation for records (OpenAI streaming, web search enabled) | | `ArtistChat` | Chat implementation for artists (OpenAI streaming, uses Wikipedia/artist context) | | `Country` | Country code (alpha-2, alpha-3, subdivision, IETF) to flag emoji conversion | -| `ErrorTracker.ErrorNotifier` | GenServer: attaches to ErrorTracker telemetry, throttles repeated errors, dispatches email notifications | +| `ErrorTracker.ErrorNotifier` | GenServer: attaches to ErrorTracker telemetry, skips muted errors, throttles repeated errors, dispatches email notifications | | `ErrorTracker.ErrorNotifier.Email` | Builds and sends Swoosh error notification emails with stack trace formatting | +| `ErrorIgnorer` | ErrorTracker.Ignorer implementation: filters non-actionable errors (e.g., NoRouteError from bot scanners) | | `RecordsOnThisDayEmail` | Builds and sends daily "records on this day" email with cover images, anniversary styling | | `MusicLibrary.Mailer` | Swoosh mailer (Mailgun in prod, local adapter in dev) | | `FormatNumber` | Number formatting utility | @@ -281,7 +282,7 @@ All authenticated routes live inside a single `live_session` with three `on_moun | Module | Purpose | |--------|---------| | `ErrorMessages` | Maps internal error terms (atoms, structs) to user-friendly gettext strings via `friendly_message/1` | -| `Markdown` | Markdown-to-HTML conversion with `[[double bracket]]` link syntax | +| `Markdown` | Markdown-to-HTML conversion (MDEx with ammonia sanitization) with `[[double bracket]]` link syntax | | `Duration` | Milliseconds to human-readable duration formatting | | `Auth` | Authentication plugs: login password check, API token validation, session enforcement | | `LiveHelpers.Params` | Pagination param parsing from URL query params | diff --git a/docs/project-conventions.md b/docs/project-conventions.md index cac593ae..2fa97fe0 100644 --- a/docs/project-conventions.md +++ b/docs/project-conventions.md @@ -56,6 +56,8 @@ Rules extracted from commit history that are specific to this project and not al - **User-facing error reasons use `ErrorMessages.friendly_message/1`** — never `inspect(reason)`. Call sites keep their contextual prefix (e.g. `gettext("Error refreshing cover")`) and append `": " <> ErrorMessages.friendly_message(reason)` for the reason part. `Logger.error` calls keep `inspect` for debugging. - **`handle_async` always handles three cases:** `{:ok, {:ok, result}}`, `{:ok, {:error, reason}}`, and `{:exit, reason}`. - **Data cascade on upstream changes:** When artist metadata changes, regenerate dependent record embeddings. +- **Non-actionable errors use `ErrorTracker.Ignorer`** behaviour to filter (e.g., NoRouteError from bot scanners) rather than blocking paths in the endpoint. +- **Muted errors skip notifications.** `ErrorTracker.ErrorNotifier` checks the `muted` flag before sending email notifications. ## Testing @@ -71,6 +73,8 @@ Rules extracted from commit history that are specific to this project and not al - **Never leak sensitive data in prod.** `show_sensitive_data_on_connection_error: false`. - **Commits are small and single-purpose.** One logical change per commit. - **Unused aliases are removed** when their module is no longer referenced. Aliases stay alphabetically sorted. +- **Markdown sanitization via MDEx (ammonia).** Use `Markdown.to_html/1` for user content. Annotate raw output with `# sobelow_skip ["XSS.Raw"]` and a comment explaining the sanitization. +- **Sobelow runs on CI** in skip mode for security analysis. ## JavaScript