feat: add project and email service

This commit is contained in:
Jet Pham 2026-03-11 13:00:51 -07:00 committed by Jet
parent 99715f6105
commit f48390b15e
29 changed files with 2631 additions and 63 deletions

55
api/src/serve.rs Normal file
View file

@ -0,0 +1,55 @@
use std::sync::{Arc, Mutex};
use axum::routing::{get, post};
use axum::Router;
use rusqlite::Connection;
use tower_http::cors::CorsLayer;
use crate::handlers;
use crate::rate_limit::RateLimiter;
pub struct AppState {
pub db: Mutex<Connection>,
pub notify_email: String,
pub rate_limiter: RateLimiter,
pub webhook_secret: String,
}
pub async fn run() -> Result<(), Box<dyn std::error::Error>> {
let db_path = std::env::var("QA_DB_PATH").unwrap_or_else(|_| "qa.db".to_string());
let notify_email = std::env::var("QA_NOTIFY_EMAIL").expect("QA_NOTIFY_EMAIL must be set");
let webhook_secret = std::env::var("WEBHOOK_SECRET").expect("WEBHOOK_SECRET must be set");
let conn = Connection::open(&db_path)?;
conn.execute_batch("PRAGMA journal_mode=WAL;")?;
conn.execute_batch(
"CREATE TABLE IF NOT EXISTS questions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
question TEXT NOT NULL,
answer TEXT,
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
answered_at TEXT
);",
)?;
let state = Arc::new(AppState {
db: Mutex::new(conn),
notify_email,
rate_limiter: RateLimiter::new(5, 3600),
webhook_secret,
});
let app = Router::new()
.route(
"/api/questions",
get(handlers::get_questions).post(handlers::post_question),
)
.route("/api/webhook", post(handlers::webhook))
.layer(CorsLayer::permissive())
.with_state(state);
let listener = tokio::net::TcpListener::bind("127.0.0.1:3001").await?;
println!("Listening on 127.0.0.1:3001");
axum::serve(listener, app).await?;
Ok(())
}