S1: Colony backend skeleton — Axum + SQLite, channels + messages CRUD
Monorepo structure:
- crates/colony-types: API types (serde + ts-rs), separate from DB models
- crates/colony: Axum server, SQLite via sqlx, migrations
Working endpoints:
- GET /api/health
- GET/POST /api/channels
- GET /api/channels/{id}
- GET /api/channels/{id}/messages (?since=, ?type=, ?user_id=)
- POST /api/channels/{id}/messages (with type + metadata)
Data model includes:
- seq monotonic ordering, soft delete, same-channel reply constraint
- Seeded users (benji, neeraj) and #general channel
Also: codex-review skill, .gitignore
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
53
crates/colony/src/main.rs
Normal file
53
crates/colony/src/main.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
mod db;
|
||||
mod routes;
|
||||
|
||||
use axum::{routing::get, Router};
|
||||
use sqlx::sqlite::SqlitePoolOptions;
|
||||
use std::env;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let db_url = env::var("DATABASE_URL").unwrap_or_else(|_| "sqlite:colony.db?mode=rwc".into());
|
||||
let port = env::var("PORT").unwrap_or_else(|_| "3001".into());
|
||||
|
||||
let pool = SqlitePoolOptions::new()
|
||||
.max_connections(5)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
.expect("Failed to connect to database");
|
||||
|
||||
// Enable WAL mode
|
||||
sqlx::query("PRAGMA journal_mode=WAL")
|
||||
.execute(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Run migrations
|
||||
let migration_sql = include_str!("../migrations/001_init.sql");
|
||||
for statement in migration_sql.split(';') {
|
||||
let stmt = statement.trim();
|
||||
if !stmt.is_empty() {
|
||||
if let Err(e) = sqlx::query(stmt).execute(&pool).await {
|
||||
eprintln!("Migration warning (may be OK): {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("Colony running on port {}", port);
|
||||
|
||||
let app = Router::new()
|
||||
.route("/api/health", get(routes::health))
|
||||
.route("/api/channels", get(routes::list_channels).post(routes::create_channel))
|
||||
.route("/api/channels/{id}", get(routes::get_channel))
|
||||
.route(
|
||||
"/api/channels/{channel_id}/messages",
|
||||
get(routes::list_messages).post(routes::post_message),
|
||||
)
|
||||
.with_state(pool);
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", port))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
||||
Reference in New Issue
Block a user