# Plan: Rename Cascade + Duplicate Check ## Features 1. After renaming a person/project/company, update all @mentions in existing text 2. On rename: prevent duplicate names of the same type --- ## Affected Files | File | Change | |------|--------| | `client/src/lib/utils/mentionReplace.ts` | NEW — `renameMentions(text, oldName, newName, type)` | | `client/src/lib/db/repositories.ts` | ADD `renameMentionCascade(oldName, newName, type)` | | `client/src/lib/components/ContextHeader.svelte` | UPDATE `saveEdit()` — duplicate check + cascade; add warning UI | --- ## New File: `mentionReplace.ts` Pure function, no Dexie dependency. ```typescript export function renameMentions( text: string, oldName: string, newName: string, type: 'person' | 'project' | 'company' ): string ``` **Regex patterns to replace:** | Type | Unquoted | Quoted | |------|----------|--------| | person | `@OldName` | `@"Old Name"` | | project | `@P:OldName` / `@p:OldName` | `@P:"Old Name"` | | company | `@F:OldName` / `@f:OldName` | `@F:"Old Name"` | | assignment (person only) | `-> OldName` | n/a (not supported by extractors) | **Replacement:** use `quoteMention`-logic — add quotes if newName contains spaces. **Boundary condition:** match must end at `[\w"]` boundary to avoid partial matches (e.g. `@Alice` must not match `@AliceBob`). --- ## `renameMentionCascade` in repositories.ts Run in a single Dexie transaction (`rw` on historyEntries, topics, contexts, ratings). **Fields to scan:** | Table | Field | Notes | |-------|-------|-------| | `historyEntries` | `text` | Primary mention location | | `topics` | `title` | Inline mentions possible | | `contexts` | `meta.notes` | PersonMeta / ProjectMeta / CompanyMeta only | | `ratings` | `comment` | Optional, may have @mentions | | `ratings` | `personName` | Structured field, person rename only (exact match) | For each changed record: increment `version`, update `updatedAt`. Pattern to follow: `renameTitleInLinks()` already exists in repositories.ts (line ~541). --- ## `ContextHeader.svelte` — `saveEdit()` changes ``` 1. trimmed = nameInput.trim() 2. if trimmed === editableName() → return (no-op) 3. if type is person/project/company: - check contextNameExists(fullName(trimmed), type) - if exists AND id !== context.id → show duplicate warning, revert, return 4. oldName = editableName() 5. await upsertContext({ id, name: fullName(trimmed) }) 6. if type is person/project/company: - await renameMentionCascade(oldName, trimmed, type) ``` Add `duplicateWarning` state + small error message below input. --- ## Sequencing 1. `mentionReplace.ts` — implement + manual regex tests 2. `repositories.ts` — add `renameMentionCascade` 3. `ContextHeader.svelte` — wire up --- ## Open Questions 1. **`-> Name` with spaces:** `extractors.ts` arrow pattern only matches `[\w]+`. If renamed from single-word to multi-word, arrow assignments break silently. Extend extractors to support `-> "First Last"`, or accept as edge case? 2. **`EventMeta.participants`:** Plain `string[]`, not mention syntax. Update on person rename? 3. **Case-only rename** (Alice → ALICE): `contextNameExists` is case-insensitive — will incorrectly block. Need to exclude self from duplicate check. 4. **Performance:** Full table scan (no text index). Acceptable for local-first small datasets — add a comment. 5. **Sync conflicts:** Cascade causes many `version++`. Last-write-wins acceptable, or need special marker?