{
  "openapi": "3.0.3",
  "info": {
    "title": "CampNow - Campground API",
    "version": "3.0.0",
    "description": "Campground profile completion flow. Three overall steps:\n\n**Step 1 — Campground Profile Setup** (4 sub-steps)\n- 1a. Basic Info (name, location, description)\n- 1b. Media — chunk upload for images and videos\n- 1c. Social & Booking Links\n- 1d. FAQs & Contact URL\n\n**Step 2 — Availability** (manual or ERP integration)\n\n**Step 3 — Activate Profile** (only available after Steps 1 + 2 are complete)\n\nAll campground endpoints require a campsite JWT obtained from `POST /api/auth/campsite/login`.\n\n---\n### Chunk Upload Flow\n1. Client splits the file into fixed-size chunks (recommended: 2 MB each).\n2. Client generates a UUID (`uploadId`) for the session.\n3. For each chunk: `POST /:id/media/chunk` with `uploadId`, `chunkIndex` (0-based), `totalChunks`, `filename`, `mimeType`, `mediaType`, and `chunk` (binary).\n4. When all chunks are received the server assembles the file and returns `{ status: 'complete', media: {...} }`.\n5. To abort: `DELETE /:id/media/chunk/:uploadId`.\n\n---\n### FAQ Flow\n- `GET /:id/faqs` auto-initializes FAQs on first call — all active admin FAQs are copied into the campsite's own collection.\n- Subsequent calls return the campsite's own FAQ records plus a `suggested` array of admin FAQs not yet added.\n- Editing any FAQ sets `isCustom: true` on that record. Admin FAQ updates never overwrite campsite data.\n- Deleting a FAQ is a **soft delete** (`isActive: false`) — the FAQ re-appears in `suggested` so the owner can re-add it.\n- To add a suggested FAQ, POST with `sourceFaqId` referencing the admin FAQ id."
  },
  "servers": [
    {
      "url": "{{baseUrl}}",
      "description": "Set baseUrl in Apidog environment (e.g. http://localhost:3000)"
    }
  ],
  "components": {
    "securitySchemes": {
      "campsiteBearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "JWT token obtained from POST /api/auth/campsite/login"
      }
    },
    "schemas": {
      "SuccessResponse": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "example": true },
          "message": { "type": "string" },
          "data":    {}
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "example": false },
          "message": { "type": "string" }
        }
      },
      "ValidationErrorResponse": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "example": false },
          "message": { "type": "string", "example": "Validation failed" },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "field":   { "type": "string" },
                "message": { "type": "string" }
              }
            }
          }
        }
      },
      "Location": {
        "type": "object",
        "properties": {
          "latitude":  { "type": "number", "example": 47.8095 },
          "longitude": { "type": "number", "example": 13.0550 },
          "address":   { "type": "string", "example": "Salzburg, Austria" }
        }
      },
      "MediaItem": {
        "type": "object",
        "properties": {
          "id":            { "type": "string", "example": "665a1b2c3d4e5f6a7b8c9d0e" },
          "url":           { "type": "string", "example": "http://localhost:3000/media/campsites/gallery/1714000000000-abc.jpg" },
          "type":          { "type": "string", "enum": ["cover", "gallery"] },
          "mediaCategory": { "type": "string", "enum": ["image", "video"] }
        }
      },
      "FaqItem": {
        "type": "object",
        "description": "A campsite-owned FAQ record. Always bilingual where provided.",
        "properties": {
          "id":          { "type": "string", "example": "666a1b2c3d4e5f6a7b8c9d0f" },
          "question_en": { "type": "string", "example": "Are pets allowed?" },
          "question_de": { "type": "string", "nullable": true, "example": "Sind Haustiere erlaubt?" },
          "answer_en":   { "type": "string", "example": "Yes, pets are welcome on a leash." },
          "answer_de":   { "type": "string", "nullable": true, "example": "Ja, Haustiere sind an der Leine willkommen." },
          "order":       { "type": "integer", "example": 1 },
          "isCustom":    { "type": "boolean", "description": "true once the owner has edited question or answer content", "example": false },
          "sourceFaqId": { "type": "string", "nullable": true, "description": "Admin FAQ this was copied from. null for pure custom FAQs.", "example": "666a000000000000000000a1" }
        }
      },
      "SuggestedFaqItem": {
        "type": "object",
        "description": "An admin FAQ not yet added to this campsite. Use the id as sourceFaqId when adding.",
        "properties": {
          "id":          { "type": "string", "example": "666a000000000000000000a3" },
          "question_en": { "type": "string", "example": "Do you have Wi-Fi?" },
          "question_de": { "type": "string", "nullable": true, "example": "Haben Sie WLAN?" },
          "answer_en":   { "type": "string", "example": "Yes, free Wi-Fi is available at the reception area." },
          "answer_de":   { "type": "string", "nullable": true, "example": "Ja, kostenloses WLAN ist im Empfangsbereich verfügbar." },
          "order":       { "type": "integer", "example": 4 }
        }
      },
      "Links": {
        "type": "object",
        "properties": {
          "website_url":   { "type": "string", "nullable": true },
          "instagram_url": { "type": "string", "nullable": true },
          "facebook_url":  { "type": "string", "nullable": true },
          "youtube_url":   { "type": "string", "nullable": true },
          "twitter_url":   { "type": "string", "nullable": true },
          "booking_url":   { "type": "string", "nullable": true },
          "contact_url":   { "type": "string", "nullable": true }
        }
      },
      "AvailabilityConfig": {
        "type": "object",
        "properties": {
          "type":         { "type": "string", "enum": ["manual", "erp"] },
          "erpProvider":  { "type": "string", "nullable": true, "example": "apaleo" },
          "isConfigured": { "type": "boolean" }
        }
      },
      "CampgroundDetail": {
        "type": "object",
        "properties": {
          "id":                    { "type": "string" },
          "campground_name":       { "type": "string", "nullable": true },
          "location":              { "$ref": "#/components/schemas/Location" },
          "short_description":     { "type": "string", "nullable": true },
          "cover_image_url":       { "type": "string", "nullable": true },
          "is_active":             { "type": "boolean" },
          "is_visible":            { "type": "boolean" },
          "slug":                  { "type": "string", "nullable": true },
          "setup_status":          { "type": "string", "enum": ["draft", "in_progress", "completed", "active"] },
          "step1_status":          { "type": "string", "enum": ["pending", "in_progress", "completed"] },
          "step2_status":          { "type": "string", "enum": ["pending", "configured"] },
          "completion_percentage": { "type": "integer", "minimum": 0, "maximum": 100, "example": 50 },
          "links":                 { "$ref": "#/components/schemas/Links" },
          "media": {
            "type": "object",
            "properties": {
              "cover":   { "nullable": true, "allOf": [{ "$ref": "#/components/schemas/MediaItem" }] },
              "gallery": { "type": "array", "items": { "$ref": "#/components/schemas/MediaItem" } }
            }
          },
          "faqs":         { "type": "array", "items": { "$ref": "#/components/schemas/FaqItem" } },
          "availability": { "nullable": true, "allOf": [{ "$ref": "#/components/schemas/AvailabilityConfig" }] }
        }
      }
    }
  },
  "tags": [
    { "name": "Campsite Auth",      "description": "Login, password reset, forgot username for campsite accounts" },
    { "name": "Campground Detail",  "description": "Full aggregated detail endpoint — use this to populate the campground detail page" },
    { "name": "Step 1a Basic Info", "description": "Campground name, location, short description" },
    { "name": "Step 1b Media",      "description": "Chunk upload for images and videos (cover + gallery)" },
    { "name": "Step 1c Links",      "description": "Website, social media and booking URLs" },
    { "name": "Step 1d FAQs",       "description": "Campsite FAQ management. FAQs are copied from admin defaults on first visit. Owner can edit, delete (soft), add custom FAQs, or add from suggested list. Admin FAQ changes never affect campsite data after initial copy." },
    { "name": "Step 2 Availability","description": "Manual setup or ERP integration" },
    { "name": "Step 3 Activate",    "description": "Complete setup, activate profile, toggle visibility" },
    { "name": "Public Profile",     "description": "Unauthenticated public-facing campground profile (slug-based)" }
  ],
  "paths": {

    "/api/auth/campsite/login": {
      "post": {
        "tags": ["Campsite Auth"],
        "summary": "Campsite Login",
        "description": "Login with campsite username and password. Copy the `accessToken` from the response and set it as the Bearer token for all campground endpoints.",
        "operationId": "campsiteLogin",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["username", "password"],
                "properties": {
                  "username": { "type": "string", "example": "alpine_hut_x7k2" },
                  "password": { "type": "string", "example": "TempPass@1234" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Login successful",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Login successful",
                  "data": {
                    "campsite": {
                      "id": "664f1a2b3c4d5e6f7a8b9c0d",
                      "name": "Alpine Hut",
                      "username": "alpine_hut_x7k2",
                      "coverImageUrl": "http://localhost:3000/media/campsites/cover/cover.jpg"
                    },
                    "owner": {
                      "id": "664f1a2b3c4d5e6f7a8b9c0e",
                      "firstName": "John",
                      "lastName": "Doe",
                      "email": "john@example.com"
                    },
                    "tokens": {
                      "accessToken": "<JWT_ACCESS_TOKEN>",
                      "refreshToken": "<JWT_REFRESH_TOKEN>"
                    },
                    "requiresPasswordReset": true,
                    "passwordResetToken": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4"
                  }
                }
              }
            }
          },
          "400": { "description": "Invalid credentials", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },

    "/api/auth/campsite/forgot-password": {
      "post": {
        "tags": ["Campsite Auth"],
        "summary": "Campsite Forgot Password",
        "description": "Send a password reset link to the owner's email using the campsite username.",
        "operationId": "campsiteForgotPassword",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["username"],
                "properties": {
                  "username": { "type": "string", "example": "alpine_hut_x7k2" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reset email sent",
            "content": { "application/json": { "example": { "success": true, "message": "Password reset instructions sent", "data": { "success": true } } } }
          }
        }
      }
    },

    "/api/auth/campsite/reset-password": {
      "post": {
        "tags": ["Campsite Auth"],
        "summary": "Campsite Reset Password",
        "description": "Reset campsite password using the token from the forgot-password email or from the login response (`passwordResetToken`). Token expires in 1 hour.",
        "operationId": "campsiteResetPassword",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["token", "newPassword"],
                "properties": {
                  "token":       { "type": "string", "example": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4" },
                  "newPassword": { "type": "string", "minLength": 6, "example": "NewSecure@99" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Password reset successful", "content": { "application/json": { "example": { "success": true, "message": "Password reset successful", "data": { "success": true } } } } },
          "400": { "description": "Invalid or expired token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },

    "/api/auth/campsite/forgot-username": {
      "post": {
        "tags": ["Campsite Auth"],
        "summary": "Campsite Forgot Username",
        "description": "Send the campsite username to the owner's email. Provide the owner's registered email and the exact campsite name.",
        "operationId": "campsiteForgotUsername",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email", "campsite_name"],
                "properties": {
                  "email":         { "type": "string", "format": "email", "example": "owner@example.com" },
                  "campsite_name": { "type": "string", "example": "Alpine Hut" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Username sent", "content": { "application/json": { "example": { "success": true, "message": "If an account matches, the username has been sent to the registered email", "data": { "success": true } } } } }
        }
      }
    },

    "/api/campground/{id}/detail": {
      "get": {
        "tags": ["Campground Detail"],
        "summary": "Get Full Campground Detail",
        "description": "Single endpoint that returns everything needed to render the campground detail page: basic info, all media, links, FAQs, availability config, step statuses, and completion percentage. Use this instead of calling individual step endpoints separately.",
        "operationId": "getCampgroundDetail",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "responses": {
          "200": {
            "description": "Full campground detail",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Campground detail retrieved successfully",
                  "data": {
                    "id": "664f1a2b3c4d5e6f7a8b9c0d",
                    "campground_name": "Alpine Hut",
                    "location": { "latitude": 47.8095, "longitude": 13.0550, "address": "Salzburg, Austria" },
                    "short_description": "<p>A beautiful alpine campsite in the heart of the mountains.</p>",
                    "cover_image_url": "http://localhost:3000/media/campsites/cover/1714000000000-abc.jpg",
                    "is_active": false,
                    "is_visible": false,
                    "slug": null,
                    "setup_status": "in_progress",
                    "step1_status": "in_progress",
                    "step2_status": "pending",
                    "completion_percentage": 25,
                    "links": {
                      "website_url": "https://www.alpinehut.at",
                      "instagram_url": "https://instagram.com/alpinehut",
                      "facebook_url": null,
                      "youtube_url": null,
                      "twitter_url": null,
                      "booking_url": null,
                      "contact_url": null
                    },
                    "media": {
                      "cover": {
                        "id": "665a1b2c3d4e5f6a7b8c9d0e",
                        "url": "http://localhost:3000/media/campsites/cover/1714000000000-abc.jpg",
                        "type": "cover",
                        "mediaCategory": "image"
                      },
                      "gallery": [
                        { "id": "665a1b2c3d4e5f6a7b8c9d10", "url": "http://localhost:3000/media/campsites/gallery/1714000000001-img.jpg", "type": "gallery", "mediaCategory": "image" },
                        { "id": "665a1b2c3d4e5f6a7b8c9d11", "url": "http://localhost:3000/media/campsites/gallery/1714000000002-vid.mp4", "type": "gallery", "mediaCategory": "video" }
                      ]
                    },
                    "faqs": [
                      {
                        "id": "666a1b2c3d4e5f6a7b8c9d01",
                        "question_en": "Are pets allowed?",
                        "question_de": "Sind Haustiere erlaubt?",
                        "answer_en": "Yes, pets are welcome on a leash.",
                        "answer_de": "Ja, Haustiere sind an der Leine willkommen.",
                        "order": 1,
                        "isCustom": false,
                        "sourceFaqId": "666a000000000000000000a1"
                      },
                      {
                        "id": "666a1b2c3d4e5f6a7b8c9d02",
                        "question_en": "Check-in is at 14:00",
                        "question_de": "Der Check-in ist um 14:00 Uhr",
                        "answer_en": "Yes, from 14:00 onwards.",
                        "answer_de": "Ja, ab 14:00 Uhr.",
                        "order": 2,
                        "isCustom": true,
                        "sourceFaqId": "666a000000000000000000a2"
                      },
                      {
                        "id": "666a1b2c3d4e5f6a7b8c9d03",
                        "question_en": "Do you offer group discounts?",
                        "question_de": null,
                        "answer_en": "Yes, contact us directly.",
                        "answer_de": null,
                        "order": 3,
                        "isCustom": true,
                        "sourceFaqId": null
                      }
                    ],
                    "availability": null
                  }
                }
              }
            }
          },
          "401": { "description": "Unauthorized" },
          "404": { "description": "Campsite not found" }
        }
      }
    },

    "/api/campground/{id}": {
      "get": {
        "tags": ["Step 1a Basic Info"],
        "summary": "Get Basic Info",
        "description": "Pre-populate Step 1a form fields.",
        "operationId": "getBasicInfo",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "responses": {
          "200": {
            "description": "Basic info retrieved",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Campground basic info retrieved successfully",
                  "data": {
                    "id": "664f1a2b3c4d5e6f7a8b9c0d",
                    "campground_name": "Alpine Hut",
                    "location": { "latitude": 47.8095, "longitude": 13.0550, "address": "Salzburg, Austria" },
                    "short_description": "<p>A beautiful alpine campsite...</p>",
                    "setup_status": "in_progress",
                    "step1_status": "in_progress"
                  }
                }
              }
            }
          },
          "401": { "description": "Unauthorized" },
          "403": { "description": "Access denied — campsite ID mismatch" },
          "404": { "description": "Campsite not found" }
        }
      },
      "patch": {
        "tags": ["Step 1a Basic Info"],
        "summary": "Update Basic Info",
        "description": "Partial update of Step 1a fields. All fields are optional — send only the ones being changed. `setup_status` is computed by the server and must NOT be sent by the client.",
        "operationId": "updateBasicInfo",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campground_name":   { "type": "string", "maxLength": 200, "example": "Alpine Hut" },
                  "location":          { "$ref": "#/components/schemas/Location" },
                  "short_description": { "type": "string", "maxLength": 10000, "example": "<p>A beautiful alpine campsite...</p>" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Basic info updated. `step1_status` is auto-recomputed: `completed` when name + location.address + description are filled AND at least 1 image exists.",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Campground basic info updated successfully",
                  "data": {
                    "id": "664f1a2b3c4d5e6f7a8b9c0d",
                    "campground_name": "Alpine Hut",
                    "location": { "latitude": 47.8095, "longitude": 13.0550, "address": "Salzburg, Austria" },
                    "short_description": "<p>A beautiful alpine campsite...</p>",
                    "setup_status": "in_progress",
                    "step1_status": "in_progress"
                  }
                }
              }
            }
          },
          "401": { "description": "Unauthorized" },
          "403": { "description": "Access denied" },
          "404": { "description": "Campsite not found" },
          "422": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidationErrorResponse" } } } }
        }
      }
    },

    "/api/campground/{id}/media": {
      "get": {
        "tags": ["Step 1b Media"],
        "summary": "Get Media",
        "description": "Returns the cover image and gallery items for this campground.",
        "operationId": "getMedia",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "responses": {
          "200": {
            "description": "Media retrieved",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Campground media retrieved successfully",
                  "data": {
                    "cover": {
                      "id": "665a1b2c3d4e5f6a7b8c9d0e",
                      "url": "http://localhost:3000/media/campsites/cover/1714000000000-abc.jpg",
                      "type": "cover",
                      "mediaCategory": "image"
                    },
                    "gallery": [
                      { "id": "665a1b2c3d4e5f6a7b8c9d10", "url": "http://localhost:3000/media/campsites/gallery/1714000000001-img.jpg", "type": "gallery", "mediaCategory": "image" },
                      { "id": "665a1b2c3d4e5f6a7b8c9d11", "url": "http://localhost:3000/media/campsites/gallery/1714000000002-vid.mp4", "type": "gallery", "mediaCategory": "video" }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },

    "/api/campground/{id}/media/chunk": {
      "post": {
        "tags": ["Step 1b Media"],
        "summary": "Upload Media Chunk",
        "description": "Upload one chunk of a file. Repeat for every chunk in order. When the last chunk arrives (`chunkIndex == totalChunks - 1`) the server assembles the file and returns `status: 'complete'` with the final media record.\n\n**Allowed MIME types**\n- Cover (`mediaType: cover`): `image/jpeg`, `image/jpg`, `image/png`, `image/webp`\n- Gallery (`mediaType: gallery`): all image types above + `video/mp4`, `video/quicktime`, `video/webm`, `video/x-msvideo`\n\n**Cover behaviour**: uploading a new cover automatically hard-deletes the previous one and syncs `coverImageUrl` on the campsite record.",
        "operationId": "uploadMediaChunk",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["chunk", "uploadId", "chunkIndex", "totalChunks", "filename", "mimeType", "mediaType"],
                "properties": {
                  "chunk":       { "type": "string", "format": "binary", "description": "Raw binary chunk data. Max 10 MB per chunk." },
                  "uploadId":    { "type": "string", "format": "uuid", "description": "Client-generated UUID for this upload session. Same value for all chunks of the same file.", "example": "550e8400-e29b-41d4-a716-446655440000" },
                  "chunkIndex":  { "type": "integer", "minimum": 0, "description": "0-based index of this chunk.", "example": 0 },
                  "totalChunks": { "type": "integer", "minimum": 1, "description": "Total number of chunks for this file.", "example": 5 },
                  "filename":    { "type": "string", "description": "Original filename including extension.", "example": "campsite-hero.jpg" },
                  "mimeType":    { "type": "string", "description": "MIME type of the complete file.", "example": "image/jpeg" },
                  "mediaType":   { "type": "string", "enum": ["cover", "gallery"], "description": "cover = single cover image (replaces previous), gallery = added to gallery." }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Chunk received — more chunks expected",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Chunk received",
                  "data": { "status": "chunk_received", "chunkIndex": 0 }
                }
              }
            }
          },
          "201": {
            "description": "Last chunk received — file assembled and media record created",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Chunk received",
                  "data": {
                    "status": "complete",
                    "media": {
                      "id":            "665a1b2c3d4e5f6a7b8c9d0e",
                      "url":           "http://localhost:3000/media/campsites/cover/1714000000000-550e8400.jpg",
                      "type":          "cover",
                      "mediaCategory": "image"
                    }
                  }
                }
              }
            }
          },
          "400": { "description": "Invalid MIME type or mediaType", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "401": { "description": "Unauthorized" },
          "404": { "description": "Campsite not found" },
          "422": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidationErrorResponse" } } } }
        }
      }
    },

    "/api/campground/{id}/media/chunk/{uploadId}": {
      "delete": {
        "tags": ["Step 1b Media"],
        "summary": "Cancel Chunk Upload",
        "description": "Abort an in-progress chunked upload. Cleans up all temporary chunk files on the server. Call this when the user cancels an upload mid-way.",
        "operationId": "cancelChunkUpload",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id",       "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" },
          { "name": "uploadId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "example": "550e8400-e29b-41d4-a716-446655440000" }
        ],
        "responses": {
          "200": {
            "description": "Upload cancelled and temp files cleaned up",
            "content": {
              "application/json": {
                "example": { "success": true, "message": "Upload cancelled", "data": { "cancelled": true } }
              }
            }
          }
        }
      }
    },

    "/api/campground/{id}/media/{mediaId}": {
      "delete": {
        "tags": ["Step 1b Media"],
        "summary": "Delete Media",
        "description": "Permanently delete a media item. The physical file is also removed from disk. If the deleted item is the cover, `coverImageUrl` on the campsite is cleared.",
        "operationId": "deleteMedia",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id",      "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" },
          { "name": "mediaId", "in": "path", "required": true, "schema": { "type": "string" }, "example": "665a1b2c3d4e5f6a7b8c9d0e" }
        ],
        "responses": {
          "200": {
            "description": "Media permanently deleted",
            "content": {
              "application/json": {
                "example": { "success": true, "message": "Media deleted successfully", "data": { "deletedId": "665a1b2c3d4e5f6a7b8c9d0e" } }
              }
            }
          },
          "404": { "description": "Media not found" }
        }
      }
    },

    "/api/campground/{id}/links": {
      "get": {
        "tags": ["Step 1c Links"],
        "summary": "Get Links",
        "description": "Pre-populate Step 1c form with existing link values.",
        "operationId": "getLinks",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "responses": {
          "200": {
            "description": "Links retrieved",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Campground links retrieved successfully",
                  "data": {
                    "website_url":   "https://www.alpinehut.at",
                    "instagram_url": "https://instagram.com/alpinehut",
                    "facebook_url":  null,
                    "youtube_url":   null,
                    "twitter_url":   null,
                    "booking_url":   null
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": ["Step 1c Links"],
        "summary": "Update Links",
        "description": "Save or update link fields. All fields are optional. `website_url` and `booking_url` must be `https://` URLs. Pass `null` or empty string to clear a field.",
        "operationId": "updateLinks",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "website_url":   { "type": "string", "example": "https://www.alpinehut.at" },
                  "instagram_url": { "type": "string", "example": "https://instagram.com/alpinehut" },
                  "facebook_url":  { "type": "string", "example": "https://facebook.com/alpinehut" },
                  "youtube_url":   { "type": "string", "example": "https://youtube.com/@alpinehut" },
                  "twitter_url":   { "type": "string", "example": "https://twitter.com/alpinehut" },
                  "booking_url":   { "type": "string", "example": "https://booking.alpinehut.at" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Links updated",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Campground links updated successfully",
                  "data": {
                    "website_url":   "https://www.alpinehut.at",
                    "instagram_url": "https://instagram.com/alpinehut",
                    "facebook_url":  null,
                    "youtube_url":   null,
                    "twitter_url":   null,
                    "booking_url":   null
                  }
                }
              }
            }
          },
          "422": { "description": "Validation error (e.g. non-https website_url)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidationErrorResponse" } } } }
        }
      }
    },

    "/api/campground/{id}/faqs": {
      "get": {
        "tags": ["Step 1d FAQs"],
        "summary": "Get FAQs & Contact",
        "description": "Returns the contact URL, the campsite's own FAQ list, and a `suggested` array of admin FAQs not yet added.\n\n**First-visit auto-init**: if this campsite has no FAQs yet, all active admin FAQs (audience: campingSpotOwners) are automatically copied into the campsite collection before returning. This is transparent — FE always receives the same shape.\n\n**`faqs`** — campsite-owned records:\n- `isCustom: false` = copied from admin, content unchanged\n- `isCustom: true` = owner has edited content\n- `sourceFaqId: null` = owner-created (no admin equivalent)\n\n**`suggested`** — admin FAQs not yet in campsite. Use `id` as `sourceFaqId` when the owner adds one.",
        "operationId": "getFaqs",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "responses": {
          "200": {
            "description": "FAQs retrieved",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "FAQs retrieved successfully",
                  "data": {
                    "contact_url": "https://www.alpinehut.at/contact",
                    "faqs": [
                      {
                        "id": "666a1b2c3d4e5f6a7b8c9d01",
                        "question_en": "Are pets allowed?",
                        "question_de": "Sind Haustiere erlaubt?",
                        "answer_en": "Yes, pets are welcome on a leash.",
                        "answer_de": "Ja, Haustiere sind an der Leine willkommen.",
                        "order": 1,
                        "isCustom": false,
                        "sourceFaqId": "666a000000000000000000a1"
                      },
                      {
                        "id": "666a1b2c3d4e5f6a7b8c9d02",
                        "question_en": "Check-in is at 15:00 (we adjusted it)",
                        "question_de": "Check-in ist um 15:00 Uhr",
                        "answer_en": "Yes, from 15:00 onwards.",
                        "answer_de": "Ja, ab 15:00 Uhr.",
                        "order": 2,
                        "isCustom": true,
                        "sourceFaqId": "666a000000000000000000a2"
                      },
                      {
                        "id": "666a1b2c3d4e5f6a7b8c9d03",
                        "question_en": "Do you offer group discounts?",
                        "question_de": null,
                        "answer_en": "Yes, contact us directly.",
                        "answer_de": null,
                        "order": 3,
                        "isCustom": true,
                        "sourceFaqId": null
                      }
                    ],
                    "suggested": [
                      {
                        "id": "666a000000000000000000a3",
                        "question_en": "Do you have Wi-Fi?",
                        "question_de": "Haben Sie WLAN?",
                        "answer_en": "Yes, free Wi-Fi is available at the reception area.",
                        "answer_de": "Ja, kostenloses WLAN ist im Empfangsbereich verfügbar.",
                        "order": 4
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": { "description": "Unauthorized" },
          "404": { "description": "Campsite not found" }
        }
      },
      "post": {
        "tags": ["Step 1d FAQs"],
        "summary": "Create FAQ / Add Suggested FAQ",
        "description": "Two modes:\n\n**Custom FAQ** — omit `sourceFaqId`. Creates a new owner-specific FAQ. Sets `isCustom: true`.\n\n**Add suggested FAQ** — provide `sourceFaqId` (the `id` from the `suggested` array). Pre-fill `question_en`/`answer_en` from the suggested item. Sets `isCustom: false`. If the owner changes the content before submitting, it still sets `isCustom: false` here — `isCustom` becomes `true` only on a subsequent PATCH.\n\n**Deduplication**: the unique index on `(campsiteId, sourceFaqId)` prevents adding the same suggested FAQ twice.",
        "operationId": "createFaq",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["question_en", "answer_en"],
                "properties": {
                  "question_en": { "type": "string", "maxLength": 500, "example": "Are pets allowed at the campsite?" },
                  "question_de": { "type": "string", "maxLength": 500, "nullable": true, "example": "Sind Haustiere auf dem Campingplatz erlaubt?" },
                  "answer_en":   { "type": "string", "maxLength": 5000, "example": "Yes, pets are welcome on a leash." },
                  "answer_de":   { "type": "string", "maxLength": 5000, "nullable": true, "example": "Ja, Haustiere sind an der Leine willkommen." },
                  "order":       { "type": "integer", "minimum": 1, "example": 3 },
                  "sourceFaqId": { "type": "string", "description": "ObjectId from `suggested[].id`. Omit for custom FAQs.", "example": "666a000000000000000000a3" }
                }
              },
              "examples": {
                "custom_faq": {
                  "summary": "Custom FAQ (no sourceFaqId)",
                  "value": {
                    "question_en": "Do you offer group discounts?",
                    "question_de": "Bieten Sie Gruppenrabatte an?",
                    "answer_en": "Yes, contact us directly for groups of 10+.",
                    "answer_de": "Ja, kontaktieren Sie uns direkt für Gruppen ab 10 Personen."
                  }
                },
                "suggested_faq": {
                  "summary": "Adding a suggested FAQ",
                  "value": {
                    "question_en": "Do you have Wi-Fi?",
                    "question_de": "Haben Sie WLAN?",
                    "answer_en": "Yes, free Wi-Fi is available at the reception area.",
                    "answer_de": "Ja, kostenloses WLAN ist im Empfangsbereich verfügbar.",
                    "sourceFaqId": "666a000000000000000000a3"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "FAQ created",
            "content": {
              "application/json": {
                "examples": {
                  "custom_created": {
                    "summary": "Custom FAQ created",
                    "value": {
                      "success": true,
                      "message": "FAQ created successfully",
                      "data": {
                        "id": "666a1b2c3d4e5f6a7b8c9d10",
                        "question_en": "Do you offer group discounts?",
                        "question_de": "Bieten Sie Gruppenrabatte an?",
                        "answer_en": "Yes, contact us directly for groups of 10+.",
                        "answer_de": "Ja, kontaktieren Sie uns direkt für Gruppen ab 10 Personen.",
                        "order": 4,
                        "isCustom": true,
                        "sourceFaqId": null
                      }
                    }
                  },
                  "suggested_added": {
                    "summary": "Suggested FAQ added",
                    "value": {
                      "success": true,
                      "message": "FAQ created successfully",
                      "data": {
                        "id": "666a1b2c3d4e5f6a7b8c9d11",
                        "question_en": "Do you have Wi-Fi?",
                        "question_de": "Haben Sie WLAN?",
                        "answer_en": "Yes, free Wi-Fi is available at the reception area.",
                        "answer_de": "Ja, kostenloses WLAN ist im Empfangsbereich verfügbar.",
                        "order": 4,
                        "isCustom": false,
                        "sourceFaqId": "666a000000000000000000a3"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": { "description": "sourceFaqId references a non-existent or inactive admin FAQ" },
          "422": { "description": "Validation error (e.g. missing question_en or answer_en)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidationErrorResponse" } } } }
        }
      }
    },

    "/api/campground/{id}/faqs/{faqId}": {
      "patch": {
        "tags": ["Step 1d FAQs"],
        "summary": "Update FAQ",
        "description": "Partial update of an existing campsite FAQ. All fields optional — send only what changed.\n\nAlways sets `isCustom: true` regardless of which field is updated. This marks that the owner has diverged from the admin default.",
        "operationId": "updateFaq",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id",    "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" },
          { "name": "faqId", "in": "path", "required": true, "schema": { "type": "string" }, "example": "666a1b2c3d4e5f6a7b8c9d01" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "question_en": { "type": "string", "maxLength": 500, "example": "Are pets allowed?" },
                  "question_de": { "type": "string", "maxLength": 500, "nullable": true, "example": "Sind Haustiere erlaubt?" },
                  "answer_en":   { "type": "string", "maxLength": 5000, "example": "Yes, on a leash at all times." },
                  "answer_de":   { "type": "string", "maxLength": 5000, "nullable": true, "example": "Ja, immer an der Leine." },
                  "order":       { "type": "integer", "minimum": 1, "example": 1 }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "FAQ updated. `isCustom` is always set to `true`.",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "FAQ updated successfully",
                  "data": {
                    "id": "666a1b2c3d4e5f6a7b8c9d01",
                    "question_en": "Are pets allowed?",
                    "question_de": "Sind Haustiere erlaubt?",
                    "answer_en": "Yes, on a leash at all times.",
                    "answer_de": "Ja, immer an der Leine.",
                    "order": 1,
                    "isCustom": true,
                    "sourceFaqId": "666a000000000000000000a1"
                  }
                }
              }
            }
          },
          "404": { "description": "FAQ not found or not active" },
          "422": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidationErrorResponse" } } } }
        }
      },
      "delete": {
        "tags": ["Step 1d FAQs"],
        "summary": "Delete FAQ (soft)",
        "description": "Soft-deletes a FAQ by setting `isActive: false`. The record is hidden from all active FAQ queries.\n\nIf the deleted FAQ had a `sourceFaqId`, it re-appears in the `suggested` array on the next `GET /faqs` call — the owner can re-add it at any time.",
        "operationId": "deleteFaq",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id",    "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" },
          { "name": "faqId", "in": "path", "required": true, "schema": { "type": "string" }, "example": "666a1b2c3d4e5f6a7b8c9d01" }
        ],
        "responses": {
          "200": {
            "description": "FAQ soft-deleted",
            "content": {
              "application/json": {
                "example": { "success": true, "message": "FAQ deleted successfully", "data": { "deletedId": "666a1b2c3d4e5f6a7b8c9d01" } }
              }
            }
          },
          "404": { "description": "FAQ not found or already inactive" }
        }
      }
    },

    "/api/campground/{id}/contact": {
      "patch": {
        "tags": ["Step 1d FAQs"],
        "summary": "Update Contact URL",
        "description": "Save or update the contact page URL. Must be a valid `https://` URL. Pass `null` or empty string to clear.",
        "operationId": "updateContact",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "contact_url": { "type": "string", "example": "https://www.alpinehut.at/contact" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contact URL updated",
            "content": {
              "application/json": {
                "example": { "success": true, "message": "Contact URL updated successfully", "data": { "contact_url": "https://www.alpinehut.at/contact" } }
              }
            }
          }
        }
      }
    },

    "/api/campground/{id}/availability": {
      "get": {
        "tags": ["Step 2 Availability"],
        "summary": "Get Availability Config",
        "description": "Returns the current availability configuration, or `null` if not yet configured.",
        "operationId": "getAvailability",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "responses": {
          "200": {
            "description": "Availability config retrieved",
            "content": {
              "application/json": {
                "examples": {
                  "manual": {
                    "summary": "Manual setup",
                    "value": { "success": true, "message": "Availability retrieved successfully", "data": { "type": "manual", "erpProvider": null, "isConfigured": true } }
                  },
                  "erp": {
                    "summary": "ERP integration",
                    "value": { "success": true, "message": "Availability retrieved successfully", "data": { "type": "erp", "erpProvider": "apaleo", "isConfigured": true } }
                  },
                  "not_configured": {
                    "summary": "Not yet configured",
                    "value": { "success": true, "message": "Availability retrieved successfully", "data": null }
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": ["Step 2 Availability"],
        "summary": "Save / Update Availability Config",
        "description": "Create or update the availability configuration (upsert). Automatically sets `step2_status` to `configured` and triggers a `setupStatus` recompute.\n\n- `type: manual` — owner manages availability manually\n- `type: erp` — owner connects an ERP system (`erpProvider` required, `erpConfig` for credentials)\n\nCalling this again with different values replaces the existing config.",
        "operationId": "upsertAvailability",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["type"],
                "properties": {
                  "type":        { "type": "string", "enum": ["manual", "erp"] },
                  "erpProvider": { "type": "string", "example": "apaleo", "description": "Required when type = erp" },
                  "erpConfig":   { "type": "object", "example": { "apiKey": "YOUR_ERP_API_KEY", "propertyId": "YOUR_PROPERTY_ID" }, "description": "ERP credentials/config. Only required for type = erp." }
                }
              },
              "examples": {
                "manual": {
                  "summary": "Manual setup",
                  "value": { "type": "manual" }
                },
                "erp": {
                  "summary": "ERP integration",
                  "value": { "type": "erp", "erpProvider": "apaleo", "erpConfig": { "apiKey": "YOUR_ERP_API_KEY", "propertyId": "YOUR_PROPERTY_ID" } }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Availability saved. `step2_status` is now `configured`.",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Availability updated successfully",
                  "data": { "type": "manual", "erpProvider": null, "isConfigured": true }
                }
              }
            }
          },
          "422": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidationErrorResponse" } } } }
        }
      }
    },

    "/api/campground/{id}/complete": {
      "post": {
        "tags": ["Step 3 Activate"],
        "summary": "Complete Setup",
        "description": "Validates that Step 1 and Step 2 are fully complete, then marks `setupStatus` as `completed` and generates the public `slug`.\n\n**Prerequisites (enforced server-side)**:\n- `step1_status = completed` (name + location.address + description filled, at least 1 image uploaded)\n- `step2_status = configured` (availability config saved)\n\nReturns 422 with a specific error message if either step is not done.",
        "operationId": "completeSetup",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "responses": {
          "200": {
            "description": "Setup completed and slug generated",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Campground setup completed successfully",
                  "data": { "setup_status": "completed", "slug": "alpine-hut-a3f2" }
                }
              }
            }
          },
          "409": { "description": "Setup already active (cannot re-complete an active profile)" },
          "422": {
            "description": "Step preconditions not met",
            "content": {
              "application/json": {
                "examples": {
                  "step1_not_done": { "summary": "Step 1 incomplete", "value": { "success": false, "message": "Step 1 is not completed. Fill in name, location, description and upload at least one image." } },
                  "step2_not_done": { "summary": "Step 2 incomplete", "value": { "success": false, "message": "Step 2 is not configured. Please set up availability first." } }
                }
              }
            }
          }
        }
      }
    },

    "/api/campground/{id}/activate": {
      "post": {
        "tags": ["Step 3 Activate"],
        "summary": "Activate Profile",
        "description": "Activates the campground profile. Requires `setupStatus = completed`. Sets `isActive = true` and `setupStatus = active`.\n\nNote: Activation does **not** make the profile publicly visible. Use `PATCH /:id/visibility` to control public visibility separately.",
        "operationId": "activateProfile",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "responses": {
          "200": {
            "description": "Profile activated",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Profile activated successfully",
                  "data": { "is_active": true, "setup_status": "active" }
                }
              }
            }
          },
          "422": { "description": "Setup not completed yet", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },

    "/api/campground/{id}/visibility": {
      "patch": {
        "tags": ["Step 3 Activate"],
        "summary": "Update Profile Visibility",
        "description": "Toggle whether the campground is publicly visible. Requires the profile to be active (`isActive = true`) first. This is independent of activation — an active profile can be temporarily hidden without deactivating it.",
        "operationId": "updateVisibility",
        "security": [{ "campsiteBearerAuth": [] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "664f1a2b3c4d5e6f7a8b9c0d" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["is_visible"],
                "properties": {
                  "is_visible": { "type": "boolean", "example": true }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Visibility updated",
            "content": {
              "application/json": {
                "example": { "success": true, "message": "Visibility updated successfully", "data": { "is_visible": true } }
              }
            }
          },
          "422": { "description": "Profile is not active yet", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },

    "/api/campground/public/{slug}": {
      "get": {
        "tags": ["Public Profile"],
        "summary": "Get Public Profile",
        "description": "Unauthenticated endpoint. Returns the publicly visible campground profile. Only works when `isActive = true` AND `isVisible = true`. Use the `slug` returned by `POST /:id/complete` to construct shareable URLs and QR codes.",
        "operationId": "getPublicProfile",
        "parameters": [
          { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" }, "example": "alpine-hut-a3f2" }
        ],
        "responses": {
          "200": {
            "description": "Public profile",
            "content": {
              "application/json": {
                "example": {
                  "success": true,
                  "message": "Public profile retrieved successfully",
                  "data": {
                    "campground_name":   "Alpine Hut",
                    "short_description": "<p>A beautiful alpine campsite in the heart of the mountains.</p>",
                    "location":          { "latitude": 47.8095, "longitude": 13.0550, "address": "Salzburg, Austria" },
                    "cover_image_url":   "http://localhost:3000/media/campsites/cover/1714000000000-abc.jpg",
                    "links": {
                      "website_url":   "https://www.alpinehut.at",
                      "instagram_url": "https://instagram.com/alpinehut",
                      "facebook_url":  null,
                      "youtube_url":   null,
                      "twitter_url":   null,
                      "booking_url":   null,
                      "contact_url":   "https://www.alpinehut.at/contact"
                    },
                    "media": {
                      "cover":   { "url": "http://localhost:3000/media/campsites/cover/1714000000000-abc.jpg" },
                      "gallery": [
                        { "url": "http://localhost:3000/media/campsites/gallery/1714000000001-img.jpg", "mediaCategory": "image" },
                        { "url": "http://localhost:3000/media/campsites/gallery/1714000000002-vid.mp4", "mediaCategory": "video" }
                      ]
                    },
                    "faqs": [
                      {
                        "id": "666a1b2c3d4e5f6a7b8c9d01",
                        "question_en": "Are pets allowed?",
                        "question_de": "Sind Haustiere erlaubt?",
                        "answer_en": "Yes, pets are welcome on a leash.",
                        "answer_de": "Ja, Haustiere sind an der Leine willkommen.",
                        "order": 1,
                        "isCustom": false,
                        "sourceFaqId": "666a000000000000000000a1"
                      },
                      {
                        "id": "666a1b2c3d4e5f6a7b8c9d03",
                        "question_en": "Do you offer group discounts?",
                        "question_de": null,
                        "answer_en": "Yes, contact us directly.",
                        "answer_de": null,
                        "order": 3,
                        "isCustom": true,
                        "sourceFaqId": null
                      }
                    ]
                  }
                }
              }
            }
          },
          "404": { "description": "Campground not found or not publicly visible" }
        }
      }
    }

  }
}
