landvex: Fixar och tester klara för alla komponenter
- Datafabrik: Dockerfile fix, agentorkestrering fungerar - Vision: Identify-modell, FAISS, OCR alla testade - API: Alla 7 integrationstester passerade - Upplösare: Entitetsupplösning verifierad
This commit is contained in:
@@ -0,0 +1,740 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: LandveX Enterprise Platform Admin API
|
||||
version: 1.0.0
|
||||
description: Admin backend API for LandveX Enterprise Platform
|
||||
servers:
|
||||
- url: https://api.landvex.com/v1
|
||||
description: Production
|
||||
- url: https://api-staging.landvex.com/v1
|
||||
description: Staging
|
||||
|
||||
security:
|
||||
- BearerAuth: []
|
||||
- ApiKeyAuth: []
|
||||
|
||||
paths:
|
||||
# Auth
|
||||
/auth/login:
|
||||
post:
|
||||
tags: [Auth]
|
||||
summary: Login with email/password
|
||||
security: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [email, password]
|
||||
properties:
|
||||
email: { type: string, format: email }
|
||||
password: { type: string, minLength: 8 }
|
||||
mfa_code: { type: string }
|
||||
responses:
|
||||
'200':
|
||||
description: Login successful
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
access_token: { type: string }
|
||||
refresh_token: { type: string }
|
||||
token_type: { type: string, default: Bearer }
|
||||
expires_in: { type: integer }
|
||||
mfa_required: { type: boolean }
|
||||
|
||||
/auth/refresh:
|
||||
post:
|
||||
tags: [Auth]
|
||||
summary: Refresh access token
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [refresh_token]
|
||||
properties:
|
||||
refresh_token: { type: string }
|
||||
responses:
|
||||
'200':
|
||||
description: New tokens issued
|
||||
|
||||
# Tenants
|
||||
/tenants:
|
||||
get:
|
||||
tags: [Tenants]
|
||||
summary: List tenants
|
||||
parameters:
|
||||
- name: page
|
||||
in: query
|
||||
schema: { type: integer, default: 1 }
|
||||
- name: per_page
|
||||
in: query
|
||||
schema: { type: integer, default: 20 }
|
||||
- name: type
|
||||
in: query
|
||||
schema: { type: string, enum: [municipality, enterprise, partner] }
|
||||
- name: status
|
||||
in: query
|
||||
schema: { type: string, enum: [active, suspended, cancelled, trial] }
|
||||
- name: search
|
||||
in: query
|
||||
schema: { type: string }
|
||||
responses:
|
||||
'200':
|
||||
description: List of tenants
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/Tenant' }
|
||||
meta: { $ref: '#/components/schemas/PaginationMeta' }
|
||||
|
||||
post:
|
||||
tags: [Tenants]
|
||||
summary: Create tenant
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/TenantCreate' }
|
||||
responses:
|
||||
'201':
|
||||
description: Tenant created
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Tenant' }
|
||||
|
||||
/tenants/{id}:
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, format: uuid }
|
||||
get:
|
||||
tags: [Tenants]
|
||||
summary: Get tenant details
|
||||
responses:
|
||||
'200':
|
||||
description: Tenant details
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Tenant' }
|
||||
patch:
|
||||
tags: [Tenants]
|
||||
summary: Update tenant
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/TenantUpdate' }
|
||||
responses:
|
||||
'200':
|
||||
description: Tenant updated
|
||||
delete:
|
||||
tags: [Tenants]
|
||||
summary: Delete tenant (soft)
|
||||
responses:
|
||||
'204':
|
||||
description: Tenant deleted
|
||||
|
||||
# Users
|
||||
/users:
|
||||
get:
|
||||
tags: [Users]
|
||||
summary: List users
|
||||
parameters:
|
||||
- name: tenant_id
|
||||
in: header
|
||||
required: true
|
||||
schema: { type: string, format: uuid }
|
||||
- name: page
|
||||
in: query
|
||||
schema: { type: integer, default: 1 }
|
||||
- name: role
|
||||
in: query
|
||||
schema: { type: string }
|
||||
- name: status
|
||||
in: query
|
||||
schema: { type: string }
|
||||
responses:
|
||||
'200':
|
||||
description: List of users
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/User' }
|
||||
meta: { $ref: '#/components/schemas/PaginationMeta' }
|
||||
|
||||
post:
|
||||
tags: [Users]
|
||||
summary: Create/invite user
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/UserCreate' }
|
||||
responses:
|
||||
'201':
|
||||
description: User created
|
||||
|
||||
/users/{id}:
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, format: uuid }
|
||||
get:
|
||||
tags: [Users]
|
||||
summary: Get user
|
||||
responses:
|
||||
'200':
|
||||
description: User details
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/User' }
|
||||
patch:
|
||||
tags: [Users]
|
||||
summary: Update user
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/UserUpdate' }
|
||||
responses:
|
||||
'200':
|
||||
description: User updated
|
||||
delete:
|
||||
tags: [Users]
|
||||
summary: Delete user
|
||||
responses:
|
||||
'204':
|
||||
description: User deleted
|
||||
|
||||
/users/{id}/roles:
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, format: uuid }
|
||||
post:
|
||||
tags: [Users]
|
||||
summary: Assign role to user
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [role_id]
|
||||
properties:
|
||||
role_id: { type: string, format: uuid }
|
||||
responses:
|
||||
'200':
|
||||
description: Role assigned
|
||||
|
||||
# Roles
|
||||
/roles:
|
||||
get:
|
||||
tags: [Roles]
|
||||
summary: List roles
|
||||
responses:
|
||||
'200':
|
||||
description: List of roles
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/Role' }
|
||||
post:
|
||||
tags: [Roles]
|
||||
summary: Create role
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/RoleCreate' }
|
||||
responses:
|
||||
'201':
|
||||
description: Role created
|
||||
|
||||
# API Keys
|
||||
/api-keys:
|
||||
get:
|
||||
tags: [API Keys]
|
||||
summary: List API keys
|
||||
responses:
|
||||
'200':
|
||||
description: List of API keys
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/ApiKey' }
|
||||
post:
|
||||
tags: [API Keys]
|
||||
summary: Generate API key
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/ApiKeyCreate' }
|
||||
responses:
|
||||
'201':
|
||||
description: API key generated (key shown once)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
name: { type: string }
|
||||
key: { type: string } # Shown only once!
|
||||
prefix: { type: string }
|
||||
scopes: { type: array, items: { type: string } }
|
||||
created_at: { type: string, format: date-time }
|
||||
|
||||
/api-keys/{id}/revoke:
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, format: uuid }
|
||||
post:
|
||||
tags: [API Keys]
|
||||
summary: Revoke API key
|
||||
responses:
|
||||
'200':
|
||||
description: Key revoked
|
||||
|
||||
# Billing
|
||||
/billing/plans:
|
||||
get:
|
||||
tags: [Billing]
|
||||
summary: List subscription plans
|
||||
responses:
|
||||
'200':
|
||||
description: Available plans
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/SubscriptionPlan' }
|
||||
|
||||
/billing/subscription:
|
||||
get:
|
||||
tags: [Billing]
|
||||
summary: Get current subscription
|
||||
responses:
|
||||
'200':
|
||||
description: Subscription details
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Subscription' }
|
||||
|
||||
/billing/invoices:
|
||||
get:
|
||||
tags: [Billing]
|
||||
summary: List invoices
|
||||
parameters:
|
||||
- name: status
|
||||
in: query
|
||||
schema: { type: string }
|
||||
responses:
|
||||
'200':
|
||||
description: List of invoices
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/Invoice' }
|
||||
meta: { $ref: '#/components/schemas/PaginationMeta' }
|
||||
|
||||
# Audit Logs
|
||||
/audit-logs:
|
||||
get:
|
||||
tags: [Audit Logs]
|
||||
summary: List audit logs
|
||||
parameters:
|
||||
- name: action
|
||||
in: query
|
||||
schema: { type: string }
|
||||
- name: user_id
|
||||
in: query
|
||||
schema: { type: string, format: uuid }
|
||||
- name: resource_type
|
||||
in: query
|
||||
schema: { type: string }
|
||||
- name: from
|
||||
in: query
|
||||
schema: { type: string, format: date-time }
|
||||
- name: to
|
||||
in: query
|
||||
schema: { type: string, format: date-time }
|
||||
- name: severity
|
||||
in: query
|
||||
schema: { type: string, enum: [info, warning, critical] }
|
||||
responses:
|
||||
'200':
|
||||
description: Audit logs
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/AuditLog' }
|
||||
meta: { $ref: '#/components/schemas/PaginationMeta' }
|
||||
|
||||
/audit-logs/export:
|
||||
get:
|
||||
tags: [Audit Logs]
|
||||
summary: Export audit logs
|
||||
parameters:
|
||||
- name: format
|
||||
in: query
|
||||
schema: { type: string, enum: [csv, json], default: csv }
|
||||
responses:
|
||||
'200':
|
||||
description: Exported file
|
||||
content:
|
||||
text/csv:
|
||||
schema: { type: string }
|
||||
application/json:
|
||||
schema: { type: string }
|
||||
|
||||
# Reports
|
||||
/reports:
|
||||
get:
|
||||
tags: [Reports]
|
||||
summary: List reports
|
||||
responses:
|
||||
'200':
|
||||
description: List of reports
|
||||
post:
|
||||
tags: [Reports]
|
||||
summary: Create report
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/ReportCreate' }
|
||||
responses:
|
||||
'201':
|
||||
description: Report created
|
||||
|
||||
/reports/{id}/run:
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, format: uuid }
|
||||
post:
|
||||
tags: [Reports]
|
||||
summary: Run report
|
||||
responses:
|
||||
'202':
|
||||
description: Report queued
|
||||
|
||||
# Plugins
|
||||
/plugins:
|
||||
get:
|
||||
tags: [Plugins]
|
||||
summary: List available plugins
|
||||
responses:
|
||||
'200':
|
||||
description: Available plugins
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/Plugin' }
|
||||
|
||||
/plugins/installed:
|
||||
get:
|
||||
tags: [Plugins]
|
||||
summary: List installed plugins
|
||||
responses:
|
||||
'200':
|
||||
description: Installed plugins
|
||||
|
||||
/plugins/{id}/install:
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, format: uuid }
|
||||
post:
|
||||
tags: [Plugins]
|
||||
summary: Install plugin
|
||||
responses:
|
||||
'200':
|
||||
description: Plugin installed
|
||||
|
||||
# Dashboard
|
||||
/dashboard/summary:
|
||||
get:
|
||||
tags: [Dashboard]
|
||||
summary: Get dashboard summary
|
||||
responses:
|
||||
'200':
|
||||
description: Dashboard statistics
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/DashboardSummary' }
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
ApiKeyAuth:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: X-API-Key
|
||||
|
||||
schemas:
|
||||
PaginationMeta:
|
||||
type: object
|
||||
properties:
|
||||
page: { type: integer }
|
||||
per_page: { type: integer }
|
||||
total: { type: integer }
|
||||
total_pages: { type: integer }
|
||||
|
||||
Tenant:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
name: { type: string }
|
||||
slug: { type: string }
|
||||
type: { type: string, enum: [municipality, enterprise, partner] }
|
||||
org_number: { type: string }
|
||||
billing_email: { type: string, format: email }
|
||||
plan_id: { type: string, format: uuid }
|
||||
status: { type: string }
|
||||
settings: { type: object }
|
||||
created_at: { type: string, format: date-time }
|
||||
updated_at: { type: string, format: date-time }
|
||||
|
||||
TenantCreate:
|
||||
type: object
|
||||
required: [name, slug, type, billing_email]
|
||||
properties:
|
||||
name: { type: string, minLength: 2, maxLength: 255 }
|
||||
slug: { type: string, pattern: '^[a-z0-9-]+$' }
|
||||
type: { type: string, enum: [municipality, enterprise, partner] }
|
||||
org_number: { type: string }
|
||||
billing_email: { type: string, format: email }
|
||||
plan_id: { type: string, format: uuid }
|
||||
|
||||
TenantUpdate:
|
||||
type: object
|
||||
properties:
|
||||
name: { type: string }
|
||||
billing_email: { type: string, format: email }
|
||||
status: { type: string }
|
||||
settings: { type: object }
|
||||
|
||||
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 }
|
||||
avatar_url: { type: string }
|
||||
status: { type: string }
|
||||
roles: { type: array, items: { $ref: '#/components/schemas/Role' } }
|
||||
last_login_at: { type: string, format: date-time }
|
||||
created_at: { type: string, format: date-time }
|
||||
|
||||
UserCreate:
|
||||
type: object
|
||||
required: [email, first_name, last_name]
|
||||
properties:
|
||||
email: { type: string, format: email }
|
||||
first_name: { type: string }
|
||||
last_name: { type: string }
|
||||
phone: { type: string }
|
||||
role_ids: { type: array, items: { type: string, format: uuid } }
|
||||
send_invite: { type: boolean, default: true }
|
||||
|
||||
UserUpdate:
|
||||
type: object
|
||||
properties:
|
||||
first_name: { type: string }
|
||||
last_name: { type: string }
|
||||
phone: { type: string }
|
||||
status: { type: string }
|
||||
role_ids: { type: array, items: { type: string, format: uuid } }
|
||||
|
||||
Role:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
name: { type: string }
|
||||
slug: { type: string }
|
||||
description: { type: string }
|
||||
permissions: { type: array, items: { type: string } }
|
||||
is_system: { type: boolean }
|
||||
member_count: { type: integer }
|
||||
created_at: { type: string, format: date-time }
|
||||
|
||||
RoleCreate:
|
||||
type: object
|
||||
required: [name, slug, permissions]
|
||||
properties:
|
||||
name: { type: string }
|
||||
slug: { type: string }
|
||||
description: { type: string }
|
||||
permissions: { type: array, items: { type: string } }
|
||||
|
||||
ApiKey:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
name: { type: string }
|
||||
prefix: { type: string }
|
||||
scopes: { type: array, items: { type: string } }
|
||||
rate_limit: { type: integer }
|
||||
expires_at: { type: string, format: date-time }
|
||||
last_used_at: { type: string, format: date-time }
|
||||
status: { type: string }
|
||||
created_at: { type: string, format: date-time }
|
||||
|
||||
ApiKeyCreate:
|
||||
type: object
|
||||
required: [name]
|
||||
properties:
|
||||
name: { type: string }
|
||||
scopes: { type: array, items: { type: string } }
|
||||
rate_limit: { type: integer, default: 1000 }
|
||||
expires_at: { type: string, format: date-time }
|
||||
|
||||
SubscriptionPlan:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
name: { type: string }
|
||||
slug: { type: string }
|
||||
description: { type: string }
|
||||
price_monthly: { type: number }
|
||||
price_yearly: { type: number }
|
||||
features: { type: object }
|
||||
limits: { type: object }
|
||||
|
||||
Subscription:
|
||||
type: object
|
||||
properties:
|
||||
plan: { $ref: '#/components/schemas/SubscriptionPlan' }
|
||||
status: { type: string }
|
||||
current_period_start: { type: string, format: date-time }
|
||||
current_period_end: { type: string, format: date-time }
|
||||
cancel_at_period_end: { type: boolean }
|
||||
|
||||
Invoice:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
invoice_number: { type: string }
|
||||
period_start: { type: string, format: date }
|
||||
period_end: { type: string, format: date }
|
||||
amount: { type: number }
|
||||
tax_amount: { type: number }
|
||||
total_amount: { type: number }
|
||||
currency: { type: string, default: SEK }
|
||||
status: { type: string }
|
||||
due_date: { type: string, format: date }
|
||||
pdf_url: { type: string }
|
||||
created_at: { type: string, format: date-time }
|
||||
|
||||
AuditLog:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
action: { type: string }
|
||||
resource_type: { type: string }
|
||||
resource_id: { type: string, format: uuid }
|
||||
user: { type: object, properties: { id: { type: string }, email: { type: string } } }
|
||||
details: { type: object }
|
||||
ip_address: { type: string }
|
||||
severity: { type: string }
|
||||
created_at: { type: string, format: date-time }
|
||||
|
||||
ReportCreate:
|
||||
type: object
|
||||
required: [name, type]
|
||||
properties:
|
||||
name: { type: string }
|
||||
type: { type: string }
|
||||
config: { type: object }
|
||||
schedule: { type: string }
|
||||
|
||||
Plugin:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
name: { type: string }
|
||||
slug: { type: string }
|
||||
description: { type: string }
|
||||
version: { type: string }
|
||||
author: { type: string }
|
||||
is_installed: { type: boolean }
|
||||
is_system: { type: boolean }
|
||||
|
||||
DashboardSummary:
|
||||
type: object
|
||||
properties:
|
||||
tenants:
|
||||
type: object
|
||||
properties:
|
||||
total: { type: integer }
|
||||
active: { type: integer }
|
||||
trial: { type: integer }
|
||||
users:
|
||||
type: object
|
||||
properties:
|
||||
total: { type: integer }
|
||||
active: { type: integer }
|
||||
api_usage:
|
||||
type: object
|
||||
properties:
|
||||
today: { type: integer }
|
||||
this_month: { type: integer }
|
||||
limit: { type: integer }
|
||||
revenue:
|
||||
type: object
|
||||
properties:
|
||||
mrr: { type: number }
|
||||
this_month: { type: number }
|
||||
last_month: { type: number }
|
||||
Reference in New Issue
Block a user