feat: Add Swagger UI documentation di root URL

This commit is contained in:
mwpn
2025-12-17 11:08:04 +07:00
parent 3f4a366c45
commit c08e0c7983
3 changed files with 693 additions and 0 deletions

48
public/docs/index.html Normal file
View File

@@ -0,0 +1,48 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>API Retribusi - Documentation</title>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@5.10.3/swagger-ui.css" />
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@5.10.3/swagger-ui-bundle.js"></script>
<script src="https://unpkg.com/swagger-ui-dist@5.10.3/swagger-ui-standalone-preset.js"></script>
<script>
window.onload = function() {
const ui = SwaggerUIBundle({
url: "./openapi.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout",
validatorUrl: null,
tryItOutEnabled: true
});
};
</script>
</body>
</html>

604
public/docs/openapi.json Normal file
View File

@@ -0,0 +1,604 @@
{
"openapi": "3.0.0",
"info": {
"title": "API Retribusi",
"description": "Sistem API Retribusi berbasis Slim Framework 4 untuk infrastruktur pemerintah",
"version": "1.0.0",
"contact": {
"name": "BTekno Development Team"
}
},
"servers": [
{
"url": "https://api.btekno.cloud",
"description": "Production Server"
},
{
"url": "http://localhost",
"description": "Local Development"
}
],
"tags": [
{
"name": "Health",
"description": "Health check endpoint"
},
{
"name": "Authentication",
"description": "JWT authentication"
},
{
"name": "Ingest",
"description": "Event ingestion (mesin YOLO)"
},
{
"name": "Frontend",
"description": "Frontend CRUD operations"
},
{
"name": "Summary",
"description": "Data summary & aggregation"
},
{
"name": "Dashboard",
"description": "Dashboard visualization data"
},
{
"name": "Realtime",
"description": "Real-time events (SSE)"
}
],
"components": {
"securitySchemes": {
"BearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT",
"description": "JWT token untuk frontend API"
},
"ApiKeyAuth": {
"type": "apiKey",
"in": "header",
"name": "X-API-KEY",
"description": "API Key untuk ingest endpoint"
}
},
"schemas": {
"Error": {
"type": "object",
"properties": {
"error": {
"type": "string",
"description": "Error code"
},
"message": {
"type": "string",
"description": "Error message"
},
"fields": {
"type": "object",
"description": "Validation errors (optional)"
}
}
},
"Success": {
"type": "object",
"properties": {
"success": {
"type": "boolean",
"example": true
},
"data": {
"type": "object"
},
"timestamp": {
"type": "integer",
"description": "Unix timestamp"
}
}
}
}
},
"paths": {
"/health": {
"get": {
"tags": ["Health"],
"summary": "Health check",
"description": "Check API health status",
"responses": {
"200": {
"description": "API is healthy",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "string",
"example": "ok"
},
"time": {
"type": "integer",
"example": 1735123456
}
}
}
}
}
}
}
}
},
"/auth/v1/login": {
"post": {
"tags": ["Authentication"],
"summary": "Login",
"description": "Authenticate user dan dapatkan JWT token",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["username", "password"],
"properties": {
"username": {
"type": "string",
"example": "admin"
},
"password": {
"type": "string",
"format": "password",
"example": "password123"
}
}
}
}
}
},
"responses": {
"200": {
"description": "Login successful",
"content": {
"application/json": {
"schema": {
"allOf": [
{"$ref": "#/components/schemas/Success"},
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"token": {
"type": "string"
},
"expires_in": {
"type": "integer"
},
"user": {
"type": "object",
"properties": {
"id": {"type": "integer"},
"username": {"type": "string"},
"role": {"type": "string"}
}
}
}
}
}
}
]
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Forbidden (user inactive)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
},
"/retribusi/v1/ingest": {
"post": {
"tags": ["Ingest"],
"summary": "Ingest event data",
"description": "Masukkan event data dari mesin YOLO",
"security": [
{
"ApiKeyAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["timestamp", "location_code", "gate_code", "category"],
"properties": {
"timestamp": {
"type": "integer",
"description": "Unix timestamp",
"example": 1735123456
},
"location_code": {
"type": "string",
"example": "kerkof_01"
},
"gate_code": {
"type": "string",
"example": "gate01"
},
"category": {
"type": "string",
"example": "motor"
}
}
}
}
}
},
"responses": {
"200": {
"description": "Event stored successfully",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Success"
}
}
}
},
"401": {
"description": "Unauthorized (invalid API key)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Not found (location/gate/tariff not found)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"422": {
"description": "Validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
},
"/retribusi/v1/frontend/locations": {
"get": {
"tags": ["Frontend"],
"summary": "Get locations list",
"description": "Mendapatkan daftar lokasi dengan pagination",
"security": [
{
"BearerAuth": []
}
],
"parameters": [
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"default": 1,
"minimum": 1
},
"description": "Page number"
},
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"default": 20,
"minimum": 1,
"maximum": 100
},
"description": "Items per page"
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Success"
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
},
"post": {
"tags": ["Frontend"],
"summary": "Create location",
"description": "Membuat lokasi baru (operator/admin only)",
"security": [
{
"BearerAuth": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["code", "name", "type", "is_active"],
"properties": {
"code": {
"type": "string",
"example": "kerkof_01"
},
"name": {
"type": "string",
"example": "Kerkof Garut"
},
"type": {
"type": "string",
"example": "parkir"
},
"is_active": {
"type": "integer",
"enum": [0, 1],
"example": 1
}
}
}
}
}
},
"responses": {
"201": {
"description": "Location created",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Success"
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Forbidden (insufficient permissions)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "Conflict (code already exists)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
},
"/retribusi/v1/summary/daily": {
"get": {
"tags": ["Summary"],
"summary": "Get daily summary",
"description": "Mendapatkan rekap harian",
"security": [
{
"BearerAuth": []
}
],
"parameters": [
{
"name": "date",
"in": "query",
"required": true,
"schema": {
"type": "string",
"format": "date",
"example": "2025-01-01"
},
"description": "Date (Y-m-d format)"
},
{
"name": "location_code",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "gate_code",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Success"
}
}
}
}
}
}
},
"/retribusi/v1/dashboard/daily": {
"get": {
"tags": ["Dashboard"],
"summary": "Get daily chart data",
"description": "Data untuk line chart harian",
"security": [
{
"BearerAuth": []
}
],
"parameters": [
{
"name": "start_date",
"in": "query",
"required": true,
"schema": {
"type": "string",
"format": "date"
}
},
{
"name": "end_date",
"in": "query",
"required": true,
"schema": {
"type": "string",
"format": "date"
}
},
{
"name": "location_code",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "gate_code",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Success"
}
}
}
}
}
}
},
"/retribusi/v1/realtime/stream": {
"get": {
"tags": ["Realtime"],
"summary": "SSE Stream",
"description": "Server-Sent Events stream untuk real-time updates",
"security": [
{
"BearerAuth": []
}
],
"parameters": [
{
"name": "last_id",
"in": "query",
"schema": {
"type": "integer"
},
"description": "Last event ID received"
},
{
"name": "location_code",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "SSE stream",
"content": {
"text/event-stream": {
"schema": {
"type": "string"
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
}
}
}