openapi: 3.0.3
info:
  title: SOAT Files API
  version: 1.0.0
  description: API for managing files (Files resource)
  contact:
    name: SOAT Team
    url: https://github.com/ttoss/soat
servers:
  - url: '{baseUrl}'
    description: Base URL of your SOAT deployment (e.g. https://your-soat.com or http://localhost:5047)
    variables:
      baseUrl:
        description: The base URL of your SOAT deployment
        default: http://localhost:5047
tags:
  - name: Files
    description: Manage files
security:
  - bearerAuth: []
paths:
  /api/v1/files:
    get:
      tags:
        - Files
      summary: List all files
      description: Returns a list of all stored files
      operationId: listFiles
      parameters:
        - name: project_id
          in: query
          required: false
          description: Filter files by project ID
          schema:
            type: string
            example: 'proj_V1StGXR8Z5jdHi6B'
        - name: limit
          in: query
          required: false
          description: Maximum number of results to return
          schema:
            type: integer
            default: 50
        - name: offset
          in: query
          required: false
          description: Number of results to skip
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: List of files returned successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/FileRecord'
                  total:
                    type: integer
                  limit:
                    type: integer
                  offset:
                    type: integer
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    post:
      tags:
        - Files
      summary: Create a file
      description: Creates a new file record in the system
      operationId: createFile
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - project_id
                - storage_type
                - storage_path
              properties:
                project_id:
                  type: string
                  description: Public ID of the project
                  example: 'proj_V1StGXR8Z5jdHi6B'
                path:
                  type: string
                  description: Logical path within the project (e.g. /images/logo.png). Defaults to /filename if omitted.
                  example: '/images/logo.png'
                filename:
                  type: string
                  description: Name of the file
                  example: 'document.pdf'
                content_type:
                  type: string
                  description: MIME type of the file
                  example: 'application/pdf'
                size:
                  type: integer
                  description: File size in bytes
                  example: 1024
                storage_type:
                  type: string
                  enum: [local, s3, gcs]
                  description: Storage backend type
                  example: 'local'
                storage_path:
                  type: string
                  description: Path where the file is stored
                  example: '/uploads/document.pdf'
                metadata:
                  type: string
                  description: JSON string with additional metadata
                  example: '{"author":"John"}'
      responses:
        '201':
          description: File created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileRecord'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /api/v1/files/upload:
    post:
      tags:
        - Files
      summary: Upload a file
      description: Uploads a file to the server and stores it in the configured storage directory
      operationId: uploadFile
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
                - project_id
              properties:
                file:
                  type: string
                  format: binary
                  description: File content
                project_id:
                  type: string
                  description: Project ID to associate the file with
                  example: 'proj_V1StGXR8Z5jdHi6B'
                metadata:
                  type: string
                  description: Additional metadata as a JSON string
                  example: '{"author":"John"}'
      responses:
        '201':
          description: File uploaded successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileRecord'
        '400':
          description: Missing file or invalid project
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /api/v1/files/upload/base64:
    post:
      tags:
        - Files
      summary: Upload a file using base64 encoding
      description: Uploads a file to the server using base64-encoded content
      operationId: uploadFileBase64
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UploadFileBase64Request'
      responses:
        '201':
          description: File uploaded successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileRecord'
        '400':
          description: Missing content or invalid project
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /api/v1/files/{file_id}:
    get:
      tags:
        - Files
      summary: Get a file by ID
      description: Returns the data and metadata of a specific file
      operationId: getFile
      parameters:
        - name: file_id
          in: path
          required: true
          description: File ID
          schema:
            type: string
            example: 'abc123'
      responses:
        '200':
          description: File found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileRecord'
        '404':
          description: File not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    delete:
      tags:
        - Files
      summary: Delete a file
      description: Removes a file from the system by ID
      operationId: deleteFile
      parameters:
        - name: file_id
          in: path
          required: true
          description: ID of the file to delete
          schema:
            type: string
            example: 'abc123'
      responses:
        '204':
          description: File deleted successfully
        '404':
          description: File not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /api/v1/files/{file_id}/download:
    get:
      tags:
        - Files
      summary: Download a file
      description: Streams the file content to the client
      operationId: downloadFile
      parameters:
        - name: file_id
          in: path
          required: true
          description: File ID
          schema:
            type: string
            example: 'fil_abc123'
      responses:
        '200':
          description: File content
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: File not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /api/v1/files/{file_id}/metadata:
    patch:
      tags:
        - Files
      summary: Update file metadata
      description: Updates the metadata field of a file
      operationId: updateFileMetadata
      parameters:
        - name: file_id
          in: path
          required: true
          description: File ID
          schema:
            type: string
            example: 'fil_abc123'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                metadata:
                  type: string
                  description: New metadata as a JSON string
                  example: '{"author":"Jane","tags":["report"]}'
                filename:
                  type: string
                  description: New filename for the file
                  example: 'renamed-file.txt'
      responses:
        '200':
          description: Metadata updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileRecord'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: File not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /api/v1/files/{file_id}/download/base64:
    get:
      tags:
        - Files
      summary: Download file as base64
      description: Returns the file content encoded as base64
      operationId: downloadFileBase64
      parameters:
        - name: file_id
          in: path
          required: true
          description: File ID
          schema:
            type: string
      responses:
        '200':
          description: File content as base64
          content:
            application/json:
              schema:
                type: object
                properties:
                  content:
                    type: string
                    description: Base64-encoded file content
                  filename:
                    type: string
                    description: Original filename
                  contentType:
                    type: string
                    description: MIME type of the file
                  size:
                    type: integer
                    description: File size in bytes
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: File not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /api/v1/files/{file_id}/tags:
    get:
      tags:
        - Files
      summary: Get file tags
      description: Returns all tags attached to the file
      operationId: getFileTags
      parameters:
        - name: file_id
          in: path
          required: true
          description: File ID
          schema:
            type: string
      responses:
        '200':
          description: File tags
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: File not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    put:
      tags:
        - Files
      summary: Replace file tags
      description: Replaces all tags on the file with the provided tags
      operationId: replaceFileTags
      parameters:
        - name: file_id
          in: path
          required: true
          description: File ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties:
                type: string
      responses:
        '200':
          description: Tags replaced
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: File not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    patch:
      tags:
        - Files
      summary: Merge file tags
      description: Merges provided tags with existing tags
      operationId: mergeFileTags
      parameters:
        - name: file_id
          in: path
          required: true
          description: File ID
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties:
                type: string
      responses:
        '200':
          description: Tags merged
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: File not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: JWT token or sk_ api key
  schemas:
    UploadFileBase64Request:
      type: object
      required:
        - project_id
        - content
      properties:
        project_id:
          type: string
          description: Public ID of the project
          example: 'proj_V1StGXR8Z5jdHi6B'
        content:
          type: string
          description: Base64-encoded file content
          example: 'SGVsbG8gV29ybGQ='
        filename:
          type: string
          description: Name of the file
          example: 'document.txt'
        path:
          type: string
          description: Logical path within the project (e.g. /images/logo.png). Defaults to /filename if omitted.
          example: '/documents/document.txt'
        content_type:
          type: string
          description: MIME type of the file
          example: 'text/plain'
        metadata:
          type: string
          description: JSON string with additional metadata
          example: '{"author":"John"}'
    FileRecord:
      type: object
      description: Stored file metadata
      properties:
        id:
          type: string
          description: Unique file identifier
          example: 'abc123'
        path:
          type: string
          nullable: true
          description: Logical path of the file within the project (e.g. /images/logo.png)
          example: '/images/logo.png'
        filename:
          type: string
          description: Name of the file
          example: 'document.pdf'
        contentType:
          type: string
          description: MIME type of the file
          example: 'application/pdf'
        size:
          type: integer
          description: File size in bytes
          example: 1024
        storage_type:
          type: string
          enum: [local, s3, gcs]
          description: Storage backend type
          example: 'local'
        storage_path:
          type: string
          description: Path where the file is stored
          example: '/uploads/document.pdf'
        metadata:
          type: string
          description: JSON string with additional metadata
          example: '{"author":"John"}'
        created_at:
          type: string
          format: date-time
          description: Creation timestamp
        updated_at:
          type: string
          format: date-time
          description: Last update timestamp
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
          description: Error message
  responses:
    Unauthorized:
      description: Authentication required
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: Insufficient permissions
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error: 'File not found'
