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(get_current_user)
36            // Buildings
37            .service(create_building)
38            .service(list_buildings)
39            .service(get_building)
40            .service(update_building)
41            .service(delete_building)
42            .service(export_annual_report_pdf) // PDF Export (Issue #47)
43            // Units
44            .service(create_unit)
45            .service(list_units)
46            .service(get_unit)
47            .service(update_unit)
48            .service(delete_unit)
49            .service(list_units_by_building)
50            .service(assign_owner)
51            // Owners
52            // IMPORTANT: /owners/me MUST be registered before /owners/{id}
53            // because {id} would catch "me" as a path parameter
54            .service(get_my_owner)
55            .service(create_owner)
56            .service(list_owners)
57            .service(get_owner)
58            .service(update_owner)
59            .service(link_owner_to_user)
60            .service(export_owner_statement_pdf) // PDF Export (Issue #47)
61            // Owner Contributions (Revenue)
62            // IMPORTANT: register specific routes BEFORE parameterized {id} routes
63            .service(create_contribution)
64            .service(get_contributions_by_owner)
65            .service(get_outstanding_contributions)
66            .service(get_contribution)
67            .service(record_payment)
68            // Call for Funds (Collective payment requests)
69            .service(create_call_for_funds)
70            .service(get_call_for_funds)
71            .service(list_call_for_funds)
72            .service(get_overdue_calls)
73            .service(send_call_for_funds)
74            .service(cancel_call_for_funds)
75            .service(delete_call_for_funds)
76            // Unit-Owner Relationships
77            .service(add_owner_to_unit)
78            .service(remove_owner_from_unit)
79            .service(update_unit_owner)
80            .service(get_unit_owners)
81            .service(get_owner_units)
82            .service(get_unit_ownership_history)
83            .service(get_owner_ownership_history)
84            .service(transfer_ownership)
85            .service(get_total_ownership_percentage)
86            .service(export_ownership_contract_pdf) // PDF Export (Issue #47)
87            // Expenses
88            .service(create_expense)
89            .service(list_expenses)
90            .service(get_expense)
91            .service(list_expenses_by_building)
92            .service(mark_expense_paid)
93            .service(mark_expense_overdue)
94            .service(cancel_expense)
95            .service(reactivate_expense)
96            .service(unpay_expense)
97            // Invoice Workflow (Issue #73)
98            .service(create_invoice_draft)
99            .service(update_invoice_draft)
100            .service(submit_invoice_for_approval)
101            .service(approve_invoice)
102            .service(reject_invoice)
103            .service(get_pending_invoices)
104            .service(get_invoice)
105            .service(export_work_quote_pdf) // PDF Export (Issue #47)
106            // Charge Distribution (Issue #73)
107            .service(calculate_and_save_distribution)
108            .service(get_distribution_by_expense)
109            .service(get_distributions_by_owner)
110            .service(get_total_due_by_owner)
111            // Meetings
112            .service(create_meeting)
113            .service(list_meetings)
114            .service(get_meeting)
115            .service(list_meetings_by_building)
116            .service(update_meeting)
117            .service(add_agenda_item)
118            .service(complete_meeting)
119            .service(cancel_meeting)
120            .service(reschedule_meeting)
121            .service(delete_meeting)
122            .service(attach_minutes)
123            .service(export_meeting_minutes_pdf)
124            // Convocations (Automatic AG Invitations - Issue #88 - Phase 2)
125            // Specific routes MUST come before parameterized /convocations/{id}
126            .service(schedule_second_convocation) // POST /convocations/second (must come before /convocations/{id})
127            .service(create_convocation)
128            .service(get_convocation_by_meeting)
129            .service(list_building_convocations)
130            .service(list_organization_convocations)
131            .service(list_convocation_recipients)
132            .service(get_convocation_tracking_summary)
133            .service(mark_recipient_email_opened)
134            .service(update_recipient_attendance)
135            .service(set_recipient_proxy)
136            .service(send_convocation_reminders)
137            .service(schedule_convocation)
138            .service(send_convocation)
139            .service(cancel_convocation)
140            .service(delete_convocation)
141            .service(get_convocation)
142            // Resolutions & Voting (Issue #46 - Phase 2)
143            .service(create_resolution)
144            .service(get_resolution)
145            .service(list_meeting_resolutions)
146            .service(delete_resolution)
147            .service(cast_vote)
148            .service(list_resolution_votes)
149            .service(change_vote)
150            .service(close_voting)
151            .service(get_meeting_vote_summary)
152            // Polls (Board Decision Polls - Issue #51 - Phase 2)
153            .service(create_poll)
154            .service(get_poll)
155            .service(update_poll)
156            .service(list_polls)
157            .service(find_active_polls)
158            .service(publish_poll)
159            .service(close_poll)
160            .service(cancel_poll)
161            .service(delete_poll)
162            .service(cast_poll_vote)
163            .service(get_poll_results)
164            .service(get_poll_building_statistics)
165            // Tickets (Maintenance Requests - Issue #85 - Phase 2)
166            // Specific routes MUST come before parameterized /tickets/{id}
167            .service(create_ticket)
168            .service(list_my_tickets)
169            .service(list_assigned_tickets)
170            .service(get_ticket_statistics_org) // /tickets/statistics (org-level)
171            .service(get_overdue_tickets_org) // /tickets/overdue (org-level)
172            .service(list_tickets_by_status)
173            .service(get_ticket_statistics) // /buildings/{id}/tickets/statistics
174            .service(get_overdue_tickets) // /buildings/{id}/tickets/overdue
175            .service(list_building_tickets)
176            .service(list_organization_tickets)
177            .service(get_ticket)
178            .service(delete_ticket)
179            .service(assign_ticket)
180            .service(start_work)
181            .service(send_work_order)
182            .service(resolve_ticket)
183            .service(close_ticket)
184            .service(cancel_ticket)
185            .service(reopen_ticket)
186            // Notifications (Multi-Channel System - Issue #86 - Phase 2)
187            // Specific routes MUST come before parameterized /notifications/{id}
188            .service(create_notification)
189            .service(list_my_notifications)
190            .service(list_unread_notifications)
191            .service(mark_all_notifications_read)
192            .service(get_notification_stats)
193            .service(get_notification)
194            .service(mark_notification_read)
195            .service(delete_notification)
196            // Notification Preferences
197            .service(get_user_preferences)
198            .service(get_preference)
199            .service(update_preference)
200            // Payments (Issue #84 - Phase 2)
201            // Specific routes MUST come before parameterized /payments/{id}
202            .service(create_payment)
203            .service(get_payment_by_stripe_intent)
204            .service(list_payments_by_status)
205            .service(list_pending_payments)
206            .service(list_failed_payments)
207            .service(list_owner_payments)
208            .service(list_building_payments)
209            .service(list_expense_payments)
210            .service(list_organization_payments)
211            .service(get_payment)
212            .service(mark_payment_processing)
213            .service(mark_payment_requires_action)
214            .service(mark_payment_succeeded)
215            .service(mark_payment_failed)
216            .service(mark_payment_cancelled)
217            .service(refund_payment)
218            .service(delete_payment)
219            .service(get_owner_payment_stats)
220            .service(get_building_payment_stats)
221            .service(get_expense_total_paid)
222            .service(get_owner_total_paid)
223            .service(get_building_total_paid)
224            // Payment Methods (Issue #84 - Phase 2)
225            .service(create_payment_method)
226            .service(get_payment_method)
227            .service(get_payment_method_by_stripe_id)
228            .service(list_owner_payment_methods)
229            .service(list_active_owner_payment_methods)
230            .service(get_default_payment_method)
231            .service(list_organization_payment_methods)
232            .service(list_payment_methods_by_type)
233            .service(update_payment_method)
234            .service(set_payment_method_as_default)
235            .service(deactivate_payment_method)
236            .service(reactivate_payment_method)
237            .service(delete_payment_method)
238            .service(count_active_payment_methods)
239            .service(has_active_payment_methods)
240            // Quotes (Contractor Quotes Module - Issue #91 - Phase 2)
241            .service(create_quote)
242            .service(get_quote)
243            .service(list_building_quotes)
244            .service(list_contractor_quotes)
245            .service(list_quotes_by_status)
246            .service(submit_quote)
247            .service(start_review)
248            .service(accept_quote)
249            .service(reject_quote)
250            .service(withdraw_quote)
251            .service(compare_quotes)
252            .service(update_contractor_rating)
253            .service(delete_quote)
254            .service(count_building_quotes)
255            .service(count_quotes_by_status)
256            // Local Exchanges (SEL - Local Exchange Trading System - Issue #49 - Phase 2)
257            .service(create_exchange)
258            .service(get_exchange)
259            .service(list_building_exchanges)
260            .service(list_available_exchanges)
261            .service(list_owner_exchanges)
262            .service(list_exchanges_by_type)
263            .service(request_exchange)
264            .service(start_exchange)
265            .service(complete_exchange)
266            .service(cancel_exchange)
267            .service(rate_provider)
268            .service(rate_requester)
269            .service(delete_exchange)
270            .service(get_credit_balance)
271            .service(get_leaderboard)
272            .service(get_sel_statistics)
273            .service(get_owner_summary)
274            // Notices (Community Notice Board - Issue #49 - Phase 2)
275            .service(create_notice)
276            .service(get_notice)
277            .service(list_building_notices)
278            .service(list_published_notices)
279            .service(list_pinned_notices)
280            .service(list_notices_by_type)
281            .service(list_notices_by_category)
282            .service(list_notices_by_status)
283            .service(list_author_notices)
284            .service(update_notice)
285            .service(publish_notice)
286            .service(archive_notice)
287            .service(pin_notice)
288            .service(unpin_notice)
289            .service(set_expiration)
290            .service(delete_notice)
291            .service(get_notice_statistics)
292            // Skills (Skills Directory - Issue #49 - Phase 3)
293            .service(create_skill)
294            .service(get_skill)
295            .service(list_building_skills)
296            .service(list_available_skills)
297            .service(list_free_skills)
298            .service(list_professional_skills)
299            .service(list_skills_by_category)
300            .service(list_skills_by_expertise)
301            .service(list_owner_skills)
302            .service(update_skill)
303            .service(mark_skill_available)
304            .service(mark_skill_unavailable)
305            .service(delete_skill)
306            .service(get_skill_statistics)
307            // Shared Objects (Object Sharing Library - Issue #49 - Phase 4)
308            // Specific routes MUST come before parameterized /shared-objects/{id}
309            .service(create_shared_object)
310            .service(list_my_borrowed_objects)
311            .service(list_building_objects)
312            .service(list_available_objects)
313            .service(list_borrowed_objects)
314            .service(list_overdue_objects)
315            .service(list_free_objects)
316            .service(list_objects_by_category)
317            .service(list_owner_objects)
318            .service(get_shared_object)
319            .service(update_shared_object)
320            .service(mark_object_available)
321            .service(mark_object_unavailable)
322            .service(borrow_object)
323            .service(return_object)
324            .service(delete_shared_object)
325            .service(get_object_statistics)
326            // Resource Bookings (Resource Booking Calendar - Issue #49 - Phase 5)
327            // Specific routes MUST come before parameterized /resource-bookings/{id}
328            .service(create_booking)
329            .service(list_my_bookings)
330            .service(list_my_bookings_by_status)
331            .service(list_active_bookings)
332            .service(check_conflicts)
333            .service(list_building_bookings)
334            .service(list_by_resource_type)
335            .service(list_by_resource)
336            .service(list_building_bookings_by_status)
337            .service(list_upcoming_bookings)
338            .service(list_past_bookings)
339            .service(get_booking_statistics)
340            .service(get_booking)
341            .service(update_booking)
342            .service(cancel_booking)
343            .service(complete_booking)
344            .service(mark_no_show)
345            .service(confirm_booking)
346            .service(delete_booking)
347            // Gamification & Achievements (Issue #49 - Phase 6)
348            // Achievements
349            .service(create_achievement)
350            .service(get_achievement)
351            .service(list_achievements)
352            .service(list_achievements_by_category)
353            .service(list_visible_achievements)
354            .service(update_achievement)
355            .service(delete_achievement)
356            // User Achievements
357            .service(award_achievement)
358            .service(get_user_achievements)
359            .service(get_recent_achievements)
360            // Challenges
361            .service(create_challenge)
362            .service(get_challenge)
363            .service(list_challenges)
364            .service(list_challenges_by_status)
365            .service(list_building_challenges)
366            .service(list_active_challenges)
367            .service(update_challenge)
368            .service(activate_challenge)
369            .service(complete_challenge)
370            .service(cancel_challenge)
371            .service(delete_challenge)
372            // Challenge Progress
373            .service(get_challenge_progress)
374            .service(list_challenge_progress)
375            .service(list_user_active_challenges)
376            .service(increment_progress)
377            // Gamification Stats
378            .service(get_gamification_user_stats)
379            .service(get_gamification_leaderboard)
380            // Board Members
381            .service(elect_board_member)
382            .service(get_my_mandates) // Must be before get_board_member to avoid UUID parsing
383            .service(get_board_dashboard) // Must be before get_board_member to avoid UUID parsing
384            .service(get_board_member)
385            .service(list_active_board_members)
386            .service(list_all_board_members)
387            .service(renew_mandate)
388            .service(remove_board_member)
389            .service(get_board_stats)
390            // Board Decisions
391            .service(create_decision)
392            .service(get_decision)
393            .service(list_decisions_by_building)
394            .service(list_decisions_by_status)
395            .service(list_overdue_decisions)
396            .service(update_decision_status)
397            .service(add_notes)
398            .service(complete_decision)
399            .service(get_decision_stats)
400            // Documents
401            .service(upload_document)
402            .service(list_documents)
403            .service(get_document)
404            .service(download_document)
405            .service(list_documents_by_building)
406            .service(list_documents_by_meeting)
407            .service(list_documents_by_expense)
408            .service(link_document_to_meeting)
409            .service(link_document_to_expense)
410            .service(delete_document)
411            // Energy Buying Groups (Achats Groupés d'Énergie - GDPR compliant)
412            .service(create_campaign)
413            .service(list_campaigns)
414            .service(get_campaign)
415            .service(get_campaign_stats)
416            .service(update_campaign_status)
417            .service(delete_campaign)
418            .service(add_offer)
419            .service(list_offers)
420            .service(select_offer)
421            .service(finalize_campaign)
422            .service(upload_bill)
423            .service(get_my_uploads)
424            .service(get_upload)
425            .service(decrypt_consumption)
426            .service(verify_upload)
427            .service(delete_upload)
428            .service(withdraw_consent)
429            .service(get_campaign_uploads)
430            // Individual Members (Issue #280 - Non-copropriétaire energy group members)
431            .service(join_campaign_as_individual) // POST /energy-campaigns/{id}/join-as-individual
432            .service(grant_consent) // POST /energy-campaigns/{campaign_id}/members/{member_id}/consent
433            .service(update_consumption) // PUT /energy-campaigns/{campaign_id}/members/{member_id}/consumption
434            .service(withdraw_from_campaign) // DELETE /energy-campaigns/{campaign_id}/members/{member_id}/withdraw
435            // Marketplace (Issue #276 - Service provider marketplace)
436            .service(search_service_providers) // GET /marketplace/providers
437            .service(get_provider_by_slug) // GET /marketplace/providers/{slug}
438            .service(create_service_provider) // POST /service-providers
439            .service(get_contract_evaluations_annual) // GET /buildings/{id}/reports/contract-evaluations/annual
440            // États Datés (Belgian legal requirement for property sales)
441            // Specific routes MUST come before parameterized /etats-dates/{id}
442            .service(create_etat_date)
443            .service(list_etats_dates)
444            .service(list_overdue)
445            .service(list_expired)
446            .service(get_stats)
447            .service(get_by_reference_number)
448            .service(list_etats_dates_by_unit)
449            .service(list_etats_dates_by_building)
450            .service(get_etat_date)
451            .service(mark_in_progress)
452            .service(mark_generated)
453            .service(mark_delivered)
454            .service(update_financial_data)
455            .service(update_additional_data)
456            .service(delete_etat_date)
457            // Budgets (Annual budget management)
458            // Specific routes MUST come before parameterized /budgets/{id}
459            .service(create_budget)
460            .service(list_budgets)
461            .service(get_budget_stats)
462            .service(list_budgets_by_fiscal_year)
463            .service(list_budgets_by_status)
464            .service(get_budget_by_building_and_fiscal_year)
465            .service(get_active_budget)
466            .service(list_budgets_by_building)
467            .service(get_budget)
468            .service(get_budget_variance)
469            .service(update_budget)
470            .service(submit_budget)
471            .service(approve_budget)
472            .service(reject_budget)
473            .service(archive_budget)
474            .service(delete_budget)
475            // Accounts (Belgian PCMN)
476            .service(create_account)
477            .service(list_accounts)
478            .service(get_account)
479            .service(get_account_by_code)
480            .service(update_account)
481            .service(delete_account)
482            .service(seed_belgian_pcmn)
483            .service(count_accounts)
484            // PCN (Belgian Chart of Accounts - Legacy)
485            .service(generate_pcn_report)
486            .service(export_pcn_pdf)
487            .service(export_pcn_excel)
488            // Financial Reports (Belgian PCMN)
489            .service(generate_balance_sheet)
490            .service(generate_income_statement)
491            .service(generate_balance_sheet_for_building)
492            .service(generate_income_statement_for_building)
493            // Journal Entries (Manual Accounting Operations - Noalyss-inspired)
494            .service(create_journal_entry)
495            .service(list_journal_entries)
496            .service(get_journal_entry)
497            .service(delete_journal_entry)
498            // Dashboard (Accountant)
499            .service(get_accountant_stats)
500            .service(get_recent_transactions)
501            // Payment Reminders (Issue #83)
502            // IMPORTANT: Specific routes BEFORE parameterized routes to avoid UUID conflicts
503            .service(get_recovery_stats) // Must be before get_reminder (/payment-reminders/stats vs /{id})
504            .service(find_overdue_without_reminders) // Must be before get_reminder
505            .service(bulk_create_reminders) // Must be before get_reminder
506            .service(list_by_organization) // /payment-reminders
507            .service(create_reminder) // POST /payment-reminders
508            .service(get_reminder) // /payment-reminders/{id}
509            .service(delete_reminder) // DELETE /payment-reminders/{id}
510            .service(list_by_expense) // /expenses/{id}/payment-reminders
511            .service(list_by_owner) // /owners/{id}/payment-reminders
512            .service(list_active_by_owner) // /owners/{id}/payment-reminders/active
513            .service(mark_as_sent) // PUT /payment-reminders/{id}/mark-sent
514            .service(mark_as_opened) // PUT /payment-reminders/{id}/mark-opened
515            .service(mark_as_paid) // PUT /payment-reminders/{id}/mark-paid
516            .service(cancel_reminder) // PUT /payment-reminders/{id}/cancel
517            .service(escalate_reminder) // POST /payment-reminders/{id}/escalate
518            .service(add_tracking_number) // PUT /payment-reminders/{id}/tracking-number
519            // Seed (SuperAdmin only) - ONE seed only
520            .service(seed_demo_data)
521            // .service(seed_realistic_data) // Disabled: we only use ONE seed
522            .service(clear_demo_data)
523            // Stats (SuperAdmin only)
524            .service(get_dashboard_stats)
525            .service(get_seed_data_stats)
526            // Stats (Syndic/Accountant)
527            .service(get_syndic_stats)
528            .service(get_syndic_urgent_tasks)
529            // Stats (Owner)
530            .service(get_owner_stats)
531            // Organizations (SuperAdmin only)
532            .service(list_organizations)
533            .service(create_organization)
534            .service(update_organization)
535            .service(activate_organization)
536            .service(suspend_organization)
537            .service(delete_organization)
538            // Users (SuperAdmin only)
539            .service(list_users)
540            .service(create_user)
541            .service(update_user)
542            .service(activate_user)
543            .service(deactivate_user)
544            .service(delete_user)
545            // GDPR (Data Privacy)
546            .service(export_user_data)
547            .service(erase_user_data)
548            .service(can_erase_user)
549            // GDPR Complementary Articles (Issue #90)
550            .service(rectify_user_data) // Article 16: Right to Rectification
551            .service(restrict_user_processing) // Article 18: Right to Restriction
552            .service(set_marketing_preference) // Article 21: Right to Object
553            // GDPR Consent Recording (Issue #315 - Privacy Policy)
554            .service(record_consent)
555            .service(get_consent_status)
556            // GDPR Admin (SuperAdmin only)
557            .service(list_audit_logs)
558            .service(admin_export_user_data)
559            .service(admin_erase_user_data)
560            // GDPR Article 28 - DPA with Sub-Processors (Issue #316)
561            .service(list_processing_activities)
562            .service(list_sub_processors)
563            // GDPR Article 33 - Security Incidents & 72h APD Notification (Issue #317)
564            .service(create_security_incident)
565            .service(list_security_incidents)
566            .service(get_security_incident)
567            .service(report_incident_to_apd)
568            .service(list_overdue_incidents)
569            // Two-Factor Authentication (2FA TOTP - Issue #78)
570            .configure(two_factor_handlers::configure_two_factor_routes)
571            // API Key Management (Public API v2 - Issues #111, #232)
572            .service(create_api_key)
573            .service(list_api_keys)
574            .service(get_api_key)
575            .service(update_api_key)
576            .service(revoke_api_key)
577            .service(rotate_api_key)
578            // Work Reports (Digital Maintenance Logbook - Issue #134)
579            .service(create_work_report)
580            .service(get_work_report)
581            .service(list_building_work_reports)
582            .service(list_organization_work_reports)
583            .service(list_work_reports_paginated)
584            .service(update_work_report)
585            .service(delete_work_report)
586            .service(get_active_warranties)
587            .service(get_expiring_warranties)
588            .service(add_photo)
589            .service(add_document)
590            // Technical Inspections (Digital Maintenance Logbook - Issue #134)
591            .service(create_technical_inspection)
592            .service(get_technical_inspection)
593            .service(list_building_technical_inspections)
594            .service(list_organization_technical_inspections)
595            .service(list_technical_inspections_paginated)
596            .service(update_technical_inspection)
597            .service(delete_technical_inspection)
598            .service(get_overdue_inspections)
599            .service(get_upcoming_inspections)
600            .service(get_inspections_by_type)
601            .service(add_report)
602            .service(add_inspection_photo)
603            .service(add_certificate)
604            // IoT Smart Meters (Linky/Ores - Issue #133 - IoT Phase 0)
605            .configure(iot_handlers::configure_iot_routes)
606            // IoT Phase 1: MQTT Home Assistant + BOINC Grid Computing
607            // IMPORTANT: specific /iot/grid/consent must be before /iot/grid/tasks
608            .service(start_mqtt_listener) // POST /iot/mqtt/start
609            .service(stop_mqtt_listener) // POST /iot/mqtt/stop
610            .service(mqtt_status) // GET  /iot/mqtt/status
611            .service(update_grid_consent) // POST /iot/grid/consent
612            .service(get_grid_consent) // GET  /iot/grid/consent/{owner_id}
613            .service(submit_grid_task) // POST /iot/grid/tasks
614            .service(cancel_grid_task) // DELETE /iot/grid/tasks/{task_id}
615            .service(get_task_status) // GET  /iot/grid/tasks/{task_id} — LAST (parameterized)
616            // AG Visioconférence (BC15 - Art. 3.87 §1 CC)
617            // Specific routes BEFORE parameterized /ag-sessions/{id}
618            .service(list_ag_sessions) // GET /ag-sessions
619            .service(get_ag_session_platform_stats) // GET /ag-sessions/platform-stats (Issue #274 - SuperAdmin only)
620            .service(create_ag_session) // POST /meetings/{meeting_id}/ag-session
621            .service(get_ag_session_for_meeting) // GET /meetings/{meeting_id}/ag-session
622            .service(get_combined_quorum) // GET /ag-sessions/{id}/quorum
623            .service(start_ag_session) // PUT /ag-sessions/{id}/start
624            .service(end_ag_session) // PUT /ag-sessions/{id}/end
625            .service(cancel_ag_session) // PUT /ag-sessions/{id}/cancel
626            .service(record_remote_join) // POST /ag-sessions/{id}/join
627            .service(delete_ag_session) // DELETE /ag-sessions/{id}
628            .service(get_ag_session) // GET /ag-sessions/{id} — LAST (parameterized)
629            // AGE Agile & Concertation (BC17 - Art. 3.87 §2 CC)
630            // Specific sub-routes BEFORE parameterized /age-requests/{id}
631            .service(create_age_request) // POST /buildings/{building_id}/age-requests
632            .service(list_age_requests) // GET /buildings/{building_id}/age-requests
633            .service(add_cosignatory) // POST /age-requests/{id}/cosignatories
634            .service(remove_cosignatory) // DELETE /age-requests/{id}/cosignatories/{owner_id}
635            .service(open_age_request) // PUT /age-requests/{id}/open
636            .service(submit_age_request) // POST /age-requests/{id}/submit
637            .service(syndic_response) // PUT /age-requests/{id}/syndic-response
638            .service(trigger_auto_convocation) // POST /age-requests/{id}/auto-convocation
639            .service(withdraw_age_request) // POST /age-requests/{id}/withdraw
640            .service(delete_age_request) // DELETE /age-requests/{id}
641            .service(get_age_request) // GET /age-requests/{id} — LAST (parameterized)
642            // Backoffice Prestataires PWA (BC16)
643            // PWA routes sans auth (magic link) BEFORE routes auth
644            .service(get_report_by_token) // GET /contractor/token/{token}
645            .service(submit_report_by_token) // POST /contractor/token/{token}/submit
646            // NEW: Improved magic link endpoints (Issue #275)
647            .service(get_report_by_magic_token) // GET /contractor-reports/magic/{token}
648            .service(submit_report_by_magic_token) // POST /contractor-reports/magic/{token}/submit
649            // Routes authentifiées — spécifiques BEFORE paramétrées
650            .service(generate_magic_link) // POST /contractor-reports/magic-link
651            .service(list_contractor_reports_by_building) // GET /buildings/{building_id}/contractor-reports
652            .service(list_contractor_reports_by_ticket) // GET /tickets/{ticket_id}/contractor-reports
653            .service(create_contractor_report) // POST /contractor-reports
654            .service(submit_contractor_report) // POST /contractor-reports/{id}/submit
655            .service(validate_contractor_report) // PUT /contractor-reports/{id}/validate
656            .service(request_corrections) // PUT /contractor-reports/{id}/request-corrections
657            .service(reject_contractor_report) // PUT /contractor-reports/{id}/reject
658            .service(update_contractor_report) // PUT /contractor-reports/{id}
659            .service(delete_contractor_report) // DELETE /contractor-reports/{id}
660            .service(get_contractor_report), // GET /contractor-reports/{id} — LAST (parameterized)
661    );
662}