diff --git a/storage/api-docs/api-docs.json b/storage/api-docs/api-docs.json new file mode 100755 index 0000000..0a877b0 --- /dev/null +++ b/storage/api-docs/api-docs.json @@ -0,0 +1,773 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Premium Template API", + "description": "Unified API for Mobile and Web Integration. Authenticated endpoints require a Bearer token from POST /v1/login.", + "contact": { + "email": "admin@example.com" + }, + "version": "1.1.0" + }, + "servers": [ + { + "url": "http://localhost:8000/api", + "description": "Local" + }, + { + "url": "https://yourdomain.com/api", + "description": "Production" + } + ], + "paths": { + "/v1/login": { + "post": { + "tags": [ + "Auth" + ], + "summary": "Authenticate a user", + "operationId": "login", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "email", + "password" + ], + "properties": { + "email": { + "type": "string", + "format": "email", + "example": "user@example.com" + }, + "password": { + "type": "string", + "format": "password", + "example": "secret" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Login successful", + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "type": "string", + "example": "success" + }, + "data": { + "properties": { + "user": { + "$ref": "#/components/schemas/User" + }, + "token": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "401": { + "description": "Invalid credentials" + }, + "403": { + "description": "Account inactive or role not permitted" + } + } + } + }, + "/v1/register": { + "post": { + "tags": [ + "Auth" + ], + "summary": "Register a new user", + "operationId": "register", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "name", + "email", + "password" + ], + "properties": { + "name": { + "type": "string", + "example": "John Doe" + }, + "email": { + "type": "string", + "format": "email" + }, + "password": { + "type": "string", + "minLength": 8 + } + }, + "type": "object" + } + } + } + }, + "responses": { + "201": { + "description": "Registration successful" + }, + "422": { + "description": "Validation error" + } + } + } + }, + "/v1/logout": { + "post": { + "tags": [ + "Auth" + ], + "summary": "Revoke current access token", + "operationId": "logout", + "responses": { + "200": { + "description": "Logged out successfully" + }, + "401": { + "description": "Unauthenticated" + } + }, + "security": [ + { + "sanctum": [] + } + ] + } + }, + "/v1/forgot-password": { + "post": { + "tags": [ + "Auth" + ], + "summary": "Send password reset link", + "operationId": "forgotPassword", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "email" + ], + "properties": { + "email": { + "type": "string", + "format": "email" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Reset link sent" + }, + "422": { + "description": "Email not found or throttled" + } + } + } + }, + "/v1/profile/update": { + "post": { + "tags": [ + "Profile" + ], + "summary": "Update authenticated user profile", + "operationId": "updateProfile", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "name", + "email" + ], + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Profile updated" + }, + "422": { + "description": "Validation error" + } + }, + "security": [ + { + "sanctum": [] + } + ] + } + }, + "/v1/profile/avatar": { + "post": { + "tags": [ + "Profile" + ], + "summary": "Upload user avatar", + "operationId": "updateAvatar", + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "properties": { + "avatar": { + "type": "string", + "format": "binary" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Avatar updated" + }, + "422": { + "description": "Validation error" + } + }, + "security": [ + { + "sanctum": [] + } + ] + } + }, + "/v1/dashboard": { + "get": { + "tags": [ + "Dashboard" + ], + "summary": "Get dashboard summary data", + "operationId": "getDashboard", + "responses": { + "200": { + "description": "Dashboard data" + }, + "401": { + "description": "Unauthenticated" + } + }, + "security": [ + { + "sanctum": [] + } + ] + } + }, + "/v1/profile/password": { + "post": { + "tags": [ + "Profile" + ], + "summary": "Change authenticated user password", + "operationId": "updatePassword", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "current_password", + "password", + "password_confirmation" + ], + "properties": { + "current_password": { + "type": "string" + }, + "password": { + "type": "string", + "minLength": 8 + }, + "password_confirmation": { + "type": "string" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Password updated" + }, + "422": { + "description": "Current password incorrect" + } + }, + "security": [ + { + "sanctum": [] + } + ] + } + }, + "/v1/profile/delete": { + "delete": { + "tags": [ + "Profile" + ], + "summary": "Permanently delete authenticated user account", + "operationId": "deleteAccount", + "responses": { + "200": { + "description": "Account deleted" + } + }, + "security": [ + { + "sanctum": [] + } + ] + } + }, + "/v1/user": { + "get": { + "tags": [ + "Auth" + ], + "summary": "Get authenticated user", + "operationId": "getUser", + "responses": { + "200": { + "description": "User object" + }, + "401": { + "description": "Unauthenticated" + } + }, + "security": [ + { + "sanctum": [] + } + ] + } + }, + "/v1/app-config": { + "get": { + "tags": [ + "Config" + ], + "summary": "Get public app configuration (branding, taglines)", + "operationId": "getAppConfig", + "responses": { + "200": { + "description": "App config" + } + } + } + }, + "/v1/devices/register": { + "post": { + "tags": [ + "Push Notifications" + ], + "summary": "Register a device token for push notifications", + "operationId": "registerDevice", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "token", + "platform" + ], + "properties": { + "token": { + "description": "FCM device token", + "type": "string" + }, + "platform": { + "type": "string", + "enum": [ + "ios", + "android", + "web" + ] + }, + "device_name": { + "type": "string", + "nullable": true + }, + "app_version": { + "type": "string", + "nullable": true + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Device registered" + }, + "422": { + "description": "Validation error" + } + }, + "security": [ + { + "sanctum": [] + } + ] + } + }, + "/v1/devices/unregister": { + "delete": { + "tags": [ + "Push Notifications" + ], + "summary": "Remove a device token", + "operationId": "unregisterDevice", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "token" + ], + "properties": { + "token": { + "type": "string" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "Device unregistered" + } + }, + "security": [ + { + "sanctum": [] + } + ] + } + }, + "/health": { + "get": { + "tags": [ + "System" + ], + "summary": "Application health check", + "description": "Returns status of database, Redis, storage, and queue. Returns 503 if any check fails.", + "operationId": "healthCheck", + "responses": { + "200": { + "description": "All systems healthy", + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "type": "string", + "example": "healthy" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "checks": { + "type": "object" + } + }, + "type": "object" + } + } + } + }, + "503": { + "description": "One or more checks degraded" + } + } + } + }, + "/mobile/sync": { + "get": { + "tags": [ + "Mobile" + ], + "summary": "Get mobile app configuration", + "description": "Returns cached mobile configuration including theme, flags, and assets.", + "operationId": "getMobileConfig", + "parameters": [ + { + "name": "p", + "in": "query", + "description": "Platform (ios/android)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "v", + "in": "query", + "description": "App Version", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "properties": { + "status": { + "type": "string", + "example": "success" + }, + "version": { + "type": "string", + "example": "1.1.0" + }, + "data": { + "type": "object" + } + }, + "type": "object" + } + } + } + } + } + } + }, + "/v1/otp/send": { + "post": { + "tags": [ + "OTP" + ], + "summary": "Send a 6-digit OTP to the given email", + "operationId": "otpSend", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "email" + ], + "properties": { + "email": { + "type": "string", + "format": "email" + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "OTP sent" + }, + "500": { + "description": "Mail delivery failed" + } + } + } + }, + "/v1/otp/verify": { + "post": { + "tags": [ + "OTP" + ], + "summary": "Verify an OTP code", + "operationId": "otpVerify", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "required": [ + "email", + "code" + ], + "properties": { + "email": { + "type": "string", + "format": "email" + }, + "code": { + "type": "string", + "example": "123456", + "maxLength": 6, + "minLength": 6 + } + }, + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "OTP verified" + }, + "422": { + "description": "Invalid or expired OTP" + } + } + } + } + }, + "components": { + "schemas": { + "User": { + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + }, + "is_active": { + "type": "boolean" + }, + "created_at": { + "type": "string", + "format": "date-time" + } + }, + "type": "object" + }, + "ApiSuccess": { + "properties": { + "status": { + "type": "string", + "example": "success" + }, + "message": { + "type": "string" + }, + "data": { + "type": "object", + "nullable": true + } + }, + "type": "object" + }, + "ApiError": { + "properties": { + "status": { + "type": "string", + "example": "error" + }, + "message": { + "type": "string" + }, + "errors": { + "type": "object", + "nullable": true + } + }, + "type": "object" + } + }, + "securitySchemes": { + "sanctum": { + "type": "http", + "description": "Enter the token returned by POST /v1/login", + "bearerFormat": "Token", + "scheme": "bearer" + } + } + }, + "tags": [ + { + "name": "Auth", + "description": "Auth" + }, + { + "name": "Profile", + "description": "Profile" + }, + { + "name": "Dashboard", + "description": "Dashboard" + }, + { + "name": "Config", + "description": "Config" + }, + { + "name": "Push Notifications", + "description": "Push Notifications" + }, + { + "name": "System", + "description": "System" + }, + { + "name": "Mobile", + "description": "Mobile" + }, + { + "name": "OTP", + "description": "OTP" + } + ] +} \ No newline at end of file diff --git a/storage/app/.gitignore b/storage/app/.gitignore new file mode 100755 index 0000000..fedb287 --- /dev/null +++ b/storage/app/.gitignore @@ -0,0 +1,4 @@ +* +!private/ +!public/ +!.gitignore diff --git a/storage/app/private/.gitignore b/storage/app/private/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/app/private/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/.gitignore b/storage/framework/.gitignore new file mode 100755 index 0000000..05c4471 --- /dev/null +++ b/storage/framework/.gitignore @@ -0,0 +1,9 @@ +compiled.php +config.php +down +events.scanned.php +maintenance.php +routes.php +routes.scanned.php +schedule-* +services.json diff --git a/storage/framework/cache/.gitignore b/storage/framework/cache/.gitignore new file mode 100755 index 0000000..01e4a6c --- /dev/null +++ b/storage/framework/cache/.gitignore @@ -0,0 +1,3 @@ +* +!data/ +!.gitignore diff --git a/storage/framework/cache/data/.gitignore b/storage/framework/cache/data/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/cache/data/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/sessions/.gitignore b/storage/framework/sessions/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/sessions/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/testing/.gitignore b/storage/framework/testing/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/testing/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/views/.gitignore b/storage/framework/views/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/views/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/logs/.gitignore b/storage/logs/.gitignore new file mode 100755 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore