""" Storage paths and layout for /data/users//notebooks/... All paths are derived from username and notebook_id; no global mutable state. """ from pathlib import Path from typing import Optional from backend.config import CHROMA_COLLECTION_NAME from backend.utils import ensure_dir, user_data_dir def user_root(username: str) -> Path: return user_data_dir(username) def notebooks_index_path(username: str) -> Path: return user_root(username) / "notebooks" / "index.json" def notebook_dir(username: str, notebook_id: str) -> Path: return user_root(username) / "notebooks" / notebook_id def files_raw_dir(username: str, notebook_id: str) -> Path: return ensure_dir(notebook_dir(username, notebook_id) / "files_raw") def files_extracted_dir(username: str, notebook_id: str) -> Path: return ensure_dir(notebook_dir(username, notebook_id) / "files_extracted") def sources_json_path(username: str, notebook_id: str) -> Path: return notebook_dir(username, notebook_id) / "sources.json" def chroma_persist_dir(username: str, notebook_id: str) -> Path: return ensure_dir(notebook_dir(username, notebook_id) / "chroma") def chat_messages_path(username: str, notebook_id: str) -> Path: return ensure_dir(notebook_dir(username, notebook_id) / "chat") / "messages.jsonl" def artifacts_root(username: str, notebook_id: str) -> Path: return ensure_dir(notebook_dir(username, notebook_id) / "artifacts") def artifacts_index_path(username: str, notebook_id: str) -> Path: return artifacts_root(username, notebook_id) / "index.json" def reports_dir(username: str, notebook_id: str) -> Path: return ensure_dir(artifacts_root(username, notebook_id) / "reports") def quizzes_dir(username: str, notebook_id: str) -> Path: return ensure_dir(artifacts_root(username, notebook_id) / "quizzes") def podcasts_dir(username: str, notebook_id: str) -> Path: return ensure_dir(artifacts_root(username, notebook_id) / "podcasts") def get_chroma_collection_name() -> str: return CHROMA_COLLECTION_NAME