Spaces:
Sleeping
Data Model: Knowledge Source Deletion Guardrails
No new persisted entities or backend schema changes. This feature only adds client-side derived values computed from existing orchestrationApi types (src/services/orchestrationApi.ts).
Existing entities reused (unchanged)
ApiDocument(orchestrationApi.ts:60-ish):{ id, filename, file_type, file_size, status, created_at, ... }β a document knowledge source.DatabaseClient:{ id, name, db_type, status, ... }β a database knowledge source.DataBindItem(orchestrationApi.ts:150):{ id, name, group_type: "document" | "database", type }β a reference from anAnalysisto a bound knowledge source.Analysis(orchestrationApi.ts:157):{ id, analysis_title, objective, business_questions, status: "active" | "inactive" | string, data_bind: DataBindItem[], data_bind_version, ... }.statusis not modified by this feature (see Clarifications in spec.md).
New client-side derived values (not persisted, not sent to the backend)
DeletionImpactSummary
Computed at delete-intent time in KnowledgeManagement.tsx, before the confirmation dialog opens.
| Field | Type | Description |
|---|---|---|
sourceIds |
string[] |
The knowledge source id(s) about to be deleted (one for single delete, many for "clear all"). |
affectedAnalyses |
{ id: string; analysis_title: string }[] |
Analyses whose data_bind contains at least one of sourceIds, deduplicated by analysis id. Derived by fetching listAnalyses() and filtering analysis.data_bind.some(item => sourceIds.includes(item.id)). |
Lifecycle: Computed fresh each time a delete action is initiated; discarded when the dialog closes (confirm or cancel). Never persisted.
Analysis usability flag (isUnusable)
Reused, not newly computed: AnalysisShell.tsx already maintains staleSources: DataBindItem[] (state at AnalysisShell.tsx:80, computed in the useEffect at AnalysisShell.tsx:117-138) by cross-referencing activeAnalysis.data_bind against live getDocuments/getDatabaseClients results β this is exactly the "unusable" derivation this feature needs, built for feature 002's stale-sources banner. This feature derives from it rather than re-implementing it:
isActiveAnalysisUnusable: boolean = staleSources.length > 0
- Any single missing bound source is sufficient to mark the whole analysis unusable (per spec Assumptions / Acceptance Scenario US3.6) β already true of
staleSources's existing filter logic. - This is a pure, stateless derivation β not stored on the
Analysisobject returned by the API, and never written back viaupdateAnalysis/UpdateAnalysisPayload. - Recomputed on-demand (page load / analysis selection), not via a live subscription (per research.md Unknown 3 and the plan's Constraints) β matching
staleSources's existing recompute trigger (theactiveAnalysis-keyed effect).
State transitions: isActiveAnalysisUnusable has no explicit transition function in this feature β it is a pure function of current data. It can only become true when a bound source is deleted (User Story 1 β 3). Per clarification, this feature has no transition back to false: once staleSources.length > 0, the update-bound-data action (including the pre-existing "Update binding" control that would normally clear staleSources) is itself disabled by this feature (FR-011/FR-014), so there is no in-app path to restore usability.
Validation rule: analysis name uniqueness
Enforced client-side in NewAnalysisDialog.tsx before calling createAnalysis():
isDuplicateName(candidate: string, existing: Analysis[]): boolean =
existing.some(a => a.analysis_title.trim().toLowerCase() === candidate.trim().toLowerCase())
- Requires the dialog to have access to the current analysis list (already loaded by the parent
AnalysisShell.tsxasanalysesstate) β passed down as a new prop, or fetched vialistAnalyses()if the dialog is opened without it in scope. - This is a client-side guard only; per FR-007/FR-008 no backend contract change is assumed to exist, so this check does not guarantee uniqueness under concurrent creation from two sessions (acceptable per spec β no server-side uniqueness constraint was requested).