openapi: 3.1.0

# ============================================================================
# GREENFIELD OpenAPI SKELETON - substrate (b): "bring a blank canvas"
#
# This is a VALID, empty starting point for a brand-new API built spec-first.
# Copy it, rename it, and author your own resource. The flow is:
#   1. Write the one-page feature spec (feature-spec-template.md).
#   2. Fill in the schemas + paths below FROM that spec - this is the contract.
#   3. Freeze it at Gate 1. Only then write tests, then implementation.
# That order is Way #1 (Describe before you generate).
#
# Standards cited inline as (REQ-API-n). This is the machine-readable contract
# the whole team works from (REQ-API-2) - keep it in sync with the code.
# Mirror the style of the real file: stacks/nextjs/openapi.yaml
# ============================================================================

info:
  title: <Your API name>
  version: 0.1.0                       # explicit, governed version (REQ-API-4).
                                       # Bump deliberately; never ship "latest".
  description: >
    <One paragraph: what this API is for, who consumes it, and any auth/context
    assumptions. For the workshop: synthetic data only, no real systems.>

servers:
  - url: /api                          # version normally lives here too, e.g.
                                       # /api/v1 - explicit versioning (REQ-API-4).

paths:
  # --------------------------------------------------------------------------
  # ONE resource, two operations. Replace `things` with your noun (plural,
  # lower-case). Keep naming and shapes consistent across every path (REQ-API-5).
  # --------------------------------------------------------------------------
  /things:
    get:
      operationId: listThings
      summary: List things
      description: >
        GET - safe and idempotent (REQ-API-6); a client may retry freely and
        no Idempotency-Key is required.
      parameters:
        # Consistent pagination conventions across the whole API (REQ-API-5).
        - name: limit
          in: query
          required: false
          schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
        - name: cursor
          in: query
          required: false
          schema: { type: string }
      responses:
        '200':
          description: A page of things.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ThingList'
        default:                       # one shared error envelope (REQ-API-5)
          description: Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'

    post:
      operationId: createThing
      summary: Create a thing
      description: >
        POST - this is a WRITE, so it is NOT idempotent by default. To make
        retries safe after a dropped response, require an Idempotency-Key
        header so the same request is applied at most once (REQ-API-6).
      parameters:
        - name: Idempotency-Key
          in: header
          required: true               # safe retries for writes (REQ-API-6)
          description: >
            Client-generated unique key. Replaying the same key returns the
            original result instead of creating a duplicate.
          schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ThingCreate'
      responses:
        '201':
          description: The created thing.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Thing'
        default:
          description: Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'

components:
  schemas:
    # Reusable building blocks - define once, $ref everywhere (REQ-API-5):
    # consistent shapes, reused not copied.
    Thing:
      type: object
      required: [id]
      properties:
        id: { type: string }
        # TODO(team): add your real fields here, from the feature spec.

    ThingCreate:
      type: object
      # required: [ ... ]              # TODO(team): the fields a caller must send.
      properties: {}

    ThingList:
      type: object
      required: [items]
      properties:
        items:
          type: array
          items: { $ref: '#/components/schemas/Thing' }
        nextCursor:
          type: string
          description: Opaque cursor for the next page; absent on the last page.

    # Shared error envelope reused by EVERY error response (REQ-API-5).
    # RFC 7807 problem+json - do not invent a second error shape.
    Problem:
      type: object
      required: [title, status]
      properties:
        type: { type: string, format: uri, default: about:blank }
        title: { type: string, example: Bad Request }
        status: { type: integer, example: 400 }
        detail: { type: string }
        instance: { type: string }
