From b1f18e1a4ee1577525bd50a11783a009ff3e33d3 Mon Sep 17 00:00:00 2001 From: nutcas3 Date: Thu, 30 Apr 2026 22:59:46 +0300 Subject: [PATCH] feat: Add comprehensive Swagger API documentation for subscriber management endpoints - Add GET /api/v1/subscribers endpoint with pagination and filtering parameters - Add POST /api/v1/subscribers endpoint for subscriber creation - Add GET /api/v1/subscribers/{id} and GET /api/v1/subscribers/imsi/{imsi} endpoints - Add PUT /api/v1/subscribers/{id} endpoint for subscriber updates - Add POST /api/v1/subscribers/{id}/suspend and /api/v1/subscribers/{id}/terminate endpoints - Add Swagger definitions --- apps/api-server/docs/docs.go | 855 ++++++++++++++++++++++++++---- apps/api-server/docs/swagger.go | 8 - apps/api-server/docs/swagger.json | 747 ++++++++++++++++++++++++++ apps/api-server/docs/swagger.yaml | 500 +++++++++++++++++ 4 files changed, 2004 insertions(+), 106 deletions(-) create mode 100644 apps/api-server/docs/swagger.json create mode 100644 apps/api-server/docs/swagger.yaml diff --git a/apps/api-server/docs/docs.go b/apps/api-server/docs/docs.go index fed8279..398fb30 100644 --- a/apps/api-server/docs/docs.go +++ b/apps/api-server/docs/docs.go @@ -1,117 +1,776 @@ -// Package docs GENERATED BY SWAG; DO NOT EDIT -// This file was generated by swaggo/swag - +// Package docs Code generated by swaggo/swag. DO NOT EDIT package docs -import ( - "strings" - - "github.com/swaggo/swag" -) +import "github.com/swaggo/swag" const docTemplate = `{ "schemes": {{ marshal .Schemes }}, "swagger": "2.0", "info": { - "description": "{{.Description}}", + "description": "{{escape .Description}}", "title": "{{.Title}}", - "termsOfService": "{{.TermsOfService}}", - "contact": { - "name": "{{.ContactName}}", - "url": "{{.ContactURL}}", - "email": "{{.ContactEmail}}" - }, - "license": { - "name": "{{.LicenseName}}", - "url": "{{.LicenseURL}}" - }, + "contact": {}, "version": "{{.Version}}" }, "host": "{{.Host}}", "basePath": "{{.BasePath}}", - "paths": {}, - "definitions": {} + "paths": { + "/api/v1/subscribers": { + "get": { + "description": "List subscribers with pagination and filtering", + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "List subscribers", + "parameters": [ + { + "type": "integer", + "default": 1, + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "default": 20, + "description": "Page size", + "name": "page_size", + "in": "query" + }, + { + "type": "string", + "description": "Subscriber status", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "Organization ID", + "name": "organization_id", + "in": "query" + }, + { + "type": "string", + "description": "Search term", + "name": "search", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/services.ListSubscribersResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + }, + "post": { + "description": "Create a new subscriber with allocated IMSI", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "Create a new subscriber", + "parameters": [ + { + "description": "Subscriber data", + "name": "subscriber", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/services.CreateSubscriberRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/models.Subscriber" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/api/v1/subscribers/imsi/{imsi}": { + "get": { + "description": "Retrieve subscriber information by IMSI", + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "Get subscriber by IMSI", + "parameters": [ + { + "type": "string", + "description": "IMSI", + "name": "imsi", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.Subscriber" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/api/v1/subscribers/{id}": { + "get": { + "description": "Retrieve subscriber information by ID", + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "Get subscriber by ID", + "parameters": [ + { + "type": "integer", + "description": "Subscriber ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.Subscriber" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + }, + "put": { + "description": "Update subscriber information", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "Update subscriber", + "parameters": [ + { + "type": "integer", + "description": "Subscriber ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Updated subscriber data", + "name": "subscriber", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/services.UpdateSubscriberRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.Subscriber" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/api/v1/subscribers/{id}/suspend": { + "post": { + "description": "Suspend a subscriber and terminate their sessions", + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "Suspend subscriber", + "parameters": [ + { + "type": "integer", + "description": "Subscriber ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/api/v1/subscribers/{id}/terminate": { + "post": { + "description": "Terminate a subscriber and deactivate their eSIM profile", + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "Terminate subscriber", + "parameters": [ + { + "type": "integer", + "description": "Subscriber ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + } + }, + "definitions": { + "handlers.ErrorResponse": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "details": { + "type": "string" + }, + "error": { + "type": "string" + } + } + }, + "models.AMBR": { + "type": "object", + "properties": { + "downlink": { + "type": "integer" + }, + "uplink": { + "type": "integer" + } + } + }, + "models.PLMN": { + "type": "object", + "properties": { + "mcc": { + "type": "string" + }, + "mnc": { + "type": "string" + } + } + }, + "models.ProfileStatus": { + "type": "string", + "enum": [ + "inactive", + "active", + "downloading", + "error" + ], + "x-enum-varnames": [ + "ProfileStatusInactive", + "ProfileStatusActive", + "ProfileStatusDownloading", + "ProfileStatusError" + ] + }, + "models.QoSProfile": { + "type": "object", + "properties": { + "arpa": { + "type": "integer" + }, + "gbr": { + "$ref": "#/definitions/models.AMBR" + }, + "mbr": { + "$ref": "#/definitions/models.AMBR" + }, + "priority": { + "type": "integer" + }, + "qci": { + "type": "integer" + } + } + }, + "models.SNSSAI": { + "type": "object", + "properties": { + "sd": { + "type": "integer" + }, + "sst": { + "type": "integer" + } + } + }, + "models.ServicePlan": { + "type": "object", + "properties": { + "ambr": { + "$ref": "#/definitions/models.AMBR" + }, + "arpa": { + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "data_limit": { + "type": "integer" + }, + "data_rate": { + "type": "number" + }, + "description": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "monthly_fee": { + "type": "number" + }, + "name": { + "type": "string" + }, + "sms_limit": { + "type": "integer" + }, + "sms_rate": { + "type": "number" + }, + "updated_at": { + "type": "string" + }, + "voice_limit": { + "type": "integer" + }, + "voice_rate": { + "type": "number" + } + } + }, + "models.Session": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "data_used": { + "type": "integer" + }, + "dnn": { + "type": "string" + }, + "end_time": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "pdu_address": { + "type": "string" + }, + "qos": { + "$ref": "#/definitions/models.QoSProfile" + }, + "session_id": { + "type": "string" + }, + "sms_used": { + "type": "integer" + }, + "snssai": { + "$ref": "#/definitions/models.SNSSAI" + }, + "start_time": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/models.SessionStatus" + }, + "subscriber_id": { + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "voice_used": { + "type": "integer" + } + } + }, + "models.SessionStatus": { + "type": "string", + "enum": [ + "active", + "inactive", + "terminating" + ], + "x-enum-varnames": [ + "SessionStatusActive", + "SessionStatusInactive", + "SessionStatusTerminating" + ] + }, + "models.Subscriber": { + "type": "object", + "properties": { + "auth_key": { + "type": "string" + }, + "balance": { + "type": "number" + }, + "created_at": { + "type": "string" + }, + "email": { + "type": "string" + }, + "euicc_id": { + "type": "string" + }, + "first_name": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "imei": { + "description": "Device identifier", + "type": "string" + }, + "imsi": { + "type": "string" + }, + "last_name": { + "type": "string" + }, + "msisdn": { + "description": "Mobile phone number", + "type": "string" + }, + "opc": { + "type": "string" + }, + "organization_id": { + "type": "string" + }, + "plan": { + "$ref": "#/definitions/models.ServicePlan" + }, + "plan_id": { + "type": "integer" + }, + "profile_id": { + "type": "string" + }, + "profile_status": { + "$ref": "#/definitions/models.ProfileStatus" + }, + "serving_plmn": { + "$ref": "#/definitions/models.PLMN" + }, + "sessions": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Session" + } + }, + "status": { + "$ref": "#/definitions/models.SubscriberStatus" + }, + "updated_at": { + "type": "string" + }, + "usage_records": { + "type": "array", + "items": { + "$ref": "#/definitions/models.UsageRecord" + } + } + } + }, + "models.SubscriberStatus": { + "type": "string", + "enum": [ + "active", + "inactive", + "suspended", + "terminated", + "provisioning" + ], + "x-enum-varnames": [ + "SubscriberStatusActive", + "SubscriberStatusInactive", + "SubscriberStatusSuspended", + "SubscriberStatusTerminated", + "SubscriberStatusProvisioning" + ] + }, + "models.UsageRecord": { + "type": "object", + "properties": { + "billing_cycle": { + "type": "string" + }, + "cost": { + "type": "number" + }, + "created_at": { + "type": "string" + }, + "end_time": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "invoice_id": { + "type": "integer" + }, + "rate": { + "type": "number" + }, + "session_id": { + "type": "integer" + }, + "start_time": { + "type": "string" + }, + "subscriber_id": { + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "usage_type": { + "$ref": "#/definitions/models.UsageType" + }, + "volume": { + "type": "integer" + } + } + }, + "models.UsageType": { + "type": "string", + "enum": [ + "data", + "voice", + "sms" + ], + "x-enum-varnames": [ + "UsageTypeData", + "UsageTypeVoice", + "UsageTypeSMS" + ] + }, + "services.CreateSubscriberRequest": { + "type": "object", + "required": [ + "email", + "first_name", + "last_name", + "msisdn", + "plan_id" + ], + "properties": { + "email": { + "type": "string" + }, + "euicc_id": { + "type": "string" + }, + "first_name": { + "type": "string" + }, + "last_name": { + "type": "string" + }, + "msisdn": { + "type": "string" + }, + "organization_id": { + "type": "string" + }, + "plan_id": { + "type": "integer" + } + } + }, + "services.ListSubscribersResponse": { + "type": "object", + "properties": { + "page": { + "type": "integer" + }, + "page_size": { + "type": "integer" + }, + "subscribers": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Subscriber" + } + }, + "total": { + "type": "integer" + } + } + }, + "services.UpdateSubscriberRequest": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "first_name": { + "type": "string" + }, + "last_name": { + "type": "string" + }, + "plan_id": { + "type": "integer" + }, + "status": { + "$ref": "#/definitions/models.SubscriberStatus" + } + } + } + } }` // SwaggerInfo holds exported Swagger Info so clients can modify it -var SwaggerInfo = struct { - Host string - BasePath string - Schemes []string - Title string - Description string - Version string - // License information - LicenseName string - LicenseURL string - // Contact information - ContactName string - ContactURL string - ContactEmail string -}{ - Host: "localhost:8000", - BasePath: "/v1", - Schemes: []string{"http", "https"}, - Title: "Telecom Platform API", - Description: "A comprehensive telecom platform API for managing subscribers, services, monitoring, deployments, plugins, automation, and billing", - Version: "1.0.0", - LicenseName: "MIT", - LicenseURL: "https://opensource.org/licenses/MIT", - ContactName: "Telecom Platform Team", - ContactURL: "https://github.com/nutcas3/telecom-platform", - ContactEmail: "support@telecom-platform.com", -} - -type s struct{} - -func (s s) ReadDoc() string { - sInfo := SwaggerInfo - description := `Telecom Platform API - -This API provides comprehensive functionality for managing a telecom platform including: -- Subscriber management and eSIM provisioning -- Service management and Kubernetes integration -- Monitoring and metrics collection -- Deployment management -- Plugin system -- Workflow automation -- Billing and invoicing -- Configuration management -- Authentication and authorization - -## Authentication - -The API uses JWT (JSON Web Token) authentication. To access protected endpoints: -1. Register a user account -2. Login to obtain an access token -3. Include the token in the Authorization header: "Bearer " - -## Rate Limiting - -API requests are rate-limited to ensure fair usage. Current limits: -- 100 requests per minute per authenticated user -- 10 requests per minute for unauthenticated requests - -## Error Handling - -The API uses standard HTTP status codes: -- 200: Success -- 201: Created -- 400: Bad Request -- 401: Unauthorized -- 403: Forbidden -- 404: Not Found -- 500: Internal Server Error - -Error responses include a JSON object with an "error" field containing a descriptive message.` - - // Replace template placeholders with actual values - result := strings.Replace(docTemplate, "{{.Version}}", sInfo.Version, -1) - result = strings.Replace(result, "{{.Description}}", description, -1) - - return result +var SwaggerInfo = &swag.Spec{ + Version: "", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", } func init() { - swag.Register(swag.Name, &s{}) + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) } diff --git a/apps/api-server/docs/swagger.go b/apps/api-server/docs/swagger.go index 785e813..53356ca 100644 --- a/apps/api-server/docs/swagger.go +++ b/apps/api-server/docs/swagger.go @@ -1,9 +1,5 @@ package docs -import ( - "github.com/swaggo/swag" -) - // @title Telecom Platform API // @version 1.0.0 // @description A comprehensive telecom platform API for managing subscribers, services, monitoring, deployments, plugins, automation, and billing @@ -19,7 +15,3 @@ import ( // @in header // @name Authorization // @description Type "Bearer" followed by a space and JWT token. - -func init() { - swag.Register(swag.Name, &s{}) -} diff --git a/apps/api-server/docs/swagger.json b/apps/api-server/docs/swagger.json new file mode 100644 index 0000000..d6ad10e --- /dev/null +++ b/apps/api-server/docs/swagger.json @@ -0,0 +1,747 @@ +{ + "swagger": "2.0", + "info": { + "contact": {} + }, + "paths": { + "/api/v1/subscribers": { + "get": { + "description": "List subscribers with pagination and filtering", + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "List subscribers", + "parameters": [ + { + "type": "integer", + "default": 1, + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "default": 20, + "description": "Page size", + "name": "page_size", + "in": "query" + }, + { + "type": "string", + "description": "Subscriber status", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "Organization ID", + "name": "organization_id", + "in": "query" + }, + { + "type": "string", + "description": "Search term", + "name": "search", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/services.ListSubscribersResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + }, + "post": { + "description": "Create a new subscriber with allocated IMSI", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "Create a new subscriber", + "parameters": [ + { + "description": "Subscriber data", + "name": "subscriber", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/services.CreateSubscriberRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/models.Subscriber" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/api/v1/subscribers/imsi/{imsi}": { + "get": { + "description": "Retrieve subscriber information by IMSI", + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "Get subscriber by IMSI", + "parameters": [ + { + "type": "string", + "description": "IMSI", + "name": "imsi", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.Subscriber" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/api/v1/subscribers/{id}": { + "get": { + "description": "Retrieve subscriber information by ID", + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "Get subscriber by ID", + "parameters": [ + { + "type": "integer", + "description": "Subscriber ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.Subscriber" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + }, + "put": { + "description": "Update subscriber information", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "Update subscriber", + "parameters": [ + { + "type": "integer", + "description": "Subscriber ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Updated subscriber data", + "name": "subscriber", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/services.UpdateSubscriberRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.Subscriber" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/api/v1/subscribers/{id}/suspend": { + "post": { + "description": "Suspend a subscriber and terminate their sessions", + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "Suspend subscriber", + "parameters": [ + { + "type": "integer", + "description": "Subscriber ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + }, + "/api/v1/subscribers/{id}/terminate": { + "post": { + "description": "Terminate a subscriber and deactivate their eSIM profile", + "produces": [ + "application/json" + ], + "tags": [ + "subscribers" + ], + "summary": "Terminate subscriber", + "parameters": [ + { + "type": "integer", + "description": "Subscriber ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } + } + } + } + } + }, + "definitions": { + "handlers.ErrorResponse": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "details": { + "type": "string" + }, + "error": { + "type": "string" + } + } + }, + "models.AMBR": { + "type": "object", + "properties": { + "downlink": { + "type": "integer" + }, + "uplink": { + "type": "integer" + } + } + }, + "models.PLMN": { + "type": "object", + "properties": { + "mcc": { + "type": "string" + }, + "mnc": { + "type": "string" + } + } + }, + "models.ProfileStatus": { + "type": "string", + "enum": [ + "inactive", + "active", + "downloading", + "error" + ], + "x-enum-varnames": [ + "ProfileStatusInactive", + "ProfileStatusActive", + "ProfileStatusDownloading", + "ProfileStatusError" + ] + }, + "models.QoSProfile": { + "type": "object", + "properties": { + "arpa": { + "type": "integer" + }, + "gbr": { + "$ref": "#/definitions/models.AMBR" + }, + "mbr": { + "$ref": "#/definitions/models.AMBR" + }, + "priority": { + "type": "integer" + }, + "qci": { + "type": "integer" + } + } + }, + "models.SNSSAI": { + "type": "object", + "properties": { + "sd": { + "type": "integer" + }, + "sst": { + "type": "integer" + } + } + }, + "models.ServicePlan": { + "type": "object", + "properties": { + "ambr": { + "$ref": "#/definitions/models.AMBR" + }, + "arpa": { + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "data_limit": { + "type": "integer" + }, + "data_rate": { + "type": "number" + }, + "description": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "monthly_fee": { + "type": "number" + }, + "name": { + "type": "string" + }, + "sms_limit": { + "type": "integer" + }, + "sms_rate": { + "type": "number" + }, + "updated_at": { + "type": "string" + }, + "voice_limit": { + "type": "integer" + }, + "voice_rate": { + "type": "number" + } + } + }, + "models.Session": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "data_used": { + "type": "integer" + }, + "dnn": { + "type": "string" + }, + "end_time": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "pdu_address": { + "type": "string" + }, + "qos": { + "$ref": "#/definitions/models.QoSProfile" + }, + "session_id": { + "type": "string" + }, + "sms_used": { + "type": "integer" + }, + "snssai": { + "$ref": "#/definitions/models.SNSSAI" + }, + "start_time": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/models.SessionStatus" + }, + "subscriber_id": { + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "voice_used": { + "type": "integer" + } + } + }, + "models.SessionStatus": { + "type": "string", + "enum": [ + "active", + "inactive", + "terminating" + ], + "x-enum-varnames": [ + "SessionStatusActive", + "SessionStatusInactive", + "SessionStatusTerminating" + ] + }, + "models.Subscriber": { + "type": "object", + "properties": { + "auth_key": { + "type": "string" + }, + "balance": { + "type": "number" + }, + "created_at": { + "type": "string" + }, + "email": { + "type": "string" + }, + "euicc_id": { + "type": "string" + }, + "first_name": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "imei": { + "description": "Device identifier", + "type": "string" + }, + "imsi": { + "type": "string" + }, + "last_name": { + "type": "string" + }, + "msisdn": { + "description": "Mobile phone number", + "type": "string" + }, + "opc": { + "type": "string" + }, + "organization_id": { + "type": "string" + }, + "plan": { + "$ref": "#/definitions/models.ServicePlan" + }, + "plan_id": { + "type": "integer" + }, + "profile_id": { + "type": "string" + }, + "profile_status": { + "$ref": "#/definitions/models.ProfileStatus" + }, + "serving_plmn": { + "$ref": "#/definitions/models.PLMN" + }, + "sessions": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Session" + } + }, + "status": { + "$ref": "#/definitions/models.SubscriberStatus" + }, + "updated_at": { + "type": "string" + }, + "usage_records": { + "type": "array", + "items": { + "$ref": "#/definitions/models.UsageRecord" + } + } + } + }, + "models.SubscriberStatus": { + "type": "string", + "enum": [ + "active", + "inactive", + "suspended", + "terminated", + "provisioning" + ], + "x-enum-varnames": [ + "SubscriberStatusActive", + "SubscriberStatusInactive", + "SubscriberStatusSuspended", + "SubscriberStatusTerminated", + "SubscriberStatusProvisioning" + ] + }, + "models.UsageRecord": { + "type": "object", + "properties": { + "billing_cycle": { + "type": "string" + }, + "cost": { + "type": "number" + }, + "created_at": { + "type": "string" + }, + "end_time": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "invoice_id": { + "type": "integer" + }, + "rate": { + "type": "number" + }, + "session_id": { + "type": "integer" + }, + "start_time": { + "type": "string" + }, + "subscriber_id": { + "type": "integer" + }, + "updated_at": { + "type": "string" + }, + "usage_type": { + "$ref": "#/definitions/models.UsageType" + }, + "volume": { + "type": "integer" + } + } + }, + "models.UsageType": { + "type": "string", + "enum": [ + "data", + "voice", + "sms" + ], + "x-enum-varnames": [ + "UsageTypeData", + "UsageTypeVoice", + "UsageTypeSMS" + ] + }, + "services.CreateSubscriberRequest": { + "type": "object", + "required": [ + "email", + "first_name", + "last_name", + "msisdn", + "plan_id" + ], + "properties": { + "email": { + "type": "string" + }, + "euicc_id": { + "type": "string" + }, + "first_name": { + "type": "string" + }, + "last_name": { + "type": "string" + }, + "msisdn": { + "type": "string" + }, + "organization_id": { + "type": "string" + }, + "plan_id": { + "type": "integer" + } + } + }, + "services.ListSubscribersResponse": { + "type": "object", + "properties": { + "page": { + "type": "integer" + }, + "page_size": { + "type": "integer" + }, + "subscribers": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Subscriber" + } + }, + "total": { + "type": "integer" + } + } + }, + "services.UpdateSubscriberRequest": { + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "first_name": { + "type": "string" + }, + "last_name": { + "type": "string" + }, + "plan_id": { + "type": "integer" + }, + "status": { + "$ref": "#/definitions/models.SubscriberStatus" + } + } + } + } +} \ No newline at end of file diff --git a/apps/api-server/docs/swagger.yaml b/apps/api-server/docs/swagger.yaml new file mode 100644 index 0000000..d5ae082 --- /dev/null +++ b/apps/api-server/docs/swagger.yaml @@ -0,0 +1,500 @@ +definitions: + handlers.ErrorResponse: + properties: + code: + type: string + details: + type: string + error: + type: string + type: object + models.AMBR: + properties: + downlink: + type: integer + uplink: + type: integer + type: object + models.PLMN: + properties: + mcc: + type: string + mnc: + type: string + type: object + models.ProfileStatus: + enum: + - inactive + - active + - downloading + - error + type: string + x-enum-varnames: + - ProfileStatusInactive + - ProfileStatusActive + - ProfileStatusDownloading + - ProfileStatusError + models.QoSProfile: + properties: + arpa: + type: integer + gbr: + $ref: '#/definitions/models.AMBR' + mbr: + $ref: '#/definitions/models.AMBR' + priority: + type: integer + qci: + type: integer + type: object + models.SNSSAI: + properties: + sd: + type: integer + sst: + type: integer + type: object + models.ServicePlan: + properties: + ambr: + $ref: '#/definitions/models.AMBR' + arpa: + type: integer + created_at: + type: string + data_limit: + type: integer + data_rate: + type: number + description: + type: string + id: + type: integer + monthly_fee: + type: number + name: + type: string + sms_limit: + type: integer + sms_rate: + type: number + updated_at: + type: string + voice_limit: + type: integer + voice_rate: + type: number + type: object + models.Session: + properties: + created_at: + type: string + data_used: + type: integer + dnn: + type: string + end_time: + type: string + id: + type: integer + pdu_address: + type: string + qos: + $ref: '#/definitions/models.QoSProfile' + session_id: + type: string + sms_used: + type: integer + snssai: + $ref: '#/definitions/models.SNSSAI' + start_time: + type: string + status: + $ref: '#/definitions/models.SessionStatus' + subscriber_id: + type: integer + updated_at: + type: string + voice_used: + type: integer + type: object + models.SessionStatus: + enum: + - active + - inactive + - terminating + type: string + x-enum-varnames: + - SessionStatusActive + - SessionStatusInactive + - SessionStatusTerminating + models.Subscriber: + properties: + auth_key: + type: string + balance: + type: number + created_at: + type: string + email: + type: string + euicc_id: + type: string + first_name: + type: string + id: + type: integer + imei: + description: Device identifier + type: string + imsi: + type: string + last_name: + type: string + msisdn: + description: Mobile phone number + type: string + opc: + type: string + organization_id: + type: string + plan: + $ref: '#/definitions/models.ServicePlan' + plan_id: + type: integer + profile_id: + type: string + profile_status: + $ref: '#/definitions/models.ProfileStatus' + serving_plmn: + $ref: '#/definitions/models.PLMN' + sessions: + items: + $ref: '#/definitions/models.Session' + type: array + status: + $ref: '#/definitions/models.SubscriberStatus' + updated_at: + type: string + usage_records: + items: + $ref: '#/definitions/models.UsageRecord' + type: array + type: object + models.SubscriberStatus: + enum: + - active + - inactive + - suspended + - terminated + - provisioning + type: string + x-enum-varnames: + - SubscriberStatusActive + - SubscriberStatusInactive + - SubscriberStatusSuspended + - SubscriberStatusTerminated + - SubscriberStatusProvisioning + models.UsageRecord: + properties: + billing_cycle: + type: string + cost: + type: number + created_at: + type: string + end_time: + type: string + id: + type: integer + invoice_id: + type: integer + rate: + type: number + session_id: + type: integer + start_time: + type: string + subscriber_id: + type: integer + updated_at: + type: string + usage_type: + $ref: '#/definitions/models.UsageType' + volume: + type: integer + type: object + models.UsageType: + enum: + - data + - voice + - sms + type: string + x-enum-varnames: + - UsageTypeData + - UsageTypeVoice + - UsageTypeSMS + services.CreateSubscriberRequest: + properties: + email: + type: string + euicc_id: + type: string + first_name: + type: string + last_name: + type: string + msisdn: + type: string + organization_id: + type: string + plan_id: + type: integer + required: + - email + - first_name + - last_name + - msisdn + - plan_id + type: object + services.ListSubscribersResponse: + properties: + page: + type: integer + page_size: + type: integer + subscribers: + items: + $ref: '#/definitions/models.Subscriber' + type: array + total: + type: integer + type: object + services.UpdateSubscriberRequest: + properties: + email: + type: string + first_name: + type: string + last_name: + type: string + plan_id: + type: integer + status: + $ref: '#/definitions/models.SubscriberStatus' + type: object +info: + contact: {} +paths: + /api/v1/subscribers: + get: + description: List subscribers with pagination and filtering + parameters: + - default: 1 + description: Page number + in: query + name: page + type: integer + - default: 20 + description: Page size + in: query + name: page_size + type: integer + - description: Subscriber status + in: query + name: status + type: string + - description: Organization ID + in: query + name: organization_id + type: string + - description: Search term + in: query + name: search + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/services.ListSubscribersResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/handlers.ErrorResponse' + summary: List subscribers + tags: + - subscribers + post: + consumes: + - application/json + description: Create a new subscriber with allocated IMSI + parameters: + - description: Subscriber data + in: body + name: subscriber + required: true + schema: + $ref: '#/definitions/services.CreateSubscriberRequest' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/models.Subscriber' + "400": + description: Bad Request + schema: + $ref: '#/definitions/handlers.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/handlers.ErrorResponse' + summary: Create a new subscriber + tags: + - subscribers + /api/v1/subscribers/{id}: + get: + description: Retrieve subscriber information by ID + parameters: + - description: Subscriber ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.Subscriber' + "404": + description: Not Found + schema: + $ref: '#/definitions/handlers.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/handlers.ErrorResponse' + summary: Get subscriber by ID + tags: + - subscribers + put: + consumes: + - application/json + description: Update subscriber information + parameters: + - description: Subscriber ID + in: path + name: id + required: true + type: integer + - description: Updated subscriber data + in: body + name: subscriber + required: true + schema: + $ref: '#/definitions/services.UpdateSubscriberRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.Subscriber' + "400": + description: Bad Request + schema: + $ref: '#/definitions/handlers.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/handlers.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/handlers.ErrorResponse' + summary: Update subscriber + tags: + - subscribers + /api/v1/subscribers/{id}/suspend: + post: + description: Suspend a subscriber and terminate their sessions + parameters: + - description: Subscriber ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "204": + description: No Content + "404": + description: Not Found + schema: + $ref: '#/definitions/handlers.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/handlers.ErrorResponse' + summary: Suspend subscriber + tags: + - subscribers + /api/v1/subscribers/{id}/terminate: + post: + description: Terminate a subscriber and deactivate their eSIM profile + parameters: + - description: Subscriber ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "204": + description: No Content + "404": + description: Not Found + schema: + $ref: '#/definitions/handlers.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/handlers.ErrorResponse' + summary: Terminate subscriber + tags: + - subscribers + /api/v1/subscribers/imsi/{imsi}: + get: + description: Retrieve subscriber information by IMSI + parameters: + - description: IMSI + in: path + name: imsi + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.Subscriber' + "404": + description: Not Found + schema: + $ref: '#/definitions/handlers.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/handlers.ErrorResponse' + summary: Get subscriber by IMSI + tags: + - subscribers +swagger: "2.0"