Some checks failed
System Monitoring / Health Checks (push) Has been cancelled
System Monitoring / Performance Monitoring (push) Has been cancelled
System Monitoring / Database Monitoring (push) Has been cancelled
System Monitoring / Cache Monitoring (push) Has been cancelled
System Monitoring / Log Monitoring (push) Has been cancelled
System Monitoring / Resource Monitoring (push) Has been cancelled
System Monitoring / Uptime Monitoring (push) Has been cancelled
System Monitoring / Backup Monitoring (push) Has been cancelled
System Monitoring / Security Monitoring (push) Has been cancelled
System Monitoring / Monitoring Dashboard (push) Has been cancelled
System Monitoring / Alerting (push) Has been cancelled
Security Scanning / Dependency Scanning (push) Has been cancelled
Security Scanning / Code Security Scanning (push) Has been cancelled
Security Scanning / Secrets Scanning (push) Has been cancelled
Security Scanning / Container Security Scanning (push) Has been cancelled
Security Scanning / Compliance Checking (push) Has been cancelled
Security Scanning / Security Dashboard (push) Has been cancelled
Security Scanning / Security Remediation (push) Has been cancelled
1331 lines
31 KiB
YAML
1331 lines
31 KiB
YAML
openapi: 3.0.0
|
|
info:
|
|
title: Multi-Tenant SaaS Platform API
|
|
description: API for Malaysian SME SaaS platform with industry-specific modules
|
|
version: 1.0.0
|
|
contact:
|
|
name: API Support
|
|
email: support@platform.com
|
|
|
|
servers:
|
|
- url: https://api.platform.com/v1
|
|
description: Production server
|
|
- url: https://staging-api.platform.com/v1
|
|
description: Staging server
|
|
- url: http://localhost:8000/v1
|
|
description: Development server
|
|
|
|
security:
|
|
- BearerAuth: []
|
|
|
|
paths:
|
|
# Authentication endpoints
|
|
/auth/login:
|
|
post:
|
|
summary: User login
|
|
tags: [Authentication]
|
|
security: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [email, password]
|
|
properties:
|
|
email:
|
|
type: string
|
|
format: email
|
|
password:
|
|
type: string
|
|
format: password
|
|
tenant_slug:
|
|
type: string
|
|
description: Tenant identifier for login
|
|
responses:
|
|
'200':
|
|
description: Login successful
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
access_token:
|
|
type: string
|
|
refresh_token:
|
|
type: string
|
|
user:
|
|
$ref: '#/components/schemas/User'
|
|
tenant:
|
|
$ref: '#/components/schemas/Tenant'
|
|
'401':
|
|
description: Invalid credentials
|
|
'404':
|
|
description: Tenant not found
|
|
|
|
/auth/logout:
|
|
post:
|
|
summary: User logout
|
|
tags: [Authentication]
|
|
responses:
|
|
'200':
|
|
description: Logout successful
|
|
'401':
|
|
description: Unauthorized
|
|
|
|
/auth/refresh:
|
|
post:
|
|
summary: Refresh access token
|
|
tags: [Authentication]
|
|
security: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [refresh_token]
|
|
properties:
|
|
refresh_token:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Token refreshed successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
access_token:
|
|
type: string
|
|
'401':
|
|
description: Invalid refresh token
|
|
|
|
# Tenant management endpoints
|
|
/tenants:
|
|
get:
|
|
summary: List tenants (admin only)
|
|
tags: [Tenants]
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
type: integer
|
|
default: 1
|
|
- name: limit
|
|
in: query
|
|
type: integer
|
|
default: 20
|
|
- name: search
|
|
in: query
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: List of tenants
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
tenants:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Tenant'
|
|
pagination:
|
|
$ref: '#/components/schemas/Pagination'
|
|
|
|
post:
|
|
summary: Create new tenant
|
|
tags: [Tenants]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [name, email, business_type]
|
|
properties:
|
|
name:
|
|
type: string
|
|
email:
|
|
type: string
|
|
format: email
|
|
phone:
|
|
type: string
|
|
address:
|
|
$ref: '#/components/schemas/Address'
|
|
business_type:
|
|
$ref: '#/components/schemas/BusinessType'
|
|
responses:
|
|
'201':
|
|
description: Tenant created successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Tenant'
|
|
'400':
|
|
description: Invalid input
|
|
|
|
/tenants/{tenant_id}:
|
|
get:
|
|
summary: Get tenant details
|
|
tags: [Tenants]
|
|
parameters:
|
|
- name: tenant_id
|
|
in: path
|
|
required: true
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Tenant details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Tenant'
|
|
'404':
|
|
description: Tenant not found
|
|
|
|
put:
|
|
summary: Update tenant
|
|
tags: [Tenants]
|
|
parameters:
|
|
- name: tenant_id
|
|
in: path
|
|
required: true
|
|
type: string
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TenantUpdate'
|
|
responses:
|
|
'200':
|
|
description: Tenant updated successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Tenant'
|
|
'404':
|
|
description: Tenant not found
|
|
|
|
# User management endpoints
|
|
/users:
|
|
get:
|
|
summary: List users
|
|
tags: [Users]
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
type: integer
|
|
default: 1
|
|
- name: limit
|
|
in: query
|
|
type: integer
|
|
default: 20
|
|
- name: role
|
|
in: query
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: List of users
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
users:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/User'
|
|
pagination:
|
|
$ref: '#/components/schemas/Pagination'
|
|
|
|
post:
|
|
summary: Create new user
|
|
tags: [Users]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [email, first_name, last_name, role]
|
|
properties:
|
|
email:
|
|
type: string
|
|
format: email
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
role:
|
|
$ref: '#/components/schemas/UserRole'
|
|
permissions:
|
|
type: array
|
|
items:
|
|
type: string
|
|
responses:
|
|
'201':
|
|
description: User created successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/User'
|
|
'400':
|
|
description: Invalid input
|
|
|
|
/users/{user_id}:
|
|
get:
|
|
summary: Get user details
|
|
tags: [Users]
|
|
parameters:
|
|
- name: user_id
|
|
in: path
|
|
required: true
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: User details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/User'
|
|
'404':
|
|
description: User not found
|
|
|
|
put:
|
|
summary: Update user
|
|
tags: [Users]
|
|
parameters:
|
|
- name: user_id
|
|
in: path
|
|
required: true
|
|
type: string
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserUpdate'
|
|
responses:
|
|
'200':
|
|
description: User updated successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/User'
|
|
'404':
|
|
description: User not found
|
|
|
|
# Subscription management endpoints
|
|
/subscriptions:
|
|
get:
|
|
summary: List subscriptions
|
|
tags: [Subscriptions]
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
type: integer
|
|
default: 1
|
|
- name: limit
|
|
in: query
|
|
type: integer
|
|
default: 20
|
|
- name: status
|
|
in: query
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: List of subscriptions
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
subscriptions:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Subscription'
|
|
pagination:
|
|
$ref: '#/components/schemas/Pagination'
|
|
|
|
post:
|
|
summary: Create new subscription
|
|
tags: [Subscriptions]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [tenant_id, plan_type, billing_cycle]
|
|
properties:
|
|
tenant_id:
|
|
type: string
|
|
plan_type:
|
|
$ref: '#/components/schemas/PlanType'
|
|
billing_cycle:
|
|
$ref: '#/components/schemas/BillingCycle'
|
|
payment_method:
|
|
type: string
|
|
module_ids:
|
|
type: array
|
|
items:
|
|
type: string
|
|
responses:
|
|
'201':
|
|
description: Subscription created successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Subscription'
|
|
'400':
|
|
description: Invalid input
|
|
|
|
/subscriptions/{subscription_id}:
|
|
get:
|
|
summary: Get subscription details
|
|
tags: [Subscriptions]
|
|
parameters:
|
|
- name: subscription_id
|
|
in: path
|
|
required: true
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Subscription details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Subscription'
|
|
'404':
|
|
description: Subscription not found
|
|
|
|
put:
|
|
summary: Update subscription
|
|
tags: [Subscriptions]
|
|
parameters:
|
|
- name: subscription_id
|
|
in: path
|
|
required: true
|
|
type: string
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SubscriptionUpdate'
|
|
responses:
|
|
'200':
|
|
description: Subscription updated successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Subscription'
|
|
'404':
|
|
description: Subscription not found
|
|
|
|
# Module management endpoints
|
|
/modules:
|
|
get:
|
|
summary: List available modules
|
|
tags: [Modules]
|
|
parameters:
|
|
- name: industry
|
|
in: query
|
|
type: string
|
|
- name: page
|
|
in: query
|
|
type: integer
|
|
default: 1
|
|
- name: limit
|
|
in: query
|
|
type: integer
|
|
default: 20
|
|
responses:
|
|
'200':
|
|
description: List of modules
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
modules:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Module'
|
|
pagination:
|
|
$ref: '#/components/schemas/Pagination'
|
|
|
|
/modules/{module_id}:
|
|
get:
|
|
summary: Get module details
|
|
tags: [Modules]
|
|
parameters:
|
|
- name: module_id
|
|
in: path
|
|
required: true
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Module details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Module'
|
|
'404':
|
|
description: Module not found
|
|
|
|
# Payment endpoints
|
|
/payments:
|
|
post:
|
|
summary: Process payment
|
|
tags: [Payments]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [subscription_id, amount, payment_method]
|
|
properties:
|
|
subscription_id:
|
|
type: string
|
|
amount:
|
|
type: number
|
|
format: decimal
|
|
currency:
|
|
type: string
|
|
default: MYR
|
|
payment_method:
|
|
type: string
|
|
description:
|
|
type: string
|
|
responses:
|
|
'201':
|
|
description: Payment processed successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/PaymentTransaction'
|
|
'400':
|
|
description: Invalid input
|
|
'402':
|
|
description: Payment failed
|
|
|
|
# Retail module endpoints
|
|
/retail/products:
|
|
get:
|
|
summary: List products (Retail module)
|
|
tags: [Retail]
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
type: integer
|
|
default: 1
|
|
- name: limit
|
|
in: query
|
|
type: integer
|
|
default: 20
|
|
- name: category
|
|
in: query
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: List of products
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
products:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Product'
|
|
pagination:
|
|
$ref: '#/components/schemas/Pagination'
|
|
|
|
post:
|
|
summary: Create product (Retail module)
|
|
tags: [Retail]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ProductCreate'
|
|
responses:
|
|
'201':
|
|
description: Product created successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Product'
|
|
'400':
|
|
description: Invalid input
|
|
|
|
/retail/sales:
|
|
post:
|
|
summary: Create sale (Retail module)
|
|
tags: [Retail]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SaleCreate'
|
|
responses:
|
|
'201':
|
|
description: Sale created successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Sale'
|
|
'400':
|
|
description: Invalid input
|
|
|
|
# Healthcare module endpoints
|
|
/healthcare/patients:
|
|
get:
|
|
summary: List patients (Healthcare module)
|
|
tags: [Healthcare]
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
type: integer
|
|
default: 1
|
|
- name: limit
|
|
in: query
|
|
type: integer
|
|
default: 20
|
|
- name: search
|
|
in: query
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: List of patients
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
patients:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Patient'
|
|
pagination:
|
|
$ref: '#/components/schemas/Pagination'
|
|
|
|
post:
|
|
summary: Create patient (Healthcare module)
|
|
tags: [Healthcare]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/PatientCreate'
|
|
responses:
|
|
'201':
|
|
description: Patient created successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Patient'
|
|
'400':
|
|
description: Invalid input
|
|
|
|
/healthcare/appointments:
|
|
get:
|
|
summary: List appointments (Healthcare module)
|
|
tags: [Healthcare]
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
type: integer
|
|
default: 1
|
|
- name: limit
|
|
in: query
|
|
type: integer
|
|
default: 20
|
|
- name: date
|
|
in: query
|
|
type: string
|
|
format: date
|
|
responses:
|
|
'200':
|
|
description: List of appointments
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
appointments:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Appointment'
|
|
pagination:
|
|
$ref: '#/components/schemas/Pagination'
|
|
|
|
post:
|
|
summary: Create appointment (Healthcare module)
|
|
tags: [Healthcare]
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AppointmentCreate'
|
|
responses:
|
|
'201':
|
|
description: Appointment created successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Appointment'
|
|
'400':
|
|
description: Invalid input
|
|
|
|
components:
|
|
securitySchemes:
|
|
BearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
|
|
schemas:
|
|
# Core schemas
|
|
Tenant:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
slug:
|
|
type: string
|
|
email:
|
|
type: string
|
|
format: email
|
|
phone:
|
|
type: string
|
|
address:
|
|
$ref: '#/components/schemas/Address'
|
|
business_type:
|
|
$ref: '#/components/schemas/BusinessType'
|
|
subscription_plan:
|
|
$ref: '#/components/schemas/PlanType'
|
|
pricing_model:
|
|
$ref: '#/components/schemas/PricingModel'
|
|
status:
|
|
$ref: '#/components/schemas/TenantStatus'
|
|
logo_url:
|
|
type: string
|
|
format: uri
|
|
settings:
|
|
type: object
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
User:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
tenant_id:
|
|
type: string
|
|
format: uuid
|
|
email:
|
|
type: string
|
|
format: email
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
role:
|
|
$ref: '#/components/schemas/UserRole'
|
|
status:
|
|
$ref: '#/components/schemas/UserStatus'
|
|
last_login:
|
|
type: string
|
|
format: date-time
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
mfa_enabled:
|
|
type: boolean
|
|
|
|
Subscription:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
tenant_id:
|
|
type: string
|
|
format: uuid
|
|
plan_type:
|
|
$ref: '#/components/schemas/PlanType'
|
|
billing_cycle:
|
|
$ref: '#/components/schemas/BillingCycle'
|
|
status:
|
|
$ref: '#/components/schemas/SubscriptionStatus'
|
|
starts_at:
|
|
type: string
|
|
format: date-time
|
|
ends_at:
|
|
type: string
|
|
format: date-time
|
|
renews_at:
|
|
type: string
|
|
format: date-time
|
|
amount:
|
|
type: number
|
|
format: decimal
|
|
currency:
|
|
type: string
|
|
default: MYR
|
|
payment_method:
|
|
type: string
|
|
module_limit:
|
|
type: integer
|
|
user_limit:
|
|
type: integer
|
|
features:
|
|
type: object
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
Module:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
slug:
|
|
type: string
|
|
description:
|
|
type: string
|
|
industry:
|
|
$ref: '#/components/schemas/BusinessType'
|
|
version:
|
|
type: string
|
|
status:
|
|
$ref: '#/components/schemas/ModuleStatus'
|
|
features:
|
|
type: object
|
|
requirements:
|
|
type: object
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
PaymentTransaction:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
tenant_id:
|
|
type: string
|
|
format: uuid
|
|
subscription_id:
|
|
type: string
|
|
format: uuid
|
|
type:
|
|
$ref: '#/components/schemas/PaymentType'
|
|
amount:
|
|
type: number
|
|
format: decimal
|
|
currency:
|
|
type: string
|
|
default: MYR
|
|
status:
|
|
$ref: '#/components/schemas/PaymentStatus'
|
|
payment_method:
|
|
type: string
|
|
transaction_id:
|
|
type: string
|
|
description:
|
|
type: string
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
# Retail module schemas
|
|
Product:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
tenant_id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
sku:
|
|
type: string
|
|
description:
|
|
type: string
|
|
category:
|
|
type: string
|
|
price:
|
|
type: number
|
|
format: decimal
|
|
cost:
|
|
type: number
|
|
format: decimal
|
|
stock_quantity:
|
|
type: integer
|
|
reorder_point:
|
|
type: integer
|
|
supplier_id:
|
|
type: string
|
|
format: uuid
|
|
status:
|
|
$ref: '#/components/schemas/ProductStatus'
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
Sale:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
tenant_id:
|
|
type: string
|
|
format: uuid
|
|
invoice_number:
|
|
type: string
|
|
customer_id:
|
|
type: string
|
|
format: uuid
|
|
subtotal:
|
|
type: number
|
|
format: decimal
|
|
tax:
|
|
type: number
|
|
format: decimal
|
|
total:
|
|
type: number
|
|
format: decimal
|
|
payment_method:
|
|
type: string
|
|
status:
|
|
$ref: '#/components/schemas/SaleStatus'
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
# Healthcare module schemas
|
|
Patient:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
tenant_id:
|
|
type: string
|
|
format: uuid
|
|
medical_record_number:
|
|
type: string
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
ic_number:
|
|
type: string
|
|
date_of_birth:
|
|
type: string
|
|
format: date
|
|
gender:
|
|
$ref: '#/components/schemas/Gender'
|
|
phone:
|
|
type: string
|
|
email:
|
|
type: string
|
|
format: email
|
|
address:
|
|
$ref: '#/components/schemas/Address'
|
|
blood_type:
|
|
type: string
|
|
allergies:
|
|
type: array
|
|
items:
|
|
type: string
|
|
medical_conditions:
|
|
type: array
|
|
items:
|
|
type: string
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
Appointment:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
tenant_id:
|
|
type: string
|
|
format: uuid
|
|
patient_id:
|
|
type: string
|
|
format: uuid
|
|
doctor_id:
|
|
type: string
|
|
format: uuid
|
|
appointment_date:
|
|
type: string
|
|
format: date-time
|
|
duration:
|
|
type: integer
|
|
status:
|
|
$ref: '#/components/schemas/AppointmentStatus'
|
|
type:
|
|
$ref: '#/components/schemas/AppointmentType'
|
|
notes:
|
|
type: string
|
|
reminder_sent:
|
|
type: boolean
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
# Supporting schemas
|
|
Address:
|
|
type: object
|
|
properties:
|
|
street:
|
|
type: string
|
|
city:
|
|
type: string
|
|
state:
|
|
type: string
|
|
postal_code:
|
|
type: string
|
|
country:
|
|
type: string
|
|
default: Malaysia
|
|
|
|
Pagination:
|
|
type: object
|
|
properties:
|
|
page:
|
|
type: integer
|
|
limit:
|
|
type: integer
|
|
total:
|
|
type: integer
|
|
pages:
|
|
type: integer
|
|
|
|
# Enum schemas
|
|
BusinessType:
|
|
type: string
|
|
enum: [RETAIL, HEALTHCARE, EDUCATION, LOGISTICS, BEAUTY]
|
|
|
|
PlanType:
|
|
type: string
|
|
enum: [STARTER, GROWTH, PRO, ENTERPRISE]
|
|
|
|
BillingCycle:
|
|
type: string
|
|
enum: [MONTHLY, YEARLY, ONE_TIME]
|
|
|
|
PricingModel:
|
|
type: string
|
|
enum: [SUBSCRIPTION, PERPETUAL]
|
|
|
|
TenantStatus:
|
|
type: string
|
|
enum: [PENDING, ACTIVE, SUSPENDED, TERMINATED]
|
|
|
|
UserRole:
|
|
type: string
|
|
enum: [ADMIN, MANAGER, STAFF, VIEWER]
|
|
|
|
UserStatus:
|
|
type: string
|
|
enum: [PENDING, ACTIVE, INACTIVE, DISABLED]
|
|
|
|
SubscriptionStatus:
|
|
type: string
|
|
enum: [ACTIVE, CANCELLED, EXPIRED, PENDING]
|
|
|
|
ModuleStatus:
|
|
type: string
|
|
enum: [ACTIVE, INACTIVE, BETA]
|
|
|
|
PaymentType:
|
|
type: string
|
|
enum: [CHARGE, REFUND, CREDIT, ADJUSTMENT]
|
|
|
|
PaymentStatus:
|
|
type: string
|
|
enum: [PENDING, COMPLETED, FAILED, REFUNDED]
|
|
|
|
ProductStatus:
|
|
type: string
|
|
enum: [ACTIVE, INACTIVE, DISCONTINUED]
|
|
|
|
SaleStatus:
|
|
type: string
|
|
enum: [PENDING, COMPLETED, REFUNDED]
|
|
|
|
Gender:
|
|
type: string
|
|
enum: [MALE, FEMALE, OTHER]
|
|
|
|
AppointmentStatus:
|
|
type: string
|
|
enum: [SCHEDULED, CONFIRMED, COMPLETED, CANCELLED, NO_SHOW]
|
|
|
|
AppointmentType:
|
|
type: string
|
|
enum: [CONSULTATION, FOLLOW_UP, PROCEDURE]
|
|
|
|
# Request schemas
|
|
TenantUpdate:
|
|
type: object
|
|
properties:
|
|
name:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
address:
|
|
$ref: '#/components/schemas/Address'
|
|
logo_url:
|
|
type: string
|
|
format: uri
|
|
settings:
|
|
type: object
|
|
|
|
UserUpdate:
|
|
type: object
|
|
properties:
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
phone:
|
|
type: string
|
|
role:
|
|
$ref: '#/components/schemas/UserRole'
|
|
permissions:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
SubscriptionUpdate:
|
|
type: object
|
|
properties:
|
|
plan_type:
|
|
$ref: '#/components/schemas/PlanType'
|
|
billing_cycle:
|
|
$ref: '#/components/schemas/BillingCycle'
|
|
payment_method:
|
|
type: string
|
|
module_ids:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
ProductCreate:
|
|
type: object
|
|
required: [name, sku, price, cost]
|
|
properties:
|
|
name:
|
|
type: string
|
|
sku:
|
|
type: string
|
|
description:
|
|
type: string
|
|
category:
|
|
type: string
|
|
price:
|
|
type: number
|
|
format: decimal
|
|
cost:
|
|
type: number
|
|
format: decimal
|
|
stock_quantity:
|
|
type: integer
|
|
reorder_point:
|
|
type: integer
|
|
supplier_id:
|
|
type: string
|
|
format: uuid
|
|
|
|
SaleCreate:
|
|
type: object
|
|
required: [customer_id, items]
|
|
properties:
|
|
customer_id:
|
|
type: string
|
|
format: uuid
|
|
items:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
product_id:
|
|
type: string
|
|
format: uuid
|
|
quantity:
|
|
type: integer
|
|
unit_price:
|
|
type: number
|
|
format: decimal
|
|
payment_method:
|
|
type: string
|
|
|
|
PatientCreate:
|
|
type: object
|
|
required: [first_name, last_name, ic_number, date_of_birth]
|
|
properties:
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
ic_number:
|
|
type: string
|
|
date_of_birth:
|
|
type: string
|
|
format: date
|
|
gender:
|
|
$ref: '#/components/schemas/Gender'
|
|
phone:
|
|
type: string
|
|
email:
|
|
type: string
|
|
format: email
|
|
address:
|
|
$ref: '#/components/schemas/Address'
|
|
blood_type:
|
|
type: string
|
|
allergies:
|
|
type: array
|
|
items:
|
|
type: string
|
|
medical_conditions:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
AppointmentCreate:
|
|
type: object
|
|
required: [patient_id, doctor_id, appointment_date, duration]
|
|
properties:
|
|
patient_id:
|
|
type: string
|
|
format: uuid
|
|
doctor_id:
|
|
type: string
|
|
format: uuid
|
|
appointment_date:
|
|
type: string
|
|
format: date-time
|
|
duration:
|
|
type: integer
|
|
type:
|
|
$ref: '#/components/schemas/AppointmentType'
|
|
notes:
|
|
type: string
|
|
|
|
# Error schemas
|
|
Error:
|
|
type: object
|
|
properties:
|
|
code:
|
|
type: string
|
|
message:
|
|
type: string
|
|
details:
|
|
type: object
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
|
|
ValidationError:
|
|
type: object
|
|
properties:
|
|
code:
|
|
type: string
|
|
default: VALIDATION_ERROR
|
|
message:
|
|
type: string
|
|
errors:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
field:
|
|
type: string
|
|
message:
|
|
type: string
|
|
|
|
UnauthorizedError:
|
|
type: object
|
|
properties:
|
|
code:
|
|
type: string
|
|
default: UNAUTHORIZED
|
|
message:
|
|
type: string
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
|
|
NotFoundError:
|
|
type: object
|
|
properties:
|
|
code:
|
|
type: string
|
|
default: NOT_FOUND
|
|
message:
|
|
type: string
|
|
timestamp:
|
|
type: string
|
|
format: date-time |