1pub mod account;
8pub mod auth;
9pub mod dashboard;
10pub mod error;
11pub mod routes;
12pub mod state;
13pub mod ws;
14
15use std::sync::Arc;
16
17use axum::middleware;
18use axum::routing::{delete, get, patch, post};
19use axum::Router;
20use tower_http::cors::CorsLayer;
21use tower_http::trace::TraceLayer;
22
23use crate::state::AppState;
24
25pub fn build_router(state: Arc<AppState>) -> Router {
27 let api = Router::new()
28 .route("/health", get(routes::health::health))
29 .route("/health/detailed", get(routes::health::health_detailed))
30 .route("/auth/login", post(auth::routes::login))
32 .route("/auth/logout", post(auth::routes::logout))
33 .route("/auth/status", get(auth::routes::status))
34 .route("/analytics/summary", get(routes::analytics::summary))
36 .route("/analytics/followers", get(routes::analytics::followers))
37 .route(
38 "/analytics/performance",
39 get(routes::analytics::performance),
40 )
41 .route("/analytics/topics", get(routes::analytics::topics))
42 .route(
43 "/analytics/recent-performance",
44 get(routes::analytics::recent_performance),
45 )
46 .route("/approval/export", get(routes::approval::export_items))
48 .route("/approval", get(routes::approval::list_items))
49 .route("/approval/stats", get(routes::approval::stats))
50 .route("/approval/approve-all", post(routes::approval::approve_all))
51 .route(
52 "/approval/{id}/history",
53 get(routes::approval::get_edit_history),
54 )
55 .route("/approval/{id}", patch(routes::approval::edit_item))
56 .route(
57 "/approval/{id}/approve",
58 post(routes::approval::approve_item),
59 )
60 .route("/approval/{id}/reject", post(routes::approval::reject_item))
61 .route("/activity/export", get(routes::activity::export_activity))
63 .route("/activity", get(routes::activity::list_activity))
64 .route(
65 "/activity/rate-limits",
66 get(routes::activity::rate_limit_usage),
67 )
68 .route("/replies", get(routes::replies::list_replies))
70 .route(
72 "/content/tweets",
73 get(routes::content::list_tweets).post(routes::content::compose_tweet),
74 )
75 .route(
76 "/content/threads",
77 get(routes::content::list_threads).post(routes::content::compose_thread),
78 )
79 .route("/content/calendar", get(routes::content::calendar))
80 .route("/content/schedule", get(routes::content::schedule))
81 .route("/content/compose", post(routes::content::compose))
82 .route(
83 "/content/scheduled/{id}",
84 patch(routes::content::edit_scheduled).delete(routes::content::cancel_scheduled),
85 )
86 .route(
88 "/content/drafts",
89 get(routes::content::list_drafts).post(routes::content::create_draft),
90 )
91 .route(
92 "/content/drafts/{id}",
93 patch(routes::content::edit_draft).delete(routes::content::delete_draft),
94 )
95 .route(
96 "/content/drafts/{id}/schedule",
97 post(routes::content::schedule_draft),
98 )
99 .route(
100 "/content/drafts/{id}/publish",
101 post(routes::content::publish_draft),
102 )
103 .route("/ingest", post(routes::ingest::ingest))
105 .route(
107 "/targets",
108 get(routes::targets::list_targets).post(routes::targets::add_target),
109 )
110 .route(
111 "/targets/{username}/timeline",
112 get(routes::targets::target_timeline),
113 )
114 .route(
115 "/targets/{username}/stats",
116 get(routes::targets::target_stats),
117 )
118 .route(
119 "/targets/{username}",
120 delete(routes::targets::remove_target),
121 )
122 .route("/strategy/current", get(routes::strategy::current))
124 .route("/strategy/history", get(routes::strategy::history))
125 .route("/strategy/refresh", post(routes::strategy::refresh))
126 .route("/strategy/inputs", get(routes::strategy::inputs))
127 .route("/costs/summary", get(routes::costs::summary))
129 .route("/costs/daily", get(routes::costs::daily))
130 .route("/costs/by-model", get(routes::costs::by_model))
131 .route("/costs/by-type", get(routes::costs::by_type))
132 .route("/costs/x-api/summary", get(routes::costs::x_api_summary))
134 .route("/costs/x-api/daily", get(routes::costs::x_api_daily))
135 .route(
136 "/costs/x-api/by-endpoint",
137 get(routes::costs::x_api_by_endpoint),
138 )
139 .route("/assist/tweet", post(routes::assist::assist_tweet))
141 .route("/assist/reply", post(routes::assist::assist_reply))
142 .route("/assist/thread", post(routes::assist::assist_thread))
143 .route("/assist/improve", post(routes::assist::assist_improve))
144 .route("/assist/topics", get(routes::assist::assist_topics))
145 .route(
146 "/assist/optimal-times",
147 get(routes::assist::assist_optimal_times),
148 )
149 .route("/assist/mode", get(routes::assist::get_mode))
150 .route("/discovery/feed", get(routes::discovery::feed))
152 .route("/discovery/keywords", get(routes::discovery::keywords))
153 .route(
154 "/discovery/{tweet_id}/compose-reply",
155 post(routes::discovery::compose_reply),
156 )
157 .route(
158 "/discovery/{tweet_id}/queue-reply",
159 post(routes::discovery::queue_reply),
160 )
161 .route("/media/upload", post(routes::media::upload))
163 .route("/media/file", get(routes::media::serve_file))
164 .route(
166 "/settings/lan",
167 get(routes::lan::get_status).patch(routes::lan::toggle_lan),
168 )
169 .route(
170 "/settings/lan/reset-passphrase",
171 post(routes::lan::reset_passphrase),
172 )
173 .route("/settings/status", get(routes::settings::config_status))
175 .route("/settings/init", post(routes::settings::init_settings))
176 .route(
177 "/settings/validate",
178 post(routes::settings::validate_settings),
179 )
180 .route("/settings/defaults", get(routes::settings::get_defaults))
181 .route("/settings/test-llm", post(routes::settings::test_llm))
182 .route(
183 "/settings",
184 get(routes::settings::get_settings).patch(routes::settings::patch_settings),
185 )
186 .route(
188 "/mcp/policy",
189 get(routes::mcp::get_policy).patch(routes::mcp::patch_policy),
190 )
191 .route("/mcp/policy/templates", get(routes::mcp::list_templates))
192 .route(
193 "/mcp/policy/templates/{name}",
194 post(routes::mcp::apply_template),
195 )
196 .route(
197 "/mcp/telemetry/summary",
198 get(routes::mcp::telemetry_summary),
199 )
200 .route(
201 "/mcp/telemetry/metrics",
202 get(routes::mcp::telemetry_metrics),
203 )
204 .route("/mcp/telemetry/errors", get(routes::mcp::telemetry_errors))
205 .route("/mcp/telemetry/recent", get(routes::mcp::telemetry_recent))
206 .route("/runtime/status", get(routes::runtime::status))
208 .route("/runtime/start", post(routes::runtime::start))
209 .route("/runtime/stop", post(routes::runtime::stop))
210 .route(
212 "/accounts",
213 get(routes::accounts::list_accounts).post(routes::accounts::create_account),
214 )
215 .route(
216 "/accounts/{id}/roles",
217 get(routes::accounts::list_roles)
218 .post(routes::accounts::set_role)
219 .delete(routes::accounts::remove_role),
220 )
221 .route(
222 "/accounts/{id}",
223 get(routes::accounts::get_account)
224 .patch(routes::accounts::update_account)
225 .delete(routes::accounts::delete_account),
226 )
227 .route("/ws", get(ws::ws_handler))
229 .layer(middleware::from_fn_with_state(
231 state.clone(),
232 auth::auth_middleware,
233 ));
234
235 Router::new()
236 .nest("/api", api)
237 .fallback(dashboard::serve_dashboard)
238 .layer(CorsLayer::permissive())
239 .layer(TraceLayer::new_for_http())
240 .with_state(state)
241}