Import source: backend/src/openapi.yaml

Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
arsam
2026-09-18 23:12:30 +03:30
parent 9ee12a84da
commit 142032462a
+523
View File
@@ -0,0 +1,523 @@
openapi: 3.1.0
info:
title: CShare API
version: 0.1.0
description: |
File-sharing API. Ownership is tracked via an HTTP-only session cookie (`cshare_sid`)
issued automatically on first request — no login required for basic uploads/downloads.
servers:
- url: /api
description: Same-origin (production)
- url: http://localhost:4001/api
description: Local development
tags:
- name: files
description: Upload, list, and delete files
- name: links
description: Resolve share links and trigger downloads / previews
- name: dashboard
description: Per-session analytics
- name: auth
description: Account registration, login, and token refresh
- name: admin
description: Internal admin endpoints (API-key protected)
# ── Common response schemas ─────────────────────────────────────────────────
components:
securitySchemes:
adminKey:
type: apiKey
in: header
name: x-admin-key
schemas:
Error:
type: object
required: [error, code]
properties:
error:
type: string
code:
type: string
FileRecord:
type: object
required: [id, linkId, originalName, mimeType, sizeBytes, status, uploader, createdAt, expiresAt, views, downloads, shareUrl]
properties:
id:
type: string
format: uuid
linkId:
type: string
example: "aB3xZ"
originalName:
type: string
example: "report.pdf"
mimeType:
type: string
example: "application/pdf"
sizeBytes:
type: integer
example: 2048000
status:
type: string
enum: [uploaded, deleted, expired]
uploader:
type: string
example: "You"
createdAt:
type: string
format: date-time
expiresAt:
type: string
format: date-time
views:
type: integer
downloads:
type: integer
shareUrl:
type: string
format: uri
example: "https://file.asabbagh.com/preview/aB3xZ"
DashboardStats:
type: object
required: [totalFiles, totalViews, totalDownloads, events]
properties:
totalFiles:
type: integer
totalViews:
type: integer
totalDownloads:
type: integer
events:
type: array
items:
type: object
properties:
linkId:
type: string
type:
type: string
enum: [view, download]
createdAt:
type: string
format: date-time
ip:
type: string
userAgent:
type: string
User:
type: object
required: [id, email, plan, verified]
properties:
id:
type: string
format: uuid
email:
type: string
format: email
plan:
type: string
enum: [free, pro, team]
verified:
type: boolean
# ── Paths ────────────────────────────────────────────────────────────────────
paths:
/v1/files/upload:
post:
tags: [files]
summary: Upload a file
description: |
Streams the file directly to Google Drive — no disk writes on the server.
Rate limited to **20 uploads per IP per hour**.
Files blocked by MIME type: EXE, DLL, COM, ELF, MSI.
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required: [file]
properties:
file:
type: string
format: binary
expiresIn:
type: integer
description: Expiry in seconds (3 600 – 7 776 000, default 2 592 000)
default: 2592000
uploader:
type: string
description: Display name shown to recipients (max 80 chars)
default: "You"
responses:
"201":
description: File uploaded
content:
application/json:
schema:
type: object
properties:
data:
$ref: "#/components/schemas/FileRecord"
"400":
description: Missing file or not multipart
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"413":
description: File exceeds size limit (500 MB)
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"415":
description: Blocked file type (executable)
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"429":
description: Rate limit exceeded
headers:
Retry-After:
schema:
type: integer
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/v1/files:
get:
tags: [files]
summary: List your files
description: Returns only files uploaded in the current browser session (scoped by `cshare_sid` cookie).
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 100
maximum: 100
responses:
"200":
description: Paginated file list
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: "#/components/schemas/FileRecord"
meta:
type: object
properties:
page:
type: integer
limit:
type: integer
total:
type: integer
/v1/files/{id}:
get:
tags: [files]
summary: Get a single file record
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: File record
content:
application/json:
schema:
type: object
properties:
data:
$ref: "#/components/schemas/FileRecord"
"404":
description: File not found
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
delete:
tags: [files]
summary: Delete a file
description: Only the session that uploaded the file can delete it.
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"204":
description: Deleted
"404":
description: File not found or not owned by this session
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/v1/links/{linkId}:
get:
tags: [links]
summary: Resolve a share link
description: Returns file metadata for the share-link page. Increments view counter.
parameters:
- name: linkId
in: path
required: true
schema:
type: string
example: "aB3xZ"
responses:
"200":
description: File metadata
content:
application/json:
schema:
type: object
properties:
data:
$ref: "#/components/schemas/FileRecord"
"404":
description: Link not found or expired
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/v1/links/{linkId}/download:
get:
tags: [links]
summary: Download a file
description: Increments download counter then issues a 302 redirect to the Google Drive download URL.
parameters:
- name: linkId
in: path
required: true
schema:
type: string
responses:
"302":
description: Redirect to Google Drive download
headers:
Location:
schema:
type: string
format: uri
"404":
description: Link not found or expired
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"429":
description: Rate limit exceeded
/v1/links/{linkId}/preview:
get:
tags: [links]
summary: Inline preview stream
description: |
Streams file content for in-browser preview (images, video, audio, text, PDF).
Only available for files ≤ 25 MB with a supported MIME type.
Content-Security-Policy is set to restrict the preview context.
parameters:
- name: linkId
in: path
required: true
schema:
type: string
responses:
"200":
description: File content stream
headers:
Content-Type:
schema:
type: string
Content-Disposition:
schema:
type: string
"404":
description: Link not found or expired
"413":
description: Preview not available (file too large or unsupported type)
/v1/dashboard/stats:
get:
tags: [dashboard]
summary: Session-scoped analytics
description: Returns aggregated stats (total files, views, downloads) and recent events for the current session only.
responses:
"200":
description: Dashboard stats
content:
application/json:
schema:
type: object
properties:
data:
$ref: "#/components/schemas/DashboardStats"
/auth/register:
post:
tags: [auth]
summary: Create an account
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [email, password]
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
responses:
"201":
description: Account created — returns access token + sets refresh cookie
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
user:
$ref: "#/components/schemas/User"
accessToken:
type: string
"400":
description: Validation error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"429":
description: Auth rate limit (5 per 15 min per IP)
/auth/login:
post:
tags: [auth]
summary: Log in
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [email, password]
properties:
email:
type: string
format: email
password:
type: string
responses:
"200":
description: Logged in — access token + refresh cookie
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
user:
$ref: "#/components/schemas/User"
accessToken:
type: string
"401":
description: Invalid credentials
"429":
description: Auth rate limit
/auth/refresh:
post:
tags: [auth]
summary: Refresh access token
description: Reads the `cshare_refresh` HTTP-only cookie. Returns a new access token and rotates the refresh token.
responses:
"200":
description: New access token issued
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
accessToken:
type: string
"401":
description: Missing or expired refresh token
/auth/logout:
post:
tags: [auth]
summary: Log out
description: Revokes the current refresh token and clears the cookie.
responses:
"204":
description: Logged out
/admin/overview:
get:
tags: [admin]
summary: Admin overview
security:
- adminKey: []
responses:
"200":
description: File and user statistics
content:
application/json:
schema:
type: object
properties:
data:
type: object
properties:
filesByStatus:
type: object
additionalProperties:
type: integer
users:
type: integer
totalEvents:
type: integer
"401":
description: Missing or invalid admin key