Refactor: Simplify case directory structure

The distinction between `open/` and `done/` directories for cases has
been removed.
All cases for a user now reside directly under the user's directory
(e.g., `<data_path>/<slug>/<case_id>/`).

This simplifies path management and eliminates redundant directory
traversals.

Key changes include:
- Removed `open/` and `done/` subdirectories in path resolution.
- Introduced a `paths::case_dir` function as a single source of truth
  for case directory layout.
- Updated various modules (`recovery`, `auth`, `routes`, `transcribe`,
  `tests`) to use the new path structure.
- Adjusted templates to reflect the simplified case status
  representation.
This commit is contained in:
2026-04-15 22:15:13 +02:00
parent 70eed20909
commit 11eb645f3f
17 changed files with 190 additions and 324 deletions
+16 -13
View File
@@ -45,13 +45,14 @@ pub async fn handle_close_case(
));
}
// Close only acts on cases in open/. A case in done/ is already finalized.
let user_root = config.data_path.join(&user.slug);
let case_dir = user_root.join("open").join(&case_id);
if !tokio::fs::try_exists(&case_dir).await.unwrap_or(false) {
warn!(slug = %user.slug, case_id = %case_id, "close: case not found in open/");
return Err(AppError::NotFound("Case not found".into()));
}
let case_dir = match locate_case(&user_root, &case_id).await {
Some(p) => p,
None => {
warn!(slug = %user.slug, case_id = %case_id, "close: case not found");
return Err(AppError::NotFound("Case not found".into()));
}
};
let input_path = case_dir.join("analysis_input_v1.json");
if tokio::fs::try_exists(&input_path).await.unwrap_or(false) {
@@ -113,11 +114,13 @@ pub async fn handle_reanalyze_case(
}
let user_root = config.data_path.join(&user.slug);
let case_dir = user_root.join("open").join(&case_id);
if !tokio::fs::try_exists(&case_dir).await.unwrap_or(false) {
warn!(slug = %user.slug, case_id = %case_id, "reanalyze: case not found in open/");
return Err(AppError::NotFound("Case not found".into()));
}
let case_dir = match locate_case(&user_root, &case_id).await {
Some(p) => p,
None => {
warn!(slug = %user.slug, case_id = %case_id, "reanalyze: case not found");
return Err(AppError::NotFound("Case not found".into()));
}
};
let current_version = find_latest_document(&case_dir)
.await
@@ -166,8 +169,8 @@ pub async fn handle_document_view(
.map_err(|_| AppError::BadRequest("Invalid case_id".into()))?;
let user_root = config.data_path.join(&user.slug);
let (case_dir, _status) = match locate_case(&user_root, &case_id).await {
Some(v) => v,
let case_dir = match locate_case(&user_root, &case_id).await {
Some(p) => p,
None => {
warn!(slug = %user.slug, case_id = %case_id, "document view: case not found");
return Err(AppError::NotFound("Case not found".into()));