{
  "openapi": "3.1.0",
  "info": {
    "title": "Remember to Roar public API",
    "version": "1.0.0",
    "summary": "API pubblica in sola lettura del sito Remember to Roar.",
    "description": "Informazioni sul sito, elenco delle pagine pubbliche e articoli del blog pubblicati dalla community. Nessuna autenticazione. Limite: 60 richieste in 60 secondi per IP, comunicato con gli header IETF RateLimit-Policy e RateLimit. Gli errori usano application/problem+json (RFC 9457).",
    "contact": {
      "name": "Riccardo Ruggiero",
      "email": "ricca.ruggiero@gmail.com",
      "url": "https://remembertoroar.com/contatti/"
    }
  },
  "externalDocs": {
    "description": "Documentazione",
    "url": "https://remembertoroar.com/docs/"
  },
  "servers": [
    {
      "url": "https://remembertoroar.com"
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "site",
      "description": "Informazioni sul sito e pagine"
    },
    {
      "name": "blog",
      "description": "Articoli pubblicati dalla community"
    }
  ],
  "paths": {
    "/api/v1/info": {
      "get": {
        "operationId": "getSiteInfo",
        "tags": [
          "site"
        ],
        "summary": "Informazioni sul sito",
        "description": "Autore, contatti, argomenti trattati e link alle risorse per agenti.",
        "responses": {
          "200": {
            "description": "Informazioni sul sito.",
            "headers": {
              "$ref": "#/components/x-rate-limit-headers"
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteInfo"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/api/v1/pages": {
      "get": {
        "operationId": "listPages",
        "tags": [
          "site"
        ],
        "summary": "Elenco delle pagine",
        "description": "Pagine pubbliche con titolo e descrizione. Ogni URL restituisce markdown con Accept: text/markdown.",
        "responses": {
          "200": {
            "description": "Elenco pagine.",
            "headers": {
              "$ref": "#/components/x-rate-limit-headers"
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PageList"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/api/v1/posts": {
      "get": {
        "operationId": "listPosts",
        "tags": [
          "blog"
        ],
        "summary": "Articoli pubblicati",
        "description": "Articoli della community pubblicati, dal più recente.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Numero massimo di articoli (1-50, predefinito 20).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Elenco articoli.",
            "headers": {
              "$ref": "#/components/x-rate-limit-headers"
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "502": {
            "$ref": "#/components/responses/Problem"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/api/v1/posts/{slug}": {
      "get": {
        "operationId": "getPost",
        "tags": [
          "blog"
        ],
        "summary": "Articolo completo",
        "description": "Testo completo di un articolo pubblicato.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Slug dell'articolo, da listPosts.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9-]{1,200}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Articolo.",
            "headers": {
              "$ref": "#/components/x-rate-limit-headers"
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Post"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem"
          },
          "404": {
            "$ref": "#/components/responses/Problem"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "502": {
            "$ref": "#/components/responses/Problem"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    }
  },
  "components": {
    "x-rate-limit-headers": {
      "RateLimit-Policy": {
        "$ref": "#/components/headers/RateLimit-Policy"
      },
      "RateLimit": {
        "$ref": "#/components/headers/RateLimit"
      }
    },
    "headers": {
      "RateLimit-Policy": {
        "description": "Politica di limite (IETF draft-ietf-httpapi-ratelimit-headers): 60 richieste per finestra di 60 secondi.",
        "schema": {
          "type": "string",
          "examples": [
            "\"default\";q=60;w=60"
          ]
        }
      },
      "RateLimit": {
        "description": "Richieste rimaste (r) e secondi al reset (t).",
        "schema": {
          "type": "string",
          "examples": [
            "\"default\";r=59;t=60"
          ]
        }
      },
      "Retry-After": {
        "description": "Secondi da attendere prima di riprovare.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "responses": {
      "Problem": {
        "description": "Errore in formato RFC 9457.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Limite di richieste superato.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimit-Policy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "required": [
          "type",
          "title",
          "status",
          "detail",
          "code",
          "resolution"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "enum": [
              "not_found",
              "post_not_found",
              "invalid_limit",
              "invalid_slug",
              "method_not_allowed",
              "rate_limited",
              "upstream_unavailable",
              "internal_error"
            ]
          },
          "resolution": {
            "type": "string"
          }
        }
      },
      "SiteInfo": {
        "type": "object",
        "required": [
          "name",
          "url",
          "language",
          "description",
          "author",
          "contact",
          "resources",
          "api_version"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "language": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "author": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            }
          },
          "contact": {
            "type": "object",
            "properties": {
              "email": {
                "type": "string",
                "format": "email"
              },
              "page": {
                "type": "string",
                "format": "uri"
              }
            }
          },
          "address": {
            "type": "object",
            "properties": {
              "locality": {
                "type": "string"
              },
              "country": {
                "type": "string"
              }
            }
          },
          "social": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "topics": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "resources": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "format": "uri"
            }
          },
          "api_version": {
            "type": "string"
          }
        }
      },
      "Page": {
        "type": "object",
        "required": [
          "path",
          "url",
          "title",
          "description",
          "indexable"
        ],
        "properties": {
          "path": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "indexable": {
            "type": "boolean",
            "description": "false per le pagine marcate noindex."
          }
        }
      },
      "PageList": {
        "type": "object",
        "required": [
          "count",
          "pages"
        ],
        "properties": {
          "count": {
            "type": "integer"
          },
          "pages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Page"
            }
          }
        }
      },
      "PostSummary": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "url",
          "tags"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "subtitle": {
            "type": [
              "string",
              "null"
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "cover_image_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Post": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PostSummary"
          },
          {
            "type": "object",
            "required": [
              "content"
            ],
            "properties": {
              "content": {
                "type": "string",
                "description": "Testo dell'articolo come scritto dall'autore."
              }
            }
          }
        ]
      },
      "PostList": {
        "type": "object",
        "required": [
          "count",
          "posts"
        ],
        "properties": {
          "count": {
            "type": "integer"
          },
          "posts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PostSummary"
            }
          }
        }
      }
    }
  }
}
