# Design: Polish & Optimization Items (Audit Medium Priority) **Date**: 2026-03-26 **Scope**: 8 polish/optimization items from the code audit **Source**: `docs/audit/00-consolidated-summary.md` — Medium Priority section --- ## 1. Batch article history INSERTs **Problem**: Each `trace_article` call does an individual INSERT. 20+ sequential DB round-trips per generation. **Fix**: Add `batch_insert_entries(pool, entries: &[ArticleHistoryEntry])` in `db/article_history.rs` using `unnest()` arrays for bulk INSERT. In `synthesis.rs`, collect traces into a `Vec` and flush in a single batch call at the end of each processing phase. **Files**: `backend/src/db/article_history.rs`, `backend/src/services/synthesis.rs` --- ## 2. Reduce `.clone()` in pipeline with `Arc` **Problem**: `model_research`, `classification_categories`, `classify_schema`, and other immutable values are cloned into every spawned task (59 clones identified). **Fix**: Wrap these values in `Arc` or `Arc` at the start of `run_generation_inner`. Spawned tasks clone the `Arc` (cheap pointer copy) instead of the full string/JSON value. Target the heaviest clones inside the batch loops. **Files**: `backend/src/services/synthesis.rs` --- ## 3. Cache CSS selectors with `LazyLock` **Problem**: `Selector::parse("a[href]")` is called on every invocation of link extraction functions, re-parsing the same static selector. **Fix**: Use `std::sync::LazyLock` for static selectors in `source_scraper.rs` and `scraper.rs`. **Files**: `backend/src/services/source_scraper.rs`, `backend/src/services/scraper.rs` --- ## 4. Standardize frontend data fetching on `createResource` **Problem**: Some pages use `createResource`, others use `onMount` + manual signals for data loading. Inconsistent patterns. **Fix**: Convert pages that use `onMount` + `createSignal` for data loading to use `createResource`. Only change pages where the pattern is clearly `onMount → fetch → setSignal` and `createResource` is a direct fit. Don't force conversions where the pattern is more complex (e.g. SSE, conditional fetching). **Files**: Frontend pages using the `onMount` + signal pattern (identify by reading each page) --- ## 5. Use existing `Button` component **Problem**: A reusable `Button` component exists but inline Tailwind button classes are duplicated across pages. **Fix**: Replace obvious inline button markup with the existing `Button` component. Only do clear-cut cases where the button matches the component's API — don't force every button into it. **Files**: Frontend pages with inline button markup --- ## 6. Align default settings between frontend and backend **Problem**: `DEFAULT_SETTINGS` in frontend and `Default for UserSettings` in backend have different category lists and potentially other divergent values. **Fix**: The backend is authoritative. Update `DEFAULT_SETTINGS` in `frontend/src/types.ts` to match `Default for UserSettings` in `backend/src/models/settings.rs`. The frontend defaults are only used as initial form state before the API response arrives, so they should match what the backend would return for a new user. **Files**: `frontend/src/types.ts` --- ## 7. Remove unused `SESSION_SECRET` **Problem**: `session_secret` is loaded from env, validated (min 64 chars), stored in `AppConfig`, but never referenced anywhere in the codebase. The app uses DB-backed session tokens, not signed cookies. **Fix**: - Remove `session_secret` field from `AppConfig` struct - Remove `required_var("SESSION_SECRET")` from config loading - Remove the `session_secret` length validation - Remove from `.env.example` - Update related tests **Files**: `backend/src/config.rs`, `.env.example` --- ## 8. Wrap `AppConfig` master key in `Arc` **Problem**: `master_encryption_key` is a cloneable `String` in `AppConfig`. Since `AppConfig` is cloned into `AppState`, the secret exists in multiple memory locations. **Fix**: Change `master_encryption_key: String` to `master_encryption_key: Arc` in `AppConfig`. Update all call sites that reference `state.config.master_encryption_key` — they already call `MasterKey::from_hex(&...)` which takes `&str`, so `Arc` derefs transparently. **Files**: `backend/src/config.rs`, and any files that access `config.master_encryption_key`