1use utoipa::{
5 openapi::security::{HttpAuthScheme, HttpBuilder, SecurityScheme},
6 Modify, OpenApi,
7};
8use utoipa_swagger_ui::SwaggerUi;
9
10#[derive(OpenApi)]
14#[openapi(
15 info(
16 title = "KoproGo API",
17 version = "1.0.0",
18 description = "Belgian Property Management SaaS Platform\n\n\
19 # Features\n\
20 - ๐ข Building & Unit Management\n\
21 - ๐ฅ Multi-owner & Multi-role Support\n\
22 - ๐ฐ Financial Management (Belgian PCMN)\n\
23 - ๐ณ๏ธ Meeting & Voting System\n\
24 - ๐ Document Management\n\
25 - ๐ Budget & รtat Datรฉ Generation\n\
26 - ๐ Notifications & Payment Recovery\n\
27 - ๐ค Community Features (SEL, Notices, Skills)\n\
28 - ๐ฎ Gamification & Achievements\n\
29 - ๐ GDPR Compliant\n\n\
30 # Authentication\n\
31 All endpoints (except /health and /public/*) require JWT Bearer token.\n\
32 Get token via POST /api/v1/auth/login\n\n\
33 # Complete API Documentation\n\
34 90 of 511 endpoints annotated with utoipa (Swagger UI live spec).\n\
35 Full 495-endpoint OpenAPI 3.0.3 spec available at docs/api/openapi.yaml.\n\n\
36 Progressive annotation ongoing โ see handlers for pattern.",
37 contact(
38 name = "KoproGo Support",
39 email = "support@koprogo.com"
40 ),
41 license(
42 name = "AGPL-3.0-or-later",
43 url = "https://www.gnu.org/licenses/agpl-3.0.en.html"
44 ),
45 ),
46 servers(
47 (url = "http://localhost:8080", description = "Local development"),
48 (url = "https://api.koprogo.com", description = "Production"),
49 ),
50 paths(
51 crate::infrastructure::web::handlers::health::health_check,
53 crate::infrastructure::web::handlers::auth_handlers::login,
55 crate::infrastructure::web::handlers::auth_handlers::register,
56 crate::infrastructure::web::handlers::auth_handlers::refresh_token,
57 crate::infrastructure::web::handlers::auth_handlers::switch_role,
58 crate::infrastructure::web::handlers::auth_handlers::get_current_user,
59 crate::infrastructure::web::handlers::building_handlers::create_building,
61 crate::infrastructure::web::handlers::building_handlers::list_buildings,
62 crate::infrastructure::web::handlers::building_handlers::get_building,
63 crate::infrastructure::web::handlers::building_handlers::update_building,
64 crate::infrastructure::web::handlers::building_handlers::delete_building,
65 crate::infrastructure::web::handlers::building_handlers::export_annual_report_pdf,
66 crate::infrastructure::web::handlers::payment_handlers::create_payment,
68 crate::infrastructure::web::handlers::payment_handlers::get_payment,
69 crate::infrastructure::web::handlers::payment_handlers::get_payment_by_stripe_intent,
70 crate::infrastructure::web::handlers::payment_handlers::list_owner_payments,
71 crate::infrastructure::web::handlers::payment_handlers::list_building_payments,
72 crate::infrastructure::web::handlers::payment_handlers::list_expense_payments,
73 crate::infrastructure::web::handlers::payment_handlers::list_organization_payments,
74 crate::infrastructure::web::handlers::payment_handlers::list_payments_by_status,
75 crate::infrastructure::web::handlers::payment_handlers::list_pending_payments,
76 crate::infrastructure::web::handlers::payment_handlers::list_failed_payments,
77 crate::infrastructure::web::handlers::payment_handlers::mark_payment_processing,
78 crate::infrastructure::web::handlers::payment_handlers::mark_payment_requires_action,
79 crate::infrastructure::web::handlers::payment_handlers::mark_payment_succeeded,
80 crate::infrastructure::web::handlers::payment_handlers::mark_payment_failed,
81 crate::infrastructure::web::handlers::payment_handlers::mark_payment_cancelled,
82 crate::infrastructure::web::handlers::payment_handlers::refund_payment,
83 crate::infrastructure::web::handlers::payment_handlers::delete_payment,
84 crate::infrastructure::web::handlers::payment_handlers::get_owner_payment_stats,
85 crate::infrastructure::web::handlers::payment_handlers::get_building_payment_stats,
86 crate::infrastructure::web::handlers::payment_handlers::get_expense_total_paid,
87 crate::infrastructure::web::handlers::payment_handlers::get_owner_total_paid,
88 crate::infrastructure::web::handlers::payment_handlers::get_building_total_paid,
89 crate::infrastructure::web::handlers::ticket_handlers::create_ticket,
91 crate::infrastructure::web::handlers::ticket_handlers::get_ticket,
92 crate::infrastructure::web::handlers::ticket_handlers::delete_ticket,
93 crate::infrastructure::web::handlers::ticket_handlers::list_my_tickets,
94 crate::infrastructure::web::handlers::ticket_handlers::list_assigned_tickets,
95 crate::infrastructure::web::handlers::ticket_handlers::list_building_tickets,
96 crate::infrastructure::web::handlers::ticket_handlers::list_organization_tickets,
97 crate::infrastructure::web::handlers::ticket_handlers::list_tickets_by_status,
98 crate::infrastructure::web::handlers::ticket_handlers::assign_ticket,
99 crate::infrastructure::web::handlers::ticket_handlers::start_work,
100 crate::infrastructure::web::handlers::ticket_handlers::resolve_ticket,
101 crate::infrastructure::web::handlers::ticket_handlers::close_ticket,
102 crate::infrastructure::web::handlers::ticket_handlers::cancel_ticket,
103 crate::infrastructure::web::handlers::ticket_handlers::reopen_ticket,
104 crate::infrastructure::web::handlers::ticket_handlers::get_ticket_statistics,
105 crate::infrastructure::web::handlers::ticket_handlers::get_ticket_statistics_org,
106 crate::infrastructure::web::handlers::ticket_handlers::get_overdue_tickets,
107 crate::infrastructure::web::handlers::ticket_handlers::get_overdue_tickets_org,
108 crate::infrastructure::web::handlers::poll_handlers::create_poll,
110 crate::infrastructure::web::handlers::poll_handlers::get_poll,
111 crate::infrastructure::web::handlers::poll_handlers::update_poll,
112 crate::infrastructure::web::handlers::poll_handlers::list_polls,
113 crate::infrastructure::web::handlers::poll_handlers::find_active_polls,
114 crate::infrastructure::web::handlers::poll_handlers::publish_poll,
115 crate::infrastructure::web::handlers::poll_handlers::close_poll,
116 crate::infrastructure::web::handlers::poll_handlers::cancel_poll,
117 crate::infrastructure::web::handlers::poll_handlers::delete_poll,
118 crate::infrastructure::web::handlers::poll_handlers::cast_poll_vote,
119 crate::infrastructure::web::handlers::poll_handlers::get_poll_results,
120 crate::infrastructure::web::handlers::poll_handlers::get_poll_building_statistics,
121 crate::infrastructure::web::handlers::resolution_handlers::create_resolution,
123 crate::infrastructure::web::handlers::resolution_handlers::get_resolution,
124 crate::infrastructure::web::handlers::resolution_handlers::list_meeting_resolutions,
125 crate::infrastructure::web::handlers::resolution_handlers::delete_resolution,
126 crate::infrastructure::web::handlers::resolution_handlers::cast_vote,
127 crate::infrastructure::web::handlers::resolution_handlers::list_resolution_votes,
128 crate::infrastructure::web::handlers::resolution_handlers::change_vote,
129 crate::infrastructure::web::handlers::resolution_handlers::close_voting,
130 crate::infrastructure::web::handlers::resolution_handlers::get_meeting_vote_summary,
131 crate::infrastructure::web::handlers::notification_handlers::create_notification,
133 crate::infrastructure::web::handlers::notification_handlers::get_notification,
134 crate::infrastructure::web::handlers::notification_handlers::list_my_notifications,
135 crate::infrastructure::web::handlers::notification_handlers::list_unread_notifications,
136 crate::infrastructure::web::handlers::notification_handlers::mark_notification_read,
137 crate::infrastructure::web::handlers::notification_handlers::mark_all_notifications_read,
138 crate::infrastructure::web::handlers::notification_handlers::delete_notification,
139 crate::infrastructure::web::handlers::notification_handlers::get_notification_stats,
140 crate::infrastructure::web::handlers::notification_handlers::get_user_preferences,
141 crate::infrastructure::web::handlers::notification_handlers::get_preference,
142 crate::infrastructure::web::handlers::notification_handlers::update_preference,
143 crate::infrastructure::web::handlers::gdpr_handlers::export_user_data,
145 crate::infrastructure::web::handlers::gdpr_handlers::erase_user_data,
146 crate::infrastructure::web::handlers::gdpr_handlers::can_erase_user,
147 crate::infrastructure::web::handlers::gdpr_handlers::rectify_user_data,
148 crate::infrastructure::web::handlers::gdpr_handlers::restrict_user_processing,
149 crate::infrastructure::web::handlers::gdpr_handlers::set_marketing_preference,
150 crate::infrastructure::web::handlers::consent_handlers::record_consent,
152 crate::infrastructure::web::handlers::consent_handlers::get_consent_status,
153 crate::infrastructure::web::handlers::legal_handlers::list_legal_rules,
155 crate::infrastructure::web::handlers::legal_handlers::get_legal_rule,
156 crate::infrastructure::web::handlers::legal_handlers::get_ag_sequence,
157 crate::infrastructure::web::handlers::legal_handlers::get_majority_for,
158 ),
159 modifiers(&SecurityAddon),
160 tags(
161 (name = "Health", description = "System health and monitoring"),
162 (name = "Auth", description = "Authentication and authorization"),
163 (name = "Buildings", description = "Building management"),
164 (name = "Units", description = "Unit management"),
165 (name = "Owners", description = "Owner management"),
166 (name = "Expenses", description = "Expense and invoice management"),
167 (name = "Meetings", description = "General assembly management"),
168 (name = "Budgets", description = "Annual budget management"),
169 (name = "Documents", description = "Document upload/download"),
170 (name = "GDPR", description = "Data privacy compliance"),
171 (name = "Payments", description = "Payment processing"),
172 (name = "PaymentMethods", description = "Stored payment methods"),
173 (name = "LocalExchanges", description = "SEL time-based exchange system"),
174 (name = "Notifications", description = "Multi-channel notifications"),
175 (name = "Tickets", description = "Maintenance request system"),
176 (name = "Resolutions", description = "Meeting voting system"),
177 (name = "BoardMembers", description = "Board of directors management"),
178 (name = "Quotes", description = "Contractor quote management"),
179 (name = "EtatsDates", description = "Property sale documentation"),
180 (name = "PaymentRecovery", description = "Automated payment reminders"),
181 (name = "Consent", description = "User consent management (GDPR Art. 7)"),
182 (name = "Legal Reference", description = "Belgian legal reference rules and majority types"),
183 )
184)]
185pub struct ApiDoc;
186
187struct SecurityAddon;
189
190impl Modify for SecurityAddon {
191 fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
192 if let Some(components) = openapi.components.as_mut() {
193 components.add_security_scheme(
194 "bearer_auth",
195 SecurityScheme::Http(
196 HttpBuilder::new()
197 .scheme(HttpAuthScheme::Bearer)
198 .bearer_format("JWT")
199 .description(Some(
200 "JWT token obtained from /api/v1/auth/login.\n\n\
201 Example: `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`\n\n\
202 To authenticate:\n\
203 1. Click 'Authorize' button above\n\
204 2. Enter token (with or without 'Bearer ' prefix)\n\
205 3. Click 'Authorize' in dialog\n\
206 4. Try endpoints",
207 ))
208 .build(),
209 ),
210 )
211 }
212 }
213}
214
215pub fn configure_swagger_ui() -> SwaggerUi {
219 SwaggerUi::new("/swagger-ui/{_:.*}")
220 .url("/api-docs/openapi.json", ApiDoc::openapi())
221 .config(
222 utoipa_swagger_ui::Config::default()
223 .try_it_out_enabled(true)
224 .persist_authorization(true)
225 .display_request_duration(true)
226 .deep_linking(true)
227 .display_operation_id(true)
228 .default_models_expand_depth(1)
229 .default_model_expand_depth(1), )
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236
237 #[test]
238 fn test_openapi_spec_generation() {
239 let spec = ApiDoc::openapi();
240
241 assert_eq!(spec.info.title, "KoproGo API");
243 assert_eq!(spec.info.version, "1.0.0");
244
245 assert!(spec.servers.is_some());
247 let servers = spec.servers.unwrap();
248 assert_eq!(servers.len(), 2);
249
250 assert!(spec.components.is_some());
252 let components = spec.components.unwrap();
253 assert!(components.security_schemes.contains_key("bearer_auth"));
254
255 assert!(spec.tags.is_some());
257 let tags = spec.tags.unwrap();
258 assert!(tags.len() >= 15);
259 }
260
261 #[test]
262 fn test_swagger_ui_configuration() {
263 let _swagger = configure_swagger_ui();
264 }
266
267 #[test]
268 fn test_openapi_json_is_valid() {
269 let spec = ApiDoc::openapi();
270
271 let json = serde_json::to_string(&spec).expect("Should serialize to JSON");
273 assert!(json.contains("\"title\":\"KoproGo API\""));
274 assert!(json.contains("\"version\":\"1.0.0\""));
275 }
276}