openapi: 3.1.0
info:
  title: Federation API
  description: API for retrieving club, accommodation and membership data.
  version: 2.1.0

servers:
  - url: https://api.example.com/v1
    description: environment

tags:
  - name: Clubs
    description: Club-related operations
  - name: Accommodations
    description: Accommodation-related operations
  - name: Memberships
    description: Membership-related operations

paths:
  /verenigingen:
    get:
      tags:
        - Clubs
      operationId: listClubs
      summary: Retrieve club data
      description: Retrieve clubs with their basic data and related accommodations.
      responses:
        '200':
          description: Clubs retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClubsResponse'
        '400':
          description: Invalid request.
        '500':
          description: Internal server error.

  /accommodaties:
    get:
      tags:
        - Accommodations
      operationId: listAccommodations
      summary: Retrieve accommodation data
      description: Retrieve accommodations with address and location data.
      responses:
        '200':
          description: Accommodations retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AccommodationsResponse'
        '400':
          description: Invalid request.
        '500':
          description: Internal server error.

  /lidmaatschappen:
    get:
      tags:
        - Memberships
      operationId: listMemberships
      summary: Retrieve membership data
      description: Retrieve memberships filtered by mutation date.
      parameters:
        - name: peildatum
          in: query
          description: >
            Optional date in format `yyyy-mm-dd`. Only memberships that were created or 
            updated between this date and the time of the request are returned, even if the 
            change concerns attributes not exposed by this API. Memberships without any 
            mutation in this period are excluded.
          required: false
          schema:
            type: string
            format: date
            pattern: '^\\d{4}-\\d{2}-\\d{2}$'
      responses:
        '200':
          description: Memberships retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MembershipsResponse'
        '400':
          description: Invalid request.
        '500':
          description: Internal server error.

components:
  schemas:
    Meta:
      type: object
      properties:
        count:
          type: integer
          description: Number of records in this response.
        total:
          type: integer
          description: Total number of records available.

    ClubsResponse:
      type: object
      properties:
        meta:
          $ref: '#/components/schemas/Meta'
        Verenigingsgegevens:
          type: array
          description: List of clubs.
          items:
            $ref: '#/components/schemas/Club'

    AccommodationsResponse:
      type: object
      properties:
        meta:
          $ref: '#/components/schemas/Meta'
        Accommodatiegegevens:
          type: array
          description: List of accommodations.
          items:
            $ref: '#/components/schemas/Accommodation'

    MembershipsResponse:
      type: object
      properties:
        meta:
          $ref: '#/components/schemas/Meta'
        Lidmaatschapsgegevens:
          type: array
          description: List of memberships.
          items:
            $ref: '#/components/schemas/Membership'

    Club:
      type: object
      required:
        - Verenigingscode
        - Naam
        - Accommodaties
      properties:
        Verenigingscode:
          type: string
          description: Unique code of the club.
        Naam:
          type: string
          description: Name of the club.
        Aanmelddatum:
          type: string
          format: date
          pattern: '^\\d{4}-\\d{2}-\\d{2}$'
          description: Registration date (yyyy-mm-dd).
        Afmelddatum:
          type: string
          format: date
          pattern: '^\\d{4}-\\d{2}-\\d{2}$'
          description: Deregistration date (yyyy-mm-dd).
        KVKnummer:
          type: string
          pattern: '^[0-9]{8}$'
          description: KvK number with exactly 8 digits.
        Accommodaties:
          type: array
          description: Accommodations associated with this club. Each accommodation object corresponds to a record as defined in the /accommodaties endpoint.
          items:
            $ref: '#/components/schemas/ClubAccommodationReference'

    ClubAccommodationReference:
      type: object
      required:
        - Postcode
        - Huisnummer
      properties:
        Postcode:
          type: string
          description: Postal code of the accommodation.
        Huisnummer:
          type: integer
          description: Numeric part of the house number (e.g. 12 from "12-B").

    Accommodation:
      allOf:
        - type: object
          required:
            - Naam
            - Postcode
            - Straat
            - Huisnummer
            - Plaats
            - Land
          properties:
            Naam:
              type: string
              description: Name of the accommodation.
            Postcode:
              type: string
              description: Postal code for the visiting address (bezoekadres). Postal code format depends on the country.
            Straat:
              type: string
              description: Street for the visiting address (bezoekadres).
            Huisnummer:
              type: integer
              description: The numeric part of the house number (e.g., '12' from '12-B') for the visiting address (bezoekadres).
            Plaats:
              type: string
              description: City of the visiting address.
            Land:
              type: string
              description: Country code, e.g., 'NL' for Netherlands. If 'NL', the postal code must match the format 1234AB.
            Longitude:
              type: string
              description: Longitude in decimal degrees between -180.0000 and 180.0000.
              pattern: '^(-?(180(\.0+)?|((1[0-7][0-9]|[1-9]?[0-9])(\.\d+)?)))$'
            Latitude:
              type: string
              description: Latitude in decimal degrees between -90.0000 and 90.0000.
              pattern: '^(-?(90(\.0+)?|([1-8]?[0-9](\.\d+)?)))$'
        - if:
            properties:
              Land:
                const: NL
          then:
            properties:
              Postcode:
                pattern: '^[1-9][0-9]{3}[A-Z]{2}$'

    Membership:
      allOf:
        - type: object
          required:
            - LidmaatschapsID
            - Lidcode
            - Verenigingscode
            - Postcode
            - Land
            - Geboortedatum
            - Geslacht
            - Aanmelddatum
          properties:
            LidmaatschapsID:
              type: string
              description: >
                Technical ID of the membership record, used by NOC*NSF for
                anonymisation processes.
            Lidcode:
              type: string
              description: Code identifying the member.
            Verenigingscode:
              type: string
              description: Code of the club the member belongs to.
            Land:
              type: string
              description: Country code, e.g., 'NL' for Netherlands. If 'NL', the postal code must match the format 1234AB.
            Postcode:
              type: string
              description: Postal code of the member's address.
            Geboortedatum:
              type: string
              format: date
              pattern: '^\\d{4}-\\d{2}-\\d{2}$'
              description: Date of birth (yyyy-mm-dd).
            Geslacht:
              type: string
              description: >
                Gender: "v" (female), "m" (male), "o" (unknown), "x"
                (gender-neutral).
              enum: [v, m, o, x]
            Aanmelddatum:
              type: string
              format: date
              pattern: '^\\d{4}-\\d{2}-\\d{2}$'
              description: Membership start date (yyyy-mm-dd).
            Afmelddatum:
              type: string
              format: date
              pattern: '^\\d{4}-\\d{2}-\\d{2}$'
              description: Membership end date (yyyy-mm-dd).
            Sporttak:
              type: array
              description: Sports or disciplines associated with the membership.
              items:
                type: string
        - if:
            properties:
              Land:
                const: NL
          then:
            properties:
              Postcode:
                pattern: '^[1-9][0-9]{3}[A-Z]{2}$'
