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 components(schemas(
160 crate::application::dto::pagination::SortOrder,
162 crate::domain::entities::resolution::ResolutionType,
165 crate::domain::entities::resolution::MajorityType,
166 crate::domain::entities::ticket::TicketCategory,
167 crate::domain::entities::ticket::TicketPriority,
168 crate::domain::entities::ticket::TicketStatus,
169 crate::domain::entities::poll::PollStatus,
170 crate::domain::entities::poll::PollType,
171 crate::domain::entities::meeting::MeetingType,
172 crate::domain::entities::meeting::MeetingStatus,
173 crate::domain::entities::expense::ExpenseCategory,
174 crate::domain::entities::expense::PaymentStatus,
175 crate::domain::entities::expense::ApprovalStatus,
176 crate::domain::entities::resource_booking::ResourceType,
177 crate::domain::entities::resource_booking::BookingStatus,
178 crate::domain::entities::resource_booking::RecurringPattern,
179 crate::domain::entities::shared_object::SharedObjectCategory,
180 crate::domain::entities::shared_object::ObjectCondition,
181 crate::domain::entities::budget::BudgetStatus,
182 crate::domain::entities::convocation::ConvocationType,
183 crate::domain::entities::convocation::ConvocationStatus,
184 crate::domain::entities::convocation_recipient::AttendanceStatus,
185 crate::domain::entities::energy_campaign::CampaignType,
186 crate::domain::entities::energy_campaign::CampaignStatus,
187 crate::domain::entities::energy_campaign::EnergyType,
188 crate::domain::entities::energy_campaign::ContractType,
189 crate::domain::entities::etat_date::EtatDateStatus,
190 crate::domain::entities::etat_date::EtatDateLanguage,
191 crate::domain::entities::achievement::AchievementCategory,
192 crate::domain::entities::achievement::AchievementTier,
193 crate::domain::entities::challenge::ChallengeStatus,
194 crate::domain::entities::challenge::ChallengeType,
195 crate::domain::entities::technical_inspection::InspectionType,
196 crate::domain::entities::technical_inspection::InspectionStatus,
197 crate::domain::entities::local_exchange::ExchangeType,
198 crate::domain::entities::local_exchange::ExchangeStatus,
199 crate::domain::entities::owner_credit_balance::CreditStatus,
200 crate::domain::entities::owner_credit_balance::ParticipationLevel,
201 crate::domain::entities::notice::NoticeType,
202 crate::domain::entities::notice::NoticeCategory,
203 crate::domain::entities::notice::NoticeStatus,
204 crate::domain::entities::payment_reminder::ReminderLevel,
205 crate::domain::entities::payment_reminder::ReminderStatus,
206 crate::domain::entities::payment_reminder::DeliveryMethod,
207 crate::domain::entities::quote::QuoteStatus,
208 crate::domain::entities::skill::SkillCategory,
209 crate::domain::entities::skill::ExpertiseLevel,
210 crate::domain::entities::work_report::WorkType,
211 crate::domain::entities::work_report::WarrantyType,
212 crate::domain::entities::resolution::ResolutionStatus,
213 crate::domain::entities::notification::NotificationStatus,
214 crate::domain::entities::notification::NotificationPriority,
215 crate::domain::entities::payment::TransactionStatus,
216 crate::domain::entities::payment_method::PaymentMethodType,
217 )),
218 modifiers(&SecurityAddon),
219 tags(
220 (name = "Health", description = "System health and monitoring"),
221 (name = "Auth", description = "Authentication and authorization"),
222 (name = "Buildings", description = "Building management"),
223 (name = "Units", description = "Unit management"),
224 (name = "Owners", description = "Owner management"),
225 (name = "Expenses", description = "Expense and invoice management"),
226 (name = "Meetings", description = "General assembly management"),
227 (name = "Budgets", description = "Annual budget management"),
228 (name = "Documents", description = "Document upload/download"),
229 (name = "GDPR", description = "Data privacy compliance"),
230 (name = "Payments", description = "Payment processing"),
231 (name = "PaymentMethods", description = "Stored payment methods"),
232 (name = "LocalExchanges", description = "SEL time-based exchange system"),
233 (name = "Notifications", description = "Multi-channel notifications"),
234 (name = "Tickets", description = "Maintenance request system"),
235 (name = "Resolutions", description = "Meeting voting system"),
236 (name = "BoardMembers", description = "Board of directors management"),
237 (name = "Quotes", description = "Contractor quote management"),
238 (name = "EtatsDates", description = "Property sale documentation"),
239 (name = "PaymentRecovery", description = "Automated payment reminders"),
240 (name = "Consent", description = "User consent management (GDPR Art. 7)"),
241 (name = "Legal Reference", description = "Belgian legal reference rules and majority types"),
242 )
243)]
244pub struct ApiDoc;
245
246struct SecurityAddon;
248
249impl Modify for SecurityAddon {
250 fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
251 if let Some(components) = openapi.components.as_mut() {
252 components.add_security_scheme(
253 "bearer_auth",
254 SecurityScheme::Http(
255 HttpBuilder::new()
256 .scheme(HttpAuthScheme::Bearer)
257 .bearer_format("JWT")
258 .description(Some(
259 "JWT token obtained from /api/v1/auth/login.\n\n\
260 Example: `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`\n\n\
261 To authenticate:\n\
262 1. Click 'Authorize' button above\n\
263 2. Enter token (with or without 'Bearer ' prefix)\n\
264 3. Click 'Authorize' in dialog\n\
265 4. Try endpoints",
266 ))
267 .build(),
268 ),
269 )
270 }
271 }
272}
273
274pub fn configure_swagger_ui() -> SwaggerUi {
278 SwaggerUi::new("/swagger-ui/{_:.*}")
279 .url("/api-docs/openapi.json", ApiDoc::openapi())
280 .config(
281 utoipa_swagger_ui::Config::default()
282 .try_it_out_enabled(true)
283 .persist_authorization(true)
284 .display_request_duration(true)
285 .deep_linking(true)
286 .display_operation_id(true)
287 .default_models_expand_depth(1)
288 .default_model_expand_depth(1), )
290}
291
292#[cfg(test)]
293mod tests {
294 use super::*;
295
296 #[test]
297 fn test_openapi_spec_generation() {
298 let spec = ApiDoc::openapi();
299
300 assert_eq!(spec.info.title, "KoproGo API");
302 assert_eq!(spec.info.version, "1.0.0");
303
304 assert!(spec.servers.is_some());
306 let servers = spec.servers.unwrap();
307 assert_eq!(servers.len(), 2);
308
309 assert!(spec.components.is_some());
311 let components = spec.components.unwrap();
312 assert!(components.security_schemes.contains_key("bearer_auth"));
313
314 assert!(spec.tags.is_some());
316 let tags = spec.tags.unwrap();
317 assert!(tags.len() >= 15);
318 }
319
320 #[test]
321 fn test_swagger_ui_configuration() {
322 let _swagger = configure_swagger_ui();
323 }
325
326 #[test]
327 fn test_openapi_json_is_valid() {
328 let spec = ApiDoc::openapi();
329
330 let json = serde_json::to_string(&spec).expect("Should serialize to JSON");
332 assert!(json.contains("\"title\":\"KoproGo API\""));
333 assert!(json.contains("\"version\":\"1.0.0\""));
334 }
335}