@@ -10,12 +10,13 @@ use tower_http::{cors::CorsLayer, trace::TraceLayer};
1010use crate :: {
1111 config:: Config ,
1212 http:: {
13- admin, audit, auth, files, health, identity, jobs, metrics as metrics_http, notifications ,
14- payments, profiles, transfers, withdrawals,
13+ admin, audit, auth, disputes , files, health, identity, jobs, metrics as metrics_http,
14+ notifications , payments, profiles, transfers, version as version_http , withdrawals,
1515 } ,
1616 job_worker:: JobWorker ,
1717 middleware:: {
1818 audit_logging, auth as auth_middleware, metrics, rate_limit, request_id, role_guard,
19+ version_middleware,
1920 } ,
2021 role:: Role ,
2122 service:: { MetricsService , ServiceContainer } ,
@@ -38,6 +39,10 @@ pub async fn create_app(
3839 }
3940 } ) ;
4041
42+ // =========================================================================
43+ // Route definitions
44+ // =========================================================================
45+
4146 // -------------------- Health --------------------
4247 let health_routes = Router :: new ( )
4348 . route ( "/health" , get ( health:: health_check) )
@@ -106,15 +111,14 @@ pub async fn create_app(
106111 . route ( "/:user_id" , patch ( profiles:: update_profile) )
107112 . route ( "/:user_id" , delete ( profiles:: delete_profile) ) ;
108113
109- // -------------------- Admin --------------------
110- // Files routes
114+ // -------------------- Files --------------------
111115 let files_routes = Router :: new ( )
112116 . route ( "/upload" , post ( files:: upload_file) )
113117 . route ( "/:id" , get ( files:: get_file) )
114118 . route ( "/:id/meta" , get ( files:: get_file_metadata) )
115119 . route ( "/:id" , delete ( files:: delete_file) ) ;
116120
117- // Admin routes (protected)
121+ // -------------------- Admin --------------------
118122 let admin_routes = Router :: new ( )
119123 . route ( "/dashboard/stats" , get ( admin:: get_dashboard_stats) )
120124 . route ( "/transactions" , get ( admin:: get_transactions) )
@@ -128,11 +132,45 @@ pub async fn create_app(
128132 . route ( "/audit-logs/:id" , get ( audit:: get_audit_log) )
129133 . layer ( middleware:: from_fn ( role_guard:: admin_only ( ) ) ) ;
130134
135+ // -------------------- Disputes (v2 only) --------------------
136+ // Payment-scoped dispute routes
137+ let payment_dispute_routes = Router :: new ( )
138+ . route (
139+ "/payments/:payment_id/disputes" ,
140+ post ( disputes:: file_dispute) ,
141+ )
142+ . route (
143+ "/payments/:payment_id/disputes" ,
144+ get ( disputes:: list_payment_disputes) ,
145+ ) ;
146+
147+ // Standalone dispute routes
148+ let dispute_routes = Router :: new ( )
149+ . route ( "/disputes" , get ( disputes:: list_all_disputes) )
150+ . route ( "/disputes/me" , get ( disputes:: list_my_disputes) )
151+ . route ( "/disputes/:dispute_id" , get ( disputes:: get_dispute) )
152+ . route (
153+ "/disputes/:dispute_id/status" ,
154+ patch ( disputes:: update_dispute_status) ,
155+ )
156+ . route (
157+ "/disputes/:dispute_id/evidence" ,
158+ post ( disputes:: add_evidence) ,
159+ )
160+ . route (
161+ "/disputes/:dispute_id/evidence" ,
162+ get ( disputes:: list_evidence) ,
163+ ) ;
164+
131165 // -------------------- Jobs --------------------
132166 let _job_routes = jobs:: create_job_routes ( ) ;
133167
134- // -------------------- Protected Routes --------------------
135- let protected_routes = Router :: new ( )
168+ // =========================================================================
169+ // Protected route bundles (auth + rate-limit + audit middleware applied)
170+ // =========================================================================
171+
172+ // Shared protected routes (available on both /api/v1 and /api/v2)
173+ let shared_protected = Router :: new ( )
136174 . nest ( "/identity" , identity_routes)
137175 . nest ( "/payments" , payment_routes)
138176 . nest ( "/transfers" , transfer_routes)
@@ -141,7 +179,30 @@ pub async fn create_app(
141179 . nest ( "/profiles" , profile_routes)
142180 . nest ( "/files" , files_routes)
143181 . nest ( "/admin" , admin_routes)
144- . nest ( "/audit" , audit_routes)
182+ . nest ( "/audit" , audit_routes) ;
183+
184+ // v2-only protected routes (disputes)
185+ let v2_only_protected = Router :: new ( )
186+ . merge ( payment_dispute_routes)
187+ . merge ( dispute_routes) ;
188+
189+ // Apply auth/rate-limit/audit middleware to shared routes
190+ let shared_protected_with_middleware = shared_protected
191+ . layer ( middleware:: from_fn_with_state (
192+ services. clone ( ) ,
193+ audit_logging,
194+ ) )
195+ . layer ( middleware:: from_fn_with_state (
196+ services. clone ( ) ,
197+ auth_middleware:: authenticate,
198+ ) )
199+ . layer ( middleware:: from_fn_with_state (
200+ services. clone ( ) ,
201+ rate_limit:: rate_limit,
202+ ) ) ;
203+
204+ // Apply auth/rate-limit/audit middleware to v2-only routes
205+ let v2_only_protected_with_middleware = v2_only_protected
145206 . layer ( middleware:: from_fn_with_state (
146207 services. clone ( ) ,
147208 audit_logging,
@@ -155,20 +216,56 @@ pub async fn create_app(
155216 rate_limit:: rate_limit,
156217 ) ) ;
157218
158- // -------------------- Anchor --------------------
159- let anchor_routes = Router :: new ( ) . route ( "/webhook" , post ( crate :: http:: anchor:: anchor_webhook) ) ;
219+ // =========================================================================
220+ // Versioned API routes
221+ // =========================================================================
222+
223+ // /api/v1 — all shared routes, no dispute endpoints
224+ let api_v1 = Router :: new ( )
225+ . merge ( shared_protected_with_middleware. clone ( ) )
226+ . layer ( middleware:: from_fn ( version_middleware) ) ;
227+
228+ // /api/v2 — shared routes + dispute endpoints
229+ let api_v2 = Router :: new ( )
230+ . merge ( shared_protected_with_middleware)
231+ . merge ( v2_only_protected_with_middleware)
232+ . layer ( middleware:: from_fn ( version_middleware) ) ;
233+
234+ // =========================================================================
235+ // Version documentation routes (public, no auth)
236+ // =========================================================================
237+ let version_doc_routes = Router :: new ( )
238+ . route ( "/versions" , get ( version_http:: list_versions) )
239+ . route ( "/versions/:version" , get ( version_http:: get_version) )
240+ . route (
241+ "/versions/:version/migration" ,
242+ get ( version_http:: get_migration_guide) ,
243+ ) ;
244+
245+ // =========================================================================
246+ // Anchor & public routes
247+ // =========================================================================
248+ let anchor_routes =
249+ Router :: new ( ) . route ( "/webhook" , post ( crate :: http:: anchor:: anchor_webhook) ) ;
160250
161- // -------------------- Public Routes --------------------
162251 let public_routes = Router :: new ( )
163252 . nest ( "/anchor" , anchor_routes)
164253 . nest ( "/auth" , auth_routes)
165254 . nest ( "/user" , user_routes)
166255 . nest ( "/health" , health_routes)
167256 . merge ( metrics_routes) ;
168257
258+ // =========================================================================
259+ // Assemble the full router
260+ // =========================================================================
169261 let app = Router :: new ( )
262+ // Versioned API namespaces
263+ . nest ( "/api/v1" , api_v1)
264+ . nest ( "/api/v2" , api_v2)
265+ // Version documentation (public)
266+ . nest ( "/api" , version_doc_routes)
267+ // Legacy unversioned public routes (backward compat)
170268 . merge ( public_routes)
171- . merge ( protected_routes)
172269 . with_state ( services)
173270 . layer ( middleware:: from_fn ( request_id:: request_id) )
174271 . layer ( middleware:: from_fn ( metrics:: track_metrics) )
0 commit comments