openapi: 3.1.0 info: title: Api version: 0.1.0 description: RAQIM — Document to Markdown conversion platform API servers: - url: /api description: Base API path tags: - name: health description: Health operations - name: auth description: Authentication operations - name: files description: File management - name: folders description: Folder management - name: convert description: Document conversion - name: shares description: File sharing - name: admin description: Admin operations - name: export description: File export paths: /healthz: get: operationId: healthCheck tags: [health] summary: Health check responses: "200": description: Healthy content: application/json: schema: $ref: "#/components/schemas/HealthStatus" # ─── AUTH ─────────────────────────────────────────────── /auth/register: post: operationId: registerUser tags: [auth] summary: Submit a join request (creates pending account) requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/RegisterBody" responses: "201": description: Join request submitted content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "409": description: Email already in use content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /auth/login: post: operationId: loginUser tags: [auth] summary: Login with email and password requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/LoginBody" responses: "200": description: Login successful content: application/json: schema: $ref: "#/components/schemas/AuthResponse" "401": description: Invalid credentials or account not approved content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /auth/logout: post: operationId: logoutUser tags: [auth] summary: Logout and invalidate refresh token responses: "200": description: Logged out content: application/json: schema: $ref: "#/components/schemas/MessageResponse" /auth/refresh: post: operationId: refreshToken tags: [auth] summary: Refresh access token responses: "200": description: New access token content: application/json: schema: $ref: "#/components/schemas/AuthResponse" "401": description: Invalid or expired refresh token content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /auth/me: get: operationId: getCurrentUser tags: [auth] summary: Get current authenticated user responses: "200": description: Current user info content: application/json: schema: $ref: "#/components/schemas/User" "401": description: Not authenticated content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /auth/forgot-password: post: operationId: forgotPassword tags: [auth] summary: Request password reset email requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ForgotPasswordBody" responses: "200": description: Reset email sent if account exists content: application/json: schema: $ref: "#/components/schemas/MessageResponse" /auth/reset-password: post: operationId: resetPassword tags: [auth] summary: Reset password using token requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ResetPasswordBody" responses: "200": description: Password reset successfully content: application/json: schema: $ref: "#/components/schemas/MessageResponse" "400": description: Invalid or expired token content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" # ─── FOLDERS ──────────────────────────────────────────── /folders: get: operationId: listFolders tags: [folders] summary: List folders for current user parameters: - in: query name: parentId schema: type: string description: Parent folder ID (null for root) responses: "200": description: List of folders content: application/json: schema: type: array items: $ref: "#/components/schemas/Folder" post: operationId: createFolder tags: [folders] summary: Create a new folder requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateFolderBody" responses: "201": description: Folder created content: application/json: schema: $ref: "#/components/schemas/Folder" /folders/{id}: patch: operationId: updateFolder tags: [folders] summary: Rename or move a folder parameters: - in: path name: id required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateFolderBody" responses: "200": description: Folder updated content: application/json: schema: $ref: "#/components/schemas/Folder" delete: operationId: deleteFolder tags: [folders] summary: Move folder to trash parameters: - in: path name: id required: true schema: type: string responses: "200": description: Folder moved to trash content: application/json: schema: $ref: "#/components/schemas/MessageResponse" # ─── FILES ────────────────────────────────────────────── /files: get: operationId: listFiles tags: [files] summary: List files for current user parameters: - in: query name: folderId schema: type: string description: Folder ID (null for root) - in: query name: search schema: type: string description: Search by name - in: query name: trashed schema: type: boolean description: Show trashed files - in: query name: shared schema: type: boolean description: Show files shared with me responses: "200": description: List of files content: application/json: schema: type: array items: $ref: "#/components/schemas/FileItem" /files/{id}: get: operationId: getFile tags: [files] summary: Get file metadata parameters: - in: path name: id required: true schema: type: string responses: "200": description: File metadata content: application/json: schema: $ref: "#/components/schemas/FileItem" patch: operationId: updateFile tags: [files] summary: Rename or move a file parameters: - in: path name: id required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateFileBody" responses: "200": description: File updated content: application/json: schema: $ref: "#/components/schemas/FileItem" delete: operationId: deleteFile tags: [files] summary: Move file to trash parameters: - in: path name: id required: true schema: type: string responses: "200": description: File moved to trash content: application/json: schema: $ref: "#/components/schemas/MessageResponse" /files/{id}/content: get: operationId: getFileContent tags: [files] summary: Get file markdown content parameters: - in: path name: id required: true schema: type: string responses: "200": description: File content content: application/json: schema: $ref: "#/components/schemas/FileContent" put: operationId: updateFileContent tags: [files] summary: Update file markdown content (auto-save) parameters: - in: path name: id required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateContentBody" responses: "200": description: Content saved content: application/json: schema: $ref: "#/components/schemas/MessageResponse" /files/{id}/restore: post: operationId: restoreFile tags: [files] summary: Restore file from trash parameters: - in: path name: id required: true schema: type: string responses: "200": description: File restored content: application/json: schema: $ref: "#/components/schemas/MessageResponse" /files/{id}/export: post: operationId: exportFile tags: [export] summary: Export file as DOCX or PDF parameters: - in: path name: id required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ExportBody" responses: "200": description: Export URL content: application/json: schema: $ref: "#/components/schemas/ExportResponse" # ─── CONVERSION ───────────────────────────────────────── /convert: post: operationId: startConversion tags: [convert] summary: Start document conversion job requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/StartConversionBody" responses: "202": description: Conversion job started content: application/json: schema: $ref: "#/components/schemas/ConversionJob" /convert/{jobId}: get: operationId: getConversionStatus tags: [convert] summary: Get conversion job status and progress parameters: - in: path name: jobId required: true schema: type: string responses: "200": description: Job status content: application/json: schema: $ref: "#/components/schemas/ConversionJob" /convert/upload: post: operationId: uploadAndConvert tags: [convert] summary: Upload file and start conversion responses: "202": description: Upload accepted and conversion started content: application/json: schema: $ref: "#/components/schemas/ConversionJob" # ─── SHARES ───────────────────────────────────────────── /shares: get: operationId: listShares tags: [shares] summary: List shares for current user (owned + shared with me) responses: "200": description: List of shares content: application/json: schema: type: array items: $ref: "#/components/schemas/Share" post: operationId: createShare tags: [shares] summary: Share a file or folder with a user requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateShareBody" responses: "201": description: Share created content: application/json: schema: $ref: "#/components/schemas/Share" /shares/{id}: patch: operationId: updateShare tags: [shares] summary: Update share permission parameters: - in: path name: id required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateShareBody" responses: "200": description: Share updated content: application/json: schema: $ref: "#/components/schemas/Share" delete: operationId: deleteShare tags: [shares] summary: Remove a share parameters: - in: path name: id required: true schema: type: string responses: "200": description: Share removed content: application/json: schema: $ref: "#/components/schemas/MessageResponse" /shares/search-users: get: operationId: searchUsersForSharing tags: [shares] summary: Search users by email or username for sharing parameters: - in: query name: q required: true schema: type: string responses: "200": description: Matching users content: application/json: schema: type: array items: $ref: "#/components/schemas/UserSummary" # ─── ADMIN ────────────────────────────────────────────── /admin/users: get: operationId: adminListUsers tags: [admin] summary: List all users parameters: - in: query name: status schema: type: string enum: [active, suspended, pending] - in: query name: role schema: type: string enum: [user, admin] - in: query name: search schema: type: string responses: "200": description: List of users content: application/json: schema: type: array items: $ref: "#/components/schemas/AdminUser" post: operationId: adminCreateUser tags: [admin] summary: Admin creates user directly (active status) requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AdminCreateUserBody" responses: "201": description: User created content: application/json: schema: $ref: "#/components/schemas/AdminUser" /admin/users/{id}: patch: operationId: adminUpdateUser tags: [admin] summary: Update user role or status parameters: - in: path name: id required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/AdminUpdateUserBody" responses: "200": description: User updated content: application/json: schema: $ref: "#/components/schemas/AdminUser" delete: operationId: adminDeleteUser tags: [admin] summary: Permanently delete a user parameters: - in: path name: id required: true schema: type: string responses: "200": description: User deleted content: application/json: schema: $ref: "#/components/schemas/MessageResponse" /admin/join-requests: get: operationId: listJoinRequests tags: [admin] summary: List pending join requests responses: "200": description: List of join requests content: application/json: schema: type: array items: $ref: "#/components/schemas/JoinRequest" /admin/join-requests/{id}: patch: operationId: processJoinRequest tags: [admin] summary: Approve or reject a join request parameters: - in: path name: id required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ProcessJoinRequestBody" responses: "200": description: Request processed content: application/json: schema: $ref: "#/components/schemas/MessageResponse" /admin/stats: get: operationId: getAdminStats tags: [admin] summary: Get platform statistics responses: "200": description: Platform stats content: application/json: schema: $ref: "#/components/schemas/PlatformStats" /trash: get: operationId: listUserTrash tags: [files] summary: List trashed files and folders for current user responses: "200": description: Trashed items content: application/json: schema: $ref: "#/components/schemas/TrashItems" /trash/empty: delete: operationId: emptyUserTrash tags: [files] summary: Permanently delete all current user's trashed items responses: "200": description: Trash emptied content: application/json: schema: $ref: "#/components/schemas/MessageResponse" /admin/trash: get: operationId: adminListTrash tags: [admin] summary: List ALL users' trashed files/folders (admin only) responses: "200": description: Trashed items content: application/json: schema: $ref: "#/components/schemas/TrashItems" /admin/trash/empty: delete: operationId: adminEmptyTrash tags: [admin] summary: Permanently delete all trashed items for current admin user responses: "200": description: Trash emptied content: application/json: schema: $ref: "#/components/schemas/MessageResponse" components: schemas: HealthStatus: type: object properties: status: type: string required: [status] MessageResponse: type: object properties: message: type: string required: [message] ErrorResponse: type: object properties: error: type: string message: type: string required: [error, message] # AUTH RegisterBody: type: object properties: email: type: string format: email password: type: string displayName: type: string required: [email, password] LoginBody: type: object properties: email: type: string format: email password: type: string required: [email, password] ForgotPasswordBody: type: object properties: email: type: string format: email required: [email] ResetPasswordBody: type: object properties: token: type: string password: type: string required: [token, password] AuthResponse: type: object properties: accessToken: type: string user: $ref: "#/components/schemas/User" required: [accessToken, user] User: type: object properties: id: type: string email: type: string displayName: type: string role: type: string enum: [user, admin] status: type: string enum: [pending, active, suspended] createdAt: type: string format: date-time required: [id, email, role, status, createdAt] UserSummary: type: object properties: id: type: string email: type: string displayName: type: string required: [id, email] # FOLDERS Folder: type: object properties: id: type: string name: type: string parentId: type: string nullable: true ownerId: type: string fileCount: type: integer createdAt: type: string format: date-time updatedAt: type: string format: date-time required: [id, name, ownerId, fileCount, createdAt, updatedAt] CreateFolderBody: type: object properties: name: type: string parentId: type: string nullable: true required: [name] UpdateFolderBody: type: object properties: name: type: string parentId: type: string nullable: true # FILES FileItem: type: object properties: id: type: string name: type: string folderId: type: string nullable: true ownerId: type: string originalName: type: string originalType: type: string sizeBytes: type: integer status: type: string enum: [uploading, queued, processing, done, failed, trashed] qualityScore: type: number nullable: true wordCount: type: integer nullable: true language: type: string nullable: true isShared: type: boolean sharedWith: type: array items: $ref: "#/components/schemas/UserSummary" permission: type: string enum: [owner, read, edit, full] nullable: true createdAt: type: string format: date-time updatedAt: type: string format: date-time required: [id, name, ownerId, originalName, originalType, sizeBytes, status, isShared, createdAt, updatedAt] UpdateFileBody: type: object properties: name: type: string folderId: type: string nullable: true FileContent: type: object properties: id: type: string markdownContent: type: string originalMarkdown: type: string updatedAt: type: string format: date-time required: [id, markdownContent, originalMarkdown, updatedAt] UpdateContentBody: type: object properties: markdownContent: type: string required: [markdownContent] ExportBody: type: object properties: format: type: string enum: [md, docx, pdf, print] fileName: type: string required: [format] ExportResponse: type: object properties: downloadUrl: type: string fileName: type: string format: type: string required: [downloadUrl, fileName, format] # CONVERSION StartConversionBody: type: object properties: fileId: type: string pageStart: type: integer nullable: true pageEnd: type: integer nullable: true required: [fileId] ConversionJob: type: object properties: jobId: type: string fileId: type: string status: type: string enum: [queued, analyzing, routing, ocr, layout, scoring, merging, cleanup, done, failed] progress: type: integer description: 0-100 steps: type: array items: $ref: "#/components/schemas/ConversionStep" queuePosition: type: integer nullable: true elapsedSeconds: type: integer nullable: true estimatedSeconds: type: integer nullable: true errorMessage: type: string nullable: true createdAt: type: string format: date-time required: [jobId, fileId, status, progress, steps, createdAt] ConversionStep: type: object properties: name: type: string status: type: string enum: [pending, running, done, failed] label: type: string required: [name, status, label] # SHARES Share: type: object properties: id: type: string fileId: type: string nullable: true folderId: type: string nullable: true ownerId: type: string sharedWithId: type: string permission: type: string enum: [read, edit, full] fileName: type: string nullable: true folderName: type: string nullable: true ownerEmail: type: string sharedWithEmail: type: string createdAt: type: string format: date-time required: [id, ownerId, sharedWithId, permission, ownerEmail, sharedWithEmail, createdAt] CreateShareBody: type: object properties: fileId: type: string nullable: true folderId: type: string nullable: true sharedWithId: type: string permission: type: string enum: [read, edit, full] required: [sharedWithId, permission] UpdateShareBody: type: object properties: permission: type: string enum: [read, edit, full] required: [permission] # ADMIN AdminUser: type: object properties: id: type: string email: type: string displayName: type: string nullable: true role: type: string enum: [user, admin] status: type: string enum: [pending, active, suspended] fileCount: type: integer lastLoginAt: type: string format: date-time nullable: true createdAt: type: string format: date-time required: [id, email, role, status, fileCount, createdAt] AdminCreateUserBody: type: object properties: email: type: string format: email password: type: string displayName: type: string role: type: string enum: [user, admin] required: [email, password] AdminUpdateUserBody: type: object properties: role: type: string enum: [user, admin] status: type: string enum: [active, suspended] JoinRequest: type: object properties: id: type: string email: type: string displayName: type: string nullable: true requestedAt: type: string format: date-time required: [id, email, requestedAt] ProcessJoinRequestBody: type: object properties: action: type: string enum: [approve, reject] reason: type: string nullable: true required: [action] PlatformStats: type: object properties: totalUsers: type: integer activeUsers: type: integer pendingRequests: type: integer totalFiles: type: integer filesConvertedToday: type: integer filesConvertedThisWeek: type: integer successRate: type: number averageQualityScore: type: number averageProcessingSeconds: type: number topFileType: type: string conversionsByType: type: object additionalProperties: type: integer required: [totalUsers, activeUsers, pendingRequests, totalFiles, filesConvertedToday, filesConvertedThisWeek, successRate, averageQualityScore, averageProcessingSeconds] TrashItems: type: object properties: files: type: array items: $ref: "#/components/schemas/FileItem" folders: type: array items: $ref: "#/components/schemas/Folder" required: [files, folders]