docs: tambah doc comment, logging, dan inline comments di semua 255 file

Meliputi:
- File-level //! doc comment: tujuan file, alur kerja, komponen utama
- Function-level /// doc comment: apa, parameter, return, flow, edge cases
- Struct/enum/trait /// doc comment: peran, field docs
- Tracing logging (tracing::info!/debug!/trace!/warn!/error!) di setiap fungsi
- Inline comments untuk variable dan branching logic penting
- Seluruh 8 crates di workspace: zesdex-backend, zesdex-cms, zesdex-entities,
  zesdex-iam, zesdex-infra, zesdex-ipc, zesdex-middleware, zesdex-utils
- Build: 0 errors, 242/242 tests passed
This commit is contained in:
asepharyana
2026-07-19 17:05:47 +07:00
parent 6680795ce7
commit 5aaedbf787
255 changed files with 5666 additions and 743 deletions
@@ -1,4 +1,9 @@
//! Authentication entities: session metadata and PID-file lock.
//!
//! # Types
//!
//! - [`Session`](session::Session) — Authenticated user session with tokens, expiry, refresh
//! - [`SessionLock`](session_lock::SessionLock) — Exclusive PID-based lock to prevent concurrent sessions
pub mod session;
pub mod session_lock;
@@ -1,22 +1,45 @@
//! Session metadata: id, title, workspace roots, and message/token counts,
//! persisted as `session.json` per session directory.
//!
//! # Flow
//!
//! Created via [`Session::new`] → mutated in-memory → persisted via [`Session::save`]
//! (atomic write with fsync). Loaded back via [`Session::load`] or enumerated via
//! [`Session::list`]. Directory traversal is blocked by input validation in `load`.
//!
//! # Components
//!
//! - `Session` struct — fields for all session metadata
//! - `new` — timestamped constructor
//! - `save` / `load` / `list` — CRUD against the filesystem
use chrono::Utc;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use tracing;
/// Metadata for one conversation session (distinct from the message
/// history itself, which lives in `Conversation`/the msglog).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Session {
/// Unique session identifier (validated against path traversal in `load`).
pub id: String,
/// Epoch-millis timestamp of creation (`Utc::now().timestamp_millis()`).
pub created_at: i64,
/// Epoch-millis timestamp of last update.
pub updated_at: i64,
/// Human-readable title for the conversation.
pub title: String,
/// Model identifier string, e.g. `"anthropic/claude-opus-4-8"`.
pub model: String,
/// Workspace root directories associated with this session.
pub workspace_roots: Vec<PathBuf>,
/// Running count of messages in the conversation.
pub message_count: u32,
/// Running count of tokens consumed.
pub token_count: u32,
/// Soft-delete flag — archived sessions are hidden from the default list.
pub archived: bool,
/// Optional AI-generated conversation summary (used for compact context).
pub summary: Option<String>,
}
@@ -64,6 +87,7 @@ impl Session {
let dir = self.session_dir(base_dir);
std::fs::create_dir_all(&dir)?;
let path = dir.join("session.json");
tracing::debug!(id = %self.id, path = %path.display(), "saving session metadata");
zesdex_utils::write_json_atomic(&path, self, None)?;
Ok(())
}
@@ -85,7 +109,8 @@ impl Session {
));
}
let path = base_dir.join("sessions").join(id).join("session.json");
let data = std::fs::read_to_string(path)?;
tracing::debug!(id = %id, path = %path.display(), "loading session metadata");
let data = std::fs::read_to_string(&path)?;
let session: Session = serde_json::from_str(&data)?;
Ok(session)
}
@@ -101,6 +126,7 @@ impl Session {
pub fn list(base_dir: &Path) -> Vec<Self> {
let sessions_dir = base_dir.join("sessions");
let Ok(entries) = std::fs::read_dir(&sessions_dir) else {
tracing::warn!(path = %sessions_dir.display(), "sessions directory not found");
return Vec::new();
};
entries
@@ -1,14 +1,32 @@
//! PID-file based advisory lock preventing two processes from operating on
//! the same session directory concurrently.
//!
//! # Flow
//!
//! [`SessionLock::new`] creates a handle → [`SessionLock::try_lock`] attempts
//! atomic `O_CREAT|O_EXCL` creation. If the lock file already exists, the
//! owning PID is checked via `kill(pid, 0)` + `/proc/<pid>/exe` verification.
//! Stale locks are overwritten atomically (temp-file + rename + fsync).
//! On [`Drop`], the lock file is removed automatically.
//!
//! # Components
//!
//! - `SessionLock` — RAII guard wrapping a lock file path and PID
//! - `try_lock` — three-phase atomic acquire with stale-lock recovery
//! - `unlock` / `Drop` — explicit and implicit release
//! - `is_alive` — liveness check via `libc::kill` + `/proc` verification
use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use tracing;
/// A PID-file lock (`<session_dir>/.lock`) tied to the current process,
/// auto-removed on drop.
#[derive(Debug)]
pub struct SessionLock {
/// Path to the `.lock` file inside the session directory.
path: PathBuf,
/// Process ID that holds (or will hold) this lock.
pid: u32,
}
@@ -47,9 +65,11 @@ impl SessionLock {
Ok(mut file) => {
write!(file, "{}", self.pid)?;
file.sync_all()?;
tracing::debug!(path = %self.path.display(), pid = self.pid, "session lock acquired");
return Ok(true);
}
Err(ref e) if e.kind() == std::io::ErrorKind::AlreadyExists => {
tracing::debug!(path = %self.path.display(), "session lock already exists, checking staleness");
// Lock file exists — check if it's stale.
}
Err(e) => return Err(e),
@@ -59,8 +79,10 @@ impl SessionLock {
let content = fs::read_to_string(&self.path).unwrap_or_default();
if let Ok(pid) = content.trim().parse::<u32>() {
if Self::is_alive(pid) {
tracing::warn!(stale = pid, path = %self.path.display(), "session lock held by live process");
return Ok(false);
}
tracing::debug!(stale = pid, "stale lock detected, overwriting");
}
// Phase 3: stale lock — overwrite it atomically (best-effort).