Add side panels, task selection, graph animation, and project docs

- Foldable left panel (user profile) and right panel (task details)
- Clicking a task in the list or graph node selects it and shows details
- Both views (task list + graph) always mounted via absolute inset-0 for
  correct canvas dimensions; tabs toggle visibility with opacity
- Graph node selection animation: other nodes repel outward (charge -600),
  then selected node smoothly slides to center (500ms cubic ease-out),
  then charge restores to -120 and graph stabilizes
- Graph re-fits on tab switch and panel resize via ResizeObserver
- Fix UUID string IDs throughout (backend returns UUIDs, not integers)
- Add TaskDetailPanel, UserPanel components
- Add CLAUDE.md project documentation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Alvis
2026-04-08 11:23:06 +00:00
parent 5c7edd4bbc
commit f1d51b8cc8
23998 changed files with 3242708 additions and 0 deletions

86
CLAUDE.md Normal file
View File

@@ -0,0 +1,86 @@
# Taskpile
A task manager with force-directed graph visualization.
## Architecture
- **Frontend**: Next.js 14 (App Router) + React 18 + Tailwind CSS 3 + TypeScript
- **Backend**: Rust (Axum 0.7) + SQLite (via SQLx)
- **Graph**: `react-force-graph-2d` for force-directed visualization
## Project Structure
```
frontend/
src/app/page.tsx — Main page: tabs, panels, task state management
src/app/layout.tsx — Root layout
src/components/
GraphView.tsx — Force graph with node selection, drag-to-center
TaskList.tsx — Pending/completed task list with selection
TaskItem.tsx — Individual task card
AddTaskForm.tsx — New task form
TaskDetailPanel.tsx — Right panel: selected task details
UserPanel.tsx — Left panel: user profile (example data)
ForceGraphClient.tsx — ForceGraph2D ref wrapper for dynamic import
src/lib/
api.ts — API client (fetch wrappers)
types.ts — TypeScript interfaces
src/__tests__/
unit/ — Jest unit tests (API, TaskItem)
e2e/ — Jest integration tests (full user flows)
backend/
src/main.rs — Axum server on port 3001
src/models.rs — Task, GraphNode, GraphEdge structs
src/db.rs — SQLite pool + migrations
src/graph.rs — Deterministic edge generation (~30% pairs)
src/routes/tasks.rs — CRUD: GET/POST /api/tasks, PATCH/DELETE /api/tasks/:id
src/routes/graph.rs — GET /api/graph
tests/integration_test.rs — Axum integration tests
```
## Running
```bash
# Backend (port 3001)
cd backend && cargo run
# Frontend (port 3003, proxies /api to backend)
cd frontend && npm run dev -- -p 3003
```
Port 3000 is used by Gitea on this machine — use 3003 for the frontend.
## Testing
```bash
# Frontend tests
cd frontend && npx jest
# Backend tests
cd backend && cargo test
```
## Key Design Decisions
- Task IDs are UUIDs (TEXT in SQLite, string from backend). Frontend `Task.id` is typed as `number` but actually receives strings — selection uses string comparison throughout.
- Graph tab and task list are switched via tabs in the center area. Left panel (user info) and right panel (task details) are independently foldable.
- Selecting a task (from list or graph node click) animates the node to the center of the viewport (drag-style, not camera pan). The node stays pinned until a different task is selected.
- `ForceGraph2D` canvas dimensions are driven by a `ResizeObserver` on a container div that always renders. The canvas is only mounted after the first measurement to avoid a 300x300 default.
- Panel transitions are 300ms CSS; graph re-fit/re-center delays 350ms to wait for the transition.
## API
All endpoints under `/api`:
| Method | Path | Description |
|--------|------|-------------|
| GET | /tasks | List all tasks |
| POST | /tasks | Create task `{title, description?}` |
| PATCH | /tasks/:id | Update task `{title?, description?, completed?}` |
| DELETE | /tasks/:id | Delete task |
| GET | /graph | Get nodes + weighted edges |
## Proxy
Do not use system proxy env vars when testing the app locally — `curl --noproxy '*'` or equivalent.

2707
backend/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

27
backend/Cargo.toml Normal file
View File

@@ -0,0 +1,27 @@
[package]
name = "taskpile-backend"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "taskpile-backend"
path = "src/main.rs"
[lib]
name = "taskpile_backend"
path = "src/lib.rs"
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "sqlite"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tower-http = { version = "0.5", features = ["cors"] }
uuid = { version = "1", features = ["v4"] }
rand = "0.8"
anyhow = "1"
[dev-dependencies]
axum-test = "14"
tower = "0.4"

27
backend/src/db.rs Normal file
View File

@@ -0,0 +1,27 @@
use anyhow::Result;
use sqlx::{sqlite::SqlitePoolOptions, SqlitePool};
pub async fn create_pool(database_url: &str) -> Result<SqlitePool> {
let pool = SqlitePoolOptions::new()
.max_connections(5)
.connect(database_url)
.await?;
Ok(pool)
}
pub async fn run_migrations(pool: &SqlitePool) -> Result<()> {
sqlx::query(
r#"
CREATE TABLE IF NOT EXISTS tasks (
id TEXT PRIMARY KEY NOT NULL,
title TEXT NOT NULL,
description TEXT,
completed BOOLEAN NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL
)
"#,
)
.execute(pool)
.await?;
Ok(())
}

117
backend/src/graph.rs Normal file
View File

@@ -0,0 +1,117 @@
use rand::{Rng, SeedableRng};
use rand::rngs::StdRng;
use crate::models::{GraphData, GraphEdge, GraphNode, Task};
/// Build graph data from a list of tasks.
/// Nodes = tasks, edges = ~30% of all pairs, deterministic seed from task IDs.
pub fn build_graph(tasks: &[Task]) -> GraphData {
let nodes: Vec<GraphNode> = tasks
.iter()
.map(|t| GraphNode {
id: t.id.clone(),
label: t.title.clone(),
completed: t.completed,
})
.collect();
let mut edges = Vec::new();
if tasks.len() < 2 {
return GraphData { nodes, edges };
}
// Derive a deterministic seed from all task IDs concatenated
let seed_str: String = tasks.iter().map(|t| t.id.as_str()).collect::<Vec<_>>().join("");
let seed: u64 = seed_str
.bytes()
.fold(0u64, |acc, b| acc.wrapping_mul(31).wrapping_add(b as u64));
let mut rng = StdRng::seed_from_u64(seed);
for i in 0..tasks.len() {
for j in (i + 1)..tasks.len() {
// ~30% chance of an edge
if rng.gen::<f64>() < 0.30 {
let weight = rng.gen_range(0.1f32..1.0f32);
edges.push(GraphEdge {
source: tasks[i].id.clone(),
target: tasks[j].id.clone(),
weight,
});
}
}
}
GraphData { nodes, edges }
}
#[cfg(test)]
mod tests {
use super::*;
fn make_tasks(n: usize) -> Vec<Task> {
(0..n)
.map(|i| Task {
id: format!("task-{i:04}"),
title: format!("Task {i}"),
description: None,
completed: i % 2 == 0,
created_at: i as i64,
})
.collect()
}
#[test]
fn test_graph_node_count_matches_tasks() {
let tasks = make_tasks(10);
let graph = build_graph(&tasks);
assert_eq!(graph.nodes.len(), 10);
}
#[test]
fn test_graph_edge_count_reasonable() {
let tasks = make_tasks(10);
let graph = build_graph(&tasks);
// 10 tasks => 45 possible pairs. ~30% => roughly 5..20 edges
assert!(graph.edges.len() <= 45);
// At least some edges should exist with 10 tasks
// (statistically overwhelmingly likely, but we just check <= max)
}
#[test]
fn test_graph_deterministic() {
let tasks = make_tasks(8);
let g1 = build_graph(&tasks);
let g2 = build_graph(&tasks);
assert_eq!(g1.edges.len(), g2.edges.len());
for (e1, e2) in g1.edges.iter().zip(g2.edges.iter()) {
assert_eq!(e1.source, e2.source);
assert_eq!(e1.target, e2.target);
}
}
#[test]
fn test_empty_tasks() {
let graph = build_graph(&[]);
assert!(graph.nodes.is_empty());
assert!(graph.edges.is_empty());
}
#[test]
fn test_single_task_no_edges() {
let tasks = make_tasks(1);
let graph = build_graph(&tasks);
assert_eq!(graph.nodes.len(), 1);
assert!(graph.edges.is_empty());
}
#[test]
fn test_edge_weights_in_range() {
let tasks = make_tasks(10);
let graph = build_graph(&tasks);
for edge in &graph.edges {
assert!(edge.weight >= 0.1 && edge.weight < 1.0);
}
}
}

4
backend/src/lib.rs Normal file
View File

@@ -0,0 +1,4 @@
pub mod db;
pub mod graph;
pub mod models;
pub mod routes;

33
backend/src/main.rs Normal file
View File

@@ -0,0 +1,33 @@
use taskpile_backend::{db, routes};
use axum::{
routing::{delete, get, patch, post},
Router,
};
use tower_http::cors::{Any, CorsLayer};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let database_url = "sqlite:taskpile.db?mode=rwc";
let pool = db::create_pool(database_url).await?;
db::run_migrations(&pool).await?;
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any);
let app = Router::new()
.route("/api/tasks", get(routes::tasks::list_tasks))
.route("/api/tasks", post(routes::tasks::create_task))
.route("/api/tasks/:id", patch(routes::tasks::update_task))
.route("/api/tasks/:id", delete(routes::tasks::delete_task))
.route("/api/graph", get(routes::graph::get_graph))
.layer(cors)
.with_state(pool);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3001").await?;
println!("Listening on http://0.0.0.0:3001");
axum::serve(listener, app).await?;
Ok(())
}

77
backend/src/models.rs Normal file
View File

@@ -0,0 +1,77 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
pub struct Task {
pub id: String,
pub title: String,
pub description: Option<String>,
pub completed: bool,
pub created_at: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphNode {
pub id: String,
pub label: String,
pub completed: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphEdge {
pub source: String,
pub target: String,
pub weight: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphData {
pub nodes: Vec<GraphNode>,
pub edges: Vec<GraphEdge>,
}
#[derive(Debug, Deserialize)]
pub struct CreateTask {
pub title: String,
pub description: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct UpdateTask {
pub title: Option<String>,
pub description: Option<String>,
pub completed: Option<bool>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_task_serialization() {
let task = Task {
id: "abc-123".to_string(),
title: "Test task".to_string(),
description: Some("A description".to_string()),
completed: false,
created_at: 1234567890,
};
let json = serde_json::to_string(&task).unwrap();
let deserialized: Task = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized.id, task.id);
assert_eq!(deserialized.title, task.title);
assert_eq!(deserialized.completed, task.completed);
}
#[test]
fn test_task_no_description() {
let task = Task {
id: "xyz".to_string(),
title: "No desc".to_string(),
description: None,
completed: true,
created_at: 0,
};
let json = serde_json::to_string(&task).unwrap();
assert!(json.contains("\"description\":null"));
}
}

View File

@@ -0,0 +1,17 @@
use axum::{extract::State, http::StatusCode, Json};
use sqlx::SqlitePool;
use crate::{graph::build_graph, models::{GraphData, Task}};
pub async fn get_graph(
State(pool): State<SqlitePool>,
) -> Result<Json<GraphData>, StatusCode> {
let tasks = sqlx::query_as::<_, Task>(
"SELECT id, title, description, completed, created_at FROM tasks ORDER BY created_at ASC",
)
.fetch_all(&pool)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(Json(build_graph(&tasks)))
}

View File

@@ -0,0 +1,2 @@
pub mod graph;
pub mod tasks;

113
backend/src/routes/tasks.rs Normal file
View File

@@ -0,0 +1,113 @@
use axum::{
extract::{Path, State},
http::StatusCode,
Json,
};
use sqlx::SqlitePool;
use std::time::{SystemTime, UNIX_EPOCH};
use uuid::Uuid;
use crate::models::{CreateTask, Task, UpdateTask};
pub async fn list_tasks(
State(pool): State<SqlitePool>,
) -> Result<Json<Vec<Task>>, StatusCode> {
let tasks = sqlx::query_as::<_, Task>(
"SELECT id, title, description, completed, created_at FROM tasks ORDER BY created_at ASC",
)
.fetch_all(&pool)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(Json(tasks))
}
pub async fn create_task(
State(pool): State<SqlitePool>,
Json(body): Json<CreateTask>,
) -> Result<(StatusCode, Json<Task>), StatusCode> {
let id = Uuid::new_v4().to_string();
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() as i64;
sqlx::query(
"INSERT INTO tasks (id, title, description, completed, created_at) VALUES (?, ?, ?, 0, ?)",
)
.bind(&id)
.bind(&body.title)
.bind(&body.description)
.bind(now)
.execute(&pool)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let task = Task {
id,
title: body.title,
description: body.description,
completed: false,
created_at: now,
};
Ok((StatusCode::CREATED, Json(task)))
}
pub async fn update_task(
State(pool): State<SqlitePool>,
Path(id): Path<String>,
Json(body): Json<UpdateTask>,
) -> Result<Json<Task>, StatusCode> {
// Fetch existing task
let existing = sqlx::query_as::<_, Task>(
"SELECT id, title, description, completed, created_at FROM tasks WHERE id = ?",
)
.bind(&id)
.fetch_optional(&pool)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
.ok_or(StatusCode::NOT_FOUND)?;
let new_title = body.title.unwrap_or(existing.title);
let new_description = body.description.or(existing.description);
let new_completed = body.completed.unwrap_or(existing.completed);
sqlx::query(
"UPDATE tasks SET title = ?, description = ?, completed = ? WHERE id = ?",
)
.bind(&new_title)
.bind(&new_description)
.bind(new_completed)
.bind(&id)
.execute(&pool)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let updated = Task {
id,
title: new_title,
description: new_description,
completed: new_completed,
created_at: existing.created_at,
};
Ok(Json(updated))
}
pub async fn delete_task(
State(pool): State<SqlitePool>,
Path(id): Path<String>,
) -> Result<StatusCode, StatusCode> {
let result = sqlx::query("DELETE FROM tasks WHERE id = ?")
.bind(&id)
.execute(&pool)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
if result.rows_affected() == 0 {
Err(StatusCode::NOT_FOUND)
} else {
Ok(StatusCode::NO_CONTENT)
}
}

View File

@@ -0,0 +1 @@
{"rustc_fingerprint":14941815660754694336,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.94.1 (e408947bf 2026-03-25)\nbinary: rustc\ncommit-hash: e408947bfd200af42db322daf0fadfe7e26d3bd1\ncommit-date: 2026-03-25\nhost: x86_64-unknown-linux-gnu\nrelease: 1.94.1\nLLVM version: 21.1.8\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/alvis/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}

View File

@@ -0,0 +1,3 @@
Signature: 8a477f597d28d172789f06886806bc55
# This file is a cache directory tag created by cargo.
# For information about cache directory tags see https://bford.info/cachedir/

View File

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
2003d49f8577788a

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"default\", \"getrandom\", \"runtime-rng\", \"std\"]","declared_features":"[\"atomic-polyfill\", \"compile-time-rng\", \"const-random\", \"default\", \"getrandom\", \"nightly-arm-aes\", \"no-rng\", \"runtime-rng\", \"serde\", \"std\"]","target":8470944000320059508,"profile":15657897354478470176,"path":6583748113720099799,"deps":[[966925859616469517,"build_script_build",false,1391155811160274894],[3612005756660025491,"zerocopy",false,13966831341034201528],[5855319743879205494,"once_cell",false,3855828545801537437],[7667230146095136825,"cfg_if",false,15397566549833576348],[18408407127522236545,"getrandom",false,3152405531555791103]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/ahash-375c2341417820f3/dep-lib-ahash","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"default\", \"getrandom\", \"runtime-rng\", \"std\"]","declared_features":"[\"atomic-polyfill\", \"compile-time-rng\", \"const-random\", \"default\", \"getrandom\", \"nightly-arm-aes\", \"no-rng\", \"runtime-rng\", \"serde\", \"std\"]","target":17883862002600103897,"profile":2225463790103693989,"path":12798855230794838362,"deps":[[5398981501050481332,"version_check",false,17005284436764087020]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/ahash-7270cfc76400b87e/dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[966925859616469517,"build_script_build",false,10995732544856850946]],"local":[{"RerunIfChanged":{"output":"debug/build/ahash-8036efc89d9b8424/output","paths":["build.rs"]}}],"rustflags":[],"config":0,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
e5fd5ca63a965655

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"alloc\"]","declared_features":"[\"alloc\", \"default\", \"fresh-rust\", \"nightly\", \"serde\", \"std\"]","target":5388200169723499962,"profile":12994027242049262075,"path":8150134181990057235,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/allocator-api2-c8f86b29da3b8e3b/dep-lib-allocator_api2","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"default\", \"std\"]","declared_features":"[\"backtrace\", \"default\", \"std\"]","target":5408242616063297496,"profile":2225463790103693989,"path":1592513962797247754,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/anyhow-7d1dbc24c2f8a68d/dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[12478428894219133322,"build_script_build",false,9916118651303091387]],"local":[{"RerunIfChanged":{"output":"debug/build/anyhow-d08f0f65b4941a1e/output","paths":["src/nightly.rs"]}},{"RerunIfEnvChanged":{"var":"RUSTC_BOOTSTRAP","val":null}}],"rustflags":[],"config":0,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
e04e1cfe484ac7af

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"default\", \"std\"]","declared_features":"[\"backtrace\", \"default\", \"std\"]","target":1563897884725121975,"profile":15657897354478470176,"path":13913051421499132848,"deps":[[12478428894219133322,"build_script_build",false,5937569798794688861]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/anyhow-f36515dc2016ce88/dep-lib-anyhow","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
a87f57a159c0e825

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[]","declared_features":"[]","target":5116616278641129243,"profile":2225463790103693989,"path":13248684844495357844,"deps":[[4289358735036141001,"proc_macro2",false,10832279275625900833],[10420560437213941093,"syn",false,10021487460367715854],[13111758008314797071,"quote",false,11666790336275478594]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/async-trait-ee5a13cb59ed0262/dep-lib-async_trait","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
f5eae0f45d630369

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"default\", \"std\"]","declared_features":"[\"default\", \"std\"]","target":2515742790907851906,"profile":15657897354478470176,"path":12575998081724658878,"deps":[[5157631553186200874,"num_traits",false,16934557128371661712]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/atoi-499707733b74063a/dep-lib-atoi","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
d9ea07632b2523b1

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[]","declared_features":"[\"portable-atomic\"]","target":14411119108718288063,"profile":15657897354478470176,"path":14866621870726532260,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/atomic-waker-843b52043047247e/dep-lib-atomic_waker","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
8d27955d6ec4f7ca

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[]","declared_features":"[]","target":10734413529022586701,"profile":15657897354478470176,"path":9811154882503335560,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/auto-future-47cd436b37ad1da2/dep-lib-auto_future","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
9e9f3fcf0e2a4a38

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[]","declared_features":"[]","target":6962977057026645649,"profile":2225463790103693989,"path":15647454825061823462,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/autocfg-9ef4b25a9bd36cd2/dep-lib-autocfg","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
ef6d6725456203d2

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"default\", \"form\", \"http1\", \"json\", \"matched-path\", \"original-uri\", \"query\", \"tokio\", \"tower-log\", \"tracing\"]","declared_features":"[\"__private_docs\", \"default\", \"form\", \"http1\", \"http2\", \"json\", \"macros\", \"matched-path\", \"multipart\", \"original-uri\", \"query\", \"tokio\", \"tower-log\", \"tracing\", \"ws\"]","target":13920321295547257648,"profile":15657897354478470176,"path":7750414729436195668,"deps":[[784494742817713399,"tower_service",false,16019076366609623065],[1363051979936526615,"memchr",false,3683407666151743318],[2251399859588827949,"pin_project_lite",false,5057344457388244224],[2517136641825875337,"sync_wrapper",false,13908361313548202605],[2620434475832828286,"http",false,12178800335506446277],[3626672138398771397,"hyper",false,3074507707550243104],[3632162862999675140,"tower",false,14384839231750677197],[3870702314125662939,"bytes",false,2709368896986884538],[4359148418957042248,"axum_core",false,7671942205820207316],[5532778797167691009,"itoa",false,6050066881301659259],[5898568623609459682,"futures_util",false,17833620431097856884],[6803352382179706244,"percent_encoding",false,2496778773300025267],[7712452662827335977,"tower_layer",false,12329683236559188260],[9678799920983747518,"matchit",false,16429123917527311703],[10229185211513642314,"mime",false,10010972161496507110],[11976082518617474977,"hyper_util",false,18105810623032798975],[13548984313718623784,"serde",false,13993743657434939901],[13795362694956882968,"serde_json",false,14792315538488301761],[14084095096285906100,"http_body",false,10962244317973710858],[14156967978702956262,"rustversion",false,10740991818506275069],[14757622794040968908,"tracing",false,3568424343064569723],[14814583949208169760,"serde_path_to_error",false,8452671690288024270],[16542808166767769916,"serde_urlencoded",false,12038355261165830975],[16611674984963787466,"async_trait",false,2731644665191694248],[16900715236047033623,"http_body_util",false,13695458902152294853],[17541620359049798014,"tokio",false,6352395554011230797]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/axum-7e00d743df34e06f/dep-lib-axum","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
f80e5e6f3c341119

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"default\", \"form\", \"http1\", \"json\", \"matched-path\", \"original-uri\", \"query\", \"tokio\", \"tower-log\", \"tracing\"]","declared_features":"[\"__private_docs\", \"default\", \"form\", \"http1\", \"http2\", \"json\", \"macros\", \"matched-path\", \"multipart\", \"original-uri\", \"query\", \"tokio\", \"tower-log\", \"tracing\", \"ws\"]","target":13920321295547257648,"profile":15657897354478470176,"path":7750414729436195668,"deps":[[784494742817713399,"tower_service",false,16019076366609623065],[1363051979936526615,"memchr",false,3683407666151743318],[2251399859588827949,"pin_project_lite",false,5057344457388244224],[2517136641825875337,"sync_wrapper",false,13908361313548202605],[2620434475832828286,"http",false,12178800335506446277],[3626672138398771397,"hyper",false,4754227432821557856],[3632162862999675140,"tower",false,14384839231750677197],[3870702314125662939,"bytes",false,2709368896986884538],[4359148418957042248,"axum_core",false,7671942205820207316],[5532778797167691009,"itoa",false,6050066881301659259],[5898568623609459682,"futures_util",false,17833620431097856884],[6803352382179706244,"percent_encoding",false,2496778773300025267],[7712452662827335977,"tower_layer",false,12329683236559188260],[9678799920983747518,"matchit",false,16429123917527311703],[10229185211513642314,"mime",false,10010972161496507110],[11976082518617474977,"hyper_util",false,11137536502163805979],[13548984313718623784,"serde",false,13993743657434939901],[13795362694956882968,"serde_json",false,14792315538488301761],[14084095096285906100,"http_body",false,10962244317973710858],[14156967978702956262,"rustversion",false,10740991818506275069],[14757622794040968908,"tracing",false,3568424343064569723],[14814583949208169760,"serde_path_to_error",false,8452671690288024270],[16542808166767769916,"serde_urlencoded",false,12038355261165830975],[16611674984963787466,"async_trait",false,2731644665191694248],[16900715236047033623,"http_body_util",false,13695458902152294853],[17541620359049798014,"tokio",false,6352395554011230797]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/axum-a18956eb1d1e4160/dep-lib-axum","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
d4803ddbc936786a

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"tracing\"]","declared_features":"[\"__private_docs\", \"tracing\"]","target":2565713999752801252,"profile":15657897354478470176,"path":4293923778822616582,"deps":[[784494742817713399,"tower_service",false,16019076366609623065],[2251399859588827949,"pin_project_lite",false,5057344457388244224],[2517136641825875337,"sync_wrapper",false,13908361313548202605],[2620434475832828286,"http",false,12178800335506446277],[3870702314125662939,"bytes",false,2709368896986884538],[5898568623609459682,"futures_util",false,17833620431097856884],[7712452662827335977,"tower_layer",false,12329683236559188260],[10229185211513642314,"mime",false,10010972161496507110],[14084095096285906100,"http_body",false,10962244317973710858],[14156967978702956262,"rustversion",false,10740991818506275069],[14757622794040968908,"tracing",false,3568424343064569723],[16611674984963787466,"async_trait",false,2731644665191694248],[16900715236047033623,"http_body_util",false,13695458902152294853]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/axum-core-dd51bc854bf4db36/dep-lib-axum_core","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
1f822cbcc287c8d7

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"default\", \"pretty-assertions\"]","declared_features":"[\"default\", \"msgpack\", \"pretty-assertions\", \"yaml\"]","target":1999684334358351018,"profile":15657897354478470176,"path":13393747337792090781,"deps":[[1528297757488249563,"url",false,4346602663945371319],[1770175401655680863,"auto_future",false,14625374293204477837],[2620434475832828286,"http",false,12178800335506446277],[3601586811267292532,"tower",false,18038603649231531543],[3626672138398771397,"hyper",false,4754227432821557856],[3666196340704888985,"smallvec",false,6999625528918773204],[3870702314125662939,"bytes",false,2709368896986884538],[4891297352905791595,"axum",false,1806282359723396856],[9278515158990611354,"rust_multipart_rfc7578_2",false,16754520526401019626],[10229185211513642314,"mime",false,10010972161496507110],[11976082518617474977,"hyper_util",false,11137536502163805979],[12478428894219133322,"anyhow",false,12666174154364178144],[13548984313718623784,"serde",false,13993743657434939901],[13795362694956882968,"serde_json",false,14792315538488301761],[14483443567775487101,"reserve_port",false,2152609931759034798],[16542808166767769916,"serde_urlencoded",false,12038355261165830975],[16611674984963787466,"async_trait",false,2731644665191694248],[16727543399706004146,"cookie",false,3465696580324336833],[16900715236047033623,"http_body_util",false,13695458902152294853],[17541620359049798014,"tokio",false,6352395554011230797],[17811409749869794184,"pretty_assertions",false,2595604308830274304]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/axum-test-38ee43f555c643d8/dep-lib-axum_test","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
35f4e3124c7e73fa

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"alloc\", \"default\", \"std\"]","declared_features":"[\"alloc\", \"default\", \"std\"]","target":13060062996227388079,"profile":15657897354478470176,"path":14709185621984536711,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/base64-a5ce8b9cc4643f8b/dep-lib-base64","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
50b88b90a6c6e0c2

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[]","declared_features":"[\"arbitrary\", \"bytemuck\", \"example_generated\", \"serde\", \"serde_core\", \"std\"]","target":7691312148208718491,"profile":15657897354478470176,"path":15191591926664195229,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/bitflags-b60e409526351a4f/dep-lib-bitflags","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
7264829b9f998268

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"std\"]","declared_features":"[\"arbitrary\", \"bytemuck\", \"example_generated\", \"serde\", \"serde_core\", \"std\"]","target":7691312148208718491,"profile":2225463790103693989,"path":15191591926664195229,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/bitflags-b7432f592fa94b32/dep-lib-bitflags","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
4d5be1c2a6847996

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[]","declared_features":"[]","target":4098124618827574291,"profile":15657897354478470176,"path":12065623917026451340,"deps":[[10520923840501062997,"generic_array",false,8150697793081606182]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/block-buffer-26340f8edc3fc036/dep-lib-block_buffer","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
24d46065068f7e5c

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"std\"]","declared_features":"[\"default\", \"i128\", \"std\"]","target":8344828840634961491,"profile":15657897354478470176,"path":15643985970352291081,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/byteorder-f3e805ad653ee201/dep-lib-byteorder","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

View File

@@ -0,0 +1 @@
ba29652ea89c9925

View File

@@ -0,0 +1 @@
{"rustc":5391851738765093524,"features":"[\"default\", \"std\"]","declared_features":"[\"default\", \"extra-platforms\", \"serde\", \"std\"]","target":11402411492164584411,"profile":5585765287293540646,"path":1403929629260805484,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/bytes-394efa973d3a621d/dep-lib-bytes","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0}

View File

@@ -0,0 +1 @@
This file has an mtime of when this was started.

Some files were not shown because too many files have changed in this diff Show More