koprogo_api/infrastructure/
openapi.rs

1/// OpenAPI Documentation Module
2/// Generates OpenAPI 3.0 specification for KoproGo API
3/// Access Swagger UI at: http://localhost:8080/swagger-ui/
4use utoipa::{
5    openapi::security::{HttpAuthScheme, HttpBuilder, SecurityScheme},
6    Modify, OpenApi,
7};
8use utoipa_swagger_ui::SwaggerUi;
9
10// Handler imports not needed โ€” utoipa paths() uses full module paths
11
12/// Main OpenAPI documentation structure
13#[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        // Health
52        crate::infrastructure::web::handlers::health::health_check,
53        // Auth
54        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        // Buildings
60        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        // Payments
67        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        // Tickets
90        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        // Polls
109        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        // Resolutions
122        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        // Notifications
132        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        // GDPR
144        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        // Consent (GDPR)
151        crate::infrastructure::web::handlers::consent_handlers::record_consent,
152        crate::infrastructure::web::handlers::consent_handlers::get_consent_status,
153        // Legal Reference
154        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
187/// Add JWT Bearer authentication to OpenAPI spec
188struct 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
215/// Configure Swagger UI service
216///
217/// Swagger UI will be available at: http://localhost:8080/swagger-ui/
218pub 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), // .doc_expansion(utoipa_swagger_ui::DocExpansion::List) // Removed: DocExpansion no longer exists in utoipa_swagger_ui
230        )
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        // Verify basic info
242        assert_eq!(spec.info.title, "KoproGo API");
243        assert_eq!(spec.info.version, "1.0.0");
244
245        // Verify servers
246        assert!(spec.servers.is_some());
247        let servers = spec.servers.unwrap();
248        assert_eq!(servers.len(), 2);
249
250        // Verify security scheme
251        assert!(spec.components.is_some());
252        let components = spec.components.unwrap();
253        assert!(components.security_schemes.contains_key("bearer_auth"));
254
255        // Verify tags
256        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        // SwaggerUi is configured, this test ensures it compiles
265    }
266
267    #[test]
268    fn test_openapi_json_is_valid() {
269        let spec = ApiDoc::openapi();
270
271        // Serialize to JSON to ensure it's valid
272        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}