{
  "openapi": "3.0.0",
  "paths": {
    "/auth/google": {
      "get": {
        "operationId": "AuthController_googleAuthRedirect",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Auth"
        ]
      }
    },
    "/auth/google/callback": {
      "get": {
        "operationId": "AuthController_googleOAuthCallback",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Auth"
        ]
      }
    },
    "/auth/github": {
      "get": {
        "operationId": "AuthController_githubAuthRedirect",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Auth"
        ]
      }
    },
    "/auth/github/callback": {
      "get": {
        "operationId": "AuthController_githubOAuthCallback",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Auth"
        ]
      }
    },
    "/auth/login": {
      "post": {
        "operationId": "AuthController_login",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Auth"
        ]
      }
    },
    "/auth/refresh": {
      "post": {
        "operationId": "AuthController_refresh",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Auth"
        ]
      }
    },
    "/auth/switch-city": {
      "post": {
        "operationId": "AuthController_switchCity",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SwitchCityDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Auth"
        ]
      }
    },
    "/auth/logout": {
      "post": {
        "operationId": "AuthController_logout",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Auth"
        ]
      }
    },
    "/users/me": {
      "get": {
        "operationId": "UserController_me",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "User"
        ]
      }
    },
    "/users": {
      "get": {
        "operationId": "UserController_listUsers",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "User"
        ]
      },
      "post": {
        "operationId": "UserController_createUser",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateUserDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "User"
        ]
      }
    },
    "/email-templates/{model}": {
      "get": {
        "operationId": "EmailTemplatesController_getByModel",
        "parameters": [
          {
            "name": "model",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "EmailTemplates"
        ]
      },
      "post": {
        "operationId": "EmailTemplatesController_createForCity",
        "parameters": [
          {
            "name": "model",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertEmailTemplateDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "EmailTemplates"
        ]
      },
      "patch": {
        "operationId": "EmailTemplatesController_updateForCity",
        "parameters": [
          {
            "name": "model",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertEmailTemplateDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "EmailTemplates"
        ]
      },
      "delete": {
        "operationId": "EmailTemplatesController_deleteForCity",
        "parameters": [
          {
            "name": "model",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "EmailTemplates"
        ]
      }
    },
    "/email-templates/{model}/global": {
      "post": {
        "operationId": "EmailTemplatesController_createGlobal",
        "parameters": [
          {
            "name": "model",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertEmailTemplateDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "EmailTemplates"
        ]
      },
      "patch": {
        "operationId": "EmailTemplatesController_updateGlobal",
        "parameters": [
          {
            "name": "model",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertEmailTemplateDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "EmailTemplates"
        ]
      },
      "delete": {
        "operationId": "EmailTemplatesController_deleteGlobal",
        "parameters": [
          {
            "name": "model",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "EmailTemplates"
        ]
      }
    },
    "/posts": {
      "get": {
        "description": "Liste paginee triee par createdAt desc. Tous statuts confondus (draft, published, scheduled).",
        "operationId": "PostsController_listPosts",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "Numero de page (1-based)",
            "schema": {
              "minimum": 1,
              "default": 1,
              "example": 1,
              "type": "number"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Nombre de posts par page",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "example": 20,
              "type": "number"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Filtre par statut (multi). CSV `?status=draft,published` ou repete `?status=draft&status=published`.",
            "schema": {
              "example": [
                "published",
                "scheduled"
              ],
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "draft",
                  "published",
                  "scheduled"
                ]
              }
            }
          },
          {
            "name": "channel",
            "required": false,
            "in": "query",
            "description": "Filtre par canal social (multi, OR). Un post est retenu si au moins un de ses canaux est dans la liste. CSV ou parametre repete.",
            "schema": {
              "example": [
                "FACEBOOK",
                "INSTAGRAM"
              ],
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "FACEBOOK",
                  "X",
                  "LINKEDIN",
                  "INSTAGRAM"
                ]
              }
            }
          },
          {
            "name": "publishDateFrom",
            "required": false,
            "in": "query",
            "description": "Borne inferieure (incluse) sur `publishDate`. Format ISO 8601. Les brouillons avec publishDate renseignee peuvent matcher.",
            "schema": {
              "example": "2026-01-01T00:00:00.000Z",
              "type": "string"
            }
          },
          {
            "name": "publishDateTo",
            "required": false,
            "in": "query",
            "description": "Borne superieure (incluse) sur `publishDate`. Format ISO 8601. Les brouillons avec publishDate renseignee peuvent matcher.",
            "schema": {
              "example": "2026-12-31T23:59:59.999Z",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Liste paginee des posts"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Lister les posts de la ville courante",
        "tags": [
          "posts"
        ]
      },
      "post": {
        "operationId": "PostsController_createPost",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePostDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Post cree avec succes"
          },
          "400": {
            "description": "Payload invalide"
          },
          "403": {
            "description": "Role insuffisant (SUPERADMIN/ADMIN/EDITOR requis)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Creer un post",
        "tags": [
          "posts"
        ]
      }
    },
    "/posts/{postId}/comments": {
      "get": {
        "operationId": "PostsController_listPostComments",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "description": "Identifiant du post",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "Numero de page des commentaires (1-based)",
            "schema": {
              "minimum": 1,
              "default": 1,
              "example": 1,
              "type": "number"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Nombre de commentaires retournes par post",
            "schema": {
              "minimum": 1,
              "maximum": 50,
              "default": 20,
              "example": 20,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Liste paginee des commentaires du post"
          },
          "404": {
            "description": "Post introuvable dans la commune courante"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Lister les commentaires d'un post",
        "tags": [
          "posts"
        ]
      },
      "post": {
        "description": "Cree un commentaire officiel de la commune (authorType=city). Fournir parentId pour repondre a un commentaire racine.",
        "operationId": "PostsController_createPostComment",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "description": "Identifiant du post",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePostCommentDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Commentaire cree"
          },
          "400": {
            "description": "Payload invalide"
          },
          "403": {
            "description": "Role insuffisant (SUPERADMIN/ADMIN/EDITOR requis)"
          },
          "404": {
            "description": "Post ou commentaire parent introuvable dans la commune courante"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Commenter un post ou repondre a un commentaire citoyen",
        "tags": [
          "posts"
        ]
      }
    },
    "/posts/{postId}/comments/{commentId}/replies": {
      "get": {
        "operationId": "PostsController_listPostCommentReplies",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "description": "Identifiant du post",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "commentId",
            "required": true,
            "in": "path",
            "description": "Identifiant du commentaire racine",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "Numero de page des commentaires (1-based)",
            "schema": {
              "minimum": 1,
              "default": 1,
              "example": 1,
              "type": "number"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Nombre de commentaires retournes par post",
            "schema": {
              "minimum": 1,
              "maximum": 50,
              "default": 20,
              "example": 20,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Liste paginee des reponses au commentaire"
          },
          "404": {
            "description": "Post ou commentaire introuvable dans la commune courante"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Lister les reponses d'un commentaire racine",
        "tags": [
          "posts"
        ]
      }
    },
    "/posts/{postId}/comments/{commentId}": {
      "delete": {
        "description": "Supprime le commentaire cible. Si c'est un commentaire racine, ses reponses et likes sont supprimes en cascade.",
        "operationId": "PostsController_deletePostComment",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "description": "Identifiant du post",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "commentId",
            "required": true,
            "in": "path",
            "description": "Identifiant du commentaire",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Commentaire supprime"
          },
          "403": {
            "description": "Role insuffisant (SUPERADMIN/ADMIN/EDITOR requis)"
          },
          "404": {
            "description": "Post ou commentaire introuvable dans la commune courante"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Supprimer un commentaire ou une reponse",
        "tags": [
          "posts"
        ]
      }
    },
    "/posts/{postId}": {
      "get": {
        "operationId": "PostsController_getPostById",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "description": "Identifiant du post",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Post trouve"
          },
          "404": {
            "description": "Post introuvable dans la commune courante"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Recuperer un post par son id",
        "tags": [
          "posts"
        ]
      },
      "patch": {
        "description": "Patch generique. Ne couvre PAS `status`/`publishDate` (utiliser `PATCH /:postId/status`) ni `channels` (utiliser `PATCH /:postId/channels`). Au moins un champ doit etre fourni.",
        "operationId": "PostsController_updatePost",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "description": "Identifiant du post",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePostDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Post mis a jour avec succes"
          },
          "400": {
            "description": "Payload invalide ou aucun champ a mettre a jour"
          },
          "403": {
            "description": "Role insuffisant (SUPERADMIN/ADMIN/EDITOR requis)"
          },
          "404": {
            "description": "Post introuvable dans la commune courante"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Mettre a jour le contenu et/ou les medias d'un post",
        "tags": [
          "posts"
        ]
      },
      "delete": {
        "operationId": "PostsController_deletePost",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "description": "Identifiant du post",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Post supprime"
          },
          "403": {
            "description": "Role insuffisant (SUPERADMIN/ADMIN/EDITOR requis)"
          },
          "404": {
            "description": "Post introuvable dans la commune courante"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Supprimer un post",
        "tags": [
          "posts"
        ]
      }
    },
    "/posts/{postId}/status": {
      "patch": {
        "operationId": "PostsController_updatePostStatus",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "description": "Identifiant du post",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePostStatusDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Statut du post mis a jour avec succes"
          },
          "400": {
            "description": "Payload invalide, incoherent, ou publishDate pas dans le futur pour un scheduled"
          },
          "403": {
            "description": "Role insuffisant (SUPERADMIN/ADMIN/EDITOR requis)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Mettre a jour le statut d'un post",
        "tags": [
          "posts"
        ]
      }
    },
    "/posts/{postId}/channels": {
      "patch": {
        "description": "Remplace integralement la liste des canaux (semantique PUT-like). Tableau vide = retire tous les canaux.",
        "operationId": "PostsController_updatePostChannels",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "description": "Identifiant du post",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePostChannelsDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Canaux du post mis a jour avec succes"
          },
          "400": {
            "description": "Payload invalide"
          },
          "403": {
            "description": "Role insuffisant (SUPERADMIN/ADMIN/EDITOR requis)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Mettre a jour les canaux sociaux d'un post",
        "tags": [
          "posts"
        ]
      }
    },
    "/settings/city": {
      "get": {
        "operationId": "SettingsController_getCitySettings",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Lire les parametres de la commune courante",
        "tags": [
          "settings"
        ]
      },
      "patch": {
        "operationId": "SettingsController_updateCitySettings",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCitySettingsDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Mettre a jour les parametres de la commune courante",
        "tags": [
          "settings"
        ]
      }
    },
    "/settings/socials": {
      "get": {
        "operationId": "SettingsController_getSocials",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Liste des canaux : `connected` = pret a publier ; si `pageSelectionPending`, `availableTargets` ; pour FACEBOOK connecte, `selectedPageName` = nom de la Page choisie"
          },
          "401": {
            "description": ""
          },
          "403": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Etat des connexions reseaux sociaux pour la commune courante",
        "tags": [
          "settings"
        ]
      },
      "patch": {
        "operationId": "SettingsController_patchSocials",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSocialSettingsDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Etat des canaux ; `oauth.authorizationUrl` si activation sans jeton ; pour Facebook/Instagram apres OAuth, envoyer `pageId` ou `instagramAccountId` pour finaliser la cible"
          },
          "401": {
            "description": ""
          },
          "403": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Activer ou desactiver les canaux sociaux ; activation declenche OAuth si besoin",
        "tags": [
          "settings"
        ]
      }
    },
    "/settings/socials/oauth/{channel}/callback": {
      "get": {
        "operationId": "SettingsController_socialOAuthCallback",
        "parameters": [
          {
            "name": "channel",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Callback OAuth (public). Redirige vers SOCIAL_OAUTH_SUCCESS_REDIRECT ; si choix Page / compte requis : `needs_target_selection=true`",
        "tags": [
          "settings"
        ]
      }
    },
    "/settings/categories": {
      "get": {
        "operationId": "SettingsCategoriesController_list",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Lister les categories visibles pour la commune (defaut non masquees + custom)",
        "tags": [
          "settings"
        ]
      },
      "post": {
        "operationId": "SettingsCategoriesController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCategoryDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Creer une categorie propre a la commune",
        "tags": [
          "settings"
        ]
      }
    },
    "/settings/categories/{categoryId}": {
      "patch": {
        "operationId": "SettingsCategoriesController_update",
        "parameters": [
          {
            "name": "categoryId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCategoryDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Modifier une categorie custom (pas les categories par defaut)",
        "tags": [
          "settings"
        ]
      },
      "delete": {
        "operationId": "SettingsCategoriesController_remove",
        "parameters": [
          {
            "name": "categoryId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Supprimer une categorie custom, ou masquer une categorie par defaut pour la commune",
        "tags": [
          "settings"
        ]
      }
    },
    "/categories": {
      "get": {
        "operationId": "CategoriesController_list",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Categories"
        ]
      },
      "post": {
        "operationId": "CategoriesController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCategoryDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Categories"
        ]
      }
    },
    "/categories/{categoryId}": {
      "patch": {
        "operationId": "CategoriesController_update",
        "parameters": [
          {
            "name": "categoryId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCategoryDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Categories"
        ]
      },
      "delete": {
        "operationId": "CategoriesController_delete",
        "parameters": [
          {
            "name": "categoryId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Categories"
        ]
      }
    },
    "/medias/upload": {
      "post": {
        "operationId": "MediasController_uploadMedia",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Medias"
        ]
      }
    },
    "/alerts": {
      "get": {
        "operationId": "AlertsController_getAllAlerts",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Liste des alertes retournee avec succes"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Lister les alertes actives de la ville courante",
        "tags": [
          "alerts"
        ]
      },
      "post": {
        "operationId": "AlertsController_createAlert",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAlertDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Alerte creee avec succes"
          },
          "400": {
            "description": "Payload invalide"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Creer une alerte",
        "tags": [
          "alerts"
        ]
      }
    },
    "/alerts/{alertId}": {
      "patch": {
        "operationId": "AlertsController_updateAlert",
        "parameters": [
          {
            "name": "alertId",
            "required": true,
            "in": "path",
            "description": "Identifiant de l'alerte",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAlertDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Alerte mise a jour avec succes"
          },
          "400": {
            "description": "Payload invalide ou incoherent"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Mettre a jour une alerte",
        "tags": [
          "alerts"
        ]
      }
    },
    "/forms": {
      "get": {
        "operationId": "FormsController_list",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Forms"
        ]
      },
      "post": {
        "operationId": "FormsController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateFormDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Forms"
        ]
      }
    },
    "/forms/{formId}": {
      "get": {
        "operationId": "FormsController_getById",
        "parameters": [
          {
            "name": "formId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Forms"
        ]
      },
      "patch": {
        "operationId": "FormsController_update",
        "parameters": [
          {
            "name": "formId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateFormDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Forms"
        ]
      },
      "delete": {
        "operationId": "FormsController_delete",
        "parameters": [
          {
            "name": "formId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Forms"
        ]
      }
    },
    "/forms/{formId}/responses/stats": {
      "get": {
        "operationId": "FormResponsesController_stats",
        "parameters": [
          {
            "name": "formId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "FormResponses"
        ]
      }
    },
    "/forms/{formId}/responses": {
      "get": {
        "operationId": "FormResponsesController_list",
        "parameters": [
          {
            "name": "formId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "FormResponses"
        ]
      },
      "post": {
        "operationId": "FormResponsesController_create",
        "parameters": [
          {
            "name": "formId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateFormResponseDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "FormResponses"
        ]
      }
    },
    "/reports": {
      "get": {
        "operationId": "ReportsController_list",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Reports"
        ]
      },
      "post": {
        "operationId": "ReportsController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateReportDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Reports"
        ]
      }
    },
    "/reports/{reportId}": {
      "get": {
        "operationId": "ReportsController_getById",
        "parameters": [
          {
            "name": "reportId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Reports"
        ]
      },
      "patch": {
        "operationId": "ReportsController_update",
        "parameters": [
          {
            "name": "reportId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateReportDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Reports"
        ]
      }
    },
    "/reports/{reportId}/comments": {
      "get": {
        "operationId": "ReportsController_listComments",
        "parameters": [
          {
            "name": "reportId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Reports"
        ]
      },
      "post": {
        "operationId": "ReportsController_createComment",
        "parameters": [
          {
            "name": "reportId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateReportCommentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "Reports"
        ]
      }
    },
    "/reports/{reportId}/comments/{commentId}/replies": {
      "get": {
        "operationId": "ReportsController_listCommentReplies",
        "parameters": [
          {
            "name": "reportId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "commentId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "Reports"
        ]
      }
    },
    "/reports/{reportId}/comments/{commentId}": {
      "delete": {
        "operationId": "ReportsController_deleteComment",
        "parameters": [
          {
            "name": "reportId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "commentId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "tags": [
          "Reports"
        ]
      }
    },
    "/events": {
      "get": {
        "description": "Liste paginee triee par createdAt desc. Tous statuts confondus. Synchronise les statuts temporels (scheduled/in_progress/finished) avant la lecture.",
        "operationId": "EventsController_list",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "Numero de page (1-based)",
            "schema": {
              "minimum": 1,
              "default": 1,
              "example": 1,
              "type": "number"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Nombre d'evenements par page",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "example": 20,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Liste paginee des evenements"
          },
          "403": {
            "description": "Role insuffisant (ADMIN/SUPERADMIN requis)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Lister les evenements de la ville courante",
        "tags": [
          "events"
        ]
      },
      "post": {
        "operationId": "EventsController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateEventDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Evenement cree avec succes"
          },
          "400": {
            "description": "Payload invalide, dates incoherentes, media ou categorie invalide"
          },
          "403": {
            "description": "Role insuffisant (ADMIN/SUPERADMIN requis)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Creer un evenement",
        "tags": [
          "events"
        ]
      }
    },
    "/events/{eventId}": {
      "get": {
        "operationId": "EventsController_getById",
        "parameters": [
          {
            "name": "eventId",
            "required": true,
            "in": "path",
            "description": "Identifiant de l'evenement",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Evenement trouve"
          },
          "403": {
            "description": "Role insuffisant (ADMIN/SUPERADMIN requis)"
          },
          "404": {
            "description": "Evenement introuvable dans la commune courante"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Recuperer un evenement par son id",
        "tags": [
          "events"
        ]
      },
      "patch": {
        "description": "Patch partiel. `mediaId`, `categoryId`, `publishDate`, `maxCapacity`, `fee` acceptent `null` pour effacer.",
        "operationId": "EventsController_update",
        "parameters": [
          {
            "name": "eventId",
            "required": true,
            "in": "path",
            "description": "Identifiant de l'evenement",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateEventDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Evenement mis a jour avec succes"
          },
          "400": {
            "description": "Payload invalide ou incoherent"
          },
          "403": {
            "description": "Role insuffisant (ADMIN/SUPERADMIN requis)"
          },
          "404": {
            "description": "Evenement introuvable dans la commune courante"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Mettre a jour un evenement",
        "tags": [
          "events"
        ]
      },
      "delete": {
        "description": "Supprime l'evenement et ses inscriptions (cascade).",
        "operationId": "EventsController_delete",
        "parameters": [
          {
            "name": "eventId",
            "required": true,
            "in": "path",
            "description": "Identifiant de l'evenement",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Evenement supprime",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean",
                      "example": true
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Role insuffisant (ADMIN/SUPERADMIN requis)"
          },
          "404": {
            "description": "Evenement introuvable dans la commune courante"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "Supprimer un evenement",
        "tags": [
          "events"
        ]
      }
    },
    "/public/auth/register": {
      "post": {
        "operationId": "CitizenAuthController_register",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CitizenRegisterDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "CitizenAuth"
        ]
      }
    },
    "/public/auth/login": {
      "post": {
        "operationId": "CitizenAuthController_login",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CitizenLoginDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "CitizenAuth"
        ]
      }
    },
    "/public/auth/refresh": {
      "post": {
        "operationId": "CitizenAuthController_refresh",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefreshDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "CitizenAuth"
        ]
      }
    },
    "/public/auth/logout": {
      "post": {
        "operationId": "CitizenAuthController_logout",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "CitizenAuth"
        ]
      }
    },
    "/public/auth/me": {
      "get": {
        "operationId": "CitizenAuthController_me",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "CitizenAuth"
        ]
      }
    },
    "/public/auth/verify-email": {
      "post": {
        "operationId": "CitizenAuthController_verifyEmail",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyEmailDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "CitizenAuth"
        ]
      }
    },
    "/public/auth/resend-verification": {
      "post": {
        "operationId": "CitizenAuthController_resendVerification",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResendVerificationDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "CitizenAuth"
        ]
      }
    },
    "/public/auth/forgot-password": {
      "post": {
        "operationId": "CitizenAuthController_forgotPassword",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ForgotPasswordDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "CitizenAuth"
        ]
      }
    },
    "/public/auth/reset-password": {
      "post": {
        "operationId": "CitizenAuthController_resetPassword",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResetPasswordDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "CitizenAuth"
        ]
      }
    },
    "/public/me": {
      "get": {
        "operationId": "CitizenProfileController_getProfile",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "CitizenProfile"
        ]
      },
      "patch": {
        "operationId": "CitizenProfileController_updateProfile",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCitizenProfileDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "CitizenProfile"
        ]
      }
    },
    "/public/me/photo": {
      "post": {
        "operationId": "CitizenProfileController_uploadPhoto",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "CitizenProfile"
        ]
      }
    },
    "/public/cities": {
      "get": {
        "operationId": "PublicCitiesController_list",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicCities"
        ]
      }
    },
    "/public/cities/followed": {
      "get": {
        "operationId": "PublicCitiesController_listFollowed",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicCities"
        ]
      }
    },
    "/public/cities/recent": {
      "get": {
        "operationId": "PublicCitiesController_listRecent",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicCities"
        ]
      }
    },
    "/public/cities/{cityId}/follow": {
      "post": {
        "operationId": "PublicCitiesController_follow",
        "parameters": [
          {
            "name": "cityId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicCities"
        ]
      },
      "delete": {
        "operationId": "PublicCitiesController_unfollow",
        "parameters": [
          {
            "name": "cityId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicCities"
        ]
      }
    },
    "/public/posts": {
      "get": {
        "operationId": "PublicPostsController_list",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicPosts"
        ]
      }
    },
    "/public/posts/{postId}/like": {
      "post": {
        "operationId": "PublicPostsController_like",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicPosts"
        ]
      },
      "delete": {
        "operationId": "PublicPostsController_unfavorite",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicPosts"
        ]
      }
    },
    "/public/posts/{postId}/comments": {
      "get": {
        "operationId": "PublicPostsController_listComments",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicPosts"
        ]
      },
      "post": {
        "operationId": "PublicPostsController_comment",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePublicPostCommentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "PublicPosts"
        ]
      }
    },
    "/public/posts/{postId}/comments/{commentId}/replies": {
      "get": {
        "operationId": "PublicPostsController_listCommentReplies",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "commentId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicPosts"
        ]
      }
    },
    "/public/posts/{postId}/comments/{commentId}/like": {
      "post": {
        "operationId": "PublicPostsController_likeComment",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "commentId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicPosts"
        ]
      },
      "delete": {
        "operationId": "PublicPostsController_unlikeComment",
        "parameters": [
          {
            "name": "postId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "commentId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicPosts"
        ]
      }
    },
    "/public/reports": {
      "get": {
        "operationId": "PublicReportsController_list",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicReports"
        ]
      },
      "post": {
        "operationId": "PublicReportsController_create",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePublicReportDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "PublicReports"
        ]
      }
    },
    "/public/reports/photos": {
      "post": {
        "operationId": "PublicReportsController_uploadPhoto",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "PublicReports"
        ]
      }
    },
    "/public/reports/{reportId}/comments": {
      "post": {
        "operationId": "PublicReportsController_createComment",
        "parameters": [
          {
            "name": "reportId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePublicReportCommentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "PublicReports"
        ]
      }
    },
    "/public/reports/{reportId}": {
      "get": {
        "operationId": "PublicReportsController_getById",
        "parameters": [
          {
            "name": "reportId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicReports"
        ]
      }
    },
    "/public/consultations": {
      "get": {
        "operationId": "PublicConsultationsController_list",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "PublicConsultations"
        ]
      }
    },
    "/public/consultations/{consultationId}/responses": {
      "post": {
        "operationId": "PublicConsultationResponsesController_respond",
        "parameters": [
          {
            "name": "consultationId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePublicConsultationResponseDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": ""
          }
        },
        "tags": [
          "PublicConsultationResponses"
        ]
      }
    },
    "/public/events": {
      "get": {
        "description": "Requiert un JWT Citizen. Filtre : pas de brouillon, publishDate <= now. Mode `finished=false` (defaut) : scheduled + in_progress. `finished=true` : termines. Tri : non inscrits d'abord, puis inscrits, puis sans inscription requise.",
        "operationId": "PublicEventsController_list",
        "parameters": [
          {
            "name": "cityIds",
            "required": true,
            "in": "query",
            "description": "UUID des communes suivies (1..50). Repeter le parametre ou CSV.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "Numero de page (1-based)",
            "schema": {
              "minimum": 1,
              "default": 1,
              "example": 1,
              "type": "number"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Nombre d'evenements par page",
            "schema": {
              "minimum": 1,
              "maximum": 50,
              "default": 10,
              "example": 10,
              "type": "number"
            }
          },
          {
            "name": "finished",
            "required": false,
            "in": "query",
            "description": "false = actifs/a venir, true = termines",
            "schema": {
              "default": false,
              "example": false,
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Liste paginee des evenements publics"
          },
          "401": {
            "description": "JWT Citizen absent ou invalide"
          }
        },
        "security": [
          {
            "citizen": []
          }
        ],
        "summary": "Lister les evenements publies pour des communes suivies",
        "tags": [
          "public-events"
        ]
      }
    },
    "/public/events/my-registrations": {
      "get": {
        "description": "Inscriptions confirmees et en file d'attente, avec evenement embarque. QR code (data URL PNG) present uniquement si status=confirmed.",
        "operationId": "PublicEventsController_listMyRegistrations",
        "parameters": [
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "Numero de page (1-based)",
            "schema": {
              "minimum": 1,
              "default": 1,
              "example": 1,
              "type": "number"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Nombre d'inscriptions par page",
            "schema": {
              "minimum": 1,
              "maximum": 50,
              "default": 10,
              "example": 10,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Liste paginee des inscriptions"
          },
          "401": {
            "description": "JWT Citizen absent ou invalide"
          }
        },
        "security": [
          {
            "citizen": []
          }
        ],
        "summary": "Lister les inscriptions du citoyen connecte",
        "tags": [
          "public-events"
        ]
      }
    },
    "/public/events/{eventId}": {
      "get": {
        "description": "L'evenement doit appartenir a une commune suivie par le citoyen (CitizenCityFollow).",
        "operationId": "PublicEventsController_getById",
        "parameters": [
          {
            "name": "eventId",
            "required": true,
            "in": "path",
            "description": "Identifiant de l'evenement",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Evenement public avec myRegistration"
          },
          "401": {
            "description": "JWT Citizen absent ou invalide"
          },
          "404": {
            "description": "Evenement introuvable, non publie ou commune non suivie"
          }
        },
        "security": [
          {
            "citizen": []
          }
        ],
        "summary": "Detail d'un evenement publie",
        "tags": [
          "public-events"
        ]
      }
    },
    "/public/events/{eventId}/registrations": {
      "post": {
        "description": "Uniquement si registrationRequired=true. Capacite en nombre de personnes (attendeeCount). Retourne qrCodeDataUrl (PNG base64) si inscription confirmee.",
        "operationId": "PublicEventsController_register",
        "parameters": [
          {
            "name": "eventId",
            "required": true,
            "in": "path",
            "description": "Identifiant de l'evenement",
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePublicEventRegistrationDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Inscription creee"
          },
          "400": {
            "description": "Pas d'inscription requise, evenement non publie/termine, date limite depassee, trop de participants"
          },
          "401": {
            "description": "JWT Citizen absent ou invalide"
          },
          "404": {
            "description": "Evenement introuvable ou commune non suivie"
          },
          "409": {
            "description": "Deja inscrit ou evenement complet sans file d'attente"
          }
        },
        "security": [
          {
            "citizen": []
          }
        ],
        "summary": "S'inscrire a un evenement",
        "tags": [
          "public-events"
        ]
      }
    }
  },
  "info": {
    "title": "Urblink Backend API",
    "description": "Documentation OpenAPI des endpoints backend",
    "version": "1.0.0",
    "contact": {}
  },
  "tags": [],
  "servers": [],
  "components": {
    "securitySchemes": {
      "bearer": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "type": "http",
        "description": "JWT utilisateur (dashboard admin / agents communaux)"
      },
      "citizen": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "type": "http",
        "description": "JWT citoyen (application mobile)"
      }
    },
    "schemas": {
      "SwitchCityDto": {
        "type": "object",
        "properties": {}
      },
      "CreateUserDto": {
        "type": "object",
        "properties": {}
      },
      "UpsertEmailTemplateDto": {
        "type": "object",
        "properties": {}
      },
      "CreatePostCommentDto": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string",
            "description": "Contenu du commentaire",
            "maxLength": 5000
          },
          "parentId": {
            "type": "string",
            "description": "Reponse a un commentaire racine du meme post (un seul niveau)"
          }
        },
        "required": [
          "content"
        ]
      },
      "CreatePostDto": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string",
            "description": "Contenu textuel du post",
            "minLength": 1,
            "maxLength": 50000,
            "example": "Travaux prevus sur la place centrale ce week-end."
          },
          "publishDate": {
            "type": "string",
            "description": "Date de publication cible. Peut etre renseignee des la creation meme si le post reste en brouillon.",
            "format": "date-time",
            "example": "2026-05-01T18:00:00.000Z"
          },
          "mediaIds": {
            "description": "Liste des identifiants de medias a rattacher au post",
            "example": [
              "cm9xabc123",
              "cm9xdef456"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "channels": {
            "type": "array",
            "description": "Canaux sociaux sur lesquels relayer la publication. Vide par defaut (publication interne uniquement).",
            "example": [
              "FACEBOOK",
              "INSTAGRAM"
            ],
            "items": {
              "type": "string",
              "enum": [
                "FACEBOOK",
                "X",
                "LINKEDIN",
                "INSTAGRAM"
              ]
            }
          }
        },
        "required": [
          "content"
        ]
      },
      "UpdatePostDto": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string",
            "description": "Nouveau contenu textuel du post",
            "minLength": 1,
            "maxLength": 50000,
            "example": "Mise a jour : reportage decale au 20 mai."
          },
          "mediaIds": {
            "description": "Nouvelle liste des identifiants de medias attaches. Remplace integralement la liste existante. `[]` est accepte et detache tous les medias.",
            "example": [
              "cm9xabc123",
              "cm9xdef456"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "UpdatePostStatusDto": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "Nouveau statut du post",
            "enum": [
              "draft",
              "published",
              "scheduled"
            ],
            "example": "scheduled"
          },
          "publishDate": {
            "type": "string",
            "description": "Date de publication cible. Requis si status=scheduled et qu'aucune date n'est deja stockee, optionnel si status=draft, ignore si status=published.",
            "format": "date-time",
            "example": "2026-05-01T18:00:00.000Z"
          }
        },
        "required": [
          "status"
        ]
      },
      "UpdatePostChannelsDto": {
        "type": "object",
        "properties": {
          "channels": {
            "type": "array",
            "description": "Liste complete des canaux. Remplace la liste actuelle (semantique PUT-like). Tableau vide = retire tous les canaux.",
            "example": [
              "FACEBOOK",
              "INSTAGRAM"
            ],
            "items": {
              "type": "string",
              "enum": [
                "FACEBOOK",
                "X",
                "LINKEDIN",
                "INSTAGRAM"
              ]
            }
          }
        },
        "required": [
          "channels"
        ]
      },
      "UpdateCitySettingsDto": {
        "type": "object",
        "properties": {}
      },
      "FacebookSocialPatchDto": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Activer ou desactiver Facebook"
          },
          "pageId": {
            "type": "string",
            "description": "Apres OAuth, identifiant de la Page sur laquelle publier (Graph `id` de la Page)"
          }
        }
      },
      "SocialChannelToggleDto": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Activer ou desactiver le canal"
          }
        }
      },
      "InstagramSocialPatchDto": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Activer ou desactiver Instagram"
          },
          "instagramAccountId": {
            "type": "string",
            "description": "Apres OAuth, identifiant du compte Instagram Business (Graph `instagram_business_account.id`)"
          }
        }
      },
      "UpdateSocialSettingsDto": {
        "type": "object",
        "properties": {
          "facebook": {
            "$ref": "#/components/schemas/FacebookSocialPatchDto"
          },
          "x": {
            "$ref": "#/components/schemas/SocialChannelToggleDto"
          },
          "linkedin": {
            "$ref": "#/components/schemas/SocialChannelToggleDto"
          },
          "instagram": {
            "$ref": "#/components/schemas/InstagramSocialPatchDto"
          }
        }
      },
      "CreateCategoryDto": {
        "type": "object",
        "properties": {}
      },
      "UpdateCategoryDto": {
        "type": "object",
        "properties": {}
      },
      "CreateAlertDto": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "Titre de l'alerte",
            "minLength": 1,
            "maxLength": 200,
            "example": "Alerte pollution"
          },
          "niveau": {
            "type": "string",
            "description": "Niveau de criticite de l'alerte",
            "enum": [
              "info",
              "alert",
              "critique"
            ],
            "example": "alert"
          },
          "statut": {
            "type": "string",
            "description": "Statut de l'alerte",
            "enum": [
              "in_progress",
              "scheduled",
              "finished",
              "canceled"
            ],
            "example": "scheduled"
          },
          "categoryId": {
            "type": "string",
            "description": "Identifiant de la categorie (table Category, cible alert ou global)",
            "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
          },
          "message": {
            "type": "string",
            "description": "Message detaille de l'alerte",
            "minLength": 1,
            "maxLength": 10000,
            "example": "Episode de pollution de l'air attendu demain matin."
          },
          "publishDate": {
            "type": "string",
            "description": "Date de debut de diffusion",
            "format": "date-time",
            "example": "2026-05-01T18:00:00.000Z"
          },
          "validUntil": {
            "type": "string",
            "description": "Date de fin de validite (absence = alerte perpetuelle)",
            "format": "date-time",
            "example": "2026-05-03T18:00:00.000Z"
          },
          "audienceIds": {
            "description": "Liste des IDs de zones cibles de l'audience",
            "example": [
              "1a2b3c4d",
              "5e6f7g8h"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "title",
          "niveau",
          "categoryId",
          "message",
          "publishDate"
        ]
      },
      "UpdateAlertDto": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "Titre de l'alerte",
            "minLength": 1,
            "maxLength": 200,
            "example": "Alerte pollution"
          },
          "niveau": {
            "type": "string",
            "description": "Niveau de criticite de l'alerte",
            "enum": [
              "info",
              "alert",
              "critique"
            ],
            "example": "critique"
          },
          "statut": {
            "type": "string",
            "description": "Statut de l'alerte",
            "enum": [
              "in_progress",
              "scheduled",
              "finished",
              "canceled"
            ],
            "example": "in_progress"
          },
          "categoryId": {
            "type": "object",
            "description": "Identifiant de la categorie (null pour retirer la categorie)",
            "nullable": true
          },
          "message": {
            "type": "string",
            "description": "Message detaille de l'alerte",
            "minLength": 1,
            "maxLength": 10000
          },
          "publishDate": {
            "type": "string",
            "description": "Date de debut de diffusion",
            "format": "date-time",
            "example": "2026-05-01T18:00:00.000Z"
          },
          "validUntil": {
            "type": "object",
            "description": "Date de fin de validite (null pour retirer la date et rendre perpetuelle)",
            "format": "date-time",
            "nullable": true,
            "example": "2026-05-03T18:00:00.000Z"
          },
          "audienceIds": {
            "description": "Liste complete des IDs de zones cibles (remplace l'audience actuelle)",
            "example": [
              "1a2b3c4d",
              "5e6f7g8h"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "CreateFormDto": {
        "type": "object",
        "properties": {}
      },
      "UpdateFormDto": {
        "type": "object",
        "properties": {}
      },
      "CreateFormResponseDto": {
        "type": "object",
        "properties": {}
      },
      "CreateReportDto": {
        "type": "object",
        "properties": {}
      },
      "UpdateReportDto": {
        "type": "object",
        "properties": {}
      },
      "CreateReportCommentDto": {
        "type": "object",
        "properties": {}
      },
      "CreateEventDto": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "Titre de l'evenement",
            "minLength": 1,
            "maxLength": 200,
            "example": "Fete de la musique"
          },
          "description": {
            "type": "string",
            "description": "Description de l'evenement",
            "minLength": 1,
            "maxLength": 10000,
            "example": "Concert sur la place centrale."
          },
          "startAt": {
            "type": "string",
            "description": "Date et heure de debut (ISO 8601)",
            "format": "date-time",
            "example": "2026-06-21T18:00:00.000Z"
          },
          "endAt": {
            "type": "string",
            "description": "Date et heure de fin (ISO 8601), strictement apres startAt",
            "format": "date-time",
            "example": "2026-06-21T23:00:00.000Z"
          },
          "location": {
            "type": "string",
            "description": "Lieu de l'evenement",
            "minLength": 1,
            "maxLength": 500,
            "example": "Place de la Mairie"
          },
          "statut": {
            "type": "string",
            "description": "Statut metier. Defaut : draft.",
            "enum": [
              "draft",
              "scheduled",
              "in_progress",
              "finished"
            ],
            "default": "draft",
            "example": "scheduled"
          },
          "mediaId": {
            "type": "string",
            "description": "Identifiant du media image (doit appartenir a la commune)",
            "example": "cm9xabc123"
          },
          "categoryId": {
            "type": "string",
            "description": "Categorie (cible EVENT ou GLOBAL, non masquee)",
            "format": "uuid"
          },
          "publishDate": {
            "type": "string",
            "description": "Date de publication. Visible cote citoyen lorsque publishDate <= now (ou null).",
            "format": "date-time",
            "example": "2026-06-01T08:00:00.000Z"
          },
          "registrationRequired": {
            "type": "boolean",
            "description": "Inscription obligatoire pour participer",
            "default": false
          },
          "channels": {
            "type": "array",
            "description": "Canaux sociaux de diffusion (intention de relais). Vide = aucun.",
            "example": [
              "FACEBOOK",
              "INSTAGRAM"
            ],
            "items": {
              "type": "string",
              "enum": [
                "FACEBOOK",
                "X",
                "LINKEDIN",
                "INSTAGRAM"
              ]
            }
          },
          "maxCapacity": {
            "type": "number",
            "description": "Capacite maximale en nombre de personnes. Absent = illimite.",
            "minimum": 1,
            "example": 200
          },
          "registrationDeadline": {
            "type": "string",
            "description": "Date limite d'inscription (ISO 8601)",
            "format": "date-time",
            "example": "2026-06-20T23:59:59.000Z"
          },
          "waitingListEnabled": {
            "type": "boolean",
            "description": "Activer la file d'attente si l'evenement est complet",
            "default": false
          },
          "fee": {
            "type": "number",
            "description": "Tarif en euros. Absent ou null = gratuit.",
            "minimum": 0,
            "example": 5.5
          },
          "maxAttendeesPerRegistration": {
            "type": "number",
            "description": "Nombre maximum de personnes par inscription citoyenne",
            "minimum": 1,
            "maximum": 50,
            "default": 1,
            "example": 4
          }
        },
        "required": [
          "title",
          "description",
          "startAt",
          "endAt",
          "location"
        ]
      },
      "UpdateEventDto": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "Titre de l'evenement",
            "minLength": 1,
            "maxLength": 200
          },
          "description": {
            "type": "string",
            "description": "Description de l'evenement",
            "minLength": 1,
            "maxLength": 10000
          },
          "startAt": {
            "type": "string",
            "description": "Date et heure de debut (ISO 8601)",
            "format": "date-time"
          },
          "endAt": {
            "type": "string",
            "description": "Date et heure de fin (ISO 8601)",
            "format": "date-time"
          },
          "location": {
            "type": "string",
            "description": "Lieu de l'evenement",
            "minLength": 1,
            "maxLength": 500
          },
          "statut": {
            "type": "string",
            "description": "Statut metier",
            "enum": [
              "draft",
              "scheduled",
              "in_progress",
              "finished"
            ]
          },
          "mediaId": {
            "type": "object",
            "description": "Media image. `null` pour retirer.",
            "nullable": true
          },
          "categoryId": {
            "type": "object",
            "description": "Categorie. `null` pour retirer.",
            "nullable": true,
            "format": "uuid"
          },
          "publishDate": {
            "type": "object",
            "description": "Date de publication. `null` pour retirer.",
            "nullable": true,
            "format": "date-time"
          },
          "registrationRequired": {
            "type": "boolean",
            "description": "Inscription obligatoire"
          },
          "channels": {
            "type": "array",
            "description": "Canaux sociaux (remplace la liste existante)",
            "items": {
              "type": "string",
              "enum": [
                "FACEBOOK",
                "X",
                "LINKEDIN",
                "INSTAGRAM"
              ]
            }
          },
          "maxCapacity": {
            "type": "object",
            "description": "Capacite max (personnes). `null` = illimite.",
            "nullable": true,
            "minimum": 1
          },
          "registrationDeadline": {
            "type": "object",
            "description": "Date limite d'inscription. `null` pour retirer.",
            "nullable": true,
            "format": "date-time"
          },
          "waitingListEnabled": {
            "type": "boolean",
            "description": "File d'attente activee"
          },
          "fee": {
            "type": "object",
            "description": "Tarif en euros. `null` = gratuit.",
            "nullable": true,
            "minimum": 0
          },
          "maxAttendeesPerRegistration": {
            "type": "number",
            "description": "Max personnes par inscription",
            "minimum": 1,
            "maximum": 50
          }
        }
      },
      "CitizenRegisterDto": {
        "type": "object",
        "properties": {}
      },
      "CitizenLoginDto": {
        "type": "object",
        "properties": {}
      },
      "RefreshDto": {
        "type": "object",
        "properties": {}
      },
      "VerifyEmailDto": {
        "type": "object",
        "properties": {}
      },
      "ResendVerificationDto": {
        "type": "object",
        "properties": {}
      },
      "ForgotPasswordDto": {
        "type": "object",
        "properties": {}
      },
      "ResetPasswordDto": {
        "type": "object",
        "properties": {}
      },
      "UpdateCitizenProfileDto": {
        "type": "object",
        "properties": {}
      },
      "CreatePublicPostCommentDto": {
        "type": "object",
        "properties": {}
      },
      "CreatePublicReportDto": {
        "type": "object",
        "properties": {}
      },
      "CreatePublicReportCommentDto": {
        "type": "object",
        "properties": {}
      },
      "CreatePublicConsultationResponseDto": {
        "type": "object",
        "properties": {}
      },
      "CreatePublicEventRegistrationDto": {
        "type": "object",
        "properties": {
          "attendeeCount": {
            "type": "number",
            "description": "Nombre de personnes pour cette inscription (groupe familial, etc.)",
            "minimum": 1,
            "default": 1,
            "example": 2
          }
        }
      }
    }
  }
}
