koprogo_api/infrastructure/web/routes.rs
1use crate::infrastructure::configure_swagger_ui;
2use crate::infrastructure::web::handlers::*;
3use actix_web::web;
4
5pub fn configure_routes(cfg: &mut web::ServiceConfig) {
6 // OpenAPI Swagger UI (accessible at /swagger-ui/)
7 cfg.service(configure_swagger_ui());
8
9 cfg.service(metrics_endpoint);
10
11 // MCP (Model Context Protocol) — Issue #252, #262, #263
12 // SSE transport for Claude/AI integration (JSON-RPC 2.0 over SSE)
13 // Note: /mcp/info is public (no auth); /mcp/sse, /mcp/messages, /mcp/system-prompt, /mcp/legal-index require JWT
14 cfg.service(mcp_info_endpoint); // GET /mcp/info — no auth required
15 cfg.service(mcp_sse_endpoint); // GET /mcp/sse — JWT required
16 cfg.service(mcp_messages_endpoint); // POST /mcp/messages — JWT required
17 cfg.service(mcp_system_prompt_endpoint); // GET /mcp/system-prompt — JWT required (Issue #263)
18 cfg.service(mcp_legal_index_endpoint); // GET /mcp/legal-index — JWT required (Issue #262)
19
20 cfg.service(
21 web::scope("/api/v1")
22 .service(health_check)
23 // Public Endpoints (no authentication required - Issue #92, #277)
24 .service(get_public_syndic_info)
25 // Legal Reference (Issue #277)
26 .service(list_legal_rules)
27 .service(get_legal_rule)
28 .service(get_ag_sequence)
29 .service(get_majority_for)
30 // Authentication
31 .service(login)
32 .service(register)
33 .service(refresh_token)
34 .service(switch_role)
35 .service(logout)
36 .service(get_current_user)
37 // ACPs (Story 1.1 — Association des Copropriétaires, ADR-0010)
38 .service(create_acp)
39 // AVANT `get_acp` : `/acps/with-metrics` serait sinon capté par
40 // `/acps/{id}`, qui tenterait de lire « with-metrics » comme un
41 // UUID et rendrait un 400 au lieu de la liste.
42 .service(list_acps_with_metrics)
43 .service(list_acps)
44 .service(get_acp)
45 .service(update_acp)
46 .service(archive_acp)
47 // Registre de modules par ACP (Story 5.1 #585, ADR-0015).
48 // Trois segments : aucun risque de capture par `/acps/{id}`.
49 .service(list_acp_modules)
50 .service(enable_acp_module)
51 .service(disable_acp_module)
52 // Portfolios (Story 2.1 — Slice 2 Refonte UX multi-rôle, ADR-0011)
53 .service(create_portfolio)
54 .service(list_portfolios)
55 .service(get_portfolio)
56 .service(update_portfolio)
57 .service(delete_portfolio)
58 .service(add_portfolio_building)
59 .service(list_portfolio_buildings)
60 .service(remove_portfolio_building)
61 .service(share_portfolio)
62 .service(list_portfolio_shares)
63 .service(unshare_portfolio)
64 // Buildings
65 .service(create_building)
66 .service(list_buildings)
67 .service(get_building)
68 .service(update_building)
69 .service(delete_building)
70 .service(export_annual_report_pdf) // PDF Export (Issue #47)
71 // Units
72 .service(create_unit)
73 .service(list_units)
74 .service(get_unit)
75 .service(update_unit)
76 .service(delete_unit)
77 .service(list_units_by_building)
78 .service(assign_owner)
79 // Owners
80 // IMPORTANT: /owners/me MUST be registered before /owners/{id}
81 // because {id} would catch "me" as a path parameter
82 .service(get_my_owner)
83 .service(create_owner)
84 .service(list_owners)
85 .service(get_owner)
86 .service(update_owner)
87 .service(link_owner_to_user)
88 .service(export_owner_statement_pdf) // PDF Export (Issue #47)
89 // Owner Contributions (Revenue)
90 // IMPORTANT: register specific routes BEFORE parameterized {id} routes
91 .service(create_contribution)
92 .service(get_contributions_by_owner)
93 .service(get_outstanding_contributions)
94 .service(get_contribution)
95 .service(record_payment)
96 // Call for Funds (Collective payment requests)
97 .service(create_call_for_funds)
98 // Même piège : `/call-for-funds/overdue` avant `/call-for-funds/{id}`.
99 .service(get_overdue_calls)
100 .service(get_call_for_funds)
101 .service(list_call_for_funds)
102 .service(send_call_for_funds)
103 .service(cancel_call_for_funds)
104 .service(delete_call_for_funds)
105 // Unit-Owner Relationships
106 .service(add_owner_to_unit)
107 .service(remove_owner_from_unit)
108 .service(update_unit_owner)
109 .service(get_unit_owners)
110 .service(get_owner_units)
111 .service(get_unit_ownership_history)
112 .service(get_owner_ownership_history)
113 .service(transfer_ownership)
114 .service(get_total_ownership_percentage)
115 .service(designate_voting_representative)
116 .service(export_ownership_contract_pdf) // PDF Export (Issue #47)
117 // Expenses
118 .service(create_expense)
119 .service(list_expenses)
120 .service(get_expense)
121 .service(list_expenses_by_building)
122 .service(mark_expense_paid)
123 .service(mark_expense_overdue)
124 .service(cancel_expense)
125 .service(reactivate_expense)
126 .service(unpay_expense)
127 // Invoice Workflow (Issue #73)
128 .service(create_invoice_draft)
129 .service(update_invoice_draft)
130 .service(submit_invoice_for_approval)
131 .service(approve_invoice)
132 .service(reject_invoice)
133 .service(get_pending_invoices)
134 .service(get_invoice)
135 .service(export_work_quote_pdf) // PDF Export (Issue #47)
136 // Charge Distribution (Issue #73)
137 .service(calculate_and_save_distribution)
138 .service(get_distribution_by_expense)
139 .service(get_distributions_by_owner)
140 .service(get_total_due_by_owner)
141 // Meetings
142 .service(create_meeting)
143 .service(list_meetings)
144 .service(get_meeting)
145 .service(list_meetings_by_building)
146 .service(update_meeting)
147 .service(add_agenda_item)
148 .service(complete_meeting)
149 .service(get_meeting_completion_checklist) // GET /meetings/{id}/completion-checklist (Track H Story H3)
150 .service(cancel_meeting)
151 .service(reschedule_meeting)
152 .service(delete_meeting)
153 .service(attach_minutes)
154 .service(validate_meeting_quorum) // POST /meetings/{id}/validate-quorum (Art. 3.87 §5 CC — #271/#272)
155 .service(export_meeting_minutes_pdf)
156 // Convocations (Automatic AG Invitations - Issue #88 - Phase 2)
157 // Specific routes MUST come before parameterized /convocations/{id}
158 .service(schedule_second_convocation) // POST /convocations/second (must come before /convocations/{id})
159 .service(create_convocation)
160 .service(get_convocation_by_meeting)
161 .service(list_building_convocations)
162 .service(list_organization_convocations)
163 .service(list_convocation_recipients)
164 .service(list_eligible_convocation_recipients) // GET /buildings/{id}/eligible-convocation-recipients (#780 verrou 1)
165 .service(get_convocation_tracking_summary)
166 .service(mark_recipient_email_opened)
167 .service(update_recipient_attendance)
168 .service(set_recipient_proxy)
169 .service(send_convocation_reminders)
170 .service(schedule_convocation)
171 .service(send_convocation)
172 .service(cancel_convocation)
173 .service(delete_convocation)
174 .service(get_convocation)
175 // Resolutions & Voting (Issue #46 - Phase 2)
176 .service(create_resolution)
177 .service(get_resolution)
178 .service(list_meeting_resolutions)
179 .service(delete_resolution)
180 .service(cast_vote)
181 .service(list_resolution_votes)
182 .service(change_vote)
183 .service(close_voting)
184 .service(get_meeting_vote_summary)
185 // Polls (Board Decision Polls - Issue #51 - Phase 2)
186 .service(create_poll)
187 .service(get_poll)
188 .service(update_poll)
189 .service(list_polls)
190 .service(find_active_polls)
191 .service(publish_poll)
192 .service(close_poll)
193 .service(cancel_poll)
194 .service(delete_poll)
195 .service(cast_poll_vote)
196 .service(get_poll_results)
197 .service(get_poll_building_statistics)
198 // Tickets (Maintenance Requests - Issue #85 - Phase 2)
199 // Specific routes MUST come before parameterized /tickets/{id}
200 .service(create_ticket)
201 .service(list_assignable_users) // /tickets/assignable-users BEFORE /tickets/{id}
202 .service(list_my_tickets)
203 .service(list_assigned_tickets)
204 .service(get_ticket_statistics_org) // /tickets/statistics (org-level)
205 .service(get_overdue_tickets_org) // /tickets/overdue (org-level)
206 .service(list_tickets_by_status)
207 .service(get_ticket_statistics) // /buildings/{id}/tickets/statistics
208 .service(get_overdue_tickets) // /buildings/{id}/tickets/overdue
209 .service(list_building_tickets)
210 .service(list_organization_tickets)
211 .service(get_ticket)
212 .service(update_ticket_fields)
213 .service(delete_ticket)
214 .service(assign_ticket)
215 .service(start_work)
216 .service(send_work_order)
217 .service(resolve_ticket)
218 .service(close_ticket)
219 .service(cancel_ticket)
220 .service(reopen_ticket)
221 // Notifications (Multi-Channel System - Issue #86 - Phase 2)
222 // Specific routes MUST come before parameterized /notifications/{id}
223 .service(create_notification)
224 .service(list_my_notifications)
225 .service(list_unread_notifications)
226 .service(mark_all_notifications_read)
227 .service(get_notification_stats)
228 .service(get_notification)
229 .service(mark_notification_read)
230 .service(delete_notification)
231 // Notification Preferences
232 .service(get_user_preferences)
233 .service(get_preference)
234 .service(update_preference)
235 // Payments (Issue #84 - Phase 2)
236 // Specific routes MUST come before parameterized /payments/{id}
237 .service(create_payment)
238 .service(get_payment_by_stripe_intent)
239 .service(list_payments_by_status)
240 .service(list_pending_payments)
241 .service(list_failed_payments)
242 .service(list_owner_payments)
243 .service(list_building_payments)
244 .service(list_expense_payments)
245 .service(list_organization_payments)
246 .service(get_payment)
247 .service(mark_payment_processing)
248 .service(mark_payment_requires_action)
249 .service(mark_payment_succeeded)
250 .service(mark_payment_failed)
251 .service(mark_payment_cancelled)
252 .service(refund_payment)
253 .service(delete_payment)
254 .service(get_owner_payment_stats)
255 .service(get_building_payment_stats)
256 .service(get_expense_total_paid)
257 .service(get_owner_total_paid)
258 .service(get_building_total_paid)
259 // Payment Methods (Issue #84 - Phase 2)
260 .service(create_payment_method)
261 .service(get_payment_method)
262 .service(get_payment_method_by_stripe_id)
263 .service(list_owner_payment_methods)
264 .service(list_active_owner_payment_methods)
265 .service(get_default_payment_method)
266 .service(list_organization_payment_methods)
267 .service(list_payment_methods_by_type)
268 .service(update_payment_method)
269 .service(set_payment_method_as_default)
270 .service(deactivate_payment_method)
271 .service(reactivate_payment_method)
272 .service(delete_payment_method)
273 .service(count_active_payment_methods)
274 .service(has_active_payment_methods)
275 // Quotes (Contractor Quotes Module - Issue #91 - Phase 2)
276 .service(create_quote)
277 .service(get_quote)
278 .service(list_building_quotes)
279 .service(list_contractor_quotes)
280 .service(list_quotes_by_status)
281 .service(submit_quote)
282 .service(start_review)
283 .service(accept_quote)
284 .service(reject_quote)
285 .service(withdraw_quote)
286 .service(compare_quotes)
287 .service(update_contractor_rating)
288 .service(delete_quote)
289 .service(count_building_quotes)
290 .service(count_quotes_by_status)
291 // Local Exchanges (SEL - Local Exchange Trading System - Issue #49 - Phase 2)
292 .service(create_exchange)
293 .service(get_exchange)
294 .service(list_building_exchanges)
295 .service(list_available_exchanges)
296 .service(list_owner_exchanges)
297 .service(list_exchanges_by_type)
298 .service(request_exchange)
299 .service(start_exchange)
300 .service(complete_exchange)
301 .service(cancel_exchange)
302 .service(rate_provider)
303 .service(rate_requester)
304 .service(delete_exchange)
305 .service(get_credit_balance)
306 .service(get_leaderboard)
307 .service(get_sel_statistics)
308 .service(get_owner_summary)
309 // Notices (Community Notice Board - Issue #49 - Phase 2)
310 .service(create_notice)
311 .service(get_notice)
312 .service(list_building_notices)
313 .service(list_published_notices)
314 .service(list_pinned_notices)
315 .service(list_notices_by_type)
316 .service(list_notices_by_category)
317 .service(list_notices_by_status)
318 .service(list_author_notices)
319 .service(update_notice)
320 .service(publish_notice)
321 .service(archive_notice)
322 .service(pin_notice)
323 .service(unpin_notice)
324 .service(set_expiration)
325 .service(delete_notice)
326 .service(get_notice_statistics)
327 // Skills (Skills Directory - Issue #49 - Phase 3)
328 .service(create_skill)
329 .service(get_skill)
330 .service(list_building_skills)
331 .service(list_available_skills)
332 .service(list_free_skills)
333 .service(list_professional_skills)
334 .service(list_skills_by_category)
335 .service(list_skills_by_expertise)
336 .service(list_owner_skills)
337 .service(update_skill)
338 .service(mark_skill_available)
339 .service(mark_skill_unavailable)
340 .service(delete_skill)
341 .service(get_skill_statistics)
342 // Shared Objects (Object Sharing Library - Issue #49 - Phase 4)
343 // Specific routes MUST come before parameterized /shared-objects/{id}
344 .service(create_shared_object)
345 .service(list_my_borrowed_objects)
346 .service(list_building_objects)
347 .service(list_available_objects)
348 .service(list_borrowed_objects)
349 .service(list_overdue_objects)
350 .service(list_free_objects)
351 .service(list_objects_by_category)
352 .service(list_owner_objects)
353 .service(get_shared_object)
354 .service(update_shared_object)
355 .service(mark_object_available)
356 .service(mark_object_unavailable)
357 .service(borrow_object)
358 .service(return_object)
359 .service(delete_shared_object)
360 .service(get_object_statistics)
361 // Resource Bookings (Resource Booking Calendar - Issue #49 - Phase 5)
362 // Specific routes MUST come before parameterized /resource-bookings/{id}
363 .service(create_booking)
364 .service(list_my_bookings)
365 .service(list_my_bookings_by_status)
366 .service(list_active_bookings)
367 .service(check_conflicts)
368 .service(list_building_bookings)
369 .service(list_by_resource_type)
370 .service(list_by_resource)
371 .service(list_building_bookings_by_status)
372 .service(list_upcoming_bookings)
373 .service(list_past_bookings)
374 .service(get_booking_statistics)
375 .service(get_booking)
376 .service(update_booking)
377 .service(cancel_booking)
378 .service(complete_booking)
379 .service(mark_no_show)
380 .service(confirm_booking)
381 .service(delete_booking)
382 // Gamification & Achievements (Issue #49 - Phase 6)
383 // Achievements
384 .service(create_achievement)
385 .service(get_achievement)
386 .service(list_achievements)
387 .service(list_achievements_by_category)
388 .service(list_visible_achievements)
389 .service(update_achievement)
390 .service(delete_achievement)
391 // User Achievements
392 .service(award_achievement)
393 .service(get_user_achievements)
394 .service(get_recent_achievements)
395 // Challenges
396 .service(create_challenge)
397 .service(get_challenge)
398 .service(list_challenges)
399 .service(list_challenges_by_status)
400 .service(list_building_challenges)
401 .service(list_active_challenges)
402 .service(update_challenge)
403 .service(activate_challenge)
404 .service(complete_challenge)
405 .service(cancel_challenge)
406 .service(delete_challenge)
407 // Challenge Progress
408 .service(get_challenge_progress)
409 .service(list_challenge_progress)
410 .service(list_user_active_challenges)
411 .service(increment_progress)
412 // Gamification Stats
413 .service(get_gamification_user_stats)
414 .service(get_gamification_leaderboard)
415 // Board Members
416 .service(elect_board_member)
417 .service(get_my_mandates) // Must be before get_board_member to avoid UUID parsing
418 .service(get_board_dashboard) // Must be before get_board_member to avoid UUID parsing
419 .service(get_board_member)
420 .service(list_active_board_members)
421 .service(list_all_board_members)
422 .service(renew_mandate)
423 .service(remove_board_member)
424 .service(get_board_stats)
425 // Board Decisions
426 .service(create_decision)
427 .service(get_decision)
428 .service(list_decisions_by_building)
429 .service(list_decisions_by_status)
430 .service(list_overdue_decisions)
431 .service(update_decision_status)
432 .service(add_notes)
433 .service(complete_decision)
434 .service(get_decision_stats)
435 // CdC — alertes + élection (Story 4.7 / #582)
436 .service(create_cdc_alert)
437 .service(list_cdc_alerts_for_meeting)
438 .service(elect_cdc_members)
439 // Documents
440 .service(upload_document)
441 .service(list_documents)
442 .service(get_document)
443 .service(download_document)
444 .service(list_documents_by_building)
445 .service(list_documents_by_meeting)
446 .service(list_documents_by_expense)
447 .service(link_document_to_meeting)
448 .service(link_document_to_expense)
449 .service(delete_document)
450 // Energy Buying Groups (Achats Groupés d'Énergie - GDPR compliant)
451 .service(create_campaign)
452 .service(list_campaigns)
453 .service(get_campaign)
454 .service(get_campaign_stats)
455 .service(update_campaign_status)
456 .service(delete_campaign)
457 .service(add_offer)
458 .service(list_offers)
459 .service(select_offer)
460 .service(finalize_campaign)
461 .service(upload_bill)
462 .service(get_my_uploads)
463 .service(get_upload)
464 .service(decrypt_consumption)
465 .service(verify_upload)
466 .service(delete_upload)
467 .service(withdraw_consent)
468 .service(get_campaign_uploads)
469 // Individual Members (Issue #280 - Non-copropriétaire energy group members)
470 .service(join_campaign_as_individual) // POST /energy-campaigns/{id}/join-as-individual
471 .service(grant_consent) // POST /energy-campaigns/{campaign_id}/members/{member_id}/consent
472 .service(update_consumption) // PUT /energy-campaigns/{campaign_id}/members/{member_id}/consumption
473 .service(withdraw_from_campaign) // DELETE /energy-campaigns/{campaign_id}/members/{member_id}/withdraw
474 // Marketplace (Issue #276 - Service provider marketplace)
475 .service(search_service_providers) // GET /marketplace/providers
476 .service(get_provider_by_slug) // GET /marketplace/providers/{slug}
477 .service(create_service_provider) // POST /service-providers
478 .service(get_contract_evaluations_annual) // GET /buildings/{id}/reports/contract-evaluations/annual
479 // États Datés (Belgian legal requirement for property sales)
480 // Specific routes MUST come before parameterized /etats-dates/{id}
481 .service(create_etat_date)
482 .service(list_etats_dates)
483 .service(list_overdue)
484 .service(list_expired)
485 .service(get_stats)
486 .service(get_by_reference_number)
487 .service(issue_notary_link) // POST /etats-dates/{id}/notary-link (#845)
488 .service(renew_notary_link) // PUT /etats-dates/{id}/notary-link/renew (#845)
489 .service(revoke_notary_link) // DELETE /etats-dates/{id}/notary-link (#845)
490 .service(list_etats_dates_by_unit)
491 .service(list_etats_dates_by_building)
492 .service(get_etat_date)
493 .service(mark_in_progress)
494 .service(mark_generated)
495 .service(mark_delivered)
496 .service(update_financial_data)
497 .service(update_additional_data)
498 .service(delete_etat_date)
499 // Budgets (Annual budget management)
500 // Specific routes MUST come before parameterized /budgets/{id}
501 .service(create_budget)
502 .service(list_budgets)
503 .service(get_budget_stats)
504 .service(list_budgets_by_fiscal_year)
505 .service(list_budgets_by_status)
506 .service(get_budget_by_building_and_fiscal_year)
507 .service(get_active_budget)
508 .service(list_budgets_by_building)
509 .service(get_budget)
510 .service(get_budget_variance)
511 .service(update_budget)
512 .service(submit_budget)
513 .service(approve_budget)
514 .service(reject_budget)
515 .service(archive_budget)
516 .service(delete_budget)
517 // Accounts (Belgian PCMN)
518 .service(create_account)
519 .service(list_accounts)
520 // `count_accounts` AVANT `get_account` : `/accounts/count` serait
521 // sinon capté par `/accounts/{id}`, qui tenterait de lire « count »
522 // comme un UUID. La route était donc inatteignable, et rendait un
523 // 400 sur un identifiant mal formé plutôt que le décompte.
524 .service(count_accounts)
525 .service(get_account)
526 .service(get_account_by_code)
527 .service(update_account)
528 .service(delete_account)
529 .service(seed_belgian_pcmn)
530 // PCN (Belgian Chart of Accounts - Legacy)
531 .service(generate_pcn_report)
532 .service(export_pcn_pdf)
533 .service(export_pcn_excel)
534 // Financial Reports (Belgian PCMN)
535 .service(generate_balance_sheet)
536 .service(generate_income_statement)
537 .service(generate_balance_sheet_for_building)
538 .service(generate_income_statement_for_building)
539 // Journal Entries (Manual Accounting Operations - Noalyss-inspired)
540 .service(create_journal_entry)
541 .service(list_journal_entries)
542 .service(get_journal_entry)
543 .service(delete_journal_entry)
544 // Dashboard (Accountant)
545 .service(get_accountant_stats)
546 .service(get_recent_transactions)
547 // Payment Reminders (Issue #83)
548 // IMPORTANT: Specific routes BEFORE parameterized routes to avoid UUID conflicts
549 .service(get_recovery_stats) // Must be before get_reminder (/payment-reminders/stats vs /{id})
550 .service(find_overdue_without_reminders) // Must be before get_reminder
551 .service(bulk_create_reminders) // Must be before get_reminder
552 .service(list_by_organization) // /payment-reminders
553 .service(create_reminder) // POST /payment-reminders
554 .service(get_reminder) // /payment-reminders/{id}
555 .service(delete_reminder) // DELETE /payment-reminders/{id}
556 .service(list_by_expense) // /expenses/{id}/payment-reminders
557 .service(list_by_owner) // /owners/{id}/payment-reminders
558 .service(list_active_by_owner) // /owners/{id}/payment-reminders/active
559 .service(mark_as_sent) // PUT /payment-reminders/{id}/mark-sent
560 .service(mark_as_opened) // PUT /payment-reminders/{id}/mark-opened
561 .service(mark_as_paid) // PUT /payment-reminders/{id}/mark-paid
562 .service(cancel_reminder) // PUT /payment-reminders/{id}/cancel
563 .service(escalate_reminder) // POST /payment-reminders/{id}/escalate
564 .service(add_tracking_number) // PUT /payment-reminders/{id}/tracking-number
565 // Seed (SuperAdmin only)
566 .service(seed_demo_data)
567 .service(clear_demo_data)
568 // Scenario-based seeds for E2E testing (Issue #347)
569 .service(seed_scenario_world)
570 .service(clear_scenario_world)
571 // Stats (SuperAdmin only)
572 .service(get_dashboard_stats)
573 .service(get_seed_data_stats)
574 // Stats (Syndic/Accountant)
575 .service(get_syndic_stats)
576 .service(get_syndic_urgent_tasks)
577 // Stats (Owner)
578 // AVANT `get_owner_stats` n'est pas requis ici — `/stats/owner` et
579 // `/stats/owner/dues-by-acp` ne se recouvrent pas, la seconde ayant
580 // un segment de plus. Mais `garde_ordre_des_routes` veille.
581 .service(get_owner_dues_by_acp)
582 .service(get_owner_stats)
583 // Organizations (SuperAdmin only)
584 .service(list_organizations)
585 .service(create_organization)
586 .service(update_organization)
587 .service(activate_organization)
588 .service(suspend_organization)
589 .service(delete_organization)
590 // Users (SuperAdmin only)
591 .service(list_users)
592 .service(list_organization_users)
593 .service(create_user)
594 .service(update_user)
595 .service(activate_user)
596 .service(deactivate_user)
597 .service(delete_user)
598 // GDPR (Data Privacy)
599 .service(export_user_data)
600 .service(erase_user_data)
601 .service(can_erase_user)
602 // GDPR Complementary Articles (Issue #90)
603 .service(rectify_user_data) // Article 16: Right to Rectification
604 .service(restrict_user_processing) // Article 18: Right to Restriction
605 .service(set_marketing_preference) // Article 21: Right to Object
606 // GDPR Consent Recording (Issue #315 - Privacy Policy)
607 .service(record_consent)
608 .service(get_consent_status)
609 // GDPR Admin (SuperAdmin only)
610 .service(list_audit_logs)
611 .service(admin_export_user_data)
612 .service(admin_erase_user_data)
613 // GDPR Article 28 - DPA with Sub-Processors (Issue #316)
614 .service(list_processing_activities)
615 .service(list_sub_processors)
616 // GDPR Article 33 - Security Incidents & 72h APD Notification (Issue #317)
617 // IMPORTANT : routes specifiques AVANT les routes parametrees.
618 //
619 // Actix apparie dans l'ordre d'enregistrement. Avec
620 // `/{incident_id}` declare en premier, un GET sur
621 // `/admin/security-incidents/overdue` etait appareille avec
622 // `incident_id = "overdue"`, l'incident n'existait evidemment pas,
623 // et l'endpoint repondait 404 — donc INATTEIGNABLE en production.
624 //
625 // C'est l'endpoint qui liste les violations depassant le delai de
626 // 72 h de notification a l'APD (RGPD Art. 33). Un instrument de
627 // conformite legale, muet depuis son ecriture.
628 //
629 // Detecte par `e2e_security_incidents::test_list_overdue_incidents`,
630 // harnais jamais execute. Meme precaution deja documentee plus haut
631 // pour `/payment-reminders/stats` face a `/payment-reminders/{id}`.
632 .service(create_security_incident)
633 .service(list_overdue_incidents)
634 .service(list_security_incidents)
635 .service(get_security_incident)
636 .service(report_incident_to_apd)
637 // Two-Factor Authentication (2FA TOTP - Issue #78)
638 .configure(two_factor_handlers::configure_two_factor_routes)
639 // API Key Management (Public API v2 - Issues #111, #232)
640 .service(create_api_key)
641 .service(list_api_keys)
642 .service(get_api_key)
643 .service(update_api_key)
644 .service(revoke_api_key)
645 .service(rotate_api_key)
646 // Work Reports (Digital Maintenance Logbook - Issue #134)
647 .service(create_work_report)
648 .service(get_work_report)
649 .service(list_building_work_reports)
650 .service(list_organization_work_reports)
651 .service(list_work_reports_paginated)
652 .service(update_work_report)
653 .service(delete_work_report)
654 .service(get_active_warranties)
655 .service(get_expiring_warranties)
656 .service(add_photo)
657 .service(add_document)
658 // Technical Inspections (Digital Maintenance Logbook - Issue #134)
659 .service(create_technical_inspection)
660 .service(get_technical_inspection)
661 .service(list_building_technical_inspections)
662 .service(list_organization_technical_inspections)
663 .service(list_technical_inspections_paginated)
664 .service(update_technical_inspection)
665 .service(delete_technical_inspection)
666 .service(get_overdue_inspections)
667 .service(get_upcoming_inspections)
668 .service(get_inspections_by_type)
669 .service(add_report)
670 .service(add_inspection_photo)
671 .service(add_certificate)
672 // IoT Smart Meters (Linky/Ores - Issue #133 - IoT Phase 0)
673 .configure(iot_handlers::configure_iot_routes)
674 // IoT Phase 1: MQTT Home Assistant + BOINC Grid Computing
675 // IMPORTANT: specific /iot/grid/consent must be before /iot/grid/tasks
676 .service(start_mqtt_listener) // POST /iot/mqtt/start
677 .service(stop_mqtt_listener) // POST /iot/mqtt/stop
678 .service(mqtt_status) // GET /iot/mqtt/status
679 .service(update_grid_consent) // POST /iot/grid/consent
680 .service(get_grid_consent) // GET /iot/grid/consent/{owner_id}
681 .service(submit_grid_task) // POST /iot/grid/tasks
682 .service(cancel_grid_task) // DELETE /iot/grid/tasks/{task_id}
683 .service(get_task_status) // GET /iot/grid/tasks/{task_id} — LAST (parameterized)
684 // AG Visioconférence (BC15 - Art. 3.87 §1 CC)
685 // Specific routes BEFORE parameterized /ag-sessions/{id}
686 .service(list_ag_sessions) // GET /ag-sessions
687 .service(get_ag_session_platform_stats) // GET /ag-sessions/platform-stats (Issue #274 - SuperAdmin only)
688 .service(create_ag_session) // POST /meetings/{meeting_id}/ag-session
689 .service(get_ag_session_for_meeting) // GET /meetings/{meeting_id}/ag-session
690 .service(get_combined_quorum) // GET /ag-sessions/{id}/quorum
691 .service(start_ag_session) // PUT /ag-sessions/{id}/start
692 .service(end_ag_session) // PUT /ag-sessions/{id}/end
693 .service(cancel_ag_session) // PUT /ag-sessions/{id}/cancel
694 .service(record_remote_join) // POST /ag-sessions/{id}/join
695 .service(delete_ag_session) // DELETE /ag-sessions/{id}
696 .service(get_ag_session) // GET /ag-sessions/{id} — LAST (parameterized)
697 // AGE Agile & Concertation (BC17 - Art. 3.87 §2 CC)
698 // Specific sub-routes BEFORE parameterized /age-requests/{id}
699 .service(create_age_request) // POST /buildings/{building_id}/age-requests
700 .service(list_age_requests) // GET /buildings/{building_id}/age-requests
701 .service(add_cosignatory) // POST /age-requests/{id}/cosignatories
702 .service(remove_cosignatory) // DELETE /age-requests/{id}/cosignatories/{owner_id}
703 .service(open_age_request) // PUT /age-requests/{id}/open
704 .service(submit_age_request) // POST /age-requests/{id}/submit
705 .service(syndic_response) // PUT /age-requests/{id}/syndic-response
706 .service(trigger_auto_convocation) // POST /age-requests/{id}/auto-convocation
707 .service(withdraw_age_request) // POST /age-requests/{id}/withdraw
708 .service(delete_age_request) // DELETE /age-requests/{id}
709 .service(get_age_request) // GET /age-requests/{id} — LAST (parameterized)
710 // Backoffice Prestataires PWA (BC16)
711 // PWA routes sans auth (magic link) BEFORE routes auth
712 .service(get_report_by_token) // GET /contractor/token/{token}
713 .service(submit_report_by_token) // POST /contractor/token/{token}/submit
714 // NEW: Improved magic link endpoints (Issue #275)
715 .service(get_report_by_magic_token) // GET /contractor-reports/magic/{token}
716 .service(submit_report_by_magic_token) // POST /contractor-reports/magic/{token}/submit
717 // Routes authentifiées — spécifiques BEFORE paramétrées
718 .service(generate_magic_link) // POST /contractor-reports/magic-link
719 .service(list_contractor_reports_by_building) // GET /buildings/{building_id}/contractor-reports
720 .service(list_contractor_reports_by_ticket) // GET /tickets/{ticket_id}/contractor-reports
721 .service(create_contractor_report) // POST /contractor-reports
722 .service(submit_contractor_report) // POST /contractor-reports/{id}/submit
723 .service(validate_contractor_report) // PUT /contractor-reports/{id}/validate
724 .service(request_corrections) // PUT /contractor-reports/{id}/request-corrections
725 .service(reject_contractor_report) // PUT /contractor-reports/{id}/reject
726 .service(update_contractor_report) // PUT /contractor-reports/{id}
727 .service(delete_contractor_report) // DELETE /contractor-reports/{id}
728 .service(get_contractor_report) // GET /contractor-reports/{id} — LAST (parameterized)
729 // Generic MagicLinks (Story 3.2 — FR6 INV-13 INV-17)
730 // POST /magic-links : syndic/superadmin issues a link
731 // GET /c/{token} : PUBLIC (no auth) — validate + consume + resolve scope
732 // POST /c/{token}/respond : PUBLIC (no auth) — write action (#835, ContractorReport)
733 .service(issue_magic_link)
734 .service(consume_magic_link)
735 .service(respond_magic_link)
736 // Mandates (Story 3.4 — FR7 INV-14)
737 // POST /mandates : syndic/superadmin issues a mandate
738 // GET /mandates?subject=<u> : list active mandates for a subject
739 // GET /mandates/{id} : mandate details
740 // POST /mandates/{id}/revoke : early revocation
741 .service(issue_mandate)
742 .service(list_mandates)
743 .service(revoke_mandate)
744 .service(get_mandate)
745 // Role Delegations (Story 3.5 — FR8 INV-8)
746 // POST /role-delegations : delegate role to another user (bounded)
747 // DELETE /role-delegations/{id} : revoke a delegation
748 // GET /role-delegations?subject=<u> : list delegations of a subject
749 .service(create_role_delegation)
750 .service(revoke_role_delegation)
751 .service(list_role_delegations)
752 // Role Assignments — CRUD REST (Story B0bis — gap Story 3.1)
753 // POST /users/{user_id}/role-assignments : assign sub-role
754 // GET /users/{user_id}/role-assignments : list user's assignments
755 // DELETE /users/{user_id}/role-assignments/{id} : revoke assignment
756 // GET /role-assignments?organization_id=&role= : superadmin filtered list
757 .service(assign_role)
758 .service(list_role_assignments_for_user)
759 .service(revoke_role_assignment)
760 .service(list_role_assignments_admin)
761 // SyndicResponse (Story 3.7 — FR32 INV-23) — append-only.
762 // POST /tickets/{id}/syndic-responses : syndic/superadmin posts a reply
763 // GET /tickets/{id}/syndic-responses : list responses for a ticket
764 .service(create_syndic_response)
765 .service(list_syndic_responses)
766 // TechnicalSpec (Story 3.8 — FR33) — versionnable + signatures multi-parties.
767 // POST /technical-specs : create Draft (syndic/superadmin)
768 // POST /technical-specs/{id}/bump : new version (syndic/superadmin)
769 // POST /technical-specs/{id}/submit : Draft -> PendingSignatures
770 // POST /technical-specs/{id}/signatures : record a signature
771 // GET /technical-specs/{id} : details
772 // GET /technical-specs?acp_id= : list for an ACP
773 .service(create_technical_spec)
774 .service(bump_technical_spec)
775 .service(submit_technical_spec)
776 .service(sign_technical_spec)
777 .service(list_technical_specs)
778 .service(get_technical_spec)
779 // ContractorEvaluation (Story 3.9 — FR34 FR35 INV-21 INV-24) — append-only.
780 // POST /contractor-evaluations : record an evaluation
781 // GET /contractor-evaluations/{id} : details
782 // GET /contractors/{contractor_user_id}/evaluations : list for a contractor
783 .service(create_contractor_evaluation)
784 .service(get_contractor_evaluation)
785 .service(list_contractor_evaluations),
786 );
787}