diff --git a/apps/docs/.gitignore b/apps/docs/.gitignore index 55a12ae..9e429e4 100644 --- a/apps/docs/.gitignore +++ b/apps/docs/.gitignore @@ -2,8 +2,6 @@ /node_modules # generated content -.contentlayer -.content-collections .source # test & build diff --git a/apps/docs/README.md b/apps/docs/README.md index a923f4d..abc0d6f 100644 --- a/apps/docs/README.md +++ b/apps/docs/README.md @@ -1,26 +1,121 @@ -# docs-v2 +# Dokploy Documentation (New) -This is a Next.js application generated with -[Create Fumadocs](https://github.com/fuma-nama/fumadocs). +This is a fresh Fumadocs project with the complete Dokploy documentation migrated from the old docs project. -Run development server: +## Features + +- ✨ **Modern Fumadocs Setup** - Built with the latest Fumadocs version +- 🎨 **Ocean Theme** - Beautiful ocean-themed UI +- 📱 **Responsive Design** - Works perfectly on all devices +- 🔍 **Advanced Search** - Built-in search functionality +- 🌙 **Dark Mode** - Full dark mode support +- 📚 **Complete Documentation** - All docs migrated including: + - Core documentation + - API references + - CLI documentation + - Remote Servers section + - Examples and tutorials + +## Getting Started + +### Development + +Run the development server: ```bash -npm run dev -# or +# From workspace root +pnpm docs-new:dev + +# Or from this directory pnpm dev -# or -yarn dev ``` -Open http://localhost:3000 with your browser to see the result. +The site will be available at `http://localhost:3000` -## Learn More +### Build -To learn more about Next.js and Fumadocs, take a look at the following -resources: +Build the documentation for production: -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js - features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. -- [Fumadocs](https://fumadocs.vercel.app) - learn about Fumadocs +```bash +# From workspace root +pnpm docs-new:build + +# Or from this directory +pnpm build +``` + +### Type Checking + +Run type checking: + +```bash +# From workspace root +pnpm docs-new:typecheck + +# Or from this directory +pnpm run types:check +``` + +## Structure + +``` +apps/docs-new/ +├── app/ # Next.js app directory +│ ├── (home)/ # Home page +│ ├── docs/ # Documentation pages +│ │ ├── [[...slug]]/ # Dynamic doc pages +│ │ └── layout.tsx # Docs layout +│ ├── api/ # API routes +│ └── layout.tsx # Root layout +├── content/ # MDX documentation content +│ └── docs/ # All documentation files +├── lib/ # Utilities +│ ├── source.ts # Content source configuration +│ └── layout.shared.tsx # Shared layout options +├── public/ # Static assets +└── source.config.ts # Fumadocs configuration +``` + +## Customization + +### Theme + +The project uses the **Ocean theme**. To change it, edit `app/global.css`: + +```css +@import 'fumadocs-ui/css/ocean.css'; /* Change this to another theme */ +``` + +Available themes: `neutral`, `black`, `vitepress`, `dusk`, `catppuccin`, `ocean`, `purple` + +### Layout Configuration + +Edit `lib/layout.shared.tsx` to customize: +- Navigation title +- Links +- GitHub URL +- Other layout options + +### Content + +Add or edit documentation in the `content/docs/` directory. The structure follows Fumadocs conventions with `meta.json` files for navigation. + +## Key Differences from Old Docs + +1. **Modern API** - Uses `fumadocs-mdx:collections/server` instead of legacy approach +2. **Better Type Safety** - Full TypeScript support with proper types +3. **Simpler Configuration** - Less boilerplate, more conventions +4. **Built-in Features** - Search, OG images, and more work out of the box +5. **No Build Errors** - Clean slate without legacy issues + +## Documentation + +- [Fumadocs Documentation](https://fumadocs.dev) +- [Fumadocs Themes](https://fumadocs.dev/docs/ui/theme) +- [Fumadocs Layouts](https://fumadocs.dev/docs/ui/blocks/layout) + +## Notes + +- The `.source` directory is auto-generated - don't edit it manually +- Run `pnpm run postinstall` after making changes to content structure +- Restart dev server after adding new MDX files diff --git a/apps/docs/api.json b/apps/docs/api.json deleted file mode 100644 index 62e798a..0000000 --- a/apps/docs/api.json +++ /dev/null @@ -1,12690 +0,0 @@ -{ - "openapi": "3.0.3", - "info": { - "title": "Dokploy API", - "description": "Endpoints for dokploy", - "version": "1.0.0" - }, - "servers": [ - { - "url": "http://your-dokploy-instance.com/api" - } - ], - "paths": { - "/admin.one": { - "get": { - "operationId": "admin-one", - "tags": ["admin"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/admin.createUserInvitation": { - "post": { - "operationId": "admin-createUserInvitation", - "tags": ["admin"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email" - } - }, - "required": ["email"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/admin.removeUser": { - "post": { - "operationId": "admin-removeUser", - "tags": ["admin"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "authId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["authId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/admin.getUserByToken": { - "get": { - "operationId": "admin-getUserByToken", - "tags": ["admin"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "token", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/admin.assignPermissions": { - "post": { - "operationId": "admin-assignPermissions", - "tags": ["admin"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "userId": { - "type": "string", - "minLength": 1 - }, - "canCreateProjects": { - "type": "boolean" - }, - "canCreateServices": { - "type": "boolean" - }, - "canDeleteProjects": { - "type": "boolean" - }, - "canDeleteServices": { - "type": "boolean" - }, - "accesedProjects": { - "type": "array", - "items": { - "type": "string" - } - }, - "accesedServices": { - "type": "array", - "items": { - "type": "string" - } - }, - "canAccessToTraefikFiles": { - "type": "boolean" - }, - "canAccessToDocker": { - "type": "boolean" - }, - "canAccessToAPI": { - "type": "boolean" - }, - "canAccessToSSHKeys": { - "type": "boolean" - }, - "canAccessToGitProviders": { - "type": "boolean" - } - }, - "required": [ - "userId", - "canCreateProjects", - "canCreateServices", - "canDeleteProjects", - "canDeleteServices", - "accesedProjects", - "accesedServices", - "canAccessToTraefikFiles", - "canAccessToDocker", - "canAccessToAPI", - "canAccessToSSHKeys", - "canAccessToGitProviders" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/docker.getContainers": { - "get": { - "operationId": "docker-getContainers", - "tags": ["docker"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "serverId", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/docker.restartContainer": { - "post": { - "operationId": "docker-restartContainer", - "tags": ["docker"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "containerId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["containerId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/docker.getConfig": { - "get": { - "operationId": "docker-getConfig", - "tags": ["docker"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "containerId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - }, - { - "name": "serverId", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/docker.getContainersByAppNameMatch": { - "get": { - "operationId": "docker-getContainersByAppNameMatch", - "tags": ["docker"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "appType", - "in": "query", - "required": false, - "schema": { - "anyOf": [ - { - "type": "string", - "enum": ["stack"] - }, - { - "type": "string", - "enum": ["docker-compose"] - } - ] - } - }, - { - "name": "appName", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - }, - { - "name": "serverId", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/docker.getContainersByAppLabel": { - "get": { - "operationId": "docker-getContainersByAppLabel", - "tags": ["docker"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "appName", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - }, - { - "name": "serverId", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.createAdmin": { - "post": { - "operationId": "auth-createAdmin", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email" - }, - "password": { - "type": "string", - "minLength": 8 - } - }, - "required": ["email", "password"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.createUser": { - "post": { - "operationId": "auth-createUser", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "password": { - "type": "string", - "minLength": 8 - }, - "id": { - "type": "string" - }, - "token": { - "type": "string", - "minLength": 1 - } - }, - "required": ["password", "id", "token"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.login": { - "post": { - "operationId": "auth-login", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email" - }, - "password": { - "type": "string", - "minLength": 8 - } - }, - "required": ["email", "password"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.get": { - "get": { - "operationId": "auth-get", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.logout": { - "post": { - "operationId": "auth-logout", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.update": { - "post": { - "operationId": "auth-update", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "email": { - "type": "string", - "nullable": true - }, - "password": { - "type": "string", - "nullable": true - }, - "rol": { - "type": "string", - "enum": ["admin", "user"] - }, - "image": { - "type": "string" - }, - "secret": { - "type": "string", - "nullable": true - }, - "token": { - "type": "string", - "nullable": true - }, - "is2FAEnabled": { - "type": "boolean" - }, - "createdAt": { - "type": "string" - }, - "resetPasswordToken": { - "type": "string", - "nullable": true - }, - "resetPasswordExpiresAt": { - "type": "string", - "nullable": true - }, - "confirmationToken": { - "type": "string", - "nullable": true - }, - "confirmationExpiresAt": { - "type": "string", - "nullable": true - } - }, - "required": ["email", "password"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.generateToken": { - "post": { - "operationId": "auth-generateToken", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.one": { - "get": { - "operationId": "auth-one", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.generate2FASecret": { - "get": { - "operationId": "auth-generate2FASecret", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.verify2FASetup": { - "post": { - "operationId": "auth-verify2FASetup", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "pin": { - "type": "string", - "minLength": 6 - }, - "secret": { - "type": "string", - "minLength": 1 - } - }, - "required": ["pin", "secret"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.verifyLogin2FA": { - "post": { - "operationId": "auth-verifyLogin2FA", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "pin": { - "type": "string", - "minLength": 6 - }, - "id": { - "type": "string" - } - }, - "required": ["pin", "id"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.disable2FA": { - "post": { - "operationId": "auth-disable2FA", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.sendResetPasswordEmail": { - "post": { - "operationId": "auth-sendResetPasswordEmail", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "email": { - "type": "string", - "minLength": 1, - "format": "email" - } - }, - "required": ["email"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.resetPassword": { - "post": { - "operationId": "auth-resetPassword", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "resetPasswordToken": { - "type": "string", - "minLength": 1 - }, - "password": { - "type": "string", - "minLength": 1 - } - }, - "required": ["resetPasswordToken", "password"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/auth.confirmEmail": { - "post": { - "operationId": "auth-confirmEmail", - "tags": ["auth"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "confirmationToken": { - "type": "string", - "minLength": 1 - } - }, - "required": ["confirmationToken"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/project.create": { - "post": { - "operationId": "project-create", - "tags": ["project"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "nullable": true - } - }, - "required": ["name"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/project.one": { - "get": { - "operationId": "project-one", - "tags": ["project"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "projectId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/project.all": { - "get": { - "operationId": "project-all", - "tags": ["project"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/project.remove": { - "post": { - "operationId": "project-remove", - "tags": ["project"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "projectId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["projectId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/project.update": { - "post": { - "operationId": "project-update", - "tags": ["project"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "nullable": true - }, - "projectId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["name", "projectId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.create": { - "post": { - "operationId": "application-create", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "appName": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "projectId": { - "type": "string" - }, - "serverId": { - "type": "string", - "nullable": true - } - }, - "required": ["name", "projectId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.one": { - "get": { - "operationId": "application-one", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "applicationId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.reload": { - "post": { - "operationId": "application-reload", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "appName": { - "type": "string" - }, - "applicationId": { - "type": "string" - } - }, - "required": ["appName", "applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.delete": { - "post": { - "operationId": "application-delete", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - } - }, - "required": ["applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.stop": { - "post": { - "operationId": "application-stop", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - } - }, - "required": ["applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.start": { - "post": { - "operationId": "application-start", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - } - }, - "required": ["applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.redeploy": { - "post": { - "operationId": "application-redeploy", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - } - }, - "required": ["applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.saveEnvironment": { - "post": { - "operationId": "application-saveEnvironment", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - }, - "env": { - "type": "string", - "nullable": true - }, - "buildArgs": { - "type": "string", - "nullable": true - } - }, - "required": ["applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.saveBuildType": { - "post": { - "operationId": "application-saveBuildType", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - }, - "buildType": { - "type": "string", - "enum": [ - "dockerfile", - "heroku_buildpacks", - "paketo_buildpacks", - "nixpacks", - "static" - ] - }, - "dockerfile": { - "type": "string", - "nullable": true - }, - "dockerContextPath": { - "type": "string", - "nullable": true - }, - "dockerBuildStage": { - "type": "string", - "nullable": true - }, - "publishDirectory": { - "type": "string", - "nullable": true - } - }, - "required": [ - "applicationId", - "buildType", - "dockerContextPath", - "dockerBuildStage" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.saveGithubProvider": { - "post": { - "operationId": "application-saveGithubProvider", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - }, - "repository": { - "type": "string", - "nullable": true - }, - "branch": { - "type": "string", - "nullable": true - }, - "owner": { - "type": "string", - "nullable": true - }, - "buildPath": { - "type": "string", - "nullable": true - }, - "githubId": { - "type": "string", - "nullable": true - } - }, - "required": ["applicationId", "owner", "githubId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.saveGitlabProvider": { - "post": { - "operationId": "application-saveGitlabProvider", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - }, - "gitlabBranch": { - "type": "string", - "nullable": true - }, - "gitlabBuildPath": { - "type": "string", - "nullable": true - }, - "gitlabOwner": { - "type": "string", - "nullable": true - }, - "gitlabRepository": { - "type": "string", - "nullable": true - }, - "gitlabId": { - "type": "string", - "nullable": true - }, - "gitlabProjectId": { - "type": "number", - "nullable": true - }, - "gitlabPathNamespace": { - "type": "string", - "nullable": true - } - }, - "required": [ - "applicationId", - "gitlabBranch", - "gitlabBuildPath", - "gitlabOwner", - "gitlabRepository", - "gitlabId", - "gitlabProjectId", - "gitlabPathNamespace" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.saveBitbucketProvider": { - "post": { - "operationId": "application-saveBitbucketProvider", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "bitbucketBranch": { - "type": "string", - "nullable": true - }, - "bitbucketBuildPath": { - "type": "string", - "nullable": true - }, - "bitbucketOwner": { - "type": "string", - "nullable": true - }, - "bitbucketRepository": { - "type": "string", - "nullable": true - }, - "bitbucketId": { - "type": "string", - "nullable": true - }, - "applicationId": { - "type": "string" - } - }, - "required": [ - "bitbucketBranch", - "bitbucketBuildPath", - "bitbucketOwner", - "bitbucketRepository", - "bitbucketId", - "applicationId" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.saveDockerProvider": { - "post": { - "operationId": "application-saveDockerProvider", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "dockerImage": { - "type": "string", - "nullable": true - }, - "applicationId": { - "type": "string" - }, - "username": { - "type": "string", - "nullable": true - }, - "password": { - "type": "string", - "nullable": true - } - }, - "required": ["applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.saveGitProdiver": { - "post": { - "operationId": "application-saveGitProdiver", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "customGitBranch": { - "type": "string", - "nullable": true - }, - "applicationId": { - "type": "string" - }, - "customGitBuildPath": { - "type": "string", - "nullable": true - }, - "customGitUrl": { - "type": "string", - "nullable": true - }, - "customGitSSHKeyId": { - "type": "string", - "nullable": true - } - }, - "required": ["applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.markRunning": { - "post": { - "operationId": "application-markRunning", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - } - }, - "required": ["applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.update": { - "post": { - "operationId": "application-update", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string", - "minLength": 1 - }, - "name": { - "type": "string", - "minLength": 1 - }, - "appName": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "env": { - "type": "string", - "nullable": true - }, - "buildArgs": { - "type": "string", - "nullable": true - }, - "memoryReservation": { - "type": "number", - "nullable": true - }, - "memoryLimit": { - "type": "number", - "nullable": true - }, - "cpuReservation": { - "type": "number", - "nullable": true - }, - "cpuLimit": { - "type": "number", - "nullable": true - }, - "title": { - "type": "string", - "nullable": true - }, - "enabled": { - "type": "boolean", - "nullable": true - }, - "subtitle": { - "type": "string", - "nullable": true - }, - "command": { - "type": "string", - "nullable": true - }, - "refreshToken": { - "type": "string", - "nullable": true - }, - "sourceType": { - "type": "string", - "enum": ["github", "docker", "git"] - }, - "repository": { - "type": "string", - "nullable": true - }, - "owner": { - "type": "string", - "nullable": true - }, - "branch": { - "type": "string", - "nullable": true - }, - "buildPath": { - "type": "string", - "nullable": true - }, - "autoDeploy": { - "type": "boolean", - "nullable": true - }, - "gitlabProjectId": { - "type": "number", - "nullable": true - }, - "gitlabRepository": { - "type": "string", - "nullable": true - }, - "gitlabOwner": { - "type": "string", - "nullable": true - }, - "gitlabBranch": { - "type": "string", - "nullable": true - }, - "gitlabBuildPath": { - "type": "string", - "nullable": true - }, - "gitlabPathNamespace": { - "type": "string", - "nullable": true - }, - "bitbucketRepository": { - "type": "string", - "nullable": true - }, - "bitbucketOwner": { - "type": "string", - "nullable": true - }, - "bitbucketBranch": { - "type": "string", - "nullable": true - }, - "bitbucketBuildPath": { - "type": "string", - "nullable": true - }, - "username": { - "type": "string", - "nullable": true - }, - "password": { - "type": "string", - "nullable": true - }, - "dockerImage": { - "type": "string", - "nullable": true - }, - "customGitUrl": { - "type": "string", - "nullable": true - }, - "customGitBranch": { - "type": "string", - "nullable": true - }, - "customGitBuildPath": { - "type": "string", - "nullable": true - }, - "customGitSSHKeyId": { - "type": "string", - "nullable": true - }, - "dockerfile": { - "type": "string", - "nullable": true - }, - "dockerContextPath": { - "type": "string", - "nullable": true - }, - "dockerBuildStage": { - "type": "string", - "nullable": true - }, - "dropBuildPath": { - "type": "string", - "nullable": true - }, - "healthCheckSwarm": { - "type": "object", - "properties": { - "Test": { - "type": "array", - "items": { - "type": "string" - } - }, - "Interval": { - "type": "number" - }, - "Timeout": { - "type": "number" - }, - "StartPeriod": { - "type": "number" - }, - "Retries": { - "type": "number" - } - }, - "additionalProperties": false, - "nullable": true - }, - "restartPolicySwarm": { - "type": "object", - "properties": { - "Condition": { - "type": "string" - }, - "Delay": { - "type": "number" - }, - "MaxAttempts": { - "type": "number" - }, - "Window": { - "type": "number" - } - }, - "additionalProperties": false, - "nullable": true - }, - "placementSwarm": { - "type": "object", - "properties": { - "Constraints": { - "type": "array", - "items": { - "type": "string" - } - }, - "Preferences": { - "type": "array", - "items": { - "type": "object", - "properties": { - "Spread": { - "type": "object", - "properties": { - "SpreadDescriptor": { - "type": "string" - } - }, - "required": ["SpreadDescriptor"], - "additionalProperties": false - } - }, - "required": ["Spread"], - "additionalProperties": false - } - }, - "MaxReplicas": { - "type": "number" - }, - "Platforms": { - "type": "array", - "items": { - "type": "object", - "properties": { - "Architecture": { - "type": "string" - }, - "OS": { - "type": "string" - } - }, - "required": ["Architecture", "OS"], - "additionalProperties": false - } - } - }, - "additionalProperties": false, - "nullable": true - }, - "updateConfigSwarm": { - "type": "object", - "properties": { - "Parallelism": { - "type": "number" - }, - "Delay": { - "type": "number" - }, - "FailureAction": { - "type": "string" - }, - "Monitor": { - "type": "number" - }, - "MaxFailureRatio": { - "type": "number" - }, - "Order": { - "type": "string" - } - }, - "required": ["Parallelism", "Order"], - "additionalProperties": false, - "nullable": true - }, - "rollbackConfigSwarm": { - "type": "object", - "properties": { - "Parallelism": { - "type": "number" - }, - "Delay": { - "type": "number" - }, - "FailureAction": { - "type": "string" - }, - "Monitor": { - "type": "number" - }, - "MaxFailureRatio": { - "type": "number" - }, - "Order": { - "type": "string" - } - }, - "required": ["Parallelism", "Order"], - "additionalProperties": false, - "nullable": true - }, - "modeSwarm": { - "type": "object", - "properties": { - "Replicated": { - "type": "object", - "properties": { - "Replicas": { - "type": "number" - } - }, - "additionalProperties": false - }, - "Global": { - "type": "object", - "properties": {}, - "additionalProperties": false - }, - "ReplicatedJob": { - "type": "object", - "properties": { - "MaxConcurrent": { - "type": "number" - }, - "TotalCompletions": { - "type": "number" - } - }, - "additionalProperties": false - }, - "GlobalJob": { - "type": "object", - "properties": {}, - "additionalProperties": false - } - }, - "additionalProperties": false, - "nullable": true - }, - "labelsSwarm": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "nullable": true - }, - "networkSwarm": { - "type": "array", - "items": { - "type": "object", - "properties": { - "Target": { - "type": "string" - }, - "Aliases": { - "type": "array", - "items": { - "type": "string" - } - }, - "DriverOpts": { - "type": "object", - "properties": {}, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - "nullable": true - }, - "replicas": { - "type": "number" - }, - "applicationStatus": { - "type": "string", - "enum": ["idle", "running", "done", "error"] - }, - "buildType": { - "type": "string", - "enum": [ - "dockerfile", - "heroku_buildpacks", - "paketo_buildpacks", - "nixpacks", - "static" - ] - }, - "publishDirectory": { - "type": "string", - "nullable": true - }, - "createdAt": { - "type": "string" - }, - "registryId": { - "type": "string", - "nullable": true - }, - "projectId": { - "type": "string" - }, - "githubId": { - "type": "string", - "nullable": true - }, - "gitlabId": { - "type": "string", - "nullable": true - }, - "bitbucketId": { - "type": "string", - "nullable": true - } - }, - "required": ["applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.refreshToken": { - "post": { - "operationId": "application-refreshToken", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - } - }, - "required": ["applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.deploy": { - "post": { - "operationId": "application-deploy", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - } - }, - "required": ["applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.cleanQueues": { - "post": { - "operationId": "application-cleanQueues", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - } - }, - "required": ["applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.readTraefikConfig": { - "get": { - "operationId": "application-readTraefikConfig", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "applicationId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.updateTraefikConfig": { - "post": { - "operationId": "application-updateTraefikConfig", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - }, - "traefikConfig": { - "type": "string" - } - }, - "required": ["applicationId", "traefikConfig"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/application.readAppMonitoring": { - "get": { - "operationId": "application-readAppMonitoring", - "tags": ["application"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "appName", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mysql.create": { - "post": { - "operationId": "mysql-create", - "tags": ["mysql"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "appName": { - "type": "string", - "minLength": 1 - }, - "dockerImage": { - "type": "string", - "default": "mysql:8" - }, - "projectId": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "databaseName": { - "type": "string", - "minLength": 1 - }, - "databaseUser": { - "type": "string", - "minLength": 1 - }, - "databasePassword": { - "type": "string" - }, - "databaseRootPassword": { - "type": "string" - }, - "serverId": { - "type": "string", - "nullable": true - } - }, - "required": [ - "name", - "appName", - "projectId", - "databaseName", - "databaseUser", - "databasePassword", - "databaseRootPassword" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mysql.one": { - "get": { - "operationId": "mysql-one", - "tags": ["mysql"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "mysqlId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mysql.start": { - "post": { - "operationId": "mysql-start", - "tags": ["mysql"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mysqlId": { - "type": "string" - } - }, - "required": ["mysqlId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mysql.stop": { - "post": { - "operationId": "mysql-stop", - "tags": ["mysql"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mysqlId": { - "type": "string" - } - }, - "required": ["mysqlId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mysql.saveExternalPort": { - "post": { - "operationId": "mysql-saveExternalPort", - "tags": ["mysql"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mysqlId": { - "type": "string" - }, - "externalPort": { - "type": "number", - "nullable": true - } - }, - "required": ["mysqlId", "externalPort"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mysql.deploy": { - "post": { - "operationId": "mysql-deploy", - "tags": ["mysql"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mysqlId": { - "type": "string" - } - }, - "required": ["mysqlId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mysql.changeStatus": { - "post": { - "operationId": "mysql-changeStatus", - "tags": ["mysql"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mysqlId": { - "type": "string" - }, - "applicationStatus": { - "type": "string", - "enum": ["idle", "running", "done", "error"] - } - }, - "required": ["mysqlId", "applicationStatus"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mysql.reload": { - "post": { - "operationId": "mysql-reload", - "tags": ["mysql"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mysqlId": { - "type": "string" - }, - "appName": { - "type": "string", - "minLength": 1 - } - }, - "required": ["mysqlId", "appName"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mysql.remove": { - "post": { - "operationId": "mysql-remove", - "tags": ["mysql"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mysqlId": { - "type": "string" - } - }, - "required": ["mysqlId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mysql.saveEnvironment": { - "post": { - "operationId": "mysql-saveEnvironment", - "tags": ["mysql"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mysqlId": { - "type": "string" - }, - "env": { - "type": "string", - "nullable": true - } - }, - "required": ["mysqlId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mysql.update": { - "post": { - "operationId": "mysql-update", - "tags": ["mysql"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mysqlId": { - "type": "string", - "minLength": 1 - }, - "name": { - "type": "string", - "minLength": 1 - }, - "appName": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "nullable": true - }, - "databaseName": { - "type": "string", - "minLength": 1 - }, - "databaseUser": { - "type": "string", - "minLength": 1 - }, - "databasePassword": { - "type": "string" - }, - "databaseRootPassword": { - "type": "string" - }, - "dockerImage": { - "type": "string", - "default": "mysql:8" - }, - "command": { - "type": "string", - "nullable": true - }, - "env": { - "type": "string", - "nullable": true - }, - "memoryReservation": { - "type": "number", - "nullable": true - }, - "memoryLimit": { - "type": "number", - "nullable": true - }, - "cpuReservation": { - "type": "number", - "nullable": true - }, - "cpuLimit": { - "type": "number", - "nullable": true - }, - "externalPort": { - "type": "number", - "nullable": true - }, - "applicationStatus": { - "type": "string", - "enum": ["idle", "running", "done", "error"] - }, - "createdAt": { - "type": "string" - }, - "projectId": { - "type": "string" - } - }, - "required": ["mysqlId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/postgres.create": { - "post": { - "operationId": "postgres-create", - "tags": ["postgres"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "appName": { - "type": "string" - }, - "databaseName": { - "type": "string", - "minLength": 1 - }, - "databaseUser": { - "type": "string", - "minLength": 1 - }, - "databasePassword": { - "type": "string" - }, - "dockerImage": { - "type": "string", - "default": "postgres:15" - }, - "projectId": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "serverId": { - "type": "string", - "nullable": true - } - }, - "required": [ - "name", - "appName", - "databaseName", - "databaseUser", - "databasePassword", - "projectId" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/postgres.one": { - "get": { - "operationId": "postgres-one", - "tags": ["postgres"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "postgresId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/postgres.start": { - "post": { - "operationId": "postgres-start", - "tags": ["postgres"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "postgresId": { - "type": "string" - } - }, - "required": ["postgresId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/postgres.stop": { - "post": { - "operationId": "postgres-stop", - "tags": ["postgres"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "postgresId": { - "type": "string" - } - }, - "required": ["postgresId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/postgres.saveExternalPort": { - "post": { - "operationId": "postgres-saveExternalPort", - "tags": ["postgres"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "postgresId": { - "type": "string" - }, - "externalPort": { - "type": "number", - "nullable": true - } - }, - "required": ["postgresId", "externalPort"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/postgres.deploy": { - "post": { - "operationId": "postgres-deploy", - "tags": ["postgres"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "postgresId": { - "type": "string" - } - }, - "required": ["postgresId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/postgres.changeStatus": { - "post": { - "operationId": "postgres-changeStatus", - "tags": ["postgres"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "postgresId": { - "type": "string" - }, - "applicationStatus": { - "type": "string", - "enum": ["idle", "running", "done", "error"] - } - }, - "required": ["postgresId", "applicationStatus"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/postgres.remove": { - "post": { - "operationId": "postgres-remove", - "tags": ["postgres"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "postgresId": { - "type": "string" - } - }, - "required": ["postgresId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/postgres.saveEnvironment": { - "post": { - "operationId": "postgres-saveEnvironment", - "tags": ["postgres"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "postgresId": { - "type": "string" - }, - "env": { - "type": "string", - "nullable": true - } - }, - "required": ["postgresId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/postgres.reload": { - "post": { - "operationId": "postgres-reload", - "tags": ["postgres"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "postgresId": { - "type": "string" - }, - "appName": { - "type": "string" - } - }, - "required": ["postgresId", "appName"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/postgres.update": { - "post": { - "operationId": "postgres-update", - "tags": ["postgres"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "postgresId": { - "type": "string", - "minLength": 1 - }, - "name": { - "type": "string", - "minLength": 1 - }, - "appName": { - "type": "string" - }, - "databaseName": { - "type": "string", - "minLength": 1 - }, - "databaseUser": { - "type": "string", - "minLength": 1 - }, - "databasePassword": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "dockerImage": { - "type": "string", - "default": "postgres:15" - }, - "command": { - "type": "string", - "nullable": true - }, - "env": { - "type": "string", - "nullable": true - }, - "memoryReservation": { - "type": "number", - "nullable": true - }, - "externalPort": { - "type": "number", - "nullable": true - }, - "memoryLimit": { - "type": "number", - "nullable": true - }, - "cpuReservation": { - "type": "number", - "nullable": true - }, - "cpuLimit": { - "type": "number", - "nullable": true - }, - "applicationStatus": { - "type": "string", - "enum": ["idle", "running", "done", "error"] - }, - "createdAt": { - "type": "string" - }, - "projectId": { - "type": "string" - } - }, - "required": ["postgresId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redis.create": { - "post": { - "operationId": "redis-create", - "tags": ["redis"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "appName": { - "type": "string", - "minLength": 1 - }, - "databasePassword": { - "type": "string" - }, - "dockerImage": { - "type": "string", - "default": "redis:8" - }, - "projectId": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "serverId": { - "type": "string", - "nullable": true - } - }, - "required": [ - "name", - "appName", - "databasePassword", - "projectId" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redis.one": { - "get": { - "operationId": "redis-one", - "tags": ["redis"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "redisId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redis.start": { - "post": { - "operationId": "redis-start", - "tags": ["redis"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "redisId": { - "type": "string" - } - }, - "required": ["redisId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redis.reload": { - "post": { - "operationId": "redis-reload", - "tags": ["redis"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "redisId": { - "type": "string" - }, - "appName": { - "type": "string", - "minLength": 1 - } - }, - "required": ["redisId", "appName"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redis.stop": { - "post": { - "operationId": "redis-stop", - "tags": ["redis"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "redisId": { - "type": "string" - } - }, - "required": ["redisId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redis.saveExternalPort": { - "post": { - "operationId": "redis-saveExternalPort", - "tags": ["redis"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "redisId": { - "type": "string" - }, - "externalPort": { - "type": "number", - "nullable": true - } - }, - "required": ["redisId", "externalPort"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redis.deploy": { - "post": { - "operationId": "redis-deploy", - "tags": ["redis"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "redisId": { - "type": "string" - } - }, - "required": ["redisId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redis.changeStatus": { - "post": { - "operationId": "redis-changeStatus", - "tags": ["redis"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "redisId": { - "type": "string" - }, - "applicationStatus": { - "type": "string", - "enum": ["idle", "running", "done", "error"] - } - }, - "required": ["redisId", "applicationStatus"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redis.remove": { - "post": { - "operationId": "redis-remove", - "tags": ["redis"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "redisId": { - "type": "string" - } - }, - "required": ["redisId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redis.saveEnvironment": { - "post": { - "operationId": "redis-saveEnvironment", - "tags": ["redis"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "redisId": { - "type": "string" - }, - "env": { - "type": "string", - "nullable": true - } - }, - "required": ["redisId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redis.update": { - "post": { - "operationId": "redis-update", - "tags": ["redis"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "redisId": { - "type": "string", - "minLength": 1 - }, - "name": { - "type": "string", - "minLength": 1 - }, - "appName": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "nullable": true - }, - "databasePassword": { - "type": "string" - }, - "dockerImage": { - "type": "string", - "default": "redis:8" - }, - "command": { - "type": "string", - "nullable": true - }, - "env": { - "type": "string", - "nullable": true - }, - "memoryReservation": { - "type": "number", - "nullable": true - }, - "memoryLimit": { - "type": "number", - "nullable": true - }, - "cpuReservation": { - "type": "number", - "nullable": true - }, - "cpuLimit": { - "type": "number", - "nullable": true - }, - "externalPort": { - "type": "number", - "nullable": true - }, - "createdAt": { - "type": "string" - }, - "applicationStatus": { - "type": "string", - "enum": ["idle", "running", "done", "error"] - }, - "projectId": { - "type": "string" - } - }, - "required": ["redisId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mongo.create": { - "post": { - "operationId": "mongo-create", - "tags": ["mongo"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "appName": { - "type": "string", - "minLength": 1 - }, - "dockerImage": { - "type": "string", - "default": "mongo:15" - }, - "projectId": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "databaseUser": { - "type": "string", - "minLength": 1 - }, - "databasePassword": { - "type": "string" - }, - "serverId": { - "type": "string", - "nullable": true - } - }, - "required": [ - "name", - "appName", - "projectId", - "databaseUser", - "databasePassword" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mongo.one": { - "get": { - "operationId": "mongo-one", - "tags": ["mongo"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "mongoId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mongo.start": { - "post": { - "operationId": "mongo-start", - "tags": ["mongo"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mongoId": { - "type": "string" - } - }, - "required": ["mongoId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mongo.stop": { - "post": { - "operationId": "mongo-stop", - "tags": ["mongo"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mongoId": { - "type": "string" - } - }, - "required": ["mongoId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mongo.saveExternalPort": { - "post": { - "operationId": "mongo-saveExternalPort", - "tags": ["mongo"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mongoId": { - "type": "string" - }, - "externalPort": { - "type": "number", - "nullable": true - } - }, - "required": ["mongoId", "externalPort"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mongo.deploy": { - "post": { - "operationId": "mongo-deploy", - "tags": ["mongo"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mongoId": { - "type": "string" - } - }, - "required": ["mongoId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mongo.changeStatus": { - "post": { - "operationId": "mongo-changeStatus", - "tags": ["mongo"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mongoId": { - "type": "string" - }, - "applicationStatus": { - "type": "string", - "enum": ["idle", "running", "done", "error"] - } - }, - "required": ["mongoId", "applicationStatus"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mongo.reload": { - "post": { - "operationId": "mongo-reload", - "tags": ["mongo"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mongoId": { - "type": "string" - }, - "appName": { - "type": "string", - "minLength": 1 - } - }, - "required": ["mongoId", "appName"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mongo.remove": { - "post": { - "operationId": "mongo-remove", - "tags": ["mongo"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mongoId": { - "type": "string" - } - }, - "required": ["mongoId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mongo.saveEnvironment": { - "post": { - "operationId": "mongo-saveEnvironment", - "tags": ["mongo"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mongoId": { - "type": "string" - }, - "env": { - "type": "string", - "nullable": true - } - }, - "required": ["mongoId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mongo.update": { - "post": { - "operationId": "mongo-update", - "tags": ["mongo"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mongoId": { - "type": "string", - "minLength": 1 - }, - "name": { - "type": "string", - "minLength": 1 - }, - "appName": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "nullable": true - }, - "databaseUser": { - "type": "string", - "minLength": 1 - }, - "databasePassword": { - "type": "string" - }, - "dockerImage": { - "type": "string", - "default": "mongo:15" - }, - "command": { - "type": "string", - "nullable": true - }, - "env": { - "type": "string", - "nullable": true - }, - "memoryReservation": { - "type": "number", - "nullable": true - }, - "memoryLimit": { - "type": "number", - "nullable": true - }, - "cpuReservation": { - "type": "number", - "nullable": true - }, - "cpuLimit": { - "type": "number", - "nullable": true - }, - "externalPort": { - "type": "number", - "nullable": true - }, - "applicationStatus": { - "type": "string", - "enum": ["idle", "running", "done", "error"] - }, - "createdAt": { - "type": "string" - }, - "projectId": { - "type": "string" - } - }, - "required": ["mongoId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mariadb.create": { - "post": { - "operationId": "mariadb-create", - "tags": ["mariadb"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "appName": { - "type": "string", - "minLength": 1 - }, - "dockerImage": { - "type": "string", - "default": "mariadb:6" - }, - "databaseRootPassword": { - "type": "string" - }, - "projectId": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "databaseName": { - "type": "string", - "minLength": 1 - }, - "databaseUser": { - "type": "string", - "minLength": 1 - }, - "databasePassword": { - "type": "string" - }, - "serverId": { - "type": "string", - "nullable": true - } - }, - "required": [ - "name", - "appName", - "databaseRootPassword", - "projectId", - "databaseName", - "databaseUser", - "databasePassword" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mariadb.one": { - "get": { - "operationId": "mariadb-one", - "tags": ["mariadb"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "mariadbId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mariadb.start": { - "post": { - "operationId": "mariadb-start", - "tags": ["mariadb"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mariadbId": { - "type": "string" - } - }, - "required": ["mariadbId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mariadb.stop": { - "post": { - "operationId": "mariadb-stop", - "tags": ["mariadb"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mariadbId": { - "type": "string" - } - }, - "required": ["mariadbId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mariadb.saveExternalPort": { - "post": { - "operationId": "mariadb-saveExternalPort", - "tags": ["mariadb"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mariadbId": { - "type": "string" - }, - "externalPort": { - "type": "number", - "nullable": true - } - }, - "required": ["mariadbId", "externalPort"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mariadb.deploy": { - "post": { - "operationId": "mariadb-deploy", - "tags": ["mariadb"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mariadbId": { - "type": "string" - } - }, - "required": ["mariadbId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mariadb.changeStatus": { - "post": { - "operationId": "mariadb-changeStatus", - "tags": ["mariadb"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mariadbId": { - "type": "string" - }, - "applicationStatus": { - "type": "string", - "enum": ["idle", "running", "done", "error"] - } - }, - "required": ["mariadbId", "applicationStatus"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mariadb.remove": { - "post": { - "operationId": "mariadb-remove", - "tags": ["mariadb"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mariadbId": { - "type": "string" - } - }, - "required": ["mariadbId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mariadb.saveEnvironment": { - "post": { - "operationId": "mariadb-saveEnvironment", - "tags": ["mariadb"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mariadbId": { - "type": "string" - }, - "env": { - "type": "string", - "nullable": true - } - }, - "required": ["mariadbId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mariadb.reload": { - "post": { - "operationId": "mariadb-reload", - "tags": ["mariadb"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mariadbId": { - "type": "string" - }, - "appName": { - "type": "string", - "minLength": 1 - } - }, - "required": ["mariadbId", "appName"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mariadb.update": { - "post": { - "operationId": "mariadb-update", - "tags": ["mariadb"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mariadbId": { - "type": "string", - "minLength": 1 - }, - "name": { - "type": "string", - "minLength": 1 - }, - "appName": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "nullable": true - }, - "databaseName": { - "type": "string", - "minLength": 1 - }, - "databaseUser": { - "type": "string", - "minLength": 1 - }, - "databasePassword": { - "type": "string" - }, - "databaseRootPassword": { - "type": "string" - }, - "dockerImage": { - "type": "string", - "default": "mariadb:6" - }, - "command": { - "type": "string", - "nullable": true - }, - "env": { - "type": "string", - "nullable": true - }, - "memoryReservation": { - "type": "number", - "nullable": true - }, - "memoryLimit": { - "type": "number", - "nullable": true - }, - "cpuReservation": { - "type": "number", - "nullable": true - }, - "cpuLimit": { - "type": "number", - "nullable": true - }, - "externalPort": { - "type": "number", - "nullable": true - }, - "applicationStatus": { - "type": "string", - "enum": ["idle", "running", "done", "error"] - }, - "createdAt": { - "type": "string" - }, - "projectId": { - "type": "string" - } - }, - "required": ["mariadbId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.create": { - "post": { - "operationId": "compose-create", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "nullable": true - }, - "projectId": { - "type": "string" - }, - "composeType": { - "type": "string", - "enum": ["docker-compose", "stack"] - }, - "appName": { - "type": "string" - }, - "serverId": { - "type": "string", - "nullable": true - } - }, - "required": ["name", "projectId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.one": { - "get": { - "operationId": "compose-one", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "composeId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.update": { - "post": { - "operationId": "compose-update", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "composeId": { - "type": "string" - }, - "name": { - "type": "string", - "minLength": 1 - }, - "appName": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "env": { - "type": "string", - "nullable": true - }, - "composeFile": { - "type": "string" - }, - "refreshToken": { - "type": "string", - "nullable": true - }, - "sourceType": { - "type": "string", - "enum": ["git", "github", "gitlab", "bitbucket", "raw"] - }, - "composeType": { - "type": "string", - "enum": ["docker-compose", "stack"] - }, - "repository": { - "type": "string", - "nullable": true - }, - "owner": { - "type": "string", - "nullable": true - }, - "branch": { - "type": "string", - "nullable": true - }, - "autoDeploy": { - "type": "boolean", - "nullable": true - }, - "gitlabProjectId": { - "type": "number", - "nullable": true - }, - "gitlabRepository": { - "type": "string", - "nullable": true - }, - "gitlabOwner": { - "type": "string", - "nullable": true - }, - "gitlabBranch": { - "type": "string", - "nullable": true - }, - "gitlabPathNamespace": { - "type": "string", - "nullable": true - }, - "bitbucketRepository": { - "type": "string", - "nullable": true - }, - "bitbucketOwner": { - "type": "string", - "nullable": true - }, - "bitbucketBranch": { - "type": "string", - "nullable": true - }, - "customGitUrl": { - "type": "string", - "nullable": true - }, - "customGitBranch": { - "type": "string", - "nullable": true - }, - "customGitSSHKeyId": { - "type": "string", - "nullable": true - }, - "command": { - "type": "string" - }, - "composePath": { - "type": "string", - "minLength": 1 - }, - "suffix": { - "type": "string" - }, - "randomize": { - "type": "boolean" - }, - "composeStatus": { - "type": "string", - "enum": ["idle", "running", "done", "error"] - }, - "projectId": { - "type": "string" - }, - "createdAt": { - "type": "string" - }, - "githubId": { - "type": "string", - "nullable": true - }, - "gitlabId": { - "type": "string", - "nullable": true - }, - "bitbucketId": { - "type": "string", - "nullable": true - } - }, - "required": ["composeId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.delete": { - "post": { - "operationId": "compose-delete", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "composeId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["composeId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.cleanQueues": { - "post": { - "operationId": "compose-cleanQueues", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "composeId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["composeId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.loadServices": { - "get": { - "operationId": "compose-loadServices", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "composeId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - }, - { - "name": "type", - "in": "query", - "required": false, - "schema": { - "anyOf": [ - { - "not": {} - }, - { - "type": "string", - "enum": ["fetch", "cache"] - } - ], - "default": "cache" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.fetchSourceType": { - "post": { - "operationId": "compose-fetchSourceType", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "composeId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["composeId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.randomizeCompose": { - "post": { - "operationId": "compose-randomizeCompose", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "composeId": { - "type": "string", - "minLength": 1 - }, - "suffix": { - "type": "string" - } - }, - "required": ["composeId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.getConvertedCompose": { - "get": { - "operationId": "compose-getConvertedCompose", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "composeId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.deploy": { - "post": { - "operationId": "compose-deploy", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "composeId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["composeId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.redeploy": { - "post": { - "operationId": "compose-redeploy", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "composeId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["composeId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.stop": { - "post": { - "operationId": "compose-stop", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "composeId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["composeId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.getDefaultCommand": { - "get": { - "operationId": "compose-getDefaultCommand", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "composeId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.refreshToken": { - "post": { - "operationId": "compose-refreshToken", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "composeId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["composeId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.deployTemplate": { - "post": { - "operationId": "compose-deployTemplate", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "projectId": { - "type": "string" - }, - "id": { - "type": "string", - "minLength": 1 - }, - "serverId": { - "type": "string" - } - }, - "required": ["projectId", "id"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.templates": { - "get": { - "operationId": "compose-templates", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/compose.getTags": { - "get": { - "operationId": "compose-getTags", - "tags": ["compose"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/user.all": { - "get": { - "operationId": "user-all", - "tags": ["user"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/user.byAuthId": { - "get": { - "operationId": "user-byAuthId", - "tags": ["user"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "authId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/user.byUserId": { - "get": { - "operationId": "user-byUserId", - "tags": ["user"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "userId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/domain.create": { - "post": { - "operationId": "domain-create", - "tags": ["domain"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "host": { - "type": "string", - "minLength": 1 - }, - "path": { - "type": "string", - "minLength": 1, - "nullable": true - }, - "port": { - "type": "number", - "minimum": 1, - "maximum": 65535, - "nullable": true - }, - "https": { - "type": "boolean" - }, - "applicationId": { - "type": "string", - "nullable": true - }, - "certificateType": { - "type": "string", - "enum": ["letsencrypt", "none"] - }, - "composeId": { - "type": "string", - "nullable": true - }, - "serviceName": { - "type": "string", - "nullable": true - }, - "domainType": { - "type": "string", - "enum": ["compose", "application"], - "nullable": true - } - }, - "required": ["host"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/domain.byApplicationId": { - "get": { - "operationId": "domain-byApplicationId", - "tags": ["domain"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "applicationId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/domain.byComposeId": { - "get": { - "operationId": "domain-byComposeId", - "tags": ["domain"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "composeId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/domain.generateDomain": { - "post": { - "operationId": "domain-generateDomain", - "tags": ["domain"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "appName": { - "type": "string" - }, - "serverId": { - "type": "string" - } - }, - "required": ["appName"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/domain.update": { - "post": { - "operationId": "domain-update", - "tags": ["domain"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "host": { - "type": "string", - "minLength": 1 - }, - "path": { - "type": "string", - "minLength": 1, - "nullable": true - }, - "port": { - "type": "number", - "minimum": 1, - "maximum": 65535, - "nullable": true - }, - "https": { - "type": "boolean" - }, - "certificateType": { - "type": "string", - "enum": ["letsencrypt", "none"] - }, - "serviceName": { - "type": "string", - "nullable": true - }, - "domainType": { - "type": "string", - "enum": ["compose", "application"], - "nullable": true - }, - "domainId": { - "type": "string" - } - }, - "required": ["host", "domainId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/domain.one": { - "get": { - "operationId": "domain-one", - "tags": ["domain"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "domainId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/domain.delete": { - "post": { - "operationId": "domain-delete", - "tags": ["domain"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "domainId": { - "type": "string" - } - }, - "required": ["domainId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/destination.create": { - "post": { - "operationId": "destination-create", - "tags": ["destination"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "accessKey": { - "type": "string" - }, - "bucket": { - "type": "string" - }, - "region": { - "type": "string" - }, - "endpoint": { - "type": "string" - }, - "secretAccessKey": { - "type": "string" - }, - "serverId": { - "type": "string" - } - }, - "required": [ - "name", - "accessKey", - "bucket", - "region", - "endpoint", - "secretAccessKey" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/destination.testConnection": { - "post": { - "operationId": "destination-testConnection", - "tags": ["destination"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "accessKey": { - "type": "string" - }, - "bucket": { - "type": "string" - }, - "region": { - "type": "string" - }, - "endpoint": { - "type": "string" - }, - "secretAccessKey": { - "type": "string" - }, - "serverId": { - "type": "string" - } - }, - "required": [ - "name", - "accessKey", - "bucket", - "region", - "endpoint", - "secretAccessKey" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/destination.one": { - "get": { - "operationId": "destination-one", - "tags": ["destination"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "destinationId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/destination.all": { - "get": { - "operationId": "destination-all", - "tags": ["destination"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/destination.remove": { - "post": { - "operationId": "destination-remove", - "tags": ["destination"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "destinationId": { - "type": "string" - } - }, - "required": ["destinationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/destination.update": { - "post": { - "operationId": "destination-update", - "tags": ["destination"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "accessKey": { - "type": "string" - }, - "bucket": { - "type": "string" - }, - "region": { - "type": "string" - }, - "endpoint": { - "type": "string" - }, - "secretAccessKey": { - "type": "string" - }, - "destinationId": { - "type": "string" - }, - "serverId": { - "type": "string" - } - }, - "required": [ - "name", - "accessKey", - "bucket", - "region", - "endpoint", - "secretAccessKey", - "destinationId" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/backup.create": { - "post": { - "operationId": "backup-create", - "tags": ["backup"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "schedule": { - "type": "string" - }, - "enabled": { - "type": "boolean", - "nullable": true - }, - "prefix": { - "type": "string", - "minLength": 1 - }, - "destinationId": { - "type": "string" - }, - "database": { - "type": "string", - "minLength": 1 - }, - "mariadbId": { - "type": "string", - "nullable": true - }, - "mysqlId": { - "type": "string", - "nullable": true - }, - "postgresId": { - "type": "string", - "nullable": true - }, - "mongoId": { - "type": "string", - "nullable": true - }, - "databaseType": { - "type": "string", - "enum": ["postgres", "mariadb", "mysql", "mongo"] - } - }, - "required": [ - "schedule", - "prefix", - "destinationId", - "database", - "databaseType" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/backup.one": { - "get": { - "operationId": "backup-one", - "tags": ["backup"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "backupId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/backup.update": { - "post": { - "operationId": "backup-update", - "tags": ["backup"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "schedule": { - "type": "string" - }, - "enabled": { - "type": "boolean", - "nullable": true - }, - "prefix": { - "type": "string", - "minLength": 1 - }, - "backupId": { - "type": "string" - }, - "destinationId": { - "type": "string" - }, - "database": { - "type": "string", - "minLength": 1 - } - }, - "required": [ - "schedule", - "prefix", - "backupId", - "destinationId", - "database" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/backup.remove": { - "post": { - "operationId": "backup-remove", - "tags": ["backup"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "backupId": { - "type": "string" - } - }, - "required": ["backupId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/backup.manualBackupPostgres": { - "post": { - "operationId": "backup-manualBackupPostgres", - "tags": ["backup"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "backupId": { - "type": "string" - } - }, - "required": ["backupId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/backup.manualBackupMySql": { - "post": { - "operationId": "backup-manualBackupMySql", - "tags": ["backup"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "backupId": { - "type": "string" - } - }, - "required": ["backupId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/backup.manualBackupMariadb": { - "post": { - "operationId": "backup-manualBackupMariadb", - "tags": ["backup"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "backupId": { - "type": "string" - } - }, - "required": ["backupId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/backup.manualBackupMongo": { - "post": { - "operationId": "backup-manualBackupMongo", - "tags": ["backup"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "backupId": { - "type": "string" - } - }, - "required": ["backupId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/deployment.all": { - "get": { - "operationId": "deployment-all", - "tags": ["deployment"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "applicationId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/deployment.allByCompose": { - "get": { - "operationId": "deployment-allByCompose", - "tags": ["deployment"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "composeId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/deployment.allByServer": { - "get": { - "operationId": "deployment-allByServer", - "tags": ["deployment"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "serverId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mounts.create": { - "post": { - "operationId": "mounts-create", - "tags": ["mounts"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["bind", "volume", "file"] - }, - "hostPath": { - "type": "string", - "nullable": true - }, - "volumeName": { - "type": "string", - "nullable": true - }, - "content": { - "type": "string", - "nullable": true - }, - "mountPath": { - "type": "string", - "minLength": 1 - }, - "serviceType": { - "type": "string", - "enum": [ - "application", - "postgres", - "mysql", - "mariadb", - "mongo", - "redis", - "compose" - ], - "default": "application" - }, - "filePath": { - "type": "string", - "nullable": true - }, - "serviceId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["type", "mountPath", "serviceId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mounts.remove": { - "post": { - "operationId": "mounts-remove", - "tags": ["mounts"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mountId": { - "type": "string" - } - }, - "required": ["mountId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mounts.one": { - "get": { - "operationId": "mounts-one", - "tags": ["mounts"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "mountId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/mounts.update": { - "post": { - "operationId": "mounts-update", - "tags": ["mounts"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "mountId": { - "type": "string", - "minLength": 1 - }, - "type": { - "type": "string", - "enum": ["bind", "volume", "file"] - }, - "hostPath": { - "type": "string", - "nullable": true - }, - "volumeName": { - "type": "string", - "nullable": true - }, - "filePath": { - "type": "string", - "nullable": true - }, - "content": { - "type": "string", - "nullable": true - }, - "serviceType": { - "type": "string", - "enum": [ - "application", - "postgres", - "mysql", - "mariadb", - "mongo", - "redis", - "compose" - ], - "default": "application" - }, - "mountPath": { - "type": "string", - "minLength": 1 - }, - "applicationId": { - "type": "string", - "nullable": true - }, - "postgresId": { - "type": "string", - "nullable": true - }, - "mariadbId": { - "type": "string", - "nullable": true - }, - "mongoId": { - "type": "string", - "nullable": true - }, - "mysqlId": { - "type": "string", - "nullable": true - }, - "redisId": { - "type": "string", - "nullable": true - }, - "composeId": { - "type": "string", - "nullable": true - } - }, - "required": ["mountId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/certificates.create": { - "post": { - "operationId": "certificates-create", - "tags": ["certificates"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "certificateId": { - "type": "string" - }, - "name": { - "type": "string", - "minLength": 1 - }, - "certificateData": { - "type": "string", - "minLength": 1 - }, - "privateKey": { - "type": "string", - "minLength": 1 - }, - "certificatePath": { - "type": "string" - }, - "autoRenew": { - "type": "boolean", - "nullable": true - }, - "adminId": { - "type": "string", - "nullable": true - }, - "serverId": { - "type": "string", - "nullable": true - } - }, - "required": ["name", "certificateData", "privateKey"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/certificates.one": { - "get": { - "operationId": "certificates-one", - "tags": ["certificates"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "certificateId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/certificates.remove": { - "post": { - "operationId": "certificates-remove", - "tags": ["certificates"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "certificateId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["certificateId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/certificates.all": { - "get": { - "operationId": "certificates-all", - "tags": ["certificates"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.reloadServer": { - "post": { - "operationId": "settings-reloadServer", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.reloadTraefik": { - "post": { - "operationId": "settings-reloadTraefik", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "serverId": { - "type": "string" - } - }, - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.toggleDashboard": { - "post": { - "operationId": "settings-toggleDashboard", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "enableDashboard": { - "type": "boolean" - }, - "serverId": { - "type": "string" - } - }, - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.cleanUnusedImages": { - "post": { - "operationId": "settings-cleanUnusedImages", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "serverId": { - "type": "string" - } - }, - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.cleanUnusedVolumes": { - "post": { - "operationId": "settings-cleanUnusedVolumes", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "serverId": { - "type": "string" - } - }, - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.cleanStoppedContainers": { - "post": { - "operationId": "settings-cleanStoppedContainers", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "serverId": { - "type": "string" - } - }, - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.cleanDockerBuilder": { - "post": { - "operationId": "settings-cleanDockerBuilder", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "serverId": { - "type": "string" - } - }, - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.cleanDockerPrune": { - "post": { - "operationId": "settings-cleanDockerPrune", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "serverId": { - "type": "string" - } - }, - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.cleanAll": { - "post": { - "operationId": "settings-cleanAll", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "serverId": { - "type": "string" - } - }, - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.cleanMonitoring": { - "post": { - "operationId": "settings-cleanMonitoring", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.saveSSHPrivateKey": { - "post": { - "operationId": "settings-saveSSHPrivateKey", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "sshPrivateKey": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.assignDomainServer": { - "post": { - "operationId": "settings-assignDomainServer", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true - }, - "certificateType": { - "type": "string", - "enum": ["letsencrypt", "none"], - "default": "none" - }, - "letsEncryptEmail": { - "type": "string", - "nullable": true - } - }, - "required": ["host"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.cleanSSHPrivateKey": { - "post": { - "operationId": "settings-cleanSSHPrivateKey", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.updateDockerCleanup": { - "post": { - "operationId": "settings-updateDockerCleanup", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "enableDockerCleanup": { - "type": "boolean" - }, - "serverId": { - "type": "string" - } - }, - "required": ["enableDockerCleanup"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.readTraefikConfig": { - "get": { - "operationId": "settings-readTraefikConfig", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.updateTraefikConfig": { - "post": { - "operationId": "settings-updateTraefikConfig", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "traefikConfig": { - "type": "string", - "minLength": 1 - } - }, - "required": ["traefikConfig"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.readWebServerTraefikConfig": { - "get": { - "operationId": "settings-readWebServerTraefikConfig", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.updateWebServerTraefikConfig": { - "post": { - "operationId": "settings-updateWebServerTraefikConfig", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "traefikConfig": { - "type": "string", - "minLength": 1 - } - }, - "required": ["traefikConfig"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.readMiddlewareTraefikConfig": { - "get": { - "operationId": "settings-readMiddlewareTraefikConfig", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.updateMiddlewareTraefikConfig": { - "post": { - "operationId": "settings-updateMiddlewareTraefikConfig", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "traefikConfig": { - "type": "string", - "minLength": 1 - } - }, - "required": ["traefikConfig"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.checkAndUpdateImage": { - "post": { - "operationId": "settings-checkAndUpdateImage", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.updateServer": { - "post": { - "operationId": "settings-updateServer", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.getDokployVersion": { - "get": { - "operationId": "settings-getDokployVersion", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.readDirectories": { - "get": { - "operationId": "settings-readDirectories", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "serverId", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.updateTraefikFile": { - "post": { - "operationId": "settings-updateTraefikFile", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "path": { - "type": "string", - "minLength": 1 - }, - "traefikConfig": { - "type": "string", - "minLength": 1 - }, - "serverId": { - "type": "string" - } - }, - "required": ["path", "traefikConfig"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.readTraefikFile": { - "get": { - "operationId": "settings-readTraefikFile", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "path", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - }, - { - "name": "serverId", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.getIp": { - "get": { - "operationId": "settings-getIp", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.getOpenApiDocument": { - "get": { - "operationId": "settings-getOpenApiDocument", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.readTraefikEnv": { - "get": { - "operationId": "settings-readTraefikEnv", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "serverId", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.writeTraefikEnv": { - "post": { - "operationId": "settings-writeTraefikEnv", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "env": { - "type": "string" - }, - "serverId": { - "type": "string" - } - }, - "required": ["env"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.haveTraefikDashboardPortEnabled": { - "get": { - "operationId": "settings-haveTraefikDashboardPortEnabled", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "serverId", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.readStats": { - "get": { - "operationId": "settings-readStats", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.getLogRotateStatus": { - "get": { - "operationId": "settings-getLogRotateStatus", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.toggleLogRotate": { - "post": { - "operationId": "settings-toggleLogRotate", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "enable": { - "type": "boolean" - } - }, - "required": ["enable"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.haveActivateRequests": { - "get": { - "operationId": "settings-haveActivateRequests", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.toggleRequests": { - "post": { - "operationId": "settings-toggleRequests", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "enable": { - "type": "boolean" - } - }, - "required": ["enable"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.isCloud": { - "get": { - "operationId": "settings-isCloud", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/settings.health": { - "get": { - "operationId": "settings-health", - "tags": ["settings"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/security.create": { - "post": { - "operationId": "security-create", - "tags": ["security"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "applicationId": { - "type": "string" - }, - "username": { - "type": "string", - "minLength": 1 - }, - "password": { - "type": "string", - "minLength": 1 - } - }, - "required": ["applicationId", "username", "password"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/security.one": { - "get": { - "operationId": "security-one", - "tags": ["security"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "securityId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/security.delete": { - "post": { - "operationId": "security-delete", - "tags": ["security"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "securityId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["securityId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/security.update": { - "post": { - "operationId": "security-update", - "tags": ["security"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "securityId": { - "type": "string", - "minLength": 1 - }, - "username": { - "type": "string", - "minLength": 1 - }, - "password": { - "type": "string", - "minLength": 1 - } - }, - "required": ["securityId", "username", "password"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redirects.create": { - "post": { - "operationId": "redirects-create", - "tags": ["redirects"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "regex": { - "type": "string", - "minLength": 1 - }, - "replacement": { - "type": "string", - "minLength": 1 - }, - "permanent": { - "type": "boolean" - }, - "applicationId": { - "type": "string" - } - }, - "required": [ - "regex", - "replacement", - "permanent", - "applicationId" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redirects.one": { - "get": { - "operationId": "redirects-one", - "tags": ["redirects"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "redirectId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redirects.delete": { - "post": { - "operationId": "redirects-delete", - "tags": ["redirects"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "redirectId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["redirectId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/redirects.update": { - "post": { - "operationId": "redirects-update", - "tags": ["redirects"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "redirectId": { - "type": "string", - "minLength": 1 - }, - "regex": { - "type": "string", - "minLength": 1 - }, - "replacement": { - "type": "string", - "minLength": 1 - }, - "permanent": { - "type": "boolean" - } - }, - "required": ["redirectId", "regex", "replacement", "permanent"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/port.create": { - "post": { - "operationId": "port-create", - "tags": ["port"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "publishedPort": { - "type": "number" - }, - "targetPort": { - "type": "number" - }, - "protocol": { - "type": "string", - "enum": ["tcp", "udp"], - "default": "tcp" - }, - "applicationId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["publishedPort", "targetPort", "applicationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/port.one": { - "get": { - "operationId": "port-one", - "tags": ["port"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "portId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/port.delete": { - "post": { - "operationId": "port-delete", - "tags": ["port"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "portId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["portId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/port.update": { - "post": { - "operationId": "port-update", - "tags": ["port"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "portId": { - "type": "string", - "minLength": 1 - }, - "publishedPort": { - "type": "number" - }, - "targetPort": { - "type": "number" - }, - "protocol": { - "type": "string", - "enum": ["tcp", "udp"], - "default": "tcp" - } - }, - "required": ["portId", "publishedPort", "targetPort"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/registry.create": { - "post": { - "operationId": "registry-create", - "tags": ["registry"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "registryName": { - "type": "string", - "minLength": 1 - }, - "username": { - "type": "string", - "minLength": 1 - }, - "password": { - "type": "string", - "minLength": 1 - }, - "registryUrl": { - "type": "string" - }, - "registryType": { - "type": "string", - "enum": ["cloud"] - }, - "imagePrefix": { - "type": "string", - "nullable": true - }, - "serverId": { - "type": "string" - } - }, - "required": [ - "registryName", - "username", - "password", - "registryUrl", - "registryType", - "imagePrefix" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/registry.remove": { - "post": { - "operationId": "registry-remove", - "tags": ["registry"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "registryId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["registryId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/registry.update": { - "post": { - "operationId": "registry-update", - "tags": ["registry"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "registryId": { - "type": "string", - "minLength": 1 - }, - "registryName": { - "type": "string", - "minLength": 1 - }, - "imagePrefix": { - "type": "string", - "nullable": true - }, - "username": { - "type": "string", - "minLength": 1 - }, - "password": { - "type": "string", - "minLength": 1 - }, - "registryUrl": { - "type": "string" - }, - "createdAt": { - "type": "string" - }, - "registryType": { - "type": "string", - "enum": ["cloud"] - }, - "adminId": { - "type": "string", - "minLength": 1 - }, - "serverId": { - "type": "string" - } - }, - "required": ["registryId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/registry.all": { - "get": { - "operationId": "registry-all", - "tags": ["registry"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/registry.one": { - "get": { - "operationId": "registry-one", - "tags": ["registry"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "registryId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/registry.testRegistry": { - "post": { - "operationId": "registry-testRegistry", - "tags": ["registry"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "registryName": { - "type": "string", - "minLength": 1 - }, - "username": { - "type": "string", - "minLength": 1 - }, - "password": { - "type": "string", - "minLength": 1 - }, - "registryUrl": { - "type": "string" - }, - "registryType": { - "type": "string", - "enum": ["cloud"] - }, - "imagePrefix": { - "type": "string", - "nullable": true - }, - "serverId": { - "type": "string" - } - }, - "required": [ - "registryName", - "username", - "password", - "registryUrl", - "registryType" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/cluster.getNodes": { - "get": { - "operationId": "cluster-getNodes", - "tags": ["cluster"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/cluster.removeWorker": { - "post": { - "operationId": "cluster-removeWorker", - "tags": ["cluster"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "nodeId": { - "type": "string" - } - }, - "required": ["nodeId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/cluster.addWorker": { - "get": { - "operationId": "cluster-addWorker", - "tags": ["cluster"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/cluster.addManager": { - "get": { - "operationId": "cluster-addManager", - "tags": ["cluster"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.createSlack": { - "post": { - "operationId": "notification-createSlack", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "appBuildError": { - "type": "boolean" - }, - "databaseBackup": { - "type": "boolean" - }, - "dokployRestart": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "appDeploy": { - "type": "boolean" - }, - "dockerCleanup": { - "type": "boolean" - }, - "webhookUrl": { - "type": "string", - "minLength": 1 - }, - "channel": { - "type": "string" - } - }, - "required": [ - "appBuildError", - "databaseBackup", - "dokployRestart", - "name", - "appDeploy", - "dockerCleanup", - "webhookUrl", - "channel" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.updateSlack": { - "post": { - "operationId": "notification-updateSlack", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "appBuildError": { - "type": "boolean" - }, - "databaseBackup": { - "type": "boolean" - }, - "dokployRestart": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "appDeploy": { - "type": "boolean" - }, - "dockerCleanup": { - "type": "boolean" - }, - "webhookUrl": { - "type": "string", - "minLength": 1 - }, - "channel": { - "type": "string" - }, - "notificationId": { - "type": "string", - "minLength": 1 - }, - "slackId": { - "type": "string" - }, - "adminId": { - "type": "string" - } - }, - "required": ["notificationId", "slackId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.testSlackConnection": { - "post": { - "operationId": "notification-testSlackConnection", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "webhookUrl": { - "type": "string", - "minLength": 1 - }, - "channel": { - "type": "string" - } - }, - "required": ["webhookUrl", "channel"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.createTelegram": { - "post": { - "operationId": "notification-createTelegram", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "appBuildError": { - "type": "boolean" - }, - "databaseBackup": { - "type": "boolean" - }, - "dokployRestart": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "appDeploy": { - "type": "boolean" - }, - "dockerCleanup": { - "type": "boolean" - }, - "botToken": { - "type": "string", - "minLength": 1 - }, - "chatId": { - "type": "string", - "minLength": 1 - } - }, - "required": [ - "appBuildError", - "databaseBackup", - "dokployRestart", - "name", - "appDeploy", - "dockerCleanup", - "botToken", - "chatId" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.updateTelegram": { - "post": { - "operationId": "notification-updateTelegram", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "appBuildError": { - "type": "boolean" - }, - "databaseBackup": { - "type": "boolean" - }, - "dokployRestart": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "appDeploy": { - "type": "boolean" - }, - "dockerCleanup": { - "type": "boolean" - }, - "botToken": { - "type": "string", - "minLength": 1 - }, - "chatId": { - "type": "string", - "minLength": 1 - }, - "notificationId": { - "type": "string", - "minLength": 1 - }, - "telegramId": { - "type": "string", - "minLength": 1 - }, - "adminId": { - "type": "string" - } - }, - "required": ["notificationId", "telegramId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.testTelegramConnection": { - "post": { - "operationId": "notification-testTelegramConnection", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "botToken": { - "type": "string", - "minLength": 1 - }, - "chatId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["botToken", "chatId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.createDiscord": { - "post": { - "operationId": "notification-createDiscord", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "appBuildError": { - "type": "boolean" - }, - "databaseBackup": { - "type": "boolean" - }, - "dokployRestart": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "appDeploy": { - "type": "boolean" - }, - "dockerCleanup": { - "type": "boolean" - }, - "webhookUrl": { - "type": "string", - "minLength": 1 - } - }, - "required": [ - "appBuildError", - "databaseBackup", - "dokployRestart", - "name", - "appDeploy", - "dockerCleanup", - "webhookUrl" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.updateDiscord": { - "post": { - "operationId": "notification-updateDiscord", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "appBuildError": { - "type": "boolean" - }, - "databaseBackup": { - "type": "boolean" - }, - "dokployRestart": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "appDeploy": { - "type": "boolean" - }, - "dockerCleanup": { - "type": "boolean" - }, - "webhookUrl": { - "type": "string", - "minLength": 1 - }, - "notificationId": { - "type": "string", - "minLength": 1 - }, - "discordId": { - "type": "string", - "minLength": 1 - }, - "adminId": { - "type": "string" - } - }, - "required": ["notificationId", "discordId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.testDiscordConnection": { - "post": { - "operationId": "notification-testDiscordConnection", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "webhookUrl": { - "type": "string", - "minLength": 1 - } - }, - "required": ["webhookUrl"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.createEmail": { - "post": { - "operationId": "notification-createEmail", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "appBuildError": { - "type": "boolean" - }, - "databaseBackup": { - "type": "boolean" - }, - "dokployRestart": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "appDeploy": { - "type": "boolean" - }, - "dockerCleanup": { - "type": "boolean" - }, - "smtpServer": { - "type": "string", - "minLength": 1 - }, - "smtpPort": { - "type": "number", - "minimum": 1 - }, - "username": { - "type": "string", - "minLength": 1 - }, - "password": { - "type": "string", - "minLength": 1 - }, - "fromAddress": { - "type": "string", - "minLength": 1 - }, - "toAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1 - } - }, - "required": [ - "appBuildError", - "databaseBackup", - "dokployRestart", - "name", - "appDeploy", - "dockerCleanup", - "smtpServer", - "smtpPort", - "username", - "password", - "fromAddress", - "toAddresses" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.updateEmail": { - "post": { - "operationId": "notification-updateEmail", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "appBuildError": { - "type": "boolean" - }, - "databaseBackup": { - "type": "boolean" - }, - "dokployRestart": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "appDeploy": { - "type": "boolean" - }, - "dockerCleanup": { - "type": "boolean" - }, - "smtpServer": { - "type": "string", - "minLength": 1 - }, - "smtpPort": { - "type": "number", - "minimum": 1 - }, - "username": { - "type": "string", - "minLength": 1 - }, - "password": { - "type": "string", - "minLength": 1 - }, - "fromAddress": { - "type": "string", - "minLength": 1 - }, - "toAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1 - }, - "notificationId": { - "type": "string", - "minLength": 1 - }, - "emailId": { - "type": "string", - "minLength": 1 - }, - "adminId": { - "type": "string" - } - }, - "required": ["notificationId", "emailId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.testEmailConnection": { - "post": { - "operationId": "notification-testEmailConnection", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "smtpServer": { - "type": "string", - "minLength": 1 - }, - "smtpPort": { - "type": "number", - "minimum": 1 - }, - "username": { - "type": "string", - "minLength": 1 - }, - "password": { - "type": "string", - "minLength": 1 - }, - "toAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1 - }, - "fromAddress": { - "type": "string", - "minLength": 1 - } - }, - "required": [ - "smtpServer", - "smtpPort", - "username", - "password", - "toAddresses", - "fromAddress" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.remove": { - "post": { - "operationId": "notification-remove", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "notificationId": { - "type": "string" - } - }, - "required": ["notificationId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.one": { - "get": { - "operationId": "notification-one", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "notificationId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/notification.all": { - "get": { - "operationId": "notification-all", - "tags": ["notification"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/sshKey.create": { - "post": { - "operationId": "sshKey-create", - "tags": ["sshKey"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "nullable": true - }, - "privateKey": { - "type": "string" - }, - "publicKey": { - "type": "string" - }, - "adminId": { - "type": "string", - "nullable": true - } - }, - "required": ["name", "privateKey", "publicKey"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/sshKey.remove": { - "post": { - "operationId": "sshKey-remove", - "tags": ["sshKey"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "sshKeyId": { - "type": "string" - } - }, - "required": ["sshKeyId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/sshKey.one": { - "get": { - "operationId": "sshKey-one", - "tags": ["sshKey"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "sshKeyId", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/sshKey.all": { - "get": { - "operationId": "sshKey-all", - "tags": ["sshKey"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/sshKey.generate": { - "post": { - "operationId": "sshKey-generate", - "tags": ["sshKey"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["rsa", "ed25519"] - } - }, - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/sshKey.update": { - "post": { - "operationId": "sshKey-update", - "tags": ["sshKey"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "nullable": true - }, - "lastUsedAt": { - "type": "string", - "nullable": true - }, - "sshKeyId": { - "type": "string" - } - }, - "required": ["sshKeyId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/gitProvider.getAll": { - "get": { - "operationId": "gitProvider-getAll", - "tags": ["gitProvider"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/gitProvider.remove": { - "post": { - "operationId": "gitProvider-remove", - "tags": ["gitProvider"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "gitProviderId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["gitProviderId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/bitbucket.create": { - "post": { - "operationId": "bitbucket-create", - "tags": ["bitbucket"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "bitbucketId": { - "type": "string" - }, - "bitbucketUsername": { - "type": "string" - }, - "appPassword": { - "type": "string" - }, - "bitbucketWorkspaceName": { - "type": "string" - }, - "gitProviderId": { - "type": "string" - }, - "authId": { - "type": "string", - "minLength": 1 - }, - "name": { - "type": "string", - "minLength": 1 - } - }, - "required": ["authId", "name"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/bitbucket.one": { - "get": { - "operationId": "bitbucket-one", - "tags": ["bitbucket"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "bitbucketId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/bitbucket.bitbucketProviders": { - "get": { - "operationId": "bitbucket-bitbucketProviders", - "tags": ["bitbucket"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/bitbucket.getBitbucketRepositories": { - "get": { - "operationId": "bitbucket-getBitbucketRepositories", - "tags": ["bitbucket"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "bitbucketId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/bitbucket.getBitbucketBranches": { - "get": { - "operationId": "bitbucket-getBitbucketBranches", - "tags": ["bitbucket"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "owner", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "repo", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "bitbucketId", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/bitbucket.testConnection": { - "post": { - "operationId": "bitbucket-testConnection", - "tags": ["bitbucket"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "bitbucketId": { - "type": "string", - "minLength": 1 - }, - "bitbucketUsername": { - "type": "string" - }, - "workspaceName": { - "type": "string" - } - }, - "required": ["bitbucketId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/bitbucket.update": { - "post": { - "operationId": "bitbucket-update", - "tags": ["bitbucket"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "bitbucketId": { - "type": "string", - "minLength": 1 - }, - "bitbucketUsername": { - "type": "string" - }, - "appPassword": { - "type": "string", - "nullable": true - }, - "bitbucketWorkspaceName": { - "type": "string" - }, - "gitProviderId": { - "type": "string" - }, - "name": { - "type": "string", - "minLength": 1 - }, - "adminId": { - "type": "string" - } - }, - "required": ["bitbucketId", "gitProviderId", "name"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/gitlab.create": { - "post": { - "operationId": "gitlab-create", - "tags": ["gitlab"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "gitlabId": { - "type": "string" - }, - "applicationId": { - "type": "string" - }, - "redirectUri": { - "type": "string" - }, - "secret": { - "type": "string" - }, - "accessToken": { - "type": "string", - "nullable": true - }, - "refreshToken": { - "type": "string", - "nullable": true - }, - "groupName": { - "type": "string" - }, - "expiresAt": { - "type": "number", - "nullable": true - }, - "gitProviderId": { - "type": "string" - }, - "authId": { - "type": "string", - "minLength": 1 - }, - "name": { - "type": "string", - "minLength": 1 - } - }, - "required": ["authId", "name"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/gitlab.one": { - "get": { - "operationId": "gitlab-one", - "tags": ["gitlab"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "gitlabId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/gitlab.gitlabProviders": { - "get": { - "operationId": "gitlab-gitlabProviders", - "tags": ["gitlab"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/gitlab.getGitlabRepositories": { - "get": { - "operationId": "gitlab-getGitlabRepositories", - "tags": ["gitlab"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "gitlabId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/gitlab.getGitlabBranches": { - "get": { - "operationId": "gitlab-getGitlabBranches", - "tags": ["gitlab"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "query", - "required": false, - "schema": { - "type": "number" - } - }, - { - "name": "owner", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "repo", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "gitlabId", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/gitlab.testConnection": { - "post": { - "operationId": "gitlab-testConnection", - "tags": ["gitlab"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "gitlabId": { - "type": "string" - }, - "groupName": { - "type": "string" - } - }, - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/gitlab.update": { - "post": { - "operationId": "gitlab-update", - "tags": ["gitlab"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "gitlabId": { - "type": "string", - "minLength": 1 - }, - "applicationId": { - "type": "string" - }, - "redirectUri": { - "type": "string" - }, - "secret": { - "type": "string" - }, - "accessToken": { - "type": "string", - "nullable": true - }, - "refreshToken": { - "type": "string", - "nullable": true - }, - "groupName": { - "type": "string" - }, - "expiresAt": { - "type": "number", - "nullable": true - }, - "gitProviderId": { - "type": "string" - }, - "name": { - "type": "string", - "minLength": 1 - } - }, - "required": ["gitlabId", "gitProviderId", "name"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/github.one": { - "get": { - "operationId": "github-one", - "tags": ["github"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "githubId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/github.getGithubRepositories": { - "get": { - "operationId": "github-getGithubRepositories", - "tags": ["github"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "githubId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/github.getGithubBranches": { - "get": { - "operationId": "github-getGithubBranches", - "tags": ["github"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "repo", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - }, - { - "name": "owner", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - }, - { - "name": "githubId", - "in": "query", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/github.githubProviders": { - "get": { - "operationId": "github-githubProviders", - "tags": ["github"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/github.testConnection": { - "post": { - "operationId": "github-testConnection", - "tags": ["github"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "githubId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["githubId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/github.update": { - "post": { - "operationId": "github-update", - "tags": ["github"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "githubId": { - "type": "string", - "minLength": 1 - }, - "githubAppName": { - "type": "string", - "nullable": true - }, - "githubAppId": { - "type": "number", - "nullable": true - }, - "githubClientId": { - "type": "string", - "nullable": true - }, - "githubClientSecret": { - "type": "string", - "nullable": true - }, - "githubInstallationId": { - "type": "string", - "nullable": true - }, - "githubPrivateKey": { - "type": "string", - "nullable": true - }, - "githubWebhookSecret": { - "type": "string", - "nullable": true - }, - "gitProviderId": { - "type": "string", - "minLength": 1 - }, - "name": { - "type": "string", - "minLength": 1 - } - }, - "required": ["githubId", "gitProviderId", "name"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/server.create": { - "post": { - "operationId": "server-create", - "tags": ["server"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "nullable": true - }, - "ipAddress": { - "type": "string" - }, - "port": { - "type": "number" - }, - "username": { - "type": "string" - }, - "sshKeyId": { - "type": "string", - "nullable": true - } - }, - "required": [ - "name", - "ipAddress", - "port", - "username", - "sshKeyId" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/server.one": { - "get": { - "operationId": "server-one", - "tags": ["server"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [ - { - "name": "serverId", - "in": "query", - "required": true, - "schema": { - "type": "string", - "minLength": 1 - } - } - ], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/server.all": { - "get": { - "operationId": "server-all", - "tags": ["server"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/server.withSSHKey": { - "get": { - "operationId": "server-withSSHKey", - "tags": ["server"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/server.setup": { - "post": { - "operationId": "server-setup", - "tags": ["server"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "serverId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["serverId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/server.remove": { - "post": { - "operationId": "server-remove", - "tags": ["server"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "serverId": { - "type": "string", - "minLength": 1 - } - }, - "required": ["serverId"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/server.update": { - "post": { - "operationId": "server-update", - "tags": ["server"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1 - }, - "description": { - "type": "string", - "nullable": true - }, - "serverId": { - "type": "string", - "minLength": 1 - }, - "ipAddress": { - "type": "string" - }, - "port": { - "type": "number" - }, - "username": { - "type": "string" - }, - "sshKeyId": { - "type": "string", - "nullable": true - } - }, - "required": [ - "name", - "serverId", - "ipAddress", - "port", - "username", - "sshKeyId" - ], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/stripe.getProducts": { - "get": { - "operationId": "stripe-getProducts", - "tags": ["stripe"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/stripe.createCheckoutSession": { - "post": { - "operationId": "stripe-createCheckoutSession", - "tags": ["stripe"], - "security": [ - { - "Authorization": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "productId": { - "type": "string" - }, - "serverQuantity": { - "type": "number", - "minimum": 1 - }, - "isAnnual": { - "type": "boolean" - } - }, - "required": ["productId", "serverQuantity", "isAnnual"], - "additionalProperties": false - } - } - } - }, - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/stripe.createCustomerPortalSession": { - "post": { - "operationId": "stripe-createCustomerPortalSession", - "tags": ["stripe"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - }, - "/stripe.canCreateMoreServers": { - "get": { - "operationId": "stripe-canCreateMoreServers", - "tags": ["stripe"], - "security": [ - { - "Authorization": [] - } - ], - "parameters": [], - "responses": { - "200": { - "description": "Successful response", - "content": { - "application/json": {} - } - }, - "default": { - "$ref": "#/components/responses/error" - } - } - } - } - }, - "components": { - "securitySchemes": { - "Authorization": { - "type": "http", - "scheme": "bearer" - } - }, - "responses": { - "error": { - "description": "Error response", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "code": { - "type": "string" - }, - "issues": { - "type": "array", - "items": { - "type": "object", - "properties": { - "message": { - "type": "string" - } - }, - "required": ["message"], - "additionalProperties": false - } - } - }, - "required": ["message", "code"], - "additionalProperties": false - } - } - } - } - } - }, - "tags": [ - { - "name": "admin" - }, - { - "name": "docker" - }, - { - "name": "compose" - }, - { - "name": "registry" - }, - { - "name": "cluster" - }, - { - "name": "user" - }, - { - "name": "domain" - }, - { - "name": "destination" - }, - { - "name": "backup" - }, - { - "name": "deployment" - }, - { - "name": "mounts" - }, - { - "name": "certificates" - }, - { - "name": "settings" - }, - { - "name": "security" - }, - { - "name": "redirects" - }, - { - "name": "port" - }, - { - "name": "project" - }, - { - "name": "application" - }, - { - "name": "mysql" - }, - { - "name": "postgres" - }, - { - "name": "redis" - }, - { - "name": "mongo" - }, - { - "name": "mariadb" - }, - { - "name": "sshRouter" - }, - { - "name": "gitProvider" - }, - { - "name": "bitbucket" - }, - { - "name": "github" - }, - { - "name": "gitlab" - } - ], - "externalDocs": { - "url": "http://app.dokploy.com/api/settings.getOpenApiDocument" - } -} diff --git a/apps/docs/app/api/search/route.ts b/apps/docs/app/api/search/route.ts index d86bfc5..909984d 100644 --- a/apps/docs/app/api/search/route.ts +++ b/apps/docs/app/api/search/route.ts @@ -1,4 +1,21 @@ import { source } from "@/lib/source"; import { createFromSource } from "fumadocs-core/search/server"; +import type { InferPageType } from "fumadocs-core/source"; -export const { GET } = createFromSource(source); +export const { GET } = createFromSource(source, { + // https://docs.orama.com/docs/orama-js/supported-languages + language: "english", + // Configure tag filter based on the first slug (core, cli, api) + buildIndex(page: InferPageType) { + const tag = page.slugs[0] || "all"; + return { + title: page.data.title, + description: page.data.description, + url: page.url, + id: page.url, + structuredData: page.data.structuredData, + // Assign tag based on the first slug (core, cli, api) + tag, + } as any; + }, +}); diff --git a/apps/docs/app/docs/[[...slug]]/page.tsx b/apps/docs/app/docs/[[...slug]]/page.tsx index 1527077..107e020 100644 --- a/apps/docs/app/docs/[[...slug]]/page.tsx +++ b/apps/docs/app/docs/[[...slug]]/page.tsx @@ -1,117 +1,54 @@ -import { source } from "@/lib/source"; -import { openapi } from "@/lib/source"; -import { baseUrl } from "@/utils/metadata"; -import { ImageZoom } from "fumadocs-ui/components/image-zoom"; -import defaultMdxComponents from "fumadocs-ui/mdx"; +import { getPageImage, source } from "@/lib/source"; +import { getMDXComponents } from "@/mdx-components"; import { - DocsBody, - DocsDescription, - DocsPage, - DocsTitle, -} from "fumadocs-ui/page"; -import { notFound, permanentRedirect } from "next/navigation"; + DocsBody, + DocsDescription, + DocsPage, + DocsTitle, +} from "fumadocs-ui/layouts/docs/page"; +import { createRelativeLink } from "fumadocs-ui/mdx"; +import type { Metadata } from "next"; +import { notFound } from "next/navigation"; -export default async function Page(props: { - params: Promise<{ slug?: string[] }>; -}) { - const params = await props.params; - const page = source.getPage(params.slug); - if (!page) { - permanentRedirect("/docs/core"); - } +export default async function Page(props: PageProps<"/docs/[[...slug]]">) { + const params = await props.params; + const page = source.getPage(params.slug); + if (!page) notFound(); - const MDX = page.data.body; + const MDX = page.data.body; - return ( - - {page.data.title} - {page.data.description} - - , - p: ({ children }) => ( -

- {children} -

- ), - li: ({ children, id }) => ( -
  • - {children} -
  • - ), - APIPage: openapi.APIPage, - }} - /> -
    -
    - ); + return ( + + {page.data.title} + {page.data.description} + + + + + ); } export async function generateStaticParams() { - return source.generateParams(); + return source.generateParams(); } -export async function generateMetadata(props: { - params: Promise<{ slug?: string[] }>; -}) { - const params = await props.params; - const page = source.getPage(params.slug); - if (!page) notFound(); +export async function generateMetadata( + props: PageProps<"/docs/[[...slug]]">, +): Promise { + const params = await props.params; + const page = source.getPage(params.slug); + if (!page) notFound(); - return { - title: page.data.title, - - description: page.data.description, - robots: "index,follow", - alternates: { - canonical: new URL(`${baseUrl}${page.url}`).toString(), - languages: { - en: `${baseUrl}/${page.url}`, - }, - }, - openGraph: { - title: page.data.title, - description: page.data.description, - url: new URL(`${baseUrl}`).toString(), - images: [ - { - url: new URL(`${baseUrl}/logo.png`).toString(), - width: 1200, - height: 630, - alt: page.data.title, - }, - ], - }, - twitter: { - card: "summary_large_image", - creator: "@getdokploy", - title: page.data.title, - description: page.data.description, - images: [ - { - url: new URL(`${baseUrl}/logo.png`).toString(), - width: 1200, - height: 630, - alt: page.data.title, - }, - ], - }, - applicationName: "Dokploy Docs", - keywords: [ - "dokploy", - "vps", - "open source", - "cloud", - "self hosting", - "free", - ], - icons: { - icon: "/icon.svg", - }, - }; + return { + title: page.data.title, + description: page.data.description, + openGraph: { + images: getPageImage(page).url, + }, + }; } diff --git a/apps/docs/app/docs/layout.tsx b/apps/docs/app/docs/layout.tsx index 322a090..027d6cb 100644 --- a/apps/docs/app/docs/layout.tsx +++ b/apps/docs/app/docs/layout.tsx @@ -1,22 +1,11 @@ -import { baseOptions } from "@/app/layout.config"; +import { baseOptions } from "@/lib/layout.shared"; import { source } from "@/lib/source"; -import { baseUrl, createMetadata } from "@/utils/metadata"; import { DocsLayout } from "fumadocs-ui/layouts/docs"; -import type { ReactNode } from "react"; -export const metadata = createMetadata({ - title: { - template: "%s | Dokploy", - default: "Dokploy", - }, - description: "The Open Source Alternative to Vercel, Heroku, and Netlify", - metadataBase: new URL(baseUrl), -}); - -export default function Layout({ children }: { children: ReactNode }) { - return ( - - {children} - - ); +export default function Layout({ children }: LayoutProps<"/docs">) { + return ( + + {children} + + ); } diff --git a/apps/docs/app/favicon-16x16.png b/apps/docs/app/favicon-16x16.png new file mode 100644 index 0000000..246b15c Binary files /dev/null and b/apps/docs/app/favicon-16x16.png differ diff --git a/apps/docs/app/favicon-32x32.png b/apps/docs/app/favicon-32x32.png new file mode 100644 index 0000000..a15c3da Binary files /dev/null and b/apps/docs/app/favicon-32x32.png differ diff --git a/apps/docs/app/favicon.ico b/apps/docs/app/favicon.ico new file mode 100644 index 0000000..bb92b63 Binary files /dev/null and b/apps/docs/app/favicon.ico differ diff --git a/apps/docs/app/global.css b/apps/docs/app/global.css index bb99b0e..89bdfc3 100644 --- a/apps/docs/app/global.css +++ b/apps/docs/app/global.css @@ -1,18 +1,123 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import 'tailwindcss'; +@import 'fumadocs-ui/css/solar.css'; +@import 'fumadocs-ui/css/preset.css'; +@import 'fumadocs-openapi/css/preset.css'; +@import "tw-animate-css"; +@custom-variant dark (&:is(.dark *)); +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} - :root { - --fd-background: 0 0% 0%; - --background: 0 0% 100%; - --card: 0 0% 97.6%; +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; } - - .dark{ - --fd-background: 0 0% 100%; - --background: 0 0% 0%; - --card: 0 0% 6.0%; + body { + @apply bg-background text-foreground; } +} diff --git a/apps/docs/app/layout.config.tsx b/apps/docs/app/layout.config.tsx deleted file mode 100644 index b643745..0000000 --- a/apps/docs/app/layout.config.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared"; -import { - Github, - GlobeIcon, - HeartIcon, - Rss, - LogIn, - UserPlus, -} from "lucide-react"; -import Link from "next/link"; -/** - * Shared layout configurations - * - * you can configure layouts individually from: - * Home Layout: app/(home)/layout.tsx - * Docs Layout: app/docs/layout.tsx - */ - -export const Logo = () => { - return ( - - - - - - - - ); -}; - -export const baseOptions: BaseLayoutProps = { - nav: { - // title: "Dokploy", - children: ( - - - Dokploy - - ), - }, - links: [ - { - text: "Login", - url: "https://app.dokploy.com/", - active: "nested-url", - icon: , - }, - { - text: "Sign Up", - url: "https://app.dokploy.com/register", - active: "nested-url", - icon: , - }, - { - text: "Website", - url: "https://dokploy.com", - active: "nested-url", - icon: , - }, - { - text: "Discord", - url: "https://discord.com/invite/2tBnJ3jDJc", - active: "nested-url", - icon: ( - <> - - - - - ), - }, - { - text: "Support", - url: "https://opencollective.com/dokploy", - active: "nested-url", - icon: ( - <> - - - ), - }, - { - text: "Github", - url: "https://github.com/dokploy/dokploy", - active: "nested-url", - icon: ( - <> - - - ), - }, - { - text: "Blog", - url: "https://dokploy.com/blog", - active: "nested-url", - icon: ( - <> - - - ), - }, - ], -}; diff --git a/apps/docs/app/layout.tsx b/apps/docs/app/layout.tsx index d2bd648..b0a09c4 100644 --- a/apps/docs/app/layout.tsx +++ b/apps/docs/app/layout.tsx @@ -1,24 +1,50 @@ +import { RootProvider } from "fumadocs-ui/provider/next"; import "./global.css"; -import { RootProvider } from "fumadocs-ui/provider"; -import { Inter } from "next/font/google"; -import type { ReactNode } from "react"; +import SearchDialog from "@/components/SearchDialog"; import { GoogleAnalytics } from "@next/third-parties/google"; +import type { Metadata } from "next"; +import { Inter } from "next/font/google"; + const inter = Inter({ - subsets: ["latin"], + subsets: ["latin"], }); -export default async function Layout({ - children, - ...rest -}: { - children: ReactNode; -}) { - return ( - - - - {children} - - - ); +export const metadata: Metadata = { + title: { + default: "Dokploy Documentation", + template: "%s | Dokploy", + }, + description: + "Open Source Alternative to Vercel, Netlify and Heroku. Deploy your applications with ease.", + keywords: [ + "dokploy", + "deployment", + "docker", + "hosting", + "devops", + "open source", + ], + authors: [{ name: "Dokploy Team" }], + openGraph: { + title: "Dokploy Documentation", + description: "Open Source Alternative to Vercel, Netlify and Heroku", + type: "website", + }, +}; + +export default function Layout({ children }: LayoutProps<"/">) { + return ( + + + + + {children} + + + + ); } diff --git a/apps/docs/app/llms-full.txt/route.ts b/apps/docs/app/llms-full.txt/route.ts new file mode 100644 index 0000000..b5b8fe6 --- /dev/null +++ b/apps/docs/app/llms-full.txt/route.ts @@ -0,0 +1,10 @@ +import { getLLMText, source } from "@/lib/source"; + +export const revalidate = false; + +export async function GET() { + const scan = source.getPages().map(getLLMText); + const scanned = await Promise.all(scan); + + return new Response(scanned.join("\n\n")); +} diff --git a/apps/docs/app/og/docs/[...slug]/route.tsx b/apps/docs/app/og/docs/[...slug]/route.tsx new file mode 100644 index 0000000..0b9be2f --- /dev/null +++ b/apps/docs/app/og/docs/[...slug]/route.tsx @@ -0,0 +1,34 @@ +import { getPageImage, source } from "@/lib/source"; +import { generate as DefaultImage } from "fumadocs-ui/og"; +import { notFound } from "next/navigation"; +import { ImageResponse } from "next/og"; + +export const revalidate = false; + +export async function GET( + _req: Request, + { params }: RouteContext<"/og/docs/[...slug]">, +) { + const { slug } = await params; + const page = source.getPage(slug.slice(0, -1)); + if (!page) notFound(); + + return new ImageResponse( + , + { + width: 1200, + height: 630, + }, + ); +} + +export function generateStaticParams() { + return source.getPages().map((page) => ({ + lang: page.locale, + slug: getPageImage(page).segments, + })); +} diff --git a/apps/docs/app/robots.ts b/apps/docs/app/robots.ts deleted file mode 100644 index 1c2ea94..0000000 --- a/apps/docs/app/robots.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { MetadataRoute } from "next"; - -export default function robots(): MetadataRoute.Robots { - return { - rules: { - userAgent: "*", - allow: "/", - }, - sitemap: "https://docs.dokploy.com/sitemap.xml", - }; -} diff --git a/apps/docs/app/sitemap.ts b/apps/docs/app/sitemap.ts deleted file mode 100644 index 49a40f1..0000000 --- a/apps/docs/app/sitemap.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { source } from "@/lib/source"; -import { url } from "@/utils/metadata"; -import type { MetadataRoute } from "next"; - -export default async function sitemap(): Promise { - return [ - ...(await Promise.all( - source.getPages().map(async (page) => { - const { lastModified } = page.data; - return { - url: url(page.url), - lastModified: lastModified ? new Date(lastModified) : undefined, - changeFrequency: "weekly", - priority: 0.5, - } as MetadataRoute.Sitemap[number]; - }), - )), - ]; -} diff --git a/apps/docs/components.json b/apps/docs/components.json new file mode 100644 index 0000000..3f9ec16 --- /dev/null +++ b/apps/docs/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "app/global.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} +} diff --git a/apps/docs/components/Logo.tsx b/apps/docs/components/Logo.tsx new file mode 100644 index 0000000..1113f68 --- /dev/null +++ b/apps/docs/components/Logo.tsx @@ -0,0 +1,27 @@ +import type { ComponentPropsWithoutRef } from "react"; + +export function Logo(props: ComponentPropsWithoutRef<"svg">) { + return ( + + + + + + + + ); +} diff --git a/apps/docs/components/NavLinks.tsx b/apps/docs/components/NavLinks.tsx new file mode 100644 index 0000000..89614ee --- /dev/null +++ b/apps/docs/components/NavLinks.tsx @@ -0,0 +1,95 @@ +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Menu } from "lucide-react"; +import { Github, Globe, Heart, LogIn, Rss, UserPlus } from "lucide-react"; + +export function NavLinks() { + const links = [ + { + text: "Login", + url: "https://app.dokploy.com/", + icon: LogIn, + }, + { + text: "Sign Up", + url: "https://app.dokploy.com/register", + icon: UserPlus, + }, + { + text: "Website", + url: "https://dokploy.com", + icon: Globe, + }, + { + text: "Discord", + url: "https://discord.com/invite/2tBnJ3jDJc", + icon: () => ( + + + + ), + }, + { + text: "Support", + url: "https://opencollective.com/dokploy", + icon: Heart, + }, + { + text: "Github", + url: "https://github.com/dokploy/dokploy", + icon: Github, + }, + { + text: "Blog", + url: "https://dokploy.com/blog", + icon: Rss, + }, + ]; + + return ( + + + + + + {links.map((link, index) => { + const IconComponent = link.icon; + const showSeparator = index === 2; + + return ( +
    + + + + {link.text} + + + {showSeparator && } +
    + ); + })} +
    +
    + ); +} diff --git a/apps/docs/components/SearchDialog.tsx b/apps/docs/components/SearchDialog.tsx new file mode 100644 index 0000000..bf8178c --- /dev/null +++ b/apps/docs/components/SearchDialog.tsx @@ -0,0 +1,54 @@ +"use client"; + +import { useDocsSearch } from "fumadocs-core/search/client"; +import { + SearchDialog, + SearchDialogClose, + SearchDialogContent, + SearchDialogFooter, + SearchDialogHeader, + SearchDialogIcon, + SearchDialogInput, + SearchDialogList, + SearchDialogOverlay, + type SharedProps, + TagsList, + TagsListItem, +} from "fumadocs-ui/components/dialog/search"; +import { useState } from "react"; + +export default function CustomSearchDialog(props: SharedProps) { + const [tag, setTag] = useState("all"); + // When tag is "all", don't filter by tag (pass undefined) + const { search, setSearch, query } = useDocsSearch({ + type: "fetch", + tag: tag === "all" ? undefined : tag, + }); + + return ( + + + + + + + + + + + + All + Core + CLI + API + + + + + ); +} diff --git a/apps/docs/components/ui/dropdown-menu.tsx b/apps/docs/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..129ec40 --- /dev/null +++ b/apps/docs/components/ui/dropdown-menu.tsx @@ -0,0 +1,257 @@ +"use client"; + +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; +import type * as React from "react"; + +import { cn } from "@/lib/utils"; + +function DropdownMenu({ + ...props +}: React.ComponentProps) { + return ; +} + +function DropdownMenuPortal({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuContent({ + className, + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +function DropdownMenuGroup({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuItem({ + className, + inset, + variant = "default", + ...props +}: React.ComponentProps & { + inset?: boolean; + variant?: "default" | "destructive"; +}) { + return ( + + ); +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + ); +} + +function DropdownMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { + return ( + + ); +} + +function DropdownMenuSub({ + ...props +}: React.ComponentProps) { + return ; +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + {children} + + + ); +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, +}; diff --git a/apps/docs/content/docs/api/admin.mdx b/apps/docs/content/docs/api/admin.mdx new file mode 100644 index 0000000..c3f863e --- /dev/null +++ b/apps/docs/content/docs/api/admin.mdx @@ -0,0 +1,19 @@ +--- +title: Admin +full: true +_openapi: + method: POST + toc: + - depth: 2 + title: Admin setup Monitoring + url: '#admin-setup-monitoring' + structuredData: + headings: + - content: Admin setup Monitoring + id: admin-setup-monitoring + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/ai.mdx b/apps/docs/content/docs/api/ai.mdx new file mode 100644 index 0000000..cacee78 --- /dev/null +++ b/apps/docs/content/docs/api/ai.mdx @@ -0,0 +1,58 @@ +--- +title: Ai +full: true +_openapi: + toc: + - depth: 2 + title: Ai one + url: '#ai-one' + - depth: 2 + title: Ai get Models + url: '#ai-get-models' + - depth: 2 + title: Ai create + url: '#ai-create' + - depth: 2 + title: Ai update + url: '#ai-update' + - depth: 2 + title: Ai get All + url: '#ai-get-all' + - depth: 2 + title: Ai get + url: '#ai-get' + - depth: 2 + title: Ai delete + url: '#ai-delete' + - depth: 2 + title: Ai suggest + url: '#ai-suggest' + - depth: 2 + title: Ai deploy + url: '#ai-deploy' + structuredData: + headings: + - content: Ai one + id: ai-one + - content: Ai get Models + id: ai-get-models + - content: Ai create + id: ai-create + - content: Ai update + id: ai-update + - content: Ai get All + id: ai-get-all + - content: Ai get + id: ai-get + - content: Ai delete + id: ai-delete + - content: Ai suggest + id: ai-suggest + - content: Ai deploy + id: ai-deploy + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/application.mdx b/apps/docs/content/docs/api/application.mdx new file mode 100644 index 0000000..0cd577e --- /dev/null +++ b/apps/docs/content/docs/api/application.mdx @@ -0,0 +1,148 @@ +--- +title: Application +full: true +_openapi: + toc: + - depth: 2 + title: Application create + url: '#application-create' + - depth: 2 + title: Application one + url: '#application-one' + - depth: 2 + title: Application reload + url: '#application-reload' + - depth: 2 + title: Application delete + url: '#application-delete' + - depth: 2 + title: Application stop + url: '#application-stop' + - depth: 2 + title: Application start + url: '#application-start' + - depth: 2 + title: Application redeploy + url: '#application-redeploy' + - depth: 2 + title: Application save Environment + url: '#application-save-environment' + - depth: 2 + title: Application save Build Type + url: '#application-save-build-type' + - depth: 2 + title: Application save Github Provider + url: '#application-save-github-provider' + - depth: 2 + title: Application save Gitlab Provider + url: '#application-save-gitlab-provider' + - depth: 2 + title: Application save Bitbucket Provider + url: '#application-save-bitbucket-provider' + - depth: 2 + title: Application save Gitea Provider + url: '#application-save-gitea-provider' + - depth: 2 + title: Application save Docker Provider + url: '#application-save-docker-provider' + - depth: 2 + title: Application save Git Provider + url: '#application-save-git-provider' + - depth: 2 + title: Application disconnect Git Provider + url: '#application-disconnect-git-provider' + - depth: 2 + title: Application mark Running + url: '#application-mark-running' + - depth: 2 + title: Application update + url: '#application-update' + - depth: 2 + title: Application refresh Token + url: '#application-refresh-token' + - depth: 2 + title: Application deploy + url: '#application-deploy' + - depth: 2 + title: Application clean Queues + url: '#application-clean-queues' + - depth: 2 + title: Application kill Build + url: '#application-kill-build' + - depth: 2 + title: Application read Traefik Config + url: '#application-read-traefik-config' + - depth: 2 + title: Application update Traefik Config + url: '#application-update-traefik-config' + - depth: 2 + title: Application read App Monitoring + url: '#application-read-app-monitoring' + - depth: 2 + title: Application move + url: '#application-move' + - depth: 2 + title: Application cancel Deployment + url: '#application-cancel-deployment' + structuredData: + headings: + - content: Application create + id: application-create + - content: Application one + id: application-one + - content: Application reload + id: application-reload + - content: Application delete + id: application-delete + - content: Application stop + id: application-stop + - content: Application start + id: application-start + - content: Application redeploy + id: application-redeploy + - content: Application save Environment + id: application-save-environment + - content: Application save Build Type + id: application-save-build-type + - content: Application save Github Provider + id: application-save-github-provider + - content: Application save Gitlab Provider + id: application-save-gitlab-provider + - content: Application save Bitbucket Provider + id: application-save-bitbucket-provider + - content: Application save Gitea Provider + id: application-save-gitea-provider + - content: Application save Docker Provider + id: application-save-docker-provider + - content: Application save Git Provider + id: application-save-git-provider + - content: Application disconnect Git Provider + id: application-disconnect-git-provider + - content: Application mark Running + id: application-mark-running + - content: Application update + id: application-update + - content: Application refresh Token + id: application-refresh-token + - content: Application deploy + id: application-deploy + - content: Application clean Queues + id: application-clean-queues + - content: Application kill Build + id: application-kill-build + - content: Application read Traefik Config + id: application-read-traefik-config + - content: Application update Traefik Config + id: application-update-traefik-config + - content: Application read App Monitoring + id: application-read-app-monitoring + - content: Application move + id: application-move + - content: Application cancel Deployment + id: application-cancel-deployment + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/backup.mdx b/apps/docs/content/docs/api/backup.mdx new file mode 100644 index 0000000..68e6438 --- /dev/null +++ b/apps/docs/content/docs/api/backup.mdx @@ -0,0 +1,68 @@ +--- +title: Backup +full: true +_openapi: + toc: + - depth: 2 + title: Backup create + url: '#backup-create' + - depth: 2 + title: Backup one + url: '#backup-one' + - depth: 2 + title: Backup update + url: '#backup-update' + - depth: 2 + title: Backup remove + url: '#backup-remove' + - depth: 2 + title: Backup manual Backup Postgres + url: '#backup-manual-backup-postgres' + - depth: 2 + title: Backup manual Backup My Sql + url: '#backup-manual-backup-my-sql' + - depth: 2 + title: Backup manual Backup Mariadb + url: '#backup-manual-backup-mariadb' + - depth: 2 + title: Backup manual Backup Compose + url: '#backup-manual-backup-compose' + - depth: 2 + title: Backup manual Backup Mongo + url: '#backup-manual-backup-mongo' + - depth: 2 + title: Backup manual Backup Web Server + url: '#backup-manual-backup-web-server' + - depth: 2 + title: Backup list Backup Files + url: '#backup-list-backup-files' + structuredData: + headings: + - content: Backup create + id: backup-create + - content: Backup one + id: backup-one + - content: Backup update + id: backup-update + - content: Backup remove + id: backup-remove + - content: Backup manual Backup Postgres + id: backup-manual-backup-postgres + - content: Backup manual Backup My Sql + id: backup-manual-backup-my-sql + - content: Backup manual Backup Mariadb + id: backup-manual-backup-mariadb + - content: Backup manual Backup Compose + id: backup-manual-backup-compose + - content: Backup manual Backup Mongo + id: backup-manual-backup-mongo + - content: Backup manual Backup Web Server + id: backup-manual-backup-web-server + - content: Backup list Backup Files + id: backup-list-backup-files + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/bitbucket.mdx b/apps/docs/content/docs/api/bitbucket.mdx new file mode 100644 index 0000000..2f6b59c --- /dev/null +++ b/apps/docs/content/docs/api/bitbucket.mdx @@ -0,0 +1,48 @@ +--- +title: Bitbucket +full: true +_openapi: + toc: + - depth: 2 + title: Bitbucket create + url: '#bitbucket-create' + - depth: 2 + title: Bitbucket one + url: '#bitbucket-one' + - depth: 2 + title: Bitbucket bitbucket Providers + url: '#bitbucket-bitbucket-providers' + - depth: 2 + title: Bitbucket get Bitbucket Repositories + url: '#bitbucket-get-bitbucket-repositories' + - depth: 2 + title: Bitbucket get Bitbucket Branches + url: '#bitbucket-get-bitbucket-branches' + - depth: 2 + title: Bitbucket test Connection + url: '#bitbucket-test-connection' + - depth: 2 + title: Bitbucket update + url: '#bitbucket-update' + structuredData: + headings: + - content: Bitbucket create + id: bitbucket-create + - content: Bitbucket one + id: bitbucket-one + - content: Bitbucket bitbucket Providers + id: bitbucket-bitbucket-providers + - content: Bitbucket get Bitbucket Repositories + id: bitbucket-get-bitbucket-repositories + - content: Bitbucket get Bitbucket Branches + id: bitbucket-get-bitbucket-branches + - content: Bitbucket test Connection + id: bitbucket-test-connection + - content: Bitbucket update + id: bitbucket-update + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/certificates.mdx b/apps/docs/content/docs/api/certificates.mdx new file mode 100644 index 0000000..fc699d6 --- /dev/null +++ b/apps/docs/content/docs/api/certificates.mdx @@ -0,0 +1,33 @@ +--- +title: Certificates +full: true +_openapi: + toc: + - depth: 2 + title: Certificates create + url: '#certificates-create' + - depth: 2 + title: Certificates one + url: '#certificates-one' + - depth: 2 + title: Certificates remove + url: '#certificates-remove' + - depth: 2 + title: Certificates all + url: '#certificates-all' + structuredData: + headings: + - content: Certificates create + id: certificates-create + - content: Certificates one + id: certificates-one + - content: Certificates remove + id: certificates-remove + - content: Certificates all + id: certificates-all + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/cluster.mdx b/apps/docs/content/docs/api/cluster.mdx new file mode 100644 index 0000000..601dbd3 --- /dev/null +++ b/apps/docs/content/docs/api/cluster.mdx @@ -0,0 +1,33 @@ +--- +title: Cluster +full: true +_openapi: + toc: + - depth: 2 + title: Cluster get Nodes + url: '#cluster-get-nodes' + - depth: 2 + title: Cluster remove Worker + url: '#cluster-remove-worker' + - depth: 2 + title: Cluster add Worker + url: '#cluster-add-worker' + - depth: 2 + title: Cluster add Manager + url: '#cluster-add-manager' + structuredData: + headings: + - content: Cluster get Nodes + id: cluster-get-nodes + - content: Cluster remove Worker + id: cluster-remove-worker + - content: Cluster add Worker + id: cluster-add-worker + - content: Cluster add Manager + id: cluster-add-manager + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/compose.mdx b/apps/docs/content/docs/api/compose.mdx new file mode 100644 index 0000000..f2a4fa3 --- /dev/null +++ b/apps/docs/content/docs/api/compose.mdx @@ -0,0 +1,143 @@ +--- +title: Compose +full: true +_openapi: + toc: + - depth: 2 + title: Compose create + url: '#compose-create' + - depth: 2 + title: Compose one + url: '#compose-one' + - depth: 2 + title: Compose update + url: '#compose-update' + - depth: 2 + title: Compose delete + url: '#compose-delete' + - depth: 2 + title: Compose clean Queues + url: '#compose-clean-queues' + - depth: 2 + title: Compose kill Build + url: '#compose-kill-build' + - depth: 2 + title: Compose load Services + url: '#compose-load-services' + - depth: 2 + title: Compose load Mounts By Service + url: '#compose-load-mounts-by-service' + - depth: 2 + title: Compose fetch Source Type + url: '#compose-fetch-source-type' + - depth: 2 + title: Compose randomize Compose + url: '#compose-randomize-compose' + - depth: 2 + title: Compose isolated Deployment + url: '#compose-isolated-deployment' + - depth: 2 + title: Compose get Converted Compose + url: '#compose-get-converted-compose' + - depth: 2 + title: Compose deploy + url: '#compose-deploy' + - depth: 2 + title: Compose redeploy + url: '#compose-redeploy' + - depth: 2 + title: Compose stop + url: '#compose-stop' + - depth: 2 + title: Compose start + url: '#compose-start' + - depth: 2 + title: Compose get Default Command + url: '#compose-get-default-command' + - depth: 2 + title: Compose refresh Token + url: '#compose-refresh-token' + - depth: 2 + title: Compose deploy Template + url: '#compose-deploy-template' + - depth: 2 + title: Compose templates + url: '#compose-templates' + - depth: 2 + title: Compose get Tags + url: '#compose-get-tags' + - depth: 2 + title: Compose disconnect Git Provider + url: '#compose-disconnect-git-provider' + - depth: 2 + title: Compose move + url: '#compose-move' + - depth: 2 + title: Compose process Template + url: '#compose-process-template' + - depth: 2 + title: Compose import + url: '#compose-import' + - depth: 2 + title: Compose cancel Deployment + url: '#compose-cancel-deployment' + structuredData: + headings: + - content: Compose create + id: compose-create + - content: Compose one + id: compose-one + - content: Compose update + id: compose-update + - content: Compose delete + id: compose-delete + - content: Compose clean Queues + id: compose-clean-queues + - content: Compose kill Build + id: compose-kill-build + - content: Compose load Services + id: compose-load-services + - content: Compose load Mounts By Service + id: compose-load-mounts-by-service + - content: Compose fetch Source Type + id: compose-fetch-source-type + - content: Compose randomize Compose + id: compose-randomize-compose + - content: Compose isolated Deployment + id: compose-isolated-deployment + - content: Compose get Converted Compose + id: compose-get-converted-compose + - content: Compose deploy + id: compose-deploy + - content: Compose redeploy + id: compose-redeploy + - content: Compose stop + id: compose-stop + - content: Compose start + id: compose-start + - content: Compose get Default Command + id: compose-get-default-command + - content: Compose refresh Token + id: compose-refresh-token + - content: Compose deploy Template + id: compose-deploy-template + - content: Compose templates + id: compose-templates + - content: Compose get Tags + id: compose-get-tags + - content: Compose disconnect Git Provider + id: compose-disconnect-git-provider + - content: Compose move + id: compose-move + - content: Compose process Template + id: compose-process-template + - content: Compose import + id: compose-import + - content: Compose cancel Deployment + id: compose-cancel-deployment + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/deployment.mdx b/apps/docs/content/docs/api/deployment.mdx new file mode 100644 index 0000000..67a5b8d --- /dev/null +++ b/apps/docs/content/docs/api/deployment.mdx @@ -0,0 +1,38 @@ +--- +title: Deployment +full: true +_openapi: + toc: + - depth: 2 + title: Deployment all + url: '#deployment-all' + - depth: 2 + title: Deployment all By Compose + url: '#deployment-all-by-compose' + - depth: 2 + title: Deployment all By Server + url: '#deployment-all-by-server' + - depth: 2 + title: Deployment all By Type + url: '#deployment-all-by-type' + - depth: 2 + title: Deployment kill Process + url: '#deployment-kill-process' + structuredData: + headings: + - content: Deployment all + id: deployment-all + - content: Deployment all By Compose + id: deployment-all-by-compose + - content: Deployment all By Server + id: deployment-all-by-server + - content: Deployment all By Type + id: deployment-all-by-type + - content: Deployment kill Process + id: deployment-kill-process + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/destination.mdx b/apps/docs/content/docs/api/destination.mdx new file mode 100644 index 0000000..28c15b4 --- /dev/null +++ b/apps/docs/content/docs/api/destination.mdx @@ -0,0 +1,43 @@ +--- +title: Destination +full: true +_openapi: + toc: + - depth: 2 + title: Destination create + url: '#destination-create' + - depth: 2 + title: Destination test Connection + url: '#destination-test-connection' + - depth: 2 + title: Destination one + url: '#destination-one' + - depth: 2 + title: Destination all + url: '#destination-all' + - depth: 2 + title: Destination remove + url: '#destination-remove' + - depth: 2 + title: Destination update + url: '#destination-update' + structuredData: + headings: + - content: Destination create + id: destination-create + - content: Destination test Connection + id: destination-test-connection + - content: Destination one + id: destination-one + - content: Destination all + id: destination-all + - content: Destination remove + id: destination-remove + - content: Destination update + id: destination-update + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/docker.mdx b/apps/docs/content/docs/api/docker.mdx new file mode 100644 index 0000000..2aa6c1c --- /dev/null +++ b/apps/docs/content/docs/api/docker.mdx @@ -0,0 +1,48 @@ +--- +title: Docker +full: true +_openapi: + toc: + - depth: 2 + title: Docker get Containers + url: '#docker-get-containers' + - depth: 2 + title: Docker restart Container + url: '#docker-restart-container' + - depth: 2 + title: Docker get Config + url: '#docker-get-config' + - depth: 2 + title: Docker get Containers By App Name Match + url: '#docker-get-containers-by-app-name-match' + - depth: 2 + title: Docker get Containers By App Label + url: '#docker-get-containers-by-app-label' + - depth: 2 + title: Docker get Stack Containers By App Name + url: '#docker-get-stack-containers-by-app-name' + - depth: 2 + title: Docker get Service Containers By App Name + url: '#docker-get-service-containers-by-app-name' + structuredData: + headings: + - content: Docker get Containers + id: docker-get-containers + - content: Docker restart Container + id: docker-restart-container + - content: Docker get Config + id: docker-get-config + - content: Docker get Containers By App Name Match + id: docker-get-containers-by-app-name-match + - content: Docker get Containers By App Label + id: docker-get-containers-by-app-label + - content: Docker get Stack Containers By App Name + id: docker-get-stack-containers-by-app-name + - content: Docker get Service Containers By App Name + id: docker-get-service-containers-by-app-name + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/domain.mdx b/apps/docs/content/docs/api/domain.mdx new file mode 100644 index 0000000..37cdd26 --- /dev/null +++ b/apps/docs/content/docs/api/domain.mdx @@ -0,0 +1,58 @@ +--- +title: Domain +full: true +_openapi: + toc: + - depth: 2 + title: Domain create + url: '#domain-create' + - depth: 2 + title: Domain by Application Id + url: '#domain-by-application-id' + - depth: 2 + title: Domain by Compose Id + url: '#domain-by-compose-id' + - depth: 2 + title: Domain generate Domain + url: '#domain-generate-domain' + - depth: 2 + title: Domain can Generate Traefik Me Domains + url: '#domain-can-generate-traefik-me-domains' + - depth: 2 + title: Domain update + url: '#domain-update' + - depth: 2 + title: Domain one + url: '#domain-one' + - depth: 2 + title: Domain delete + url: '#domain-delete' + - depth: 2 + title: Domain validate Domain + url: '#domain-validate-domain' + structuredData: + headings: + - content: Domain create + id: domain-create + - content: Domain by Application Id + id: domain-by-application-id + - content: Domain by Compose Id + id: domain-by-compose-id + - content: Domain generate Domain + id: domain-generate-domain + - content: Domain can Generate Traefik Me Domains + id: domain-can-generate-traefik-me-domains + - content: Domain update + id: domain-update + - content: Domain one + id: domain-one + - content: Domain delete + id: domain-delete + - content: Domain validate Domain + id: domain-validate-domain + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/environment.mdx b/apps/docs/content/docs/api/environment.mdx new file mode 100644 index 0000000..b3afe7b --- /dev/null +++ b/apps/docs/content/docs/api/environment.mdx @@ -0,0 +1,43 @@ +--- +title: Environment +full: true +_openapi: + toc: + - depth: 2 + title: Environment create + url: '#environment-create' + - depth: 2 + title: Environment one + url: '#environment-one' + - depth: 2 + title: Environment by Project Id + url: '#environment-by-project-id' + - depth: 2 + title: Environment remove + url: '#environment-remove' + - depth: 2 + title: Environment update + url: '#environment-update' + - depth: 2 + title: Environment duplicate + url: '#environment-duplicate' + structuredData: + headings: + - content: Environment create + id: environment-create + - content: Environment one + id: environment-one + - content: Environment by Project Id + id: environment-by-project-id + - content: Environment remove + id: environment-remove + - content: Environment update + id: environment-update + - content: Environment duplicate + id: environment-duplicate + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/gitea.mdx b/apps/docs/content/docs/api/gitea.mdx new file mode 100644 index 0000000..cd68119 --- /dev/null +++ b/apps/docs/content/docs/api/gitea.mdx @@ -0,0 +1,53 @@ +--- +title: Gitea +full: true +_openapi: + toc: + - depth: 2 + title: Gitea create + url: '#gitea-create' + - depth: 2 + title: Gitea one + url: '#gitea-one' + - depth: 2 + title: Gitea gitea Providers + url: '#gitea-gitea-providers' + - depth: 2 + title: Gitea get Gitea Repositories + url: '#gitea-get-gitea-repositories' + - depth: 2 + title: Gitea get Gitea Branches + url: '#gitea-get-gitea-branches' + - depth: 2 + title: Gitea test Connection + url: '#gitea-test-connection' + - depth: 2 + title: Gitea update + url: '#gitea-update' + - depth: 2 + title: Gitea get Gitea Url + url: '#gitea-get-gitea-url' + structuredData: + headings: + - content: Gitea create + id: gitea-create + - content: Gitea one + id: gitea-one + - content: Gitea gitea Providers + id: gitea-gitea-providers + - content: Gitea get Gitea Repositories + id: gitea-get-gitea-repositories + - content: Gitea get Gitea Branches + id: gitea-get-gitea-branches + - content: Gitea test Connection + id: gitea-test-connection + - content: Gitea update + id: gitea-update + - content: Gitea get Gitea Url + id: gitea-get-gitea-url + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/github.mdx b/apps/docs/content/docs/api/github.mdx new file mode 100644 index 0000000..86e6225 --- /dev/null +++ b/apps/docs/content/docs/api/github.mdx @@ -0,0 +1,43 @@ +--- +title: Github +full: true +_openapi: + toc: + - depth: 2 + title: Github one + url: '#github-one' + - depth: 2 + title: Github get Github Repositories + url: '#github-get-github-repositories' + - depth: 2 + title: Github get Github Branches + url: '#github-get-github-branches' + - depth: 2 + title: Github github Providers + url: '#github-github-providers' + - depth: 2 + title: Github test Connection + url: '#github-test-connection' + - depth: 2 + title: Github update + url: '#github-update' + structuredData: + headings: + - content: Github one + id: github-one + - content: Github get Github Repositories + id: github-get-github-repositories + - content: Github get Github Branches + id: github-get-github-branches + - content: Github github Providers + id: github-github-providers + - content: Github test Connection + id: github-test-connection + - content: Github update + id: github-update + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/gitlab.mdx b/apps/docs/content/docs/api/gitlab.mdx new file mode 100644 index 0000000..2dd86ac --- /dev/null +++ b/apps/docs/content/docs/api/gitlab.mdx @@ -0,0 +1,48 @@ +--- +title: Gitlab +full: true +_openapi: + toc: + - depth: 2 + title: Gitlab create + url: '#gitlab-create' + - depth: 2 + title: Gitlab one + url: '#gitlab-one' + - depth: 2 + title: Gitlab gitlab Providers + url: '#gitlab-gitlab-providers' + - depth: 2 + title: Gitlab get Gitlab Repositories + url: '#gitlab-get-gitlab-repositories' + - depth: 2 + title: Gitlab get Gitlab Branches + url: '#gitlab-get-gitlab-branches' + - depth: 2 + title: Gitlab test Connection + url: '#gitlab-test-connection' + - depth: 2 + title: Gitlab update + url: '#gitlab-update' + structuredData: + headings: + - content: Gitlab create + id: gitlab-create + - content: Gitlab one + id: gitlab-one + - content: Gitlab gitlab Providers + id: gitlab-gitlab-providers + - content: Gitlab get Gitlab Repositories + id: gitlab-get-gitlab-repositories + - content: Gitlab get Gitlab Branches + id: gitlab-get-gitlab-branches + - content: Gitlab test Connection + id: gitlab-test-connection + - content: Gitlab update + id: gitlab-update + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/gitprovider.mdx b/apps/docs/content/docs/api/gitprovider.mdx new file mode 100644 index 0000000..fc9aa47 --- /dev/null +++ b/apps/docs/content/docs/api/gitprovider.mdx @@ -0,0 +1,23 @@ +--- +title: Git Provider +full: true +_openapi: + toc: + - depth: 2 + title: Git Provider get All + url: '#git-provider-get-all' + - depth: 2 + title: Git Provider remove + url: '#git-provider-remove' + structuredData: + headings: + - content: Git Provider get All + id: git-provider-get-all + - content: Git Provider remove + id: git-provider-remove + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/mariadb.mdx b/apps/docs/content/docs/api/mariadb.mdx new file mode 100644 index 0000000..9bc53e1 --- /dev/null +++ b/apps/docs/content/docs/api/mariadb.mdx @@ -0,0 +1,78 @@ +--- +title: Mariadb +full: true +_openapi: + toc: + - depth: 2 + title: Mariadb create + url: '#mariadb-create' + - depth: 2 + title: Mariadb one + url: '#mariadb-one' + - depth: 2 + title: Mariadb start + url: '#mariadb-start' + - depth: 2 + title: Mariadb stop + url: '#mariadb-stop' + - depth: 2 + title: Mariadb save External Port + url: '#mariadb-save-external-port' + - depth: 2 + title: Mariadb deploy + url: '#mariadb-deploy' + - depth: 2 + title: Mariadb change Status + url: '#mariadb-change-status' + - depth: 2 + title: Mariadb remove + url: '#mariadb-remove' + - depth: 2 + title: Mariadb save Environment + url: '#mariadb-save-environment' + - depth: 2 + title: Mariadb reload + url: '#mariadb-reload' + - depth: 2 + title: Mariadb update + url: '#mariadb-update' + - depth: 2 + title: Mariadb move + url: '#mariadb-move' + - depth: 2 + title: Mariadb rebuild + url: '#mariadb-rebuild' + structuredData: + headings: + - content: Mariadb create + id: mariadb-create + - content: Mariadb one + id: mariadb-one + - content: Mariadb start + id: mariadb-start + - content: Mariadb stop + id: mariadb-stop + - content: Mariadb save External Port + id: mariadb-save-external-port + - content: Mariadb deploy + id: mariadb-deploy + - content: Mariadb change Status + id: mariadb-change-status + - content: Mariadb remove + id: mariadb-remove + - content: Mariadb save Environment + id: mariadb-save-environment + - content: Mariadb reload + id: mariadb-reload + - content: Mariadb update + id: mariadb-update + - content: Mariadb move + id: mariadb-move + - content: Mariadb rebuild + id: mariadb-rebuild + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/meta.json b/apps/docs/content/docs/api/meta.json index 7fd17a1..78e0e84 100644 --- a/apps/docs/content/docs/api/meta.json +++ b/apps/docs/content/docs/api/meta.json @@ -1,7 +1,7 @@ { "title": "API", - "description": "API Documentation", - "icon": "Building2", + "description": "RESTful API reference for programmatic access to Dokploy", + "icon": "Code", "root": true, - "pages": ["---Get Started---", "index", "---API---", "...", "---Reference---"] + "pages": ["---Get Started---", "index", "---Reference---", "..."] } diff --git a/apps/docs/content/docs/api/mongo.mdx b/apps/docs/content/docs/api/mongo.mdx new file mode 100644 index 0000000..019c0c2 --- /dev/null +++ b/apps/docs/content/docs/api/mongo.mdx @@ -0,0 +1,78 @@ +--- +title: Mongo +full: true +_openapi: + toc: + - depth: 2 + title: Mongo create + url: '#mongo-create' + - depth: 2 + title: Mongo one + url: '#mongo-one' + - depth: 2 + title: Mongo start + url: '#mongo-start' + - depth: 2 + title: Mongo stop + url: '#mongo-stop' + - depth: 2 + title: Mongo save External Port + url: '#mongo-save-external-port' + - depth: 2 + title: Mongo deploy + url: '#mongo-deploy' + - depth: 2 + title: Mongo change Status + url: '#mongo-change-status' + - depth: 2 + title: Mongo reload + url: '#mongo-reload' + - depth: 2 + title: Mongo remove + url: '#mongo-remove' + - depth: 2 + title: Mongo save Environment + url: '#mongo-save-environment' + - depth: 2 + title: Mongo update + url: '#mongo-update' + - depth: 2 + title: Mongo move + url: '#mongo-move' + - depth: 2 + title: Mongo rebuild + url: '#mongo-rebuild' + structuredData: + headings: + - content: Mongo create + id: mongo-create + - content: Mongo one + id: mongo-one + - content: Mongo start + id: mongo-start + - content: Mongo stop + id: mongo-stop + - content: Mongo save External Port + id: mongo-save-external-port + - content: Mongo deploy + id: mongo-deploy + - content: Mongo change Status + id: mongo-change-status + - content: Mongo reload + id: mongo-reload + - content: Mongo remove + id: mongo-remove + - content: Mongo save Environment + id: mongo-save-environment + - content: Mongo update + id: mongo-update + - content: Mongo move + id: mongo-move + - content: Mongo rebuild + id: mongo-rebuild + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/mounts.mdx b/apps/docs/content/docs/api/mounts.mdx new file mode 100644 index 0000000..f0308b4 --- /dev/null +++ b/apps/docs/content/docs/api/mounts.mdx @@ -0,0 +1,38 @@ +--- +title: Mounts +full: true +_openapi: + toc: + - depth: 2 + title: Mounts create + url: '#mounts-create' + - depth: 2 + title: Mounts remove + url: '#mounts-remove' + - depth: 2 + title: Mounts one + url: '#mounts-one' + - depth: 2 + title: Mounts update + url: '#mounts-update' + - depth: 2 + title: Mounts all Named By Application Id + url: '#mounts-all-named-by-application-id' + structuredData: + headings: + - content: Mounts create + id: mounts-create + - content: Mounts remove + id: mounts-remove + - content: Mounts one + id: mounts-one + - content: Mounts update + id: mounts-update + - content: Mounts all Named By Application Id + id: mounts-all-named-by-application-id + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/mysql.mdx b/apps/docs/content/docs/api/mysql.mdx new file mode 100644 index 0000000..35ed666 --- /dev/null +++ b/apps/docs/content/docs/api/mysql.mdx @@ -0,0 +1,78 @@ +--- +title: Mysql +full: true +_openapi: + toc: + - depth: 2 + title: Mysql create + url: '#mysql-create' + - depth: 2 + title: Mysql one + url: '#mysql-one' + - depth: 2 + title: Mysql start + url: '#mysql-start' + - depth: 2 + title: Mysql stop + url: '#mysql-stop' + - depth: 2 + title: Mysql save External Port + url: '#mysql-save-external-port' + - depth: 2 + title: Mysql deploy + url: '#mysql-deploy' + - depth: 2 + title: Mysql change Status + url: '#mysql-change-status' + - depth: 2 + title: Mysql reload + url: '#mysql-reload' + - depth: 2 + title: Mysql remove + url: '#mysql-remove' + - depth: 2 + title: Mysql save Environment + url: '#mysql-save-environment' + - depth: 2 + title: Mysql update + url: '#mysql-update' + - depth: 2 + title: Mysql move + url: '#mysql-move' + - depth: 2 + title: Mysql rebuild + url: '#mysql-rebuild' + structuredData: + headings: + - content: Mysql create + id: mysql-create + - content: Mysql one + id: mysql-one + - content: Mysql start + id: mysql-start + - content: Mysql stop + id: mysql-stop + - content: Mysql save External Port + id: mysql-save-external-port + - content: Mysql deploy + id: mysql-deploy + - content: Mysql change Status + id: mysql-change-status + - content: Mysql reload + id: mysql-reload + - content: Mysql remove + id: mysql-remove + - content: Mysql save Environment + id: mysql-save-environment + - content: Mysql update + id: mysql-update + - content: Mysql move + id: mysql-move + - content: Mysql rebuild + id: mysql-rebuild + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/organization.mdx b/apps/docs/content/docs/api/organization.mdx new file mode 100644 index 0000000..338660b --- /dev/null +++ b/apps/docs/content/docs/api/organization.mdx @@ -0,0 +1,58 @@ +--- +title: Organization +full: true +_openapi: + toc: + - depth: 2 + title: Organization create + url: '#organization-create' + - depth: 2 + title: Organization all + url: '#organization-all' + - depth: 2 + title: Organization one + url: '#organization-one' + - depth: 2 + title: Organization update + url: '#organization-update' + - depth: 2 + title: Organization delete + url: '#organization-delete' + - depth: 2 + title: Organization all Invitations + url: '#organization-all-invitations' + - depth: 2 + title: Organization remove Invitation + url: '#organization-remove-invitation' + - depth: 2 + title: Organization update Member Role + url: '#organization-update-member-role' + - depth: 2 + title: Organization set Default + url: '#organization-set-default' + structuredData: + headings: + - content: Organization create + id: organization-create + - content: Organization all + id: organization-all + - content: Organization one + id: organization-one + - content: Organization update + id: organization-update + - content: Organization delete + id: organization-delete + - content: Organization all Invitations + id: organization-all-invitations + - content: Organization remove Invitation + id: organization-remove-invitation + - content: Organization update Member Role + id: organization-update-member-role + - content: Organization set Default + id: organization-set-default + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/port.mdx b/apps/docs/content/docs/api/port.mdx new file mode 100644 index 0000000..7687be7 --- /dev/null +++ b/apps/docs/content/docs/api/port.mdx @@ -0,0 +1,33 @@ +--- +title: Port +full: true +_openapi: + toc: + - depth: 2 + title: Port create + url: '#port-create' + - depth: 2 + title: Port one + url: '#port-one' + - depth: 2 + title: Port delete + url: '#port-delete' + - depth: 2 + title: Port update + url: '#port-update' + structuredData: + headings: + - content: Port create + id: port-create + - content: Port one + id: port-one + - content: Port delete + id: port-delete + - content: Port update + id: port-update + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/postgres.mdx b/apps/docs/content/docs/api/postgres.mdx new file mode 100644 index 0000000..cf8ef92 --- /dev/null +++ b/apps/docs/content/docs/api/postgres.mdx @@ -0,0 +1,78 @@ +--- +title: Postgres +full: true +_openapi: + toc: + - depth: 2 + title: Postgres create + url: '#postgres-create' + - depth: 2 + title: Postgres one + url: '#postgres-one' + - depth: 2 + title: Postgres start + url: '#postgres-start' + - depth: 2 + title: Postgres stop + url: '#postgres-stop' + - depth: 2 + title: Postgres save External Port + url: '#postgres-save-external-port' + - depth: 2 + title: Postgres deploy + url: '#postgres-deploy' + - depth: 2 + title: Postgres change Status + url: '#postgres-change-status' + - depth: 2 + title: Postgres remove + url: '#postgres-remove' + - depth: 2 + title: Postgres save Environment + url: '#postgres-save-environment' + - depth: 2 + title: Postgres reload + url: '#postgres-reload' + - depth: 2 + title: Postgres update + url: '#postgres-update' + - depth: 2 + title: Postgres move + url: '#postgres-move' + - depth: 2 + title: Postgres rebuild + url: '#postgres-rebuild' + structuredData: + headings: + - content: Postgres create + id: postgres-create + - content: Postgres one + id: postgres-one + - content: Postgres start + id: postgres-start + - content: Postgres stop + id: postgres-stop + - content: Postgres save External Port + id: postgres-save-external-port + - content: Postgres deploy + id: postgres-deploy + - content: Postgres change Status + id: postgres-change-status + - content: Postgres remove + id: postgres-remove + - content: Postgres save Environment + id: postgres-save-environment + - content: Postgres reload + id: postgres-reload + - content: Postgres update + id: postgres-update + - content: Postgres move + id: postgres-move + - content: Postgres rebuild + id: postgres-rebuild + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/project.mdx b/apps/docs/content/docs/api/project.mdx new file mode 100644 index 0000000..b138c7c --- /dev/null +++ b/apps/docs/content/docs/api/project.mdx @@ -0,0 +1,43 @@ +--- +title: Project +full: true +_openapi: + toc: + - depth: 2 + title: Project create + url: '#project-create' + - depth: 2 + title: Project one + url: '#project-one' + - depth: 2 + title: Project all + url: '#project-all' + - depth: 2 + title: Project remove + url: '#project-remove' + - depth: 2 + title: Project update + url: '#project-update' + - depth: 2 + title: Project duplicate + url: '#project-duplicate' + structuredData: + headings: + - content: Project create + id: project-create + - content: Project one + id: project-one + - content: Project all + id: project-all + - content: Project remove + id: project-remove + - content: Project update + id: project-update + - content: Project duplicate + id: project-duplicate + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/redirects.mdx b/apps/docs/content/docs/api/redirects.mdx new file mode 100644 index 0000000..ae29464 --- /dev/null +++ b/apps/docs/content/docs/api/redirects.mdx @@ -0,0 +1,33 @@ +--- +title: Redirects +full: true +_openapi: + toc: + - depth: 2 + title: Redirects create + url: '#redirects-create' + - depth: 2 + title: Redirects one + url: '#redirects-one' + - depth: 2 + title: Redirects delete + url: '#redirects-delete' + - depth: 2 + title: Redirects update + url: '#redirects-update' + structuredData: + headings: + - content: Redirects create + id: redirects-create + - content: Redirects one + id: redirects-one + - content: Redirects delete + id: redirects-delete + - content: Redirects update + id: redirects-update + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/redis.mdx b/apps/docs/content/docs/api/redis.mdx new file mode 100644 index 0000000..55c1459 --- /dev/null +++ b/apps/docs/content/docs/api/redis.mdx @@ -0,0 +1,78 @@ +--- +title: Redis +full: true +_openapi: + toc: + - depth: 2 + title: Redis create + url: '#redis-create' + - depth: 2 + title: Redis one + url: '#redis-one' + - depth: 2 + title: Redis start + url: '#redis-start' + - depth: 2 + title: Redis reload + url: '#redis-reload' + - depth: 2 + title: Redis stop + url: '#redis-stop' + - depth: 2 + title: Redis save External Port + url: '#redis-save-external-port' + - depth: 2 + title: Redis deploy + url: '#redis-deploy' + - depth: 2 + title: Redis change Status + url: '#redis-change-status' + - depth: 2 + title: Redis remove + url: '#redis-remove' + - depth: 2 + title: Redis save Environment + url: '#redis-save-environment' + - depth: 2 + title: Redis update + url: '#redis-update' + - depth: 2 + title: Redis move + url: '#redis-move' + - depth: 2 + title: Redis rebuild + url: '#redis-rebuild' + structuredData: + headings: + - content: Redis create + id: redis-create + - content: Redis one + id: redis-one + - content: Redis start + id: redis-start + - content: Redis reload + id: redis-reload + - content: Redis stop + id: redis-stop + - content: Redis save External Port + id: redis-save-external-port + - content: Redis deploy + id: redis-deploy + - content: Redis change Status + id: redis-change-status + - content: Redis remove + id: redis-remove + - content: Redis save Environment + id: redis-save-environment + - content: Redis update + id: redis-update + - content: Redis move + id: redis-move + - content: Redis rebuild + id: redis-rebuild + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/generated/reference-admin.mdx b/apps/docs/content/docs/api/reference-admin.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-admin.mdx rename to apps/docs/content/docs/api/reference-admin.mdx diff --git a/apps/docs/content/docs/api/generated/reference-ai.mdx b/apps/docs/content/docs/api/reference-ai.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-ai.mdx rename to apps/docs/content/docs/api/reference-ai.mdx diff --git a/apps/docs/content/docs/api/generated/reference-application.mdx b/apps/docs/content/docs/api/reference-application.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-application.mdx rename to apps/docs/content/docs/api/reference-application.mdx diff --git a/apps/docs/content/docs/api/generated/reference-backup.mdx b/apps/docs/content/docs/api/reference-backup.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-backup.mdx rename to apps/docs/content/docs/api/reference-backup.mdx diff --git a/apps/docs/content/docs/api/generated/reference-bitbucket.mdx b/apps/docs/content/docs/api/reference-bitbucket.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-bitbucket.mdx rename to apps/docs/content/docs/api/reference-bitbucket.mdx diff --git a/apps/docs/content/docs/api/generated/reference-certificates.mdx b/apps/docs/content/docs/api/reference-certificates.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-certificates.mdx rename to apps/docs/content/docs/api/reference-certificates.mdx diff --git a/apps/docs/content/docs/api/generated/reference-cluster.mdx b/apps/docs/content/docs/api/reference-cluster.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-cluster.mdx rename to apps/docs/content/docs/api/reference-cluster.mdx diff --git a/apps/docs/content/docs/api/generated/reference-compose.mdx b/apps/docs/content/docs/api/reference-compose.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-compose.mdx rename to apps/docs/content/docs/api/reference-compose.mdx diff --git a/apps/docs/content/docs/api/generated/reference-deployment.mdx b/apps/docs/content/docs/api/reference-deployment.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-deployment.mdx rename to apps/docs/content/docs/api/reference-deployment.mdx diff --git a/apps/docs/content/docs/api/generated/reference-destination.mdx b/apps/docs/content/docs/api/reference-destination.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-destination.mdx rename to apps/docs/content/docs/api/reference-destination.mdx diff --git a/apps/docs/content/docs/api/generated/reference-docker.mdx b/apps/docs/content/docs/api/reference-docker.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-docker.mdx rename to apps/docs/content/docs/api/reference-docker.mdx diff --git a/apps/docs/content/docs/api/generated/reference-domain.mdx b/apps/docs/content/docs/api/reference-domain.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-domain.mdx rename to apps/docs/content/docs/api/reference-domain.mdx diff --git a/apps/docs/content/docs/api/generated/reference-environment.mdx b/apps/docs/content/docs/api/reference-environment.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-environment.mdx rename to apps/docs/content/docs/api/reference-environment.mdx diff --git a/apps/docs/content/docs/api/generated/reference-gitProvider.mdx b/apps/docs/content/docs/api/reference-gitProvider.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-gitProvider.mdx rename to apps/docs/content/docs/api/reference-gitProvider.mdx diff --git a/apps/docs/content/docs/api/generated/reference-gitea.mdx b/apps/docs/content/docs/api/reference-gitea.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-gitea.mdx rename to apps/docs/content/docs/api/reference-gitea.mdx diff --git a/apps/docs/content/docs/api/generated/reference-github.mdx b/apps/docs/content/docs/api/reference-github.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-github.mdx rename to apps/docs/content/docs/api/reference-github.mdx diff --git a/apps/docs/content/docs/api/generated/reference-gitlab.mdx b/apps/docs/content/docs/api/reference-gitlab.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-gitlab.mdx rename to apps/docs/content/docs/api/reference-gitlab.mdx diff --git a/apps/docs/content/docs/api/generated/reference-mariadb.mdx b/apps/docs/content/docs/api/reference-mariadb.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-mariadb.mdx rename to apps/docs/content/docs/api/reference-mariadb.mdx diff --git a/apps/docs/content/docs/api/generated/reference-mongo.mdx b/apps/docs/content/docs/api/reference-mongo.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-mongo.mdx rename to apps/docs/content/docs/api/reference-mongo.mdx diff --git a/apps/docs/content/docs/api/generated/reference-mounts.mdx b/apps/docs/content/docs/api/reference-mounts.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-mounts.mdx rename to apps/docs/content/docs/api/reference-mounts.mdx diff --git a/apps/docs/content/docs/api/generated/reference-mysql.mdx b/apps/docs/content/docs/api/reference-mysql.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-mysql.mdx rename to apps/docs/content/docs/api/reference-mysql.mdx diff --git a/apps/docs/content/docs/api/generated/reference-notification.mdx b/apps/docs/content/docs/api/reference-notification.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-notification.mdx rename to apps/docs/content/docs/api/reference-notification.mdx diff --git a/apps/docs/content/docs/api/generated/reference-organization.mdx b/apps/docs/content/docs/api/reference-organization.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-organization.mdx rename to apps/docs/content/docs/api/reference-organization.mdx diff --git a/apps/docs/content/docs/api/generated/reference-port.mdx b/apps/docs/content/docs/api/reference-port.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-port.mdx rename to apps/docs/content/docs/api/reference-port.mdx diff --git a/apps/docs/content/docs/api/generated/reference-postgres.mdx b/apps/docs/content/docs/api/reference-postgres.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-postgres.mdx rename to apps/docs/content/docs/api/reference-postgres.mdx diff --git a/apps/docs/content/docs/api/generated/reference-previewDeployment.mdx b/apps/docs/content/docs/api/reference-previewDeployment.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-previewDeployment.mdx rename to apps/docs/content/docs/api/reference-previewDeployment.mdx diff --git a/apps/docs/content/docs/api/generated/reference-project.mdx b/apps/docs/content/docs/api/reference-project.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-project.mdx rename to apps/docs/content/docs/api/reference-project.mdx diff --git a/apps/docs/content/docs/api/generated/reference-redirects.mdx b/apps/docs/content/docs/api/reference-redirects.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-redirects.mdx rename to apps/docs/content/docs/api/reference-redirects.mdx diff --git a/apps/docs/content/docs/api/generated/reference-redis.mdx b/apps/docs/content/docs/api/reference-redis.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-redis.mdx rename to apps/docs/content/docs/api/reference-redis.mdx diff --git a/apps/docs/content/docs/api/generated/reference-registry.mdx b/apps/docs/content/docs/api/reference-registry.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-registry.mdx rename to apps/docs/content/docs/api/reference-registry.mdx diff --git a/apps/docs/content/docs/api/generated/reference-rollback.mdx b/apps/docs/content/docs/api/reference-rollback.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-rollback.mdx rename to apps/docs/content/docs/api/reference-rollback.mdx diff --git a/apps/docs/content/docs/api/generated/reference-schedule.mdx b/apps/docs/content/docs/api/reference-schedule.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-schedule.mdx rename to apps/docs/content/docs/api/reference-schedule.mdx diff --git a/apps/docs/content/docs/api/generated/reference-security.mdx b/apps/docs/content/docs/api/reference-security.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-security.mdx rename to apps/docs/content/docs/api/reference-security.mdx diff --git a/apps/docs/content/docs/api/generated/reference-server.mdx b/apps/docs/content/docs/api/reference-server.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-server.mdx rename to apps/docs/content/docs/api/reference-server.mdx diff --git a/apps/docs/content/docs/api/generated/reference-settings.mdx b/apps/docs/content/docs/api/reference-settings.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-settings.mdx rename to apps/docs/content/docs/api/reference-settings.mdx diff --git a/apps/docs/content/docs/api/generated/reference-sshKey.mdx b/apps/docs/content/docs/api/reference-sshKey.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-sshKey.mdx rename to apps/docs/content/docs/api/reference-sshKey.mdx diff --git a/apps/docs/content/docs/api/generated/reference-stripe.mdx b/apps/docs/content/docs/api/reference-stripe.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-stripe.mdx rename to apps/docs/content/docs/api/reference-stripe.mdx diff --git a/apps/docs/content/docs/api/generated/reference-swarm.mdx b/apps/docs/content/docs/api/reference-swarm.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-swarm.mdx rename to apps/docs/content/docs/api/reference-swarm.mdx diff --git a/apps/docs/content/docs/api/generated/reference-user.mdx b/apps/docs/content/docs/api/reference-user.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-user.mdx rename to apps/docs/content/docs/api/reference-user.mdx diff --git a/apps/docs/content/docs/api/generated/reference-volumeBackups.mdx b/apps/docs/content/docs/api/reference-volumeBackups.mdx similarity index 100% rename from apps/docs/content/docs/api/generated/reference-volumeBackups.mdx rename to apps/docs/content/docs/api/reference-volumeBackups.mdx diff --git a/apps/docs/content/docs/api/registry.mdx b/apps/docs/content/docs/api/registry.mdx new file mode 100644 index 0000000..356a5d8 --- /dev/null +++ b/apps/docs/content/docs/api/registry.mdx @@ -0,0 +1,43 @@ +--- +title: Registry +full: true +_openapi: + toc: + - depth: 2 + title: Registry create + url: '#registry-create' + - depth: 2 + title: Registry remove + url: '#registry-remove' + - depth: 2 + title: Registry update + url: '#registry-update' + - depth: 2 + title: Registry all + url: '#registry-all' + - depth: 2 + title: Registry one + url: '#registry-one' + - depth: 2 + title: Registry test Registry + url: '#registry-test-registry' + structuredData: + headings: + - content: Registry create + id: registry-create + - content: Registry remove + id: registry-remove + - content: Registry update + id: registry-update + - content: Registry all + id: registry-all + - content: Registry one + id: registry-one + - content: Registry test Registry + id: registry-test-registry + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/rollback.mdx b/apps/docs/content/docs/api/rollback.mdx new file mode 100644 index 0000000..33e3c18 --- /dev/null +++ b/apps/docs/content/docs/api/rollback.mdx @@ -0,0 +1,23 @@ +--- +title: Rollback +full: true +_openapi: + toc: + - depth: 2 + title: Rollback delete + url: '#rollback-delete' + - depth: 2 + title: Rollback rollback + url: '#rollback-rollback' + structuredData: + headings: + - content: Rollback delete + id: rollback-delete + - content: Rollback rollback + id: rollback-rollback + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/schedule.mdx b/apps/docs/content/docs/api/schedule.mdx new file mode 100644 index 0000000..9e0f1a8 --- /dev/null +++ b/apps/docs/content/docs/api/schedule.mdx @@ -0,0 +1,43 @@ +--- +title: Schedule +full: true +_openapi: + toc: + - depth: 2 + title: Schedule create + url: '#schedule-create' + - depth: 2 + title: Schedule update + url: '#schedule-update' + - depth: 2 + title: Schedule delete + url: '#schedule-delete' + - depth: 2 + title: Schedule list + url: '#schedule-list' + - depth: 2 + title: Schedule one + url: '#schedule-one' + - depth: 2 + title: Schedule run Manually + url: '#schedule-run-manually' + structuredData: + headings: + - content: Schedule create + id: schedule-create + - content: Schedule update + id: schedule-update + - content: Schedule delete + id: schedule-delete + - content: Schedule list + id: schedule-list + - content: Schedule one + id: schedule-one + - content: Schedule run Manually + id: schedule-run-manually + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/security.mdx b/apps/docs/content/docs/api/security.mdx new file mode 100644 index 0000000..0480629 --- /dev/null +++ b/apps/docs/content/docs/api/security.mdx @@ -0,0 +1,33 @@ +--- +title: Security +full: true +_openapi: + toc: + - depth: 2 + title: Security create + url: '#security-create' + - depth: 2 + title: Security one + url: '#security-one' + - depth: 2 + title: Security delete + url: '#security-delete' + - depth: 2 + title: Security update + url: '#security-update' + structuredData: + headings: + - content: Security create + id: security-create + - content: Security one + id: security-one + - content: Security delete + id: security-delete + - content: Security update + id: security-update + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/server.mdx b/apps/docs/content/docs/api/server.mdx new file mode 100644 index 0000000..556cdb0 --- /dev/null +++ b/apps/docs/content/docs/api/server.mdx @@ -0,0 +1,93 @@ +--- +title: Server +full: true +_openapi: + toc: + - depth: 2 + title: Server create + url: '#server-create' + - depth: 2 + title: Server one + url: '#server-one' + - depth: 2 + title: Server get Default Command + url: '#server-get-default-command' + - depth: 2 + title: Server all + url: '#server-all' + - depth: 2 + title: Server count + url: '#server-count' + - depth: 2 + title: Server with S S H Key + url: '#server-with-s-s-h-key' + - depth: 2 + title: Server build Servers + url: '#server-build-servers' + - depth: 2 + title: Server setup + url: '#server-setup' + - depth: 2 + title: Server validate + url: '#server-validate' + - depth: 2 + title: Server security + url: '#server-security' + - depth: 2 + title: Server setup Monitoring + url: '#server-setup-monitoring' + - depth: 2 + title: Server remove + url: '#server-remove' + - depth: 2 + title: Server update + url: '#server-update' + - depth: 2 + title: Server public Ip + url: '#server-public-ip' + - depth: 2 + title: Server get Server Time + url: '#server-get-server-time' + - depth: 2 + title: Server get Server Metrics + url: '#server-get-server-metrics' + structuredData: + headings: + - content: Server create + id: server-create + - content: Server one + id: server-one + - content: Server get Default Command + id: server-get-default-command + - content: Server all + id: server-all + - content: Server count + id: server-count + - content: Server with S S H Key + id: server-with-s-s-h-key + - content: Server build Servers + id: server-build-servers + - content: Server setup + id: server-setup + - content: Server validate + id: server-validate + - content: Server security + id: server-security + - content: Server setup Monitoring + id: server-setup-monitoring + - content: Server remove + id: server-remove + - content: Server update + id: server-update + - content: Server public Ip + id: server-public-ip + - content: Server get Server Time + id: server-get-server-time + - content: Server get Server Metrics + id: server-get-server-metrics + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/settings.mdx b/apps/docs/content/docs/api/settings.mdx new file mode 100644 index 0000000..53ba081 --- /dev/null +++ b/apps/docs/content/docs/api/settings.mdx @@ -0,0 +1,243 @@ +--- +title: Settings +full: true +_openapi: + toc: + - depth: 2 + title: Settings reload Server + url: '#settings-reload-server' + - depth: 2 + title: Settings clean Redis + url: '#settings-clean-redis' + - depth: 2 + title: Settings reload Redis + url: '#settings-reload-redis' + - depth: 2 + title: Settings reload Traefik + url: '#settings-reload-traefik' + - depth: 2 + title: Settings toggle Dashboard + url: '#settings-toggle-dashboard' + - depth: 2 + title: Settings clean Unused Images + url: '#settings-clean-unused-images' + - depth: 2 + title: Settings clean Unused Volumes + url: '#settings-clean-unused-volumes' + - depth: 2 + title: Settings clean Stopped Containers + url: '#settings-clean-stopped-containers' + - depth: 2 + title: Settings clean Docker Builder + url: '#settings-clean-docker-builder' + - depth: 2 + title: Settings clean Docker Prune + url: '#settings-clean-docker-prune' + - depth: 2 + title: Settings clean All + url: '#settings-clean-all' + - depth: 2 + title: Settings clean Monitoring + url: '#settings-clean-monitoring' + - depth: 2 + title: Settings save S S H Private Key + url: '#settings-save-s-s-h-private-key' + - depth: 2 + title: Settings assign Domain Server + url: '#settings-assign-domain-server' + - depth: 2 + title: Settings clean S S H Private Key + url: '#settings-clean-s-s-h-private-key' + - depth: 2 + title: Settings update Docker Cleanup + url: '#settings-update-docker-cleanup' + - depth: 2 + title: Settings read Traefik Config + url: '#settings-read-traefik-config' + - depth: 2 + title: Settings update Traefik Config + url: '#settings-update-traefik-config' + - depth: 2 + title: Settings read Web Server Traefik Config + url: '#settings-read-web-server-traefik-config' + - depth: 2 + title: Settings update Web Server Traefik Config + url: '#settings-update-web-server-traefik-config' + - depth: 2 + title: Settings read Middleware Traefik Config + url: '#settings-read-middleware-traefik-config' + - depth: 2 + title: Settings update Middleware Traefik Config + url: '#settings-update-middleware-traefik-config' + - depth: 2 + title: Settings get Update Data + url: '#settings-get-update-data' + - depth: 2 + title: Settings update Server + url: '#settings-update-server' + - depth: 2 + title: Settings get Dokploy Version + url: '#settings-get-dokploy-version' + - depth: 2 + title: Settings get Release Tag + url: '#settings-get-release-tag' + - depth: 2 + title: Settings read Directories + url: '#settings-read-directories' + - depth: 2 + title: Settings update Traefik File + url: '#settings-update-traefik-file' + - depth: 2 + title: Settings read Traefik File + url: '#settings-read-traefik-file' + - depth: 2 + title: Settings get Ip + url: '#settings-get-ip' + - depth: 2 + title: Settings get Open Api Document + url: '#settings-get-open-api-document' + - depth: 2 + title: Settings read Traefik Env + url: '#settings-read-traefik-env' + - depth: 2 + title: Settings write Traefik Env + url: '#settings-write-traefik-env' + - depth: 2 + title: Settings have Traefik Dashboard Port Enabled + url: '#settings-have-traefik-dashboard-port-enabled' + - depth: 2 + title: Settings have Activate Requests + url: '#settings-have-activate-requests' + - depth: 2 + title: Settings toggle Requests + url: '#settings-toggle-requests' + - depth: 2 + title: Settings is Cloud + url: '#settings-is-cloud' + - depth: 2 + title: Settings is User Subscribed + url: '#settings-is-user-subscribed' + - depth: 2 + title: Settings health + url: '#settings-health' + - depth: 2 + title: Settings setup G P U + url: '#settings-setup-g-p-u' + - depth: 2 + title: Settings check G P U Status + url: '#settings-check-g-p-u-status' + - depth: 2 + title: Settings update Traefik Ports + url: '#settings-update-traefik-ports' + - depth: 2 + title: Settings get Traefik Ports + url: '#settings-get-traefik-ports' + - depth: 2 + title: Settings update Log Cleanup + url: '#settings-update-log-cleanup' + - depth: 2 + title: Settings get Log Cleanup Status + url: '#settings-get-log-cleanup-status' + - depth: 2 + title: Settings get Dokploy Cloud Ips + url: '#settings-get-dokploy-cloud-ips' + structuredData: + headings: + - content: Settings reload Server + id: settings-reload-server + - content: Settings clean Redis + id: settings-clean-redis + - content: Settings reload Redis + id: settings-reload-redis + - content: Settings reload Traefik + id: settings-reload-traefik + - content: Settings toggle Dashboard + id: settings-toggle-dashboard + - content: Settings clean Unused Images + id: settings-clean-unused-images + - content: Settings clean Unused Volumes + id: settings-clean-unused-volumes + - content: Settings clean Stopped Containers + id: settings-clean-stopped-containers + - content: Settings clean Docker Builder + id: settings-clean-docker-builder + - content: Settings clean Docker Prune + id: settings-clean-docker-prune + - content: Settings clean All + id: settings-clean-all + - content: Settings clean Monitoring + id: settings-clean-monitoring + - content: Settings save S S H Private Key + id: settings-save-s-s-h-private-key + - content: Settings assign Domain Server + id: settings-assign-domain-server + - content: Settings clean S S H Private Key + id: settings-clean-s-s-h-private-key + - content: Settings update Docker Cleanup + id: settings-update-docker-cleanup + - content: Settings read Traefik Config + id: settings-read-traefik-config + - content: Settings update Traefik Config + id: settings-update-traefik-config + - content: Settings read Web Server Traefik Config + id: settings-read-web-server-traefik-config + - content: Settings update Web Server Traefik Config + id: settings-update-web-server-traefik-config + - content: Settings read Middleware Traefik Config + id: settings-read-middleware-traefik-config + - content: Settings update Middleware Traefik Config + id: settings-update-middleware-traefik-config + - content: Settings get Update Data + id: settings-get-update-data + - content: Settings update Server + id: settings-update-server + - content: Settings get Dokploy Version + id: settings-get-dokploy-version + - content: Settings get Release Tag + id: settings-get-release-tag + - content: Settings read Directories + id: settings-read-directories + - content: Settings update Traefik File + id: settings-update-traefik-file + - content: Settings read Traefik File + id: settings-read-traefik-file + - content: Settings get Ip + id: settings-get-ip + - content: Settings get Open Api Document + id: settings-get-open-api-document + - content: Settings read Traefik Env + id: settings-read-traefik-env + - content: Settings write Traefik Env + id: settings-write-traefik-env + - content: Settings have Traefik Dashboard Port Enabled + id: settings-have-traefik-dashboard-port-enabled + - content: Settings have Activate Requests + id: settings-have-activate-requests + - content: Settings toggle Requests + id: settings-toggle-requests + - content: Settings is Cloud + id: settings-is-cloud + - content: Settings is User Subscribed + id: settings-is-user-subscribed + - content: Settings health + id: settings-health + - content: Settings setup G P U + id: settings-setup-g-p-u + - content: Settings check G P U Status + id: settings-check-g-p-u-status + - content: Settings update Traefik Ports + id: settings-update-traefik-ports + - content: Settings get Traefik Ports + id: settings-get-traefik-ports + - content: Settings update Log Cleanup + id: settings-update-log-cleanup + - content: Settings get Log Cleanup Status + id: settings-get-log-cleanup-status + - content: Settings get Dokploy Cloud Ips + id: settings-get-dokploy-cloud-ips + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/sshrouter.mdx b/apps/docs/content/docs/api/sshrouter.mdx new file mode 100644 index 0000000..6c45a14 --- /dev/null +++ b/apps/docs/content/docs/api/sshrouter.mdx @@ -0,0 +1,13 @@ +--- +title: Ssh Router +full: true +_openapi: + toc: [] + structuredData: + headings: [] + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/swarm.mdx b/apps/docs/content/docs/api/swarm.mdx new file mode 100644 index 0000000..8126abf --- /dev/null +++ b/apps/docs/content/docs/api/swarm.mdx @@ -0,0 +1,28 @@ +--- +title: Swarm +full: true +_openapi: + toc: + - depth: 2 + title: Swarm get Nodes + url: '#swarm-get-nodes' + - depth: 2 + title: Swarm get Node Info + url: '#swarm-get-node-info' + - depth: 2 + title: Swarm get Node Apps + url: '#swarm-get-node-apps' + structuredData: + headings: + - content: Swarm get Nodes + id: swarm-get-nodes + - content: Swarm get Node Info + id: swarm-get-node-info + - content: Swarm get Node Apps + id: swarm-get-node-apps + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/user.mdx b/apps/docs/content/docs/api/user.mdx new file mode 100644 index 0000000..ce713d7 --- /dev/null +++ b/apps/docs/content/docs/api/user.mdx @@ -0,0 +1,103 @@ +--- +title: User +full: true +_openapi: + toc: + - depth: 2 + title: User all + url: '#user-all' + - depth: 2 + title: User one + url: '#user-one' + - depth: 2 + title: User get + url: '#user-get' + - depth: 2 + title: User have Root Access + url: '#user-have-root-access' + - depth: 2 + title: User get Backups + url: '#user-get-backups' + - depth: 2 + title: User get Server Metrics + url: '#user-get-server-metrics' + - depth: 2 + title: User update + url: '#user-update' + - depth: 2 + title: User get User By Token + url: '#user-get-user-by-token' + - depth: 2 + title: User get Metrics Token + url: '#user-get-metrics-token' + - depth: 2 + title: User remove + url: '#user-remove' + - depth: 2 + title: User assign Permissions + url: '#user-assign-permissions' + - depth: 2 + title: User get Invitations + url: '#user-get-invitations' + - depth: 2 + title: User get Container Metrics + url: '#user-get-container-metrics' + - depth: 2 + title: User generate Token + url: '#user-generate-token' + - depth: 2 + title: User delete Api Key + url: '#user-delete-api-key' + - depth: 2 + title: User create Api Key + url: '#user-create-api-key' + - depth: 2 + title: User check User Organizations + url: '#user-check-user-organizations' + - depth: 2 + title: User send Invitation + url: '#user-send-invitation' + structuredData: + headings: + - content: User all + id: user-all + - content: User one + id: user-one + - content: User get + id: user-get + - content: User have Root Access + id: user-have-root-access + - content: User get Backups + id: user-get-backups + - content: User get Server Metrics + id: user-get-server-metrics + - content: User update + id: user-update + - content: User get User By Token + id: user-get-user-by-token + - content: User get Metrics Token + id: user-get-metrics-token + - content: User remove + id: user-remove + - content: User assign Permissions + id: user-assign-permissions + - content: User get Invitations + id: user-get-invitations + - content: User get Container Metrics + id: user-get-container-metrics + - content: User generate Token + id: user-generate-token + - content: User delete Api Key + id: user-delete-api-key + - content: User create Api Key + id: user-create-api-key + - content: User check User Organizations + id: user-check-user-organizations + - content: User send Invitation + id: user-send-invitation + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api/volumebackups.mdx b/apps/docs/content/docs/api/volumebackups.mdx new file mode 100644 index 0000000..f725399 --- /dev/null +++ b/apps/docs/content/docs/api/volumebackups.mdx @@ -0,0 +1,43 @@ +--- +title: Volume Backups +full: true +_openapi: + toc: + - depth: 2 + title: Volume Backups list + url: '#volume-backups-list' + - depth: 2 + title: Volume Backups create + url: '#volume-backups-create' + - depth: 2 + title: Volume Backups one + url: '#volume-backups-one' + - depth: 2 + title: Volume Backups delete + url: '#volume-backups-delete' + - depth: 2 + title: Volume Backups update + url: '#volume-backups-update' + - depth: 2 + title: Volume Backups run Manually + url: '#volume-backups-run-manually' + structuredData: + headings: + - content: Volume Backups list + id: volume-backups-list + - content: Volume Backups create + id: volume-backups-create + - content: Volume Backups one + id: volume-backups-one + - content: Volume Backups delete + id: volume-backups-delete + - content: Volume Backups update + id: volume-backups-update + - content: Volume Backups run Manually + id: volume-backups-run-manually + contents: [] +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/cli/meta.json b/apps/docs/content/docs/cli/meta.json index 2429f37..11e4b1b 100644 --- a/apps/docs/content/docs/cli/meta.json +++ b/apps/docs/content/docs/cli/meta.json @@ -1,7 +1,7 @@ { "title": "CLI", - "description": "CLI Documentation", - "icon": "Building2", + "description": "Command-line interface for managing Dokploy from your terminal", + "icon": "SquareTerminal", "root": true, "pages": [ "---Get Started---", diff --git a/apps/docs/content/docs/core/(Notifications)/lark.mdx b/apps/docs/content/docs/core/(Notifications)/lark.mdx new file mode 100644 index 0000000..814ec13 --- /dev/null +++ b/apps/docs/content/docs/core/(Notifications)/lark.mdx @@ -0,0 +1,24 @@ +--- +title: Lark +description: 'Configure Lark notifications for your applications.' +--- + +Lark notifications are a great way to stay up to date with important events in your Dokploy panel. You can choose to receive notifications for specific events or all events. + +## Lark Notifications + +To start receiving Lark notifications, you need to fill the form with the following details: + +- **Name**: Enter any name you want. +- **Webhook URL**: Enter the webhook URL. eg. `https://open.larksuite.com/open-apis/bot/v2/hook/xxxxxxxxxxxxxxxxxxxxxxxx` + +To setup Lark notifications, follow these steps: + +1. Go to your Lark workspace and navigate to the bot configuration. +2. Create a new bot or use an existing one. +3. Copy the webhook URL from your Lark bot settings. +4. Go to Dokploy **Notifications** and select **Lark** as the notification provider. +5. Enter a name for your notification configuration. +6. Paste the webhook URL you copied in the previous step. +7. Click on **Test** to make sure everything is working. +8. Click on **Create** to save the notification. diff --git a/apps/docs/content/docs/core/(Notifications)/meta.json b/apps/docs/content/docs/core/(Notifications)/meta.json new file mode 100644 index 0000000..4c8db4f --- /dev/null +++ b/apps/docs/content/docs/core/(Notifications)/meta.json @@ -0,0 +1,14 @@ +{ + "title": "Notifications", + "pages": [ + "overview", + "slack", + "telegram", + "discord", + "lark", + "email", + "gotify", + "ntfy", + "webhook" + ] +} diff --git a/apps/docs/content/docs/core/(Notifications)/overview.mdx b/apps/docs/content/docs/core/(Notifications)/overview.mdx index b5ea691..df95094 100644 --- a/apps/docs/content/docs/core/(Notifications)/overview.mdx +++ b/apps/docs/content/docs/core/(Notifications)/overview.mdx @@ -5,18 +5,29 @@ description: 'Configure general notifications for your applications and services import { Callout } from 'fumadocs-ui/components/callout'; -Dokploy offer multiples notifications options to notify about some events. +Dokploy offers multiple notification options to notify you about important events in your applications and services. -1. **App Deploy**: Notify when a new version of your application is deployed. -2. **App Deploy Error**: Notify when a new version of your application fails to deploy. -3. **Docker Cleanup**: Notify when a Docker cleanup is triggered. -4. **Dokploy Restart**: Notify when Dokploy Server restarts. -5. **Database Backup**: Notify when a new database backup is created(Success or Error). +## Actions -## Providers: +You can select which actions trigger notifications: + +1. **App Deploy**: Trigger the action when an app is deployed. +2. **App Build Error**: Trigger the action when the build fails. +3. **Database Backup**: Trigger the action when a database backup is created. +4. **Volume Backup**: Trigger the action when a volume backup is created. +5. **Docker Cleanup**: Trigger the action when the docker cleanup is performed. +6. **Dokploy Restart**: Trigger the action when Dokploy is restarted. + +## Providers + +Dokploy supports the following notification providers: 1. **Slack**: Slack is a platform for team communication and collaboration. 2. **Telegram**: Telegram is a messaging platform that allows users to send and receive messages. 3. **Discord**: Discord is generally used for communication between users in a chat or voice channel. -4. **Email**: Email is a popular method for sending messages to a group of recipients. +4. **Lark**: Lark is a collaboration platform that provides messaging and team communication features. +5. **Email**: Email is a popular method for sending messages to a group of recipients. +6. **Gotify**: Gotify is a self-hosted push notification service. +7. **Ntfy**: Ntfy is a simple HTTP-based pub-sub notification service. +8. **Webhook**: Webhook is a generic webhook notification service. diff --git a/apps/docs/content/docs/core/(Notifications)/webhook.mdx b/apps/docs/content/docs/core/(Notifications)/webhook.mdx new file mode 100644 index 0000000..193d116 --- /dev/null +++ b/apps/docs/content/docs/core/(Notifications)/webhook.mdx @@ -0,0 +1,50 @@ +--- +title: Webhook +description: 'Configure webhook notifications for your applications.' +--- + +Webhook notifications are a generic way to receive notifications from Dokploy to any HTTP endpoint. You can choose to receive notifications for specific events or all events. Notifications are sent in JSON format. + +## Webhook Notifications + +To start receiving webhook notifications, you need to fill the form with the following details: + +- **Name**: Enter any name you want. +- **Webhook URL**: Enter the webhook URL where you want to receive notifications. eg. `https://your-endpoint.com/webhook` + +## Testing Your Webhook + +For testing purposes, you can use [Webhook.site](https://webhook.site) to generate a unique URL and inspect the JSON payload that Dokploy sends: + +1. Go to [https://webhook.site](https://webhook.site) +2. Copy your unique webhook URL +3. Go to Dokploy **Notifications** and select **Webhook** as the notification provider +4. Enter a name for your notification configuration +5. Paste the webhook URL you copied +6. Click on **Test** to send a test notification +7. Check your Webhook.site page to see the JSON payload +8. Click on **Create** to save the notification + +## JSON Format + +Dokploy sends notifications in JSON format. The payload structure includes information about the event type, timestamp, and relevant details about the action that triggered the notification. + +**Example notification payload:** + +```json +{ + "title": "Test Notification", + "message": "Hi, From Dokploy 👋", + "timestamp": "2025-12-07T19:41:53.470Z" +} +``` + +## Production Setup + +For production use, ensure your webhook endpoint: + +- Accepts POST requests +- Returns a 2xx HTTP status code for successful delivery +- Handles JSON payloads +- Is accessible from the internet (or from your Dokploy server's network) +- Implements proper authentication if needed (consider using HTTPS with API keys in headers) diff --git a/apps/docs/content/docs/core/(Users)/permissions.mdx b/apps/docs/content/docs/core/(Users)/permissions.mdx index 022b16e..8825097 100644 --- a/apps/docs/content/docs/core/(Users)/permissions.mdx +++ b/apps/docs/content/docs/core/(Users)/permissions.mdx @@ -3,24 +3,53 @@ title: Permissions description: 'Add permissions to your users to manage your applications and services.' --- -Manage user roles and permissions within Dokploy. Note that only one admin role is allowed per instance. +Manage user roles and permissions within Dokploy. Dokploy handles three distinct roles with different levels of access and capabilities. -## Permissions +## Roles -Dokploy offers multiple permissions to manage your users effectively: +Dokploy supports three roles for managing user access: -- **Create Projects**: Allows the user to create new projects. -- **Create Services**: Allows the user to create new applications or databases. -- **Access Traefik Files Tab**: Allows the user to access the Traefik files tab. -- **Delete Projects**: Allows the user to delete projects. -- **Delete Services**: Allows the user to delete services. -- **Access Docker Tab**: Allows the user to access the Docker tab. -- **Access API/CLI**: Allows the user to access the API/CLI, including the Swagger route. -- **Access to Git Providers**: Allows the user to access the Git Providers. -- **Access to SSH Keys**: Allows the user to access the SSH Keys. +### Owner + +The **Owner** is the creator of the organization and has the highest level of access: + +- Full administrative privileges +- Can perform all actions that admins can do +- Can delete and edit the role of admins +- **Intransferable**: The owner role cannot be transferred to another user +- Only one owner exists per organization + +### Admin + +**Admin** users have extensive administrative capabilities: + +- Can perform all actions that the owner can do +- Full access to all features and settings +- **Limitations**: Cannot delete or edit the role of other admins +- **Limitations**: Cannot delete or edit the role of the owner + +### Members + +**Members** are regular users who have access based on the permissions assigned to them. Members can be granted specific permissions to manage applications and services. + +#### Permissions + +The following permissions are available for **Members** to manage your users effectively: + +- **Create Projects**: Allow the user to create projects. +- **Delete Projects**: Allow the user to delete projects. +- **Create Services**: Allow the user to create services. +- **Delete Services**: Allow the user to delete services. +- **Create Environments**: Allow the user to create environments. +- **Delete Environments**: Allow the user to delete environments. +- **Access to Traefik Files**: Allow the user to access to the Traefik Tab Files. +- **Access to Docker**: Allow the user to access to the Docker Tab. +- **Access to API/CLI**: Allow the user to access to the API/CLI. +- **Access to SSH Keys**: Allow to users to access to the SSH Keys section. +- **Access to Git Providers**: Allow to users to access to the Git Providers section. You can also grant permissions to specific users for accessing particular projects or services. -### Project Permissions +#### Project Permissions -Based on your projects and services, you can assign permissions to specific users to give them access to particular projects or services. +Based on your projects and services, you can assign permissions to specific users to give them access to particular projects or services. You can also select specific environments within projects, allowing you to grant granular access control at the environment level. diff --git a/apps/docs/content/docs/core/applications/advanced.mdx b/apps/docs/content/docs/core/applications/advanced.mdx index 619c22a..8e7ebcf 100644 --- a/apps/docs/content/docs/core/applications/advanced.mdx +++ b/apps/docs/content/docs/core/applications/advanced.mdx @@ -3,7 +3,7 @@ title: Advanced description: Learn how to use advanced features in your application. --- -This section is designed for experienced users who need to manage complex configurations and orchestration settings in Dokploy. Here, you can execute custom commands, manage cluster replicas, select Docker registries, and configure Docker Swarm settings. +This section is designed for experienced users who need to manage complex configurations and orchestration settings in Dokploy. The **Advanced** tab is located in your **Applications** settings. Here, you can execute custom commands, manage cluster replicas, select Docker registries, and configure Docker Swarm settings. ### Run Command @@ -13,7 +13,7 @@ This section is designed for experienced users who need to manage complex config ### Cluster Settings - **Purpose**: Manages the scaling and distribution of the application across multiple servers or nodes. -- **Replicas**: Set the number of instances of your application that should be running. +- **Replicas**: Set the number of instances of your **application** that should be running. - **Registry Selection**: Choose the Docker registry from which your container images will be pulled. This is crucial for ensuring that the correct images are used during deployment. #### Important Note @@ -99,14 +99,158 @@ Assigns metadata to containers to help identify and organize them, the configura Modifying Swarm Settings requires careful consideration as incorrect configurations can disrupt the entire container orchestration. Always ensure you understand the implications of the changes you are making. +## Build Server + +You can configure your application to use an external build server to compile and build your application. This feature allows you to separate the build process from your deployment servers, which is particularly useful when you want to: + +- Use powerful build resources without paying for expensive deployment servers +- Keep your deployment servers lightweight +- Build once and deploy to multiple servers +- Isolate the build process from production environments + +When you enable a custom build server: + +1. **Build Phase**: Dokploy connects to your build server via SSH, clones your repository, and builds the Docker image on the build server +2. **Push Phase**: The built image is pushed to your configured Docker registry +3. **Deploy Phase**: Your deployment server(s) pull the image from the registry and deploy it + + + **Important**: Build servers are currently **only available for Applications**. This feature is not supported for Docker Compose deployments. + + + + **Required Configuration**: When using a build server, you must configure a Docker registry in your Dokploy settings. The built image needs to be stored in a registry that's accessible to your deployment servers. See [Docker Registry](/docs/core/registry) for configuration details. + + +**For complete setup instructions, configuration details, and best practices, please read the comprehensive [Build Server guide](/docs/core/remote-servers/build-server).** + ## Resources -Manage the memory and CPU resources allocated to your applications or databases. +Manage the memory and CPU resources allocated to your applications or databases. These settings help control resource consumption and ensure fair distribution across your containers. -- **Memory Reservation**: The minimum amount of memory guaranteed to the application. -- **Memory Limit**: The maximum amount of memory the application can use. -- **CPU Limit**: The maximum number of CPU units that the application can utilize. -- **CPU Reservation**: The minimum number of CPU units reserved for the application. + + Remember to click **Redeploy** after modifying the resources to apply the changes. + + +### Memory Resources + +Docker API expects memory values in **bytes**. Dokploy provides a user-friendly interface that accepts values with units and converts them automatically. + +#### Memory Limit + +The maximum amount of memory the container can use. If the container tries to use more memory than this limit, it will be killed by the Docker daemon. + +**Format**: Enter a number followed by the unit (B, KB, MB, GB) + +**Docker API Value**: The value is converted to bytes internally +- `1073741824` bytes = 1GB +- `268435456` bytes = 256MB +- `536870912` bytes = 512MB + +**Examples**: +- `256MB` → Limits container to 256 megabytes +- `1GB` → Limits container to 1 gigabyte +- `2GB` → Limits container to 2 gigabytes + +#### Memory Reservation + +The minimum amount of memory guaranteed to the container. Docker will try to ensure this amount is always available, but the container can use more if available. + +**Format**: Enter a number followed by the unit (B, KB, MB, GB) + +**Docker API Value**: The value is converted to bytes internally +- `268435456` bytes = 256MB +- `536870912` bytes = 512MB + +**Examples**: +- `128MB` → Reserves at least 128 megabytes +- `256MB` → Reserves at least 256 megabytes +- `512MB` → Reserves at least 512 megabytes + + + Memory Reservation should always be **less than or equal to** Memory Limit. If you set a reservation higher than the limit, Docker will use the limit value. + + +### CPU Resources + +Docker API expects CPU values in **nanoseconds** (for periods) or as a decimal fraction of available CPU cores. Dokploy displays this in a user-friendly format. + +#### CPU Limit + +The maximum number of CPU cores the container can use. This is a hard limit enforced by the Docker daemon. + +**Format**: Enter as a decimal number representing CPU cores +- `2000000000` nanoseconds = 2 CPUs (2 full cores) +- `1000000000` nanoseconds = 1 CPU (1 full core) +- `500000000` nanoseconds = 0.5 CPU (half a core) + +**Docker API Value**: Internally represented as `NanoCPUs` + +**Examples**: +- `1 CPU` → Limits to 1 full CPU core (1000000000 nanoseconds) +- `2 CPUs` → Limits to 2 full CPU cores (2000000000 nanoseconds) +- `0.5 CPU` → Limits to half a CPU core (500000000 nanoseconds) +- `4 CPUs` → Limits to 4 full CPU cores (4000000000 nanoseconds) + +#### CPU Reservation + +The minimum number of CPU cores reserved for the container. Docker will try to ensure this amount is always available. + +**Format**: Enter as a decimal number representing CPU cores +- `1000000000` nanoseconds = 1 CPU +- `500000000` nanoseconds = 0.5 CPU + +**Docker API Value**: Internally represented as `NanoCPUs` + +**Examples**: +- `0.5 CPU` → Reserves half a CPU core (500000000 nanoseconds) +- `1 CPU` → Reserves 1 full CPU core (1000000000 nanoseconds) +- `0.25 CPU` → Reserves a quarter CPU core (250000000 nanoseconds) + + + CPU Reservation should always be **less than or equal to** CPU Limit. Setting it too high may prevent the container from starting if resources aren't available. + + + + +#### Docker API Reference + +When Dokploy communicates with Docker API, these values are sent in the service specification: + +```json +{ + "TaskTemplate": { + "Resources": { + "Limits": { + "NanoCPUs": 2000000000, + "MemoryBytes": 1073741824 + }, + "Reservations": { + "NanoCPUs": 1000000000, + "MemoryBytes": 536870912 + } + } + } +} +``` + +This JSON represents: +- **CPU Limit**: 2 CPUs (2000000000 nanoseconds) +- **Memory Limit**: 1GB (1073741824 bytes) +- **CPU Reservation**: 1 CPU (1000000000 nanoseconds) +- **Memory Reservation**: 512MB (536870912 bytes) + +#### Learn More + +For detailed information about Docker API resource specifications and service creation, refer to the official Docker Engine API documentation: + +[Docker Engine API - Service Create](https://docs.docker.com/reference/api/engine/version/v1.51/#tag/Service/operation/ServiceCreate) + +This documentation includes: +- Complete resource specification schema +- Advanced configuration options +- API request/response examples +- Additional parameters and constraints ### Volumes/Mounts @@ -127,7 +271,7 @@ Configure persistent storage for your application to ensure data remains intact 2. **File Path**: The name of the file. 3. **Mount Path**: Path in the container where the file is placed. **The path must also contain the filename.** -File mounts are a dokploy features, this create a file in a folder called `files` inside your project, so it recreates every single time you deploy your project. +File mounts are a Dokploy feature. When you create a file mount, Dokploy stores the file in a folder called `files` inside your project directory. This file is created once when you set up the file mount and persists across deployments. diff --git a/apps/docs/content/docs/core/applications/build-type.mdx b/apps/docs/content/docs/core/applications/build-type.mdx index 08f103c..a9f2fb0 100644 --- a/apps/docs/content/docs/core/applications/build-type.mdx +++ b/apps/docs/content/docs/core/applications/build-type.mdx @@ -56,7 +56,30 @@ Railpack exposes multiple Build Variables, you can define them in the `Environme | `RAILPACK_BUILD_APT_PACKAGES` | Install additional Apt packages during build | | `RAILPACK_DEPLOY_APT_PACKAGES` | Install additional Apt packages in the final image | -you can read more about Railpack [here](https://railpack.com/config/environment-variables). +### Specifying Railpack Version + +Dokploy provides a **Railpack Version** field in the application settings where you can specify a specific version of Railpack to use. This allows you to: + +- **Pin to a specific version**: Ensure consistent builds across deployments +- **Use a newer version**: Test or use features from a specific release +- **Stay on a stable version**: Avoid potential issues from automatic updates + +**How to use:** + +1. Navigate to your application settings +2. Find the **Railpack Version** field +3. Enter the version you want to use (e.g., `0.15.1`) +4. Dokploy will automatically download and use the specified version for your builds + +**Example:** + +To use Railpack version `0.15.1`, simply enter `0.15.1` in the Railpack Version field. + + + If you specify an invalid version, Dokploy will show an error. Make sure to use a valid version from the [Railpack releases page](https://github.com/railwayapp/railpack/releases). + + +You can read more about Railpack [here](https://railpack.com/config/environment-variables). Railpack supports Nodejs, Python, Go, PHP, Go, StaticFile, Shell Scripts. @@ -70,6 +93,18 @@ Dokploy expose 3 Fields to be configured: - `Docker Context Path`: This is where the Dockerfile is located, eg. If your Dockerfile is in the root of your application you can just specify the `.` (dot) character, is basically to tell docker what context will use to build your application, you can read [Dockerfile Context](https://docs.docker.com/build/concepts/context/) for more information. - `Docker Build Stage`: This is the build stage to use for building the application, eg. If you want to use the `builder` stage you can specify the `builder` stage, read more about build stages [here](https://docs.docker.com/build/building/multi-stage/). +#### Environment Variables for Dockerfile Builds + +When you enable the Dockerfile build type, two additional fields become available in the **Environment** tab: + +- **Build Time Arguments**: Configure [build arguments (ARG)](https://docs.docker.com/build/building/variables/) that are passed to your Dockerfile during the build process. Build arguments allow you to parameterize your Dockerfile, making it more flexible and reusable. For example, you can specify versions of dependencies, feature flags, or other build-time configurations. + +- **Build-time Secrets**: Configure [build secrets](https://docs.docker.com/build/building/secrets/) to securely pass sensitive information (such as API tokens, passwords, or SSH keys) to your build process. Unlike build arguments, secrets are not exposed in the final image or build history, making them the recommended way to handle sensitive data during builds. + + + Build arguments and environment variables are inappropriate for passing secrets, as they persist in the final image. Always use build-time secrets for sensitive information like API tokens or passwords. + + ### Buildpack diff --git a/apps/docs/content/docs/core/applications/meta.json b/apps/docs/content/docs/core/applications/meta.json new file mode 100644 index 0000000..11a9927 --- /dev/null +++ b/apps/docs/content/docs/core/applications/meta.json @@ -0,0 +1,11 @@ +{ + "title": "Applications", + "pages": [ + "advanced", + "build-type", + "preview-deployments", + "rollbacks", + "zero-downtime", + "going-production" + ] +} diff --git a/apps/docs/content/docs/core/applications/rollbacks.mdx b/apps/docs/content/docs/core/applications/rollbacks.mdx index dfb15ec..bb70a24 100644 --- a/apps/docs/content/docs/core/applications/rollbacks.mdx +++ b/apps/docs/content/docs/core/applications/rollbacks.mdx @@ -3,16 +3,35 @@ title: Rollbacks description: Learn how to rollback your application in Dokploy. --- +import { Callout } from 'fumadocs-ui/components/callout'; + Rollbacks are a powerful feature that allows you to easily revert changes to your application. This is particularly useful when you encounter issues or want to revert to a previous version of your application. +## Types of Rollbacks + +Dokploy supports two types of rollback mechanisms: + +1. **Docker Swarm Rollbacks** (Automatic): Based on health checks, automatically reverts to the previous version if a deployment fails health checks +2. **Registry-based Rollbacks** (Manual): Uses Docker registry to store each deployment's image, allowing you to manually rollback to any specific deployment version + + + The rollback methods described in the first section of this guide are based on **Docker Swarm's automatic rollback feature**. Dokploy also supports **registry-based rollbacks** at the deployment level, which allows you to save each deployment's image to a registry and rollback to any specific version. See the "Rollback to a specific version" section below for more details. + ## Requirements 1. Have a `/health` endpoint in your application. 2. Have `curl` available in your container (if you use alpine for example, it won't be installed by default). -## Steps to Rollback +## Docker Swarm Automatic Rollback +This method uses Docker Swarm's built-in rollback feature, which automatically reverts to the previous version if health checks fail during deployment. + + + This rollback method is **automatic** and based on Docker Swarm's health check system. It only works if the new deployment fails health checks, triggering an automatic rollback to the previous version. + + +### Steps to Configure Automatic Rollback Let's suppose we have a NodeJS application that has a health check route `/api/health` that returns a 200 status code and running in the port 3000. @@ -50,25 +69,55 @@ Paste the following code: } ``` -## Rollback to a specific version +## Registry-based Rollback to Specific Versions -The previous steps covered Docker Swarm's automatic rollback feature. Since v0.23.0, Dokploy also supports manual rollbacks to specific deployment points, giving you more control over your application versions. +The previous section covered Docker Swarm's automatic rollback feature, which only works when health checks fail. Dokploy also supports **registry-based rollbacks** at the deployment level, which provides more control and flexibility. -### Enabling Rollback Feature +### How Registry-based Rollbacks Work -To start saving deployment snapshots for rollbacks: +When using registry-based rollbacks, Dokploy: + +- **Saves each deployment's image to your configured registry**: Every time you deploy, the built image is tagged and pushed to your Docker registry (Docker Hub, GHCR, etc.) +- **Associates each deployment with its image**: Each deployment record in Dokploy is linked to a specific image tag in your registry +- **Enables rollback to any deployment**: You can rollback to any previous deployment by using the image that was saved during that deployment + +This approach is different from Docker Swarm rollbacks because: +- ✅ **Works with any deployment**: Not limited to health check failures +- ✅ **Rollback to any version**: Can rollback to any previous deployment, not just the immediate previous one +- ✅ **Uses registry storage**: Images are stored in your registry, making them persistent and accessible + + + Registry-based rollbacks require that your application is configured to use a Docker registry. The images are automatically pushed to your registry during each deployment, and Dokploy tracks which image corresponds to each deployment. + + +### Prerequisites for Registry-based Rollbacks + +To use registry-based rollbacks, you need: + +1. **A configured Docker registry** in Dokploy (Docker Hub, GHCR, or custom registry) +2. **Registry credentials** set up in Dokploy's registry settings +3. **Application configured to push images** to the registry during deployment + + + When you enable rollbacks, Dokploy will automatically push each deployment's image to your configured registry with a unique tag, allowing you to rollback to any specific deployment version. + + +### Enabling Registry-based Rollbacks + +To start saving deployment images to your registry for rollbacks: 1. Navigate to your application 2. Go to **Deployments** → **Rollback Settings** 3. Enable the **Rollback** option +4. Select the registry you want to use for rollbacks +5. Click on **Save** -### How it works +Once enabled, Dokploy will: +- **Automatically tag and push images**: Every deployment's image is tagged and pushed to your configured registry +- **Track deployment associations**: Each deployment is linked to its specific image tag in the registry +- **Enable rollback buttons**: You'll see a **Rollback** button next to each deployment in the Deployments section -- **Automatic snapshots**: Every time you deploy, Dokploy creates a rollback point associated with that deployment -- **Manual rollback**: Click the **Rollback** button next to any deployment to revert to that specific version -- **Automatic cleanup**: When old deployments are deleted, their associated rollback snapshots and images are also removed to save space - -### Performing a rollback +### Performing a Registry-based Rollback 1. Go to your application's **Deployments** section 2. Find the deployment version you want to rollback to @@ -76,9 +125,6 @@ To start saving deployment snapshots for rollbacks: 4. Confirm the rollback action - Having rollbacks enabled will increase storage usage, as it saves previous versions of your application. Consider your storage capacity when enabling this feature. + After clicking **Rollback**, you'll need to wait a few seconds for Dokploy to download the image from your registry. The container will not appear in the **Logs** tab immediately - wait a moment for the image download to complete before checking the logs to see the container running. - - **Important**: If you manually clean Docker images using commands like `docker image prune` or `docker system prune`, the rollback snapshots may be lost. Avoid cleaning Docker images if you want to preserve your rollback history. - diff --git a/apps/docs/content/docs/core/comparison.mdx b/apps/docs/content/docs/core/comparison.mdx index eb7833b..d27fc4f 100644 --- a/apps/docs/content/docs/core/comparison.mdx +++ b/apps/docs/content/docs/core/comparison.mdx @@ -29,7 +29,8 @@ Comparison of the following deployment tools: | **Shared Enviroment Variables** | ✅ | ❌ | ❌ | ✅ | | **Environments** | ✅ | ❌ | ❌ | ✅ | | **Schedules Jobs** | ✅ | ❌ | ❌ | ✅ | -| **Cloudflare Tunnels** | ❌ | ❌ | ❌ | ✅ | +| **Cloudflare Tunnels** | ✅ | ❌ | ❌ | ✅ | +| **Custom Build Server** | ✅ | ❌ | ❌ | ✅ | | **Volume Backups** | ✅ | ❌ | ❌ | ❌ | | **Preview Deployments** | ✅ | ❌ | ❌ | ✅ | | **Teams** | ✅ | ❌ | ❌ | ✅ | diff --git a/apps/docs/content/docs/core/docker-compose/domains.mdx b/apps/docs/content/docs/core/docker-compose/domains.mdx index 6b419b5..b7b3827 100644 --- a/apps/docs/content/docs/core/docker-compose/domains.mdx +++ b/apps/docs/content/docs/core/docker-compose/domains.mdx @@ -3,24 +3,111 @@ title: Domains description: Configure domains for your Docker Compose application. --- -When using Docker Compose, adding a domain to a service is a straightforward process. This guide will walk you through the necessary steps to configure manual domains for your application. +import { Callout } from "fumadocs-ui/components/callout"; -Key Steps: +When using Docker Compose, there are **two ways** to configure domains for your services: + +## Method 1: Using Dokploy Domains (Recommended) + +The easiest way to configure domains is using Dokploy's native domain management feature. This method allows you to configure domains directly through the Dokploy UI without manually editing your Docker Compose file. + + + **Recommended**: Since v0.7.0, Dokploy supports domains natively. You can configure your domains directly in the Dokploy UI through the **Domains** tab of your Docker Compose application. This is the simplest and most user-friendly approach. + + +To use this method: +1. Navigate to your Docker Compose application in Dokploy +2. Go to the **Domains** tab +3. Click **Add Domain** and configure your domain +4. Dokploy will automatically handle the routing configuration + +### How It Works + +At runtime, during the deployment phase, Dokploy automatically adds Traefik labels internally to your Docker Compose file. You don't need to manually add these labels - Dokploy handles this automatically based on the domains you configure in the UI. + +**Example:** + +Here's a default Docker Compose file: + +```yaml +version: "3.8" + +services: + beszel: + image: henrygd/beszel:0.10.2 + restart: unless-stopped + ports: + - 8090 + volumes: + - beszel_data:/beszel_data + - /var/run/docker.sock:/var/run/docker.sock:ro + +volumes: + beszel_data: {} +``` + +**Preview Compose Feature:** + +You can click the **Preview Compose** button to see the final Docker Compose file that will be executed. If you have at least one domain added, the preview will show the compose file with all the labels and network configurations automatically added. + +Here's what the final compose file looks like when deployed (this example uses [Isolated Deployments](/docs/core/docker-compose/utilities#isolated-deployments)): + +```yaml +version: "3.8" + +services: + beszel: + image: henrygd/beszel:0.10.2 + restart: unless-stopped + ports: + - 8090 + volumes: + - beszel_data:/beszel_data + - /var/run/docker.sock:/var/run/docker.sock:ro + networks: + - a-beszel-a95pzl + labels: + - traefik.http.routers.a-beszel-a95pzl-715-web.rule=Host(`a-beszel-d073ee-31-220-108-27.traefik.me`) + - traefik.http.routers.a-beszel-a95pzl-715-web.entrypoints=web + - traefik.http.services.a-beszel-a95pzl-715-web.loadbalancer.server.port=8090 + - traefik.http.routers.a-beszel-a95pzl-715-web.service=a-beszel-a95pzl-715-web + - traefik.enable=true + +volumes: + beszel_data: {} + +networks: + a-beszel-a95pzl: + name: a-beszel-a95pzl + external: true +``` + +**Important Notes:** + +- If you don't add any domains through the UI and don't use [Isolated Deployments](/docs/core/docker-compose/utilities#isolated-deployments), your application will be deployed exactly as you specified in your original Docker Compose file - no labels or network modifications will be added. +- The Preview Compose button is useful for verifying how Dokploy will modify your compose file before deployment. +- All label generation and network configuration is handled automatically by Dokploy based on your domain settings. + +For detailed instructions on using Dokploy's domain management, see the [Domains guide](/docs/core/domains). + +## Method 2: Manual Configuration (Advanced) + +If you prefer to configure domains manually using Traefik labels in your Docker Compose file, you can do so by following the steps below. This method gives you more control but requires manual configuration. + + + Manual configuration is more complex and requires editing your Docker Compose file. We recommend using Method 1 (Dokploy Domains) unless you have specific requirements that need manual Traefik label configuration. + + +### Manual Configuration Steps + +Key Steps for manual configuration: 1. Add the service to the `dokploy-network`. 2. Use Traefik labels to configure routing. -import { Callout } from "fumadocs-ui/components/callout"; +### Example Scenario - - Since v0.7.0 Dokploy support domains natively. This means that you can - configure your domain directly in the Dokploy UI, without doing the rest of - the steps check on the [domains section](/docs/core/domains). - - -Example Scenario - -Let's consider an application with three components: a frontend, a backend, and a database. We'll start with a basic Docker Compose file and then enhance it with domain configuration. +Let's consider an application with three components: a frontend, a backend, and a database. We'll start with a basic Docker Compose file and then enhance it with manual domain configuration. ```yaml version: "3.8" @@ -63,10 +150,14 @@ volumes: db-data: ``` -## Step 1: Add the Network +### Step 1: Add the Network First, we'll add the dokploy-network to our services: + + **Tip**: If you prefer to isolate all services and avoid adding them to the `dokploy-network`, you can use the **Isolated Deployments** feature. This feature isolates all services and eliminates the need to manually add them to the dokploy-network. See the [Isolated Deployments guide](/docs/core/docker-compose/utilities#isolated-deployments) for more information. + + ```yaml version: "3.8" @@ -94,10 +185,14 @@ networks: external: true ``` -Step 2: Configuring Traefik Labels +### Step 2: Configuring Traefik Labels Now, let's add Traefik labels to route domains to our services. We'll focus on the frontend and backend services: + + **Important for Docker Stack**: If you're using **Docker Stack** (Docker Swarm mode), the Traefik labels must be placed in the `deploy.labels` section instead of directly in the `labels` section. See the Docker Stack example below. + + ```yaml version: "3.8" @@ -151,7 +246,7 @@ networks: external: true ``` -Understanding Traefik Labels +### Understanding Traefik Labels 1. `traefik.enable=true` Enables Traefik routing for the service. 2. `traefik.http.routers..rule=Host('your-domain.dokploy.com')` Specifies the domain for the service @@ -160,14 +255,73 @@ Understanding Traefik Labels **Note**: Replace `` with a unique identifier for each service (e.g., frontend-app, backend-app, etc.). -## Important Considerations +#### Docker Stack Configuration + +When using **Docker Stack** (Docker Swarm mode), labels must be placed under the `deploy.labels` section. Additionally, Docker Stack does not support the `build` directive, so you must use pre-built images from a registry: + + + **Important**: Docker Stack does not support the `build` directive. You must build your images separately and push them to a Docker registry, then reference them using the `image:` directive. + + +```yaml +version: "3.8" + +services: + frontend: + image: your-registry.com/frontend:latest # Pre-built image from registry + volumes: + - ./frontend:/app + expose: + - 3000 + networks: + - dokploy-network + deploy: + labels: + - traefik.enable=true + - traefik.http.routers.frontend-app.rule=Host(`frontend.dokploy.com`) + - traefik.http.routers.frontend-app.entrypoints=web + - traefik.http.services.frontend-app.loadbalancer.server.port=3000 + + backend: + image: your-registry.com/backend:latest # Pre-built image from registry + volumes: + - ./backend:/app + expose: + - 5000 + networks: + - dokploy-network + deploy: + labels: + - traefik.enable=true + - traefik.http.routers.backend-app.rule=Host(`backend.dokploy.com`) + - traefik.http.routers.backend-app.entrypoints=web + - traefik.http.services.backend-app.loadbalancer.server.port=5000 + +networks: + dokploy-network: + external: true +``` + + + The key differences for **Docker Stack** are: + 1. Labels must be nested under `deploy.labels` (not directly under `labels`) + 2. You must use `image:` with a pre-built image from a registry (Docker Stack does not support `build`) + 3. Build your images separately and push them to a registry before deploying with Docker Stack + + +### Important Considerations 1. **Port Exposure**: Use `expose` instead of `ports` to limit port access to the container network, avoiding exposure to the host machine. 2. **DNS Configuration**: Ensure you create `A` records pointing to your domain in your DNS Provider Settings. 3. **HTTPS**: For HTTPS, you can use Let's Encrypt or other SSL/TLS certificates. +4. **Isolated Deployments**: As an alternative to manually adding services to `dokploy-network`, you can use the [Isolated Deployments](/docs/core/docker-compose/utilities#isolated-deployments) feature, which automatically isolates all services and handles networking configuration for you. -## Deployment +### Deployment -With these configurations in place, you're now ready to deploy your application using Docker Compose. This setup should be sufficient to get your services up and running with custom domain routing through Traefik. +With these manual configurations in place, you're now ready to deploy your application using Docker Compose. This setup should be sufficient to get your services up and running with custom domain routing through Traefik. + + + Remember: For most use cases, we recommend using **Method 1 (Dokploy Domains)** as it's simpler and doesn't require manual Docker Compose file editing. See the [Domains guide](/docs/core/domains) for more information. + If you have any further questions or need assistance, join our [Discord server](https://discord.com/invite/2tBnJ3jDJc) and we'll be happy to help. diff --git a/apps/docs/content/docs/core/docker-compose/example.mdx b/apps/docs/content/docs/core/docker-compose/example.mdx index 89cddc2..4dc7833 100644 --- a/apps/docs/content/docs/core/docker-compose/example.mdx +++ b/apps/docs/content/docs/core/docker-compose/example.mdx @@ -8,6 +8,14 @@ description: "Learn how to use Docker Compose with Dokploy" In this tutorial, we will create a simple application using Docker Compose and route the traffic to an accessible domain. + + **Note**: There are two ways to configure domains for Docker Compose applications: + 1. **Using Dokploy Domains** (Recommended): Configure domains directly in the Dokploy UI through the **Domains** tab. See the [Domains guide](/docs/core/domains) for details. + 2. **Manual Configuration**: Configure domains using Traefik labels in your Docker Compose file (shown in this tutorial). + + This tutorial demonstrates the manual method. For most users, we recommend using the Dokploy Domains feature as it's simpler and doesn't require editing your Docker Compose file. + + ### Steps @@ -104,7 +112,8 @@ Deploy the application by clicking on "deploy" and wait for the deployment to co **Tips**: 1. Set unique names for each router: `traefik.http.routers.` -2. Set unique names for each service: `traefik.http.services.` +2. Set unique names for each service: `traefik.http.services.` 3. Ensure the network is linked to the `dokploy-network` 4. Set the entry point to websecure and the certificate resolver to letsencrypt to generate certificates. +5. **For Docker Stack**: If you're using Docker Stack (Docker Swarm mode), place the labels under `deploy.labels` instead of directly under `labels`. See the [Domains guide](/docs/core/docker-compose/domains) for the Docker Stack configuration example. diff --git a/apps/docs/content/docs/core/docker-compose/index.mdx b/apps/docs/content/docs/core/docker-compose/index.mdx index 9c9ea50..1659354 100644 --- a/apps/docs/content/docs/core/docker-compose/index.mdx +++ b/apps/docs/content/docs/core/docker-compose/index.mdx @@ -58,14 +58,20 @@ This section provides advanced configuration options for experienced users. It i Docker volumes are a way to persist data generated and used by Docker containers. They are particularly useful for maintaining data between container restarts or for sharing data among different containers. -To bind a volume to the host machine, you can use the following syntax in your docker-compose.yml file, but this way will clean up the volumes when a new deployment is made: +Dokploy supports two methods for data persistence in Docker Compose: + +### Method 1: Bind Mounts (../files folder) + +Use bind mounts for simple persistence needs, configuration files, or when you need direct access to files on the host. This method maps a directory from the host machine into the container. + +**Important:** Avoid using absolute host paths, as they will be cleaned up during deployments: ```yaml volumes: - "/folder:/path/in/container" ❌ ``` -It's recommended to use the ../files folder to ensure your data persists between deployments. For example: +Instead, use the `../files` folder to ensure your data persists between deployments: ```yaml volumes: @@ -73,6 +79,48 @@ volumes: - "../files/my-configs:/etc/my-app/config" ✅ ``` +**Use bind mounts when:** +- You need simple data persistence +- You're mounting configuration files or small datasets +- You want direct file access on the host +- You don't need automated backups via Dokploy's Volume Backups feature + +### Method 2: Docker Named Volumes + +Use Docker named volumes when you need automated backups, better portability, or Docker-managed storage. Named volumes are managed by Docker and can be backed up automatically using Dokploy's [Volume Backups](/docs/core/volume-backups) feature. + +```yaml +services: + app: + image: dokploy/dokploy:latest + volumes: + - my-database:/var/lib/mysql + - my-app-data:/app/data + +volumes: + my-database: + my-app-data: +``` + +**Use named volumes when:** +- You need automated backups to S3 (via Volume Backups) +- You want Docker-managed storage (better portability) +- You're storing databases or large datasets +- You need backup and restore capabilities + +**Note:** Volume Backups only work with Docker named volumes, not with bind mounts (`../files`). If you need backup functionality, use named volumes instead of bind mounts. + +### Choosing the Right Method + +| Feature | Bind Mounts (../files) | Named Volumes | +|---------|----------------------|---------------| +| Simple persistence | ✅ Yes | ✅ Yes | +| Direct host access | ✅ Yes | ❌ No | +| Automated backups | ❌ No | ✅ Yes | +| Docker-managed | ❌ No | ✅ Yes | +| Best for config files | ✅ Yes | ⚠️ Possible but less common | +| Best for databases | ⚠️ Possible | ✅ Recommended | + **Important:** If you need to use files from your repository (configuration files, scripts, etc.), you must move them to Dokploy's File Mounts (via Advanced → Mounts) instead of mounting them directly from the repository. When using AutoDeploy, Dokploy performs a `git clone` on each deployment, which clears the repository directory. Mounting files directly from your repository using relative paths (e.g., `./` or `./config/file.conf`) will cause them to be lost or empty in subsequent deployments. See the [Troubleshooting guide](/docs/core/troubleshooting#using-files-from-your-repository) for more details. diff --git a/apps/docs/content/docs/core/docker-compose/utilities.mdx b/apps/docs/content/docs/core/docker-compose/utilities.mdx index 8799ee8..698155b 100644 --- a/apps/docs/content/docs/core/docker-compose/utilities.mdx +++ b/apps/docs/content/docs/core/docker-compose/utilities.mdx @@ -30,25 +30,27 @@ services: When Isolated Deployments is enabled, Dokploy will: -1. Add a prefix to all your defined networks -2. Create a network based on your service's appName and associate it with each service in your compose file +1. Create a network based on your `appName` and associate it with each service in your compose file +2. Add the network to every service in your compose file 3. Connect the Traefik load balancer to this isolated network, maintaining service isolation while ensuring proper routing When using this feature, you don't need to explicitly define dokploy-network in your networks section, as isolation is handled automatically. -## Randomize Compose + + **Important: Installation Type Considerations** -Dokploy offers functionality to randomize various compose properties: + If you're using a **custom installation** that replaces the standalone Traefik container with a Docker service (see [Manual Installation](/docs/core/manual-installation)), be aware of the following risks: -1. Volumes -2. Networks -3. Services -4. Configs -5. Secrets + 1. **System Restart Issues**: If your system restarts, your services may lose their network references to Traefik. This happens because Docker Swarm changes network references after a restart, which can cause connectivity issues between your services and Traefik. + + 2. **Manual Redeployment Required**: After a system restart, you may need to manually redeploy your Docker Compose applications to restore network connectivity, which can be tedious and time-consuming. + + 3. **Reference**: For more details about this issue, see [GitHub Issue #1004](https://github.com/Dokploy/dokploy/issues/1004). + + **Recommended Approach**: If you use the **official installation** or **manual installation with the standalone Traefik container**, you won't experience these issues. Your services should start normally after a system restart without requiring manual intervention. + -You can specify a custom prefix that will be used as a suffix for each compose property. -Note: If both Isolated Deployments and Randomize Compose are enabled, the Isolated Deployments configuration takes precedence. diff --git a/apps/docs/content/docs/core/domains/index.mdx b/apps/docs/content/docs/core/domains/index.mdx index 86addb0..1df7ac3 100644 --- a/apps/docs/content/docs/core/domains/index.mdx +++ b/apps/docs/content/docs/core/domains/index.mdx @@ -23,6 +23,64 @@ Domains are supported for: - **Applications** - **Docker Compose** +## How Domains Are Managed + +Dokploy handles domains differently depending on whether you're using Applications or Docker Compose: + +### Applications + +For **Applications**, Dokploy creates a unique configuration file for each domain you create or update. These files are managed automatically and can be viewed in: + +- **Traefik File System**: Accessible through the Dokploy UI +- **Advanced Settings**: Scroll to the bottom of the Advanced tab to view the Traefik configuration + +Each domain configuration follows this structure: + +```yaml +http: + routers: + dokploy-app-name-router-1: + rule: Host(`your-domain.com`) + service: dokploy-app-name-service-1 + middlewares: + - redirect-to-https + entryPoints: + - web + dokploy-app-name-router-websecure-1: + rule: Host(`your-domain.com`) + service: dokploy-app-name-service-1 + middlewares: [] + entryPoints: + - websecure + tls: + certResolver: letsencrypt + services: + dokploy-app-name-service-1: + loadBalancer: + servers: + - url: http://dokploy-app-name:3000 + passHostHeader: true +``` + +**Key Points for Applications:** + +- **No Redeployment Required**: Changes to domains take effect immediately without needing to redeploy your application +- **Hot Reload**: Dokploy uses Traefik's [File Provider](https://doc.traefik.io/traefik/reference/install-configuration/providers/others/file/) which supports hot reloading, so configuration changes are applied automatically +- **Troubleshooting**: If you make changes and your domain doesn't work, check the Traefik logs for any errors. The logs should provide helpful information about what might be wrong + +### Docker Compose + +For **Docker Compose**, domains are managed using [Traefik Docker Labels](https://doc.traefik.io/traefik/expose/docker/). This means: + +- **No Configuration Files**: Domains are configured directly through Docker labels in your compose file +- **Redeployment Required**: Unlike Applications, you **must redeploy** your Docker Compose application for domain changes to take effect +- **No Hot Reload**: Docker Compose does not support hot reloading of domain configurations, so Traefik needs to read the labels from a fresh deployment + +**Key Points for Docker Compose:** + +- Each time you modify a domain, you need to redeploy the application +- Domain changes are applied when Traefik reads the Docker labels during deployment +- For more details on configuring domains manually with Docker Compose, see the [Docker Compose Domains guide](/docs/core/docker-compose/domains) ## Requirements (Optional) diff --git a/apps/docs/content/docs/core/guides/cloudflare-tunnels.mdx b/apps/docs/content/docs/core/guides/cloudflare-tunnels.mdx new file mode 100644 index 0000000..05dcc86 --- /dev/null +++ b/apps/docs/content/docs/core/guides/cloudflare-tunnels.mdx @@ -0,0 +1,165 @@ +--- +title: Cloudflare Tunnels +description: Learn how to use Cloudflare Tunnels to securely expose your Dokploy applications without opening ports on your server. +--- + +import { Callout } from 'fumadocs-ui/components/callout'; + +Cloudflare Tunnels provide a secure way to connect your applications to the internet without exposing ports on your server. This is particularly useful for home servers or networks where you can't easily configure port forwarding or want enhanced security. + +## What are Cloudflare Tunnels? + +Cloudflare Tunnels (formerly Argo Tunnels) create an encrypted tunnel between your origin server and Cloudflare's global network. Instead of opening ports 80 and 443 on your server, the tunnel establishes an outbound-only connection to Cloudflare, which then routes traffic to your applications. + +### Benefits + +- **Enhanced Security**: No need to open inbound ports on your firewall +- **Simple Setup**: Works behind NAT and restrictive firewalls +- **DDoS Protection**: Traffic is routed through Cloudflare's network +- **Free Tier Available**: Included with free Cloudflare accounts +- **Wildcard Support**: Route multiple subdomains through a single tunnel + +## Prerequisites + +Before setting up Cloudflare Tunnels with Dokploy, ensure you have: + +- A domain managed by Cloudflare (free tier works) +- Dokploy installed and running +- Access to Cloudflare dashboard + + + When using Cloudflare Tunnels, you should **disable Let's Encrypt** in Dokploy and use HTTP instead of HTTPS for internal connections. Cloudflare handles SSL/TLS termination at their edge. + + +## Cloudflare Tunnel Setup + +### Step 1: Create a Tunnel in Cloudflare + +- Log in to your [Cloudflare Dashboard](https://dash.cloudflare.com/) +- Navigate to **Zero Trust** (or **Access** in older dashboards) +- Go to **Networks** → **Connectors** +- Click **Create a tunnel** +- Choose **Cloudflared** as the connector type +- Give your tunnel a name (e.g., `dokploy-tunnel`) +- Copy the **Tunnel Token** that's generated (you'll need this later) + + + Keep your tunnel token secure! It provides access to route traffic to your server. + + +### Step 2: Configure SSL/TLS Settings + +For Cloudflare Tunnels to work properly with Dokploy: + +- In Cloudflare Dashboard, go to **SSL/TLS** +- Set the encryption mode to **Full** or **Full (Strict)** + + + Do not use "Flexible" mode as it may cause redirect loops with Traefik. + + +### Step 3: Create Cloudflare Service in Dokploy + +1. Create a new application +2. Select Docker Provider and set the Image name as `cloudflare/cloudflared` +3. Go to the Environments tab and add the token you copied: `TUNNEL_TOKEN="TOKEN-YOU-COPIED"` +4. Go to the Advanced tab, in the Arguments field add 2 entries: first `tunnel`, second `run`, then click save +5. Deploy the application. You should see the container in healthy status in the logs section + + +### Step 4: Configuring Public Hostnames (Domains) + +After deploying cloudflared, you need to configure which domains route through the tunnel. + +#### Understanding Traefik Routing vs Direct Access + +Dokploy uses **Traefik** as its reverse proxy to route traffic to your applications. When configuring Cloudflare Tunnels, you have two options: + +**Option 1: Route through Traefik (Recommended)** +- **Traffic flow**: Cloudflare → Tunnel → Traefik → Your Apps +- **Benefits**: + - Support for multiple applications with a single tunnel (wildcard domains) + - Leverage all Dokploy domain configurations (redirects, path rewrites, etc.) + - Traefik automatically routes based on the domain you configured in Dokploy + - Configure once, works for all apps + +**Option 2: Direct Container Access** +- **Traffic flow**: Cloudflare → Tunnel → Your App (bypasses Traefik) +- **Benefits**: + - Simpler setup for single applications + - Slightly lower latency (one less hop) +- **When to use**: For single dedicated services or special cases +- **Note**: You'll need a separate public hostname in Cloudflare for each container + +#### For Applications (via Traefik) + +- In Cloudflare Dashboard, go to your tunnel +- Click **Configure** +- Go to the **Published application routes** tab +- Click **Add a published application route** +- Configure: + - **Subdomain**: Your subdomain (e.g., `app`) + - **Domain**: Your domain (e.g., `example.com`) - Select from dropdown + - **Service**: + - **Type**: HTTP + - **URL**: `dokploy-traefik:80` +- Click **Save** + + + With this setup, Traefik will route the request to the correct application based on the domain you configured in Dokploy's domain settings. + + +**Example:** + +To test this, let's create a minimal app: + +1. Create a simple application +2. Select Docker Provider and set the image name to `nginx` +3. Click on Deploy +4. Go to the Domains tab +5. Create a new domain (Important: make sure to use the same domain you created in Cloudflare dashboard under `Published application routes`) +6. Set the correct port where your application is running (nginx runs on port `80` by default) +7. Don't enable HTTPS toggle or select any certificate provider (this can cause conflicts with Cloudflare SSL) + +#### For Direct Container Access + +If you prefer to bypass Traefik and connect directly to a container: + +- Configure the public hostname with: + - **Service**: + - **Type**: HTTP + - **URL**: `appName:port` (e.g., `dokploy:3000`, `my-app:8080`) + +Note: The app name in Dokploy is shown under the service name, usually formatted as `project-serviceName-hash` + + + When using direct access, you bypass Traefik completely. Domain configurations in Dokploy won't apply, and you'll need to configure each container separately in Cloudflare. + + +### For Wildcard Subdomains (Multiple Apps) + +To support multiple applications/subdomains with a single tunnel configuration: + +**Note:** You need to create a manual CNAME wildcard record in your Cloudflare DNS configuration. + +1. Go to the **Connectors** section and copy the **Tunnel ID** value +2. Go to **DNS Records** of your domain +3. Create a new record: + - **Type**: CNAME + - **Name**: `*` + - **Content**: `your-tunnel-id.cfargotunnel.com` (replace `your-tunnel-id` with the ID you copied) +4. Click Save + +Then, go to the configuration of your tunnel under **Published application routes**: +- Add a public hostname with: + - **Subdomain**: `*` (asterisk for wildcard) + - **Domain**: Your domain (e.g., `example.com`) + - **Service**: + - **Type**: HTTP + - **URL**: `dokploy-traefik:80` + +This allows all subdomains (`app1.example.com`, `app2.example.com`, etc.) to route through Traefik, which then directs traffic to the appropriate container based on your Dokploy domain configurations. + + + With wildcard routing, you only need ONE public hostname in Cloudflare Tunnel. Traefik handles routing to different apps based on the domain configured in Dokploy. + \ No newline at end of file diff --git a/apps/docs/content/docs/core/guides/ec2-instructions.mdx b/apps/docs/content/docs/core/guides/ec2-instructions.mdx new file mode 100644 index 0000000..cee1dea --- /dev/null +++ b/apps/docs/content/docs/core/guides/ec2-instructions.mdx @@ -0,0 +1,86 @@ +--- +title: EC2 Instructions +description: "Instructions for setting up a remote server on EC2" +--- + +import { ImageZoom } from "fumadocs-ui/components/image-zoom"; +import { Callout } from "fumadocs-ui/components/callout"; + +In this guide we will show you how to setup a remote server on AWS EC2 and add an SSH Key on dokploy to connect to the server and start deploying your applications. + +## Requirements + +1. An AWS account +2. A domain that is managed by AWS Route53 + +## 1. Create an SSH Key + + + If you already have an SSH Key you can skip this step and simply go to settings -> SSH Keys and add the SSH Key you have stored on your machine + + +Navigate to Dokploy Settings -> SSH Keys and add a new key + +You will receive a public key and a private key. Copy the public key and save it. + + + +## 2. Create an EC2 Instance + +Login to your AWS account, navigate to EC2 and click on Launch Instance. + +We will then be prompted to select an AMI (Amazon Machine Image) and we will select the Ubuntu Server 22.04 LTS AMI. + +It should like this: + + + +Select the instance type you want to use. For this guide we will use the `t2.micro` instance type which is free tier eligible. + +Now we need to add the SSH Key we created in step 1 to the EC2 instance. + +Click on Security Group and then add a new key pair. + +Add the name of your SSH Key and paste the public key you copied in step 1. + + + +You will have to create a security group that allows SSH (port 22) access from your IP address. and open all HTTP and HTTPS ports for ingress and egress traffic (Port 80 and 443). + + + Opening port 22 to the internet is a security risk. It is recommended to use a bastion host or a VPN to access your EC2 instance securely. + + +Now click on Launch Instance and wait for the instance to be created. + +## 3. Add the Server to Dokploy + +Now that we have the EC2 instance running, we can add it to Dokploy. + +Navigate to Dokploy -> Settings -> Servers and click on Add Server and copy the server IP Address. + +## 4. Setup the Server + +Navigate to Dokploy -> Settings -> Servers -> Setup Server and follow the instructions. + +## 5. Deploy your application + +Now that the server is setup, you can deploy your application to the server. diff --git a/apps/docs/content/docs/core/guides/tailscale.mdx b/apps/docs/content/docs/core/guides/tailscale.mdx new file mode 100644 index 0000000..67590ae --- /dev/null +++ b/apps/docs/content/docs/core/guides/tailscale.mdx @@ -0,0 +1,358 @@ +--- +title: Tailscale +description: Learn how to use Tailscale to securely access your Dokploy applications and servers through a private network without opening ports. +--- + +import { Callout } from 'fumadocs-ui/components/callout'; + +Tailscale creates a secure, private network that connects your devices and servers using WireGuard. This allows you to access your Dokploy applications and servers securely without opening ports on your firewall or exposing services to the public internet. + +**Tailscale is particularly useful for preventing unauthorized access to your services.** By keeping your Dokploy instance and applications on a private network, only devices that are explicitly added to your Tailscale network can access them. This means your services remain completely private and invisible to the public internet, significantly reducing the attack surface and preventing unauthorized users from discovering or accessing your infrastructure. + +## What is Tailscale? + +Tailscale is a zero-config VPN that creates a mesh network between your devices and servers. It uses the WireGuard protocol to establish encrypted connections, making it easy to access your infrastructure securely from anywhere. + +### Benefits + +- **Zero-Config VPN**: Automatic key management and network setup +- **No Port Forwarding**: Access services without opening firewall ports +- **Secure by Default**: All traffic is encrypted end-to-end +- **Private Services**: Keep your services completely private and prevent unauthorized access +- **Easy Access**: Connect from any device with Tailscale installed +- **Private IPs**: Each device gets a private IP address (100.x.x.x) +- **Free Tier Available**: Up to 100 devices for personal use +- **ACLs**: Fine-grained access control lists for security + +## Prerequisites + +Before setting up Tailscale with Dokploy, ensure you have: + +- A Tailscale account (free tier works) +- Dokploy installed and running +- Access to your server via SSH or console +- Tailscale installed on your client devices (optional, for accessing services) + + + Tailscale works great for accessing Dokploy's admin interface and your applications from anywhere, without exposing them to the public internet. This keeps your services private and prevents unauthorized users from discovering or accessing them. + + +## Tailscale Setup + +This guide will walk you through setting up Tailscale to securely access your Dokploy server and applications through a private network. + +### Step 1: Prerequisites + +Before starting, ensure you have: + +1. **Dokploy installed and running** - Follow the [installation guide](/docs/core/installation) if needed +2. **A Tailscale account** - Create one at [tailscale.com](https://login.tailscale.com/login) (free tier works) + +### Step 2: Get Docker Network Subnet + +First, we need to identify the Docker network subnet that Dokploy uses. This will be advertised to the Tailscale network to allow access to your containers. + +Run the following command on your Dokploy server: + +```bash +docker network inspect dokploy-network | grep Subnet +``` + +You should see output like this: + +``` +"Subnet": "10.254.0.0/24", +``` + +Copy the subnet value (e.g., `10.254.0.0/24`) - you'll need it in the next step. + +### Step 3: Configure Tailscale Server + +Now we'll set up Tailscale on your Dokploy server with subnet routing enabled. + +#### 3.1: Create Server in Tailscale Admin + +1. Go to [Tailscale Admin Console](https://login.tailscale.com/admin/machines/new-linux) +2. Click **Add a device** → **Linux** +3. Scroll down and click **Generate install script** + +You'll see a script like this: + +```bash +curl -fsSL https://tailscale.com/install.sh | sh && sudo tailscale up --auth-key=tskey-auth-something-random +``` + +#### 3.2: Modify the Install Command + +We need to modify this command to: +- Enable SSH access with the `--ssh` flag +- Advertise the Docker subnet with `--advertise-routes` flag + +Replace `subnet-of-docker` with the subnet you copied in Step 2: + +```bash +curl -fsSL https://tailscale.com/install.sh | sh && sudo tailscale up --ssh --advertise-routes=10.254.0.0/24 --auth-key=tskey-auth-something-random +``` + + + Replace `10.254.0.0/24` with your actual Docker network subnet from Step 2. + + +#### 3.3: Run the Command + +Execute the modified command on your Dokploy server terminal. + +#### 3.4: Approve Subnet Routes + +After running the command, you need to approve the subnet routes in Tailscale: + +1. Go to [Tailscale Admin Console](https://login.tailscale.com/admin/machines/) +2. Find your server and approve the advertised routes + +#### 3.5: Verify Server Connection + +Verify that your server is connected to Tailscale: + +```bash +sudo tailscale status +``` + +You should see your server listed. Get the server's Tailscale IP address: + +```bash +sudo tailscale ip -4 +``` + +This will return something like: +``` +100.100.100.100 +``` + +Copy this IPv4 address - you'll use it to access your server and Dokploy. + +### Step 4: Configure Client Devices + +Now you'll set up client devices (your computer, phone, etc.) to connect to the Tailscale network. + +#### 4.1: Add Client Device + +1. Go to [Tailscale Admin Console](https://login.tailscale.com/admin/machines) +2. Click **Add a device** → **Client device** +3. Select your device type: + - Windows + - macOS + - Linux + - Android + - iPhone & iPad + - Synology + +#### 4.2: Install Tailscale on Client + +**For macOS:** +- Download the native app from [tailscale.com/download/macos](https://tailscale.com/download/macos) +- Install and authenticate with your Tailscale account + +**For other platforms:** +- Visit [tailscale.com/download](https://tailscale.com/download) for your specific platform +- Follow the installation instructions + + + +Login to your Tailscale account and you should see both your server and client device connected to the network it will also display in the tailscale dashboard. + +### Step 5: Access Dokploy via Tailscale + +Now you can access Dokploy and your applications through the Tailscale network. + +#### Access Dokploy Dashboard + +1. Use your server's Tailscale IP address (from Step 3.5): + ``` + http://100.100.100.100:3000 + ``` + Replace `100.100.100.100` with your actual Tailscale IP. + +2. Or use the Tailscale hostname (if MagicDNS is enabled): + ``` + http://your-server-name.tailscale.ts.net:3000 + ``` + +#### Access via SSH + +You can also SSH into your server using the Tailscale IP: + +```bash +ssh root@100.100.100.100 +``` + +Replace `100.100.100.100` with your server's Tailscale IP address. + + + With this setup, you can access Dokploy and your applications without any port forwarding or exposing services to the public internet. Only devices in your Tailscale network can access these services, ensuring they remain private and protected from unauthorized access. + + +## Configuring Applications + +### Accessing Applications via Tailscale + +Once Tailscale is set up, you can access your Dokploy applications through the Tailscale network: + +1. **Using Tailscale IP**: Access applications directly using your server's Tailscale IP and the port configured in Dokploy +2. **Using Tailscale DNS**: Use your server's Tailscale hostname (e.g., `your-server.tailscale.ts.net`) + +### Example: Accessing an Application + +If you have an application running on port `8080`: + +1. Get your server's Tailscale IP: + ```bash + sudo tailscale ip -4 + ``` + +2. Access your application your application/compose should expose the port: + ``` + http://YOUR_TAILSCALE_IP:8080 + ``` + +You can access from your client device or any device in the Tailscale network. + +## Advanced Configuration + +### Enabling MagicDNS + +MagicDNS provides automatic DNS resolution for devices in your Tailscale network: + +1. Go to [Tailscale Admin Console](https://login.tailscale.com/admin/dns) +2. Enable **MagicDNS** +3. Optionally add custom DNS names for your devices + +With MagicDNS enabled, you can access your server using its hostname. + +For example, to access the Dokploy dashboard (which runs on port 3000): + +``` +http://your-server-name.tailscale.ts.net:3000 +``` + +### Using Custom Domains with MagicDNS + +If you want to use a custom domain for your Dokploy server, you'll need to find the Full Domain assigned by Tailscale: + +1. Go to [Tailscale Admin Console](https://login.tailscale.com/admin/machines/) +2. Navigate to **Machines** and search for your server +3. Scroll down to find the **Full Domain** field +4. The Full Domain will look something like: `ubuntu-2gb-ash-4.tail1ff529.ts.net` + +Once you have the Full Domain, you can use it to access your Dokploy server: + +``` +http://ubuntu-2gb-ash-4.tail1ff529.ts.net:3000 +``` + + + Replace `ubuntu-2gb-ash-4.tail1ff529.ts.net` with your actual server's Full Domain from the Tailscale admin console. + + +## Securing Your Server with UFW + +Once Tailscale is configured, you can further enhance your server's security by using UFW (Uncomplicated Firewall) to block all public internet traffic and only allow connections through Tailscale. This prevents unauthorized access attempts and bot attacks that are common on public-facing servers. + + + **Important**: Before proceeding, ensure you can SSH into your server using the Tailscale IP address (from Step 3.5). If you lock down SSH access and lose Tailscale connectivity, you may need console access to your server to regain access. + + +### Why Use UFW with Tailscale? + +Servers on the public internet are constantly scanned and attacked by bots looking for vulnerabilities. By using UFW to block all public traffic and only allowing Tailscale connections, you: + +- **Eliminate attack surface**: Your server becomes invisible to attackers on the public internet +- **Prevent bot scans**: No more failed login attempts in your logs +- **Maintain easy access**: You can still access everything through your private Tailscale network +- **Keep services private**: Dokploy (port 3000) and Traefik (ports 80/443) are only accessible through Tailscale + +### Step 1: SSH Over Tailscale + +Before locking down public access, verify you can SSH using your Tailscale IP: + +1. Get your server's Tailscale IP: + ```bash + sudo tailscale ip -4 + ``` + +2. Exit your current SSH session and reconnect using the Tailscale IP: + ```bash + exit + ssh @ + ``` + +If you can successfully connect, you're ready to proceed. + +### Step 2: Enable UFW + +UFW comes pre-installed on Ubuntu. Enable it: + +```bash +sudo ufw enable +``` + +### Step 3: Configure Default Rules + +Set UFW to deny all incoming traffic by default, but allow all outgoing traffic: + +```bash +sudo ufw default deny incoming +sudo ufw default allow outgoing +``` + +### Step 4: Allow Tailscale Traffic + +Allow all traffic on the Tailscale interface (`tailscale0`): + +```bash +sudo ufw allow in on tailscale0 +``` + +This ensures all Tailscale connections work properly, including: +- SSH access +- Dokploy dashboard (port 3000) +- Traefik (ports 80/443) +- All your applications + +### Step 5: Review and Remove Public Access Rules + +Check your current firewall rules: + +```bash +sudo ufw status verbose +``` + +You might see rules like: +``` +To Action From +-- ------ ---- +Anywhere on tailscale0 ALLOW Anywhere +Anywhere (v6) on tailscale0 ALLOW Anywhere (v6) +``` + +Since we're using Tailscale for all access, your server is now configured to only accept connections through the Tailscale network. This means: + +- ✅ **SSH access**: Only available via Tailscale IP +- ✅ **Dokploy dashboard**: Only accessible via Tailscale IP +- ✅ **Traefik**: Only accessible via Tailscale IP +- ✅ **All applications**: Only accessible via Tailscale IP + + + **Important Note About Docker and UFW**: Docker directly manipulates `iptables`, which can bypass UFW rules. This means Docker-published ports (like Dokploy on port 3000 or Traefik on ports 80/443) might still be accessible from the public internet even with UFW configured. + + **Solutions:** + + 1. **Use your VPS provider's firewall** (recommended): Configure your cloud provider's firewall to block public access to ports 22, 80, 443, and 3000. This operates before Docker's iptables rules. + + 2. **Use ufw-docker utility**: This tool integrates Docker with UFW properly. However, with Tailscale and subnet routing, this is usually not necessary since all access goes through Tailscale. + + 3. **Bind Docker ports to localhost**: Modify Docker services to bind to `127.0.0.1` instead of `0.0.0.0`, but this may break Tailscale access unless configured carefully. + + For Dokploy with Tailscale, the recommended approach is to use your VPS provider's firewall to block public access, as this provides the most reliable protection. + + +With this configuration, your server is now protected from public internet access. All services (SSH, Dokploy, Traefik, and applications) are only accessible through your private Tailscale network, ensuring they remain secure and invisible to unauthorized users. \ No newline at end of file diff --git a/apps/docs/content/docs/core/manual-installation.mdx b/apps/docs/content/docs/core/manual-installation.mdx index 6279ca0..40266d1 100644 --- a/apps/docs/content/docs/core/manual-installation.mdx +++ b/apps/docs/content/docs/core/manual-installation.mdx @@ -12,6 +12,7 @@ If you wish to customize the Dokploy installation on your server, you can modify 5. **RELEASE_TAG** - Set to a dokploy docker hub tag(latest, canary, feature, etc) 6. **DATABASE_URL** - Set to another database url if you want to use a different database. 7. **REDIS_HOST** - Set to another redis url if you want to use a different redis. +8. **TZ** - Set to another timezone if you want to use a different timezone. ## Installation Script @@ -284,6 +285,16 @@ docker service create \ dokploy/dokploy:latest ``` +## Setup Dokploy Timezone + +To setup the timezone of Dokploy, you can use the following command: + +```bash +docker service update --env-add TZ=America/New_York dokploy +``` + + + ## Manual Upgrade To upgrade Dokploy manually, you can use the following command: @@ -292,3 +303,17 @@ To upgrade Dokploy manually, you can use the following command: curl -sSL https://dokploy.com/install.sh | sh -s update ``` +To use a specific version, you can use the following command: + +```bash +export DOKPLOY_VERSION=canary && curl -sSL https://dokploy.com/install.sh | sh +export DOKPLOY_VERSION=feature && curl -sSL https://dokploy.com/install.sh | sh +curl -sSL https://dokploy.com/install.sh | sh (defaults to latest) +``` + +Alternatively, you can use `bash -s`: + +```bash +DOKPLOY_VERSION=canary bash -s < <(curl -sSL https://dokploy.com/install.sh) +DOKPLOY_VERSION=feature bash -s < <(curl -sSL https://dokploy.com/install.sh) +``` diff --git a/apps/docs/content/docs/core/meta.json b/apps/docs/content/docs/core/meta.json index aca81dd..094e2d1 100644 --- a/apps/docs/content/docs/core/meta.json +++ b/apps/docs/content/docs/core/meta.json @@ -1,7 +1,7 @@ { "title": "Core", - "description": "The core of Dokploy", - "icon": "Building2", + "description": "Essential guides for deploying and managing applications, databases, and server configurations", + "icon": "Package", "root": true, "pages": [ "---Introduction---", @@ -13,7 +13,8 @@ "reset-password", "uninstall", "videos", - "...", + "goodies", + "troubleshooting", "---Cloud---", "cloud", "monitoring", @@ -40,8 +41,18 @@ "volume-backups", "providers", "watch-paths", + "---Remote Servers---", + "remote-servers/index", + "remote-servers/instructions", + "remote-servers/build-server", + "remote-servers/deployments", + "remote-servers/security", + "remote-servers/validate", + "---Guides---", + "guides/cloudflare-tunnels", + "guides/tailscale", + "guides/ec2-instructions", "---Advanced---", - "cluster", - "multi-server" + "cluster" ] } diff --git a/apps/docs/content/docs/core/multi-server/ec2-instructions.mdx b/apps/docs/content/docs/core/multi-server/ec2-instructions.mdx deleted file mode 100644 index e2ee2a6..0000000 --- a/apps/docs/content/docs/core/multi-server/ec2-instructions.mdx +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: EC2 Instructions -description: "Instructions for setting up a multi-server on EC2" ---- - -When using EC2 instances, by default you don't have root access, and Dokploy needs root access to install the necessary packages without restrictions. - -To do this, you need to make manual modifications to the instance: - -1. **Click on launch instance** - -2. **Select the distribution of your choice** (we recommend Ubuntu, Debian or Amazon Linux) - -3. **Choose your instance type** and all the other settings you want - -4. **In the Network settings**, click on: - - `Allow SSH traffic from the internet` - - `Allow HTTPS traffic from the internet` - - `Allow HTTP traffic from the internet` - -5. **Click on `Launch instance`** (If you see a warning about adding a new key pair, just skip it) - -6. **Now go to your instance and click on `Connect`** - -7. **Type this command** `sudo nano /etc/ssh/sshd_config` and find the line `#PermitRootLogin prohibit-password` and change it to `PermitRootLogin yes`. Save and exit. - -8. **Restart the SSH service** by typing this command: - ```bash - sudo systemctl restart sshd - ``` - -9. **Go back to the EC2 instance and click on `Connect`** but instead of using the default username `ec2-user`, type `root` - -10. **Connect using the `root` user** - -11. **Create a server in the Dokploy dashboard** in the remote server section - -12. **Specify the server details**: - - **IP field**: IPv4 public address of the instance - - **Username field**: `root` - - **SSH key**: Select the SSH key you created earlier - - Click on `Create Server` - -13. **Click on action `Setup Server`** in the `SSH Keys` tab, follow the manual process (Copy the Command and paste in the server manually) - -14. **Connect to the server** - you should now be able to setup the server properly and deploy your applications - diff --git a/apps/docs/content/docs/core/multi-server/index.mdx b/apps/docs/content/docs/core/multi-server/index.mdx deleted file mode 100644 index 084abea..0000000 --- a/apps/docs/content/docs/core/multi-server/index.mdx +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: Multi Server -description: "Deploy your apps to multiple servers remotely." ---- - -import { Callout } from "fumadocs-ui/components/callout"; - -Multi server allows you to deploy your apps remotely to different servers without needing to build and run them where the Dokploy UI is installed. - -To use the multi-server feature, you need to have Dokploy UI installed either locally or on a remote server. We recommend using a remote server for better connectivity, security, and isolation, for remote instances we install only a traefik instance. - -If you plan to only deploy apps to remote servers and use Dokploy UI for managing deployments, Dokploy will use around 250 MB of RAM and minimal CPU, so a low-resource server should be sufficient. - -All the features we have documented previously are supported by Dokploy Multi Server. The only feature not supported is remote server monitoring, due to performance reasons. However, all functionalities should work the same as when deploying on the same server where Dokploy UI is installed. - -## Features - -1. **Enter the terminal**: Allows you to access the terminal of the remote server. -2. **Setup Server**: Allows you to configure the remote server. - - **SSH Keys**: Steps to add SSH keys to the remote server. - - **Deployments**: Steps to configure the remote server for deploying applications. -3. **Edit Server**: Allows you to modify the remote server's details, such as SSH key, name, description, IP, etc. -4. **View Actions**: Lets you perform actions like managing the Traefik instance, storage, and activating Docker cleanup. -5. **Show Traefik File System**: Displays the contents of the remote server's directory. -6. **Show Docker Containers**: Shows the Docker containers running on the remote server. -7. **Show Docker Swarm Overview**: Shows the Docker Swarm overview of the remote server. diff --git a/apps/docs/content/docs/core/multi-server/validate.mdx b/apps/docs/content/docs/core/multi-server/validate.mdx deleted file mode 100644 index ab665a3..0000000 --- a/apps/docs/content/docs/core/multi-server/validate.mdx +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: Validate -description: "Validate your remote server deployment" ---- - -Dokploy requires the following 7 components to be properly configured for the multi-server feature: - -1. **Docker Installed**: Docker must be installed on the remote server. -2. **RClone Installed**: RClone must be installed on the remote server. -3. **Nixpacks Installed**: Nixpacks must be installed on the remote server. -4. **Buildpacks Installed**: Buildpacks must be installed on the remote server. -5. **Docker Swarm Initialized**: Docker Swarm must be initialized on the remote server. -6. **Dokploy Network Created**: A Docker network for Dokploy must be created on the remote server. -7. **Main Directory Created**: A directory must be created on the remote server to store applications. - -Once all requirements are met, you will see a green checkmark next to each item in the validation section. - - \ No newline at end of file diff --git a/apps/docs/content/docs/core/remote-servers/build-server.mdx b/apps/docs/content/docs/core/remote-servers/build-server.mdx new file mode 100644 index 0000000..ea21772 --- /dev/null +++ b/apps/docs/content/docs/core/remote-servers/build-server.mdx @@ -0,0 +1,138 @@ +--- +title: Build Server +description: "Learn how to configure a custom build server to compile your applications separately from your deployment servers." +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +Build servers allow you to separate the build process from your deployment servers. This is particularly useful when you want to compile your applications on a dedicated server with more resources, or when you want to keep your deployment servers lightweight. + + + Build servers are currently **only available for Applications**. This feature is not supported for Docker Compose deployments. + + +## Overview + +A **Build Server** is a remote server dedicated to building and compiling your applications. Instead of building your application on the deployment server, Dokploy will: + +1. Connect to the build server +2. Clone your repository and build your application +3. Create a Docker image +4. Push the image to a registry +5. Deploy the image to your deployment server + +This approach offers several benefits: +- **Resource Optimization**: Use powerful build servers without paying for expensive deployment servers +- **Security**: Keep your source code and build process separate from production +- **Flexibility**: Build once, deploy to multiple servers +- **Performance**: Dedicated build resources mean faster builds + +## Prerequisites + +Before setting up a build server, ensure you have: + +1. A Dokploy instance running +2. A remote server for builds (VPS, cloud instance, or dedicated server) +3. SSH access to the build server +4. Docker installed on the build server (or use Dokploy's automatic setup) +5. A Docker registry to store your built images (Docker Hub, GitHub Container Registry, etc.) + + + You can use the same SSH key you created for deploy servers, or create a dedicated one for build servers. + + +## Setting Up a Build Server + +### Step 1: Add a New Server + +Navigate to **Dashboard → Remote Servers → Add Server -> Build Type (Build Server)** in your Dokploy dashboard. + +Fill in the server details: +- **Name**: A descriptive name (e.g., "Build Server - EU") +- **IP Address**: The public IP address of your build server +- **Port**: SSH port (default is 22) +- **Username**: SSH username (usually `root` or your custom user) +- **SSH Key**: Select the SSH key to use for authentication + +### Step 2: Setup the Build Server + +After creating the server, you need to install Docker and configure it: + +1. Click on the server you just created +2. Click on **Setup Server ->** +3. Follow the setup instructions: + - **Automatic Setup**: Copy the command and run it on your server + - **Manual Setup**: Follow the step-by-step instructions if automatic setup fails + + + Make sure your build server has enough disk space for Docker images. Build processes can consume significant storage. To prevent disk space issues, you can: + - Enable **Docker Cleanup** in the server settings to automatically remove unused images + - Create a **Scheduled Job** to periodically clean up Docker images (e.g., `docker image prune -af`) + + +### Step 3: Configure as Build Server + +Once you have access to the server, you need to configure it as a build server: + +1. Go to the **Deployments** tab +2. Click on the **Setup Server** button +3. A modal will appear showing the commands being executed on the server to configure everything necessary +4. Once the setup process finishes, navigate to the **Validate** tab +5. Verify that all status items show as green, indicating the build server is ready + + + The build server setup only installs build dependencies and tools. No Docker containers or active processes are deployed. The following tools are installed: **Nixpacks**, **Docker**, **Railpack**, and **Heroku Buildpacks**. + + +## Using a Build Server + +### Configure an Application to Use a Build Server + +When creating or editing an application: + +1. Go to the **Advanced** tab +2. In the **Build Server** section: + - **Enable Custom Build Server**: Toggle this on + - **Select Build Server**: Choose your build server from the dropdown + +3. **Configure Registry** (required for build servers): + - Go to **Settings → Registries** + - Add a Docker registry (Docker Hub, GHCR, etc.) + - Configure your registry credentials + +4. **Select Registry in Application**: + - In your application's **Advanced** tab + - Under **Cluster Settings** + - Select the registry where built images will be pushed + + + A registry is required when using build servers because the built image needs to be stored somewhere accessible to your deployment servers. + + +### Build Process Flow + +When you deploy an application with a custom build server: + +1. **Build Phase**: + - Dokploy connects to your build server via SSH + - Clones your repository on the build server + - Builds the Docker image on the build server + - Pushes the image to your configured registry + +2. **Deploy Phase**: + - Dokploy connects to your deployment server(s) + - Pulls the built image from the registry + - Deploys the container on your deployment server(s) + + + + + After the build image is pushed to the registry, allow a few moments for your deployment server(s) to pull and cache the image before it becomes available for deployment. + + + +## Docker Registry Configuration + +Build servers require a Docker registry to store built images. For detailed instructions on configuring a registry, see the [Docker Registry](/docs/core/registry) guide. + + diff --git a/apps/docs/content/docs/core/multi-server/deployments.mdx b/apps/docs/content/docs/core/remote-servers/deployments.mdx similarity index 89% rename from apps/docs/content/docs/core/multi-server/deployments.mdx rename to apps/docs/content/docs/core/remote-servers/deployments.mdx index 14d3fac..25fb373 100644 --- a/apps/docs/content/docs/core/multi-server/deployments.mdx +++ b/apps/docs/content/docs/core/remote-servers/deployments.mdx @@ -6,7 +6,7 @@ description: "Configure and set up your remote server deployment" import { ImageZoom } from "fumadocs-ui/components/image-zoom"; import { Callout } from "fumadocs-ui/components/callout"; -To get started with multi-server, you'll need to configure the initial setup for your remote server. +To get started with remote servers, you'll need to configure the initial setup for your remote server. ## Server Setup @@ -22,7 +22,7 @@ The server setup process prepares the necessary environment for securely and eff @@ -36,7 +36,7 @@ Example of the server setup logs: \ No newline at end of file diff --git a/apps/docs/content/docs/core/remote-servers/index.mdx b/apps/docs/content/docs/core/remote-servers/index.mdx new file mode 100644 index 0000000..af01c54 --- /dev/null +++ b/apps/docs/content/docs/core/remote-servers/index.mdx @@ -0,0 +1,60 @@ +--- +title: Introduction +description: "Deploy your apps to multiple servers remotely." +--- + +import { Callout } from "fumadocs-ui/components/callout"; + +Remote servers allows you to deploy your apps remotely to different servers without needing to build and run them where the Dokploy UI is installed. + +To use the remote servers feature, you need to have Dokploy UI installed either locally or on a remote server. We recommend using a remote server for better connectivity, security, and isolation, for remote instances we install only a traefik instance. + +If you plan to only deploy apps to remote servers and use Dokploy UI for managing deployments, Dokploy will use around 250 MB of RAM and minimal CPU, so a low-resource server should be sufficient. + +All the features we have documented previously are supported by Dokploy Remote Servers. The only feature not supported is remote server monitoring, due to performance reasons. However, all functionalities should work the same as when deploying on the same server where Dokploy UI is installed. + +## Server Types + +Dokploy supports two types of remote servers: + +### Deployment Servers + +**Deployment servers** are used to run and host your applications. These servers: +- Run your containerized applications +- Handle traffic routing through Traefik +- Manage application deployments and updates +- Store application data and volumes + +When you deploy an application, it runs on a deployment server. You can have multiple deployment servers to distribute your applications across different locations or for redundancy. + +### Build Servers + +**Build servers** are dedicated servers used to compile and build your applications. These servers: +- Clone your repository +- Build Docker images from your source code +- Push built images to a Docker registry +- Do not run any containers or active processes + +Build servers are particularly useful when you want to: +- Separate the build process from deployment +- Use powerful build resources without paying for expensive deployment servers +- Build once and deploy to multiple servers +- Keep your deployment servers lightweight + + + Build servers are currently **only available for Applications**. This feature is not supported for Docker Compose deployments. + + +You can configure an application to use a build server by selecting it in the application's **Advanced** settings. The built image will be pushed to a Docker registry, and then pulled by your deployment server(s) for deployment. + +## Features + +1. **Enter the terminal**: Allows you to access the terminal of the remote server. +2. **Setup Server**: Allows you to configure the remote server. + - **SSH Keys**: Steps to add SSH keys to the remote server. + - **Deployments**: Steps to configure the remote server for deploying applications. +3. **Edit Server**: Allows you to modify the remote server's details, such as SSH key, name, description, IP, etc. +4. **View Actions**: Lets you perform actions like managing the Traefik instance, storage, and activating Docker cleanup. +5. **Show Traefik File System**: Displays the contents of the remote server's directory. +6. **Show Docker Containers**: Shows the Docker containers running on the remote server. +7. **Show Docker Swarm Overview**: Shows the Docker Swarm overview of the remote server. diff --git a/apps/docs/content/docs/core/multi-server/instructions.mdx b/apps/docs/content/docs/core/remote-servers/instructions.mdx similarity index 94% rename from apps/docs/content/docs/core/multi-server/instructions.mdx rename to apps/docs/content/docs/core/remote-servers/instructions.mdx index f3e1152..ff034c3 100644 --- a/apps/docs/content/docs/core/multi-server/instructions.mdx +++ b/apps/docs/content/docs/core/remote-servers/instructions.mdx @@ -1,11 +1,11 @@ --- -title: Instructions -description: "Example to setup a remote server and deploy application in a VPS." +title: Deploy Server +description: "Step-by-step guide to setup a remote server and deploy applications on a VPS." --- import { Callout } from "fumadocs-ui/components/callout"; -Multi server allows you to deploy your apps remotely to different servers without needing to build and run them where the Dokploy UI is installed. +Remote servers allows you to deploy your apps remotely to different servers without needing to build and run them where the Dokploy UI is installed. ## Requirements diff --git a/apps/docs/content/docs/core/multi-server/security.mdx b/apps/docs/content/docs/core/remote-servers/security.mdx similarity index 100% rename from apps/docs/content/docs/core/multi-server/security.mdx rename to apps/docs/content/docs/core/remote-servers/security.mdx diff --git a/apps/docs/content/docs/core/remote-servers/validate.mdx b/apps/docs/content/docs/core/remote-servers/validate.mdx new file mode 100644 index 0000000..47c7cf2 --- /dev/null +++ b/apps/docs/content/docs/core/remote-servers/validate.mdx @@ -0,0 +1,50 @@ +--- +title: Validate +description: "Validate your remote server deployment" +--- + +import { Callout } from 'fumadocs-ui/components/callout'; + +Dokploy validates different components depending on the type of remote server you're configuring. The validation requirements differ between **Deployment Servers** and **Build Servers**. + +## Deployment Servers + +For **Deployment Servers**, Dokploy requires the following 7 components to be properly configured: + +1. **Docker Installed**: Docker must be installed on the remote server. +2. **RClone Installed**: RClone must be installed on the remote server. +3. **Nixpacks Installed**: Nixpacks must be installed on the remote server. +4. **Railpack Installed**: Railpack must be installed on the remote server. +5. **Buildpacks Installed**: Buildpacks must be installed on the remote server. +6. **Docker Swarm Initialized**: Docker Swarm must be initialized on the remote server. +7. **Dokploy Network Created**: A Docker network for Dokploy must be created on the remote server. +8. **Main Directory Created**: A directory must be created on the remote server to store applications. + + + Deployment servers are used to run and host your applications. They require Docker Swarm and network configuration since they need to run containers and manage deployments. + + +## Build Servers + +For **Build Servers**, Dokploy only validates the following components: + +1. **Docker Installed**: Docker must be installed on the remote server. +2. **RClone Installed**: RClone must be installed on the remote server. +3. **Nixpacks Installed**: Nixpacks must be installed on the remote server. +4. **Railpack Installed**: Railpack must be installed on the remote server. +5. **Buildpacks Installed**: Buildpacks must be installed on the remote server. +6. **Main Directory Created**: A directory must be created on the remote server to store applications. + + + Build servers are dedicated to building and compiling applications. They don't require Docker Swarm or network configuration since they only build images and push them to a registry, without running any containers. + + +## Validation Status + +Once all requirements are met for your server type, you will see a green checkmark next to each item in the validation section. + + \ No newline at end of file diff --git a/apps/docs/content/docs/core/schedule-jobs.mdx b/apps/docs/content/docs/core/schedule-jobs.mdx index 0d42d39..296db61 100644 --- a/apps/docs/content/docs/core/schedule-jobs.mdx +++ b/apps/docs/content/docs/core/schedule-jobs.mdx @@ -12,8 +12,8 @@ Dokploy supports four types of scheduled jobs: 1. **Application Jobs**: Run commands inside specific application containers 2. **Compose Jobs**: Execute commands in Docker Compose services -3. **Server Jobs**: Run scripts on remote servers -4. **Dokploy Server Jobs**: Execute tasks on the Dokploy server itself +3. **Server Jobs**: Run scripts on remote servers (executed on the host) +4. **Dokploy Server Jobs**: Execute tasks at the container level within the Dokploy container. These jobs can interact with commands inside the Dokploy container (e.g., `docker ps`, `docker image prune`), but they are not executed directly on the host system ## Container-based Jobs (Application and Compose) @@ -40,7 +40,27 @@ For docker compose jobs, is required to not change the COMPOSE_PROJECT_NAME envi ## Server-based Jobs (Server and Dokploy Server) -For remote servers and the Dokploy server, you can write bash scripts to perform various tasks. These scripts can use any command or tool available on the target system. +### Server Jobs + +For remote servers, you can write bash scripts to perform various tasks. These scripts are executed directly on the host system and can use any command or tool available on the target server. + +### Dokploy Server Jobs + +Dokploy Server Jobs are executed at the container level within the Dokploy container. This means: + +- Commands run inside the Dokploy container environment +- You can interact with Docker commands (e.g., `docker ps`, `docker image prune`, `docker system prune`) +- Scripts have access to the Docker socket and can manage containers and images +- Jobs do not execute directly on the host system, but within the containerized Dokploy environment + +**Example**: You can create a scheduled job to clean up unused Docker images: + +```bash +#!/bin/bash +docker image prune -af +``` + +This command will run inside the Dokploy container and can interact with Docker to clean up images. Make sure any required dependencies are installed on the target server before using them in your scripts. diff --git a/apps/docs/content/docs/core/volume-backups.mdx b/apps/docs/content/docs/core/volume-backups.mdx index ca14208..36923ad 100644 --- a/apps/docs/content/docs/core/volume-backups.mdx +++ b/apps/docs/content/docs/core/volume-backups.mdx @@ -7,6 +7,10 @@ Volume backups are essential when your service doesn't fit the traditional datab Volume backups allow you to backup [Docker named volumes](https://docs.docker.com/engine/storage/volumes/) to S3 destinations, providing a comprehensive backup solution for any type of data stored in volumes. + +**Important:** Volume Backups only work with Docker named volumes, not with bind mounts (like the `../files` folder). If you're currently using bind mounts and need backup functionality, you'll need to migrate to named volumes. See the [Docker Compose guide](/docs/core/docker-compose#volumes) for a comparison of both methods and guidance on choosing the right approach for your needs. + + ## Supported Services Volume backups are available for: @@ -16,6 +20,8 @@ Volume backups are available for: ## Setting Up Volume Mounts +Volume Backups require Docker named volumes. If you're using bind mounts (like `../files`), you'll need to switch to named volumes to use this feature. + ### For Applications 1. Navigate to your application @@ -24,7 +30,7 @@ Volume backups are available for: ### For Docker Compose -Define volumes directly in your `docker-compose.yml` file: +Define named volumes directly in your `docker-compose.yml` file. **Note:** Bind mounts (e.g., `../files/my-data:/app/data`) cannot be backed up using Volume Backups—you must use named volumes: ```yaml services: @@ -37,6 +43,8 @@ volumes: my-volume: ``` +For more information on choosing between bind mounts and named volumes, see the [Docker Compose volumes section](/docs/core/docker-compose#volumes). + ## Practical Example: N8N Backup Let's walk through a common scenario using N8N, which runs on SQLite and stores data in Docker volumes. diff --git a/apps/docs/content/docs/core/watch-paths.mdx b/apps/docs/content/docs/core/watch-paths.mdx index 39468ac..d3fc5a5 100644 --- a/apps/docs/content/docs/core/watch-paths.mdx +++ b/apps/docs/content/docs/core/watch-paths.mdx @@ -1,7 +1,7 @@ ---- +--- title: Watch Paths description: Learn how to use watch paths in your application or docker compose. ---- +--- Watch paths are a feature that allows you to monitor specific directories or files for changes and automatically trigger actions when modifications occur. diff --git a/apps/docs/generate-docs.mjs b/apps/docs/generate-docs.mjs index ba639a7..fa5f473 100644 --- a/apps/docs/generate-docs.mjs +++ b/apps/docs/generate-docs.mjs @@ -1,18 +1,19 @@ import { generateFiles } from "fumadocs-openapi"; +import { createOpenAPI } from "fumadocs-openapi/server"; + +const openapi = createOpenAPI({ + input: ["./public/openapi.json"], +}); try { - void generateFiles({ - input: ["./public/openapi.json"], - output: "./content/docs/api/generated", + await generateFiles({ + input: openapi, + output: "./content/docs/api", per: "tag", - name: (tag, name) => { - console.log(tag, name); - return `reference-${name}`; - }, + includeDescription: true, }); - console.log("Done"); + console.log("✓ Generated API documentation files"); } catch (error) { - console.error(error); + console.error("Error generating docs:", error.message); + process.exit(1); } - -// united.com/customer-care diff --git a/apps/docs/lib/layout.shared.tsx b/apps/docs/lib/layout.shared.tsx new file mode 100644 index 0000000..2332a3c --- /dev/null +++ b/apps/docs/lib/layout.shared.tsx @@ -0,0 +1,19 @@ +import { Logo } from "@/components/Logo"; +import { NavLinks } from "@/components/NavLinks"; +import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared"; + +export function baseOptions(): BaseLayoutProps { + return { + nav: { + title: ( +
    + + Dokploy +
    + ), + url: "https://dokploy.com", + children: , + }, + githubUrl: "https://github.com/Dokploy/dokploy", + }; +} diff --git a/apps/docs/lib/source.ts b/apps/docs/lib/source.ts index d588396..a5cb8f7 100644 --- a/apps/docs/lib/source.ts +++ b/apps/docs/lib/source.ts @@ -1,17 +1,35 @@ -import { docs, meta } from "@/.source"; -import { loader } from "fumadocs-core/source"; -import { createMDXSource } from "fumadocs-mdx"; +import { docs } from "fumadocs-mdx:collections/server"; +import { type InferPageType, loader } from "fumadocs-core/source"; +import { lucideIconsPlugin } from "fumadocs-core/source/lucide-icons"; import { createOpenAPI } from "fumadocs-openapi/server"; -import { attachFile } from "fumadocs-openapi/server"; +import { createAPIPage } from "fumadocs-openapi/ui"; +// See https://fumadocs.dev/docs/headless/source-api for more info export const source = loader({ - baseUrl: "/docs", - source: createMDXSource(docs, meta), - // pageTree: { - // attachFile, - // }, + baseUrl: "/docs", + source: docs.toFumadocsSource(), + plugins: [lucideIconsPlugin()], }); export const openapi = createOpenAPI({ - // options + input: ["./public/openapi.json"], }); + +export const APIPage = createAPIPage(openapi); + +export function getPageImage(page: InferPageType) { + const segments = [...page.slugs, "image.png"]; + + return { + segments, + url: `/og/docs/${segments.join("/")}`, + }; +} + +export async function getLLMText(page: InferPageType) { + const processed = await page.data.getText("processed"); + + return `# ${page.data.title} + +${processed}`; +} diff --git a/apps/docs/lib/utils.ts b/apps/docs/lib/utils.ts new file mode 100644 index 0000000..ac680b3 --- /dev/null +++ b/apps/docs/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/apps/docs/mdx-components.tsx b/apps/docs/mdx-components.tsx new file mode 100644 index 0000000..ee98bd2 --- /dev/null +++ b/apps/docs/mdx-components.tsx @@ -0,0 +1,23 @@ +import { APIPage } from "@/lib/source"; +import { Callout } from "fumadocs-ui/components/callout"; +import { ImageZoom } from "fumadocs-ui/components/image-zoom"; +import defaultMdxComponents from "fumadocs-ui/mdx"; +import type { MDXComponents } from "mdx/types"; + +export function getMDXComponents(components?: MDXComponents): MDXComponents { + return { + ...defaultMdxComponents, + ImageZoom, + Callout, + APIPage, + ...components, + p: ({ children }) => ( +

    {children}

    + ), + li: ({ children, id }) => ( +
  • + {children} +
  • + ), + }; +} diff --git a/apps/docs/package.json b/apps/docs/package.json index 3c965ef..c9012ca 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -4,34 +4,38 @@ "private": true, "scripts": { "build": "next build", - "dev": "TURBOPACK=1 next dev", + "dev": "next dev --port 3002", "start": "next start", + "types:check": "fumadocs-mdx && tsc --noEmit", "postinstall": "fumadocs-mdx", "fix-openapi": "node scripts/fix-openapi.mjs", - "build:docs": "npm run fix-openapi && node generate-docs.mjs", - "typecheck": "tsc --noEmit" + "build:docs": "npm run fix-openapi && node generate-docs.mjs" }, "dependencies": { + "@next/third-parties": "16.0.7", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "fumadocs-core": "16.2.3", + "fumadocs-mdx": "14.1.0", + "fumadocs-openapi": "10.1.1", + "fumadocs-ui": "16.2.3", + "lucide-react": "^0.552.0", "next": "16.0.7", - "fumadocs-ui": "14.3.1", - "fumadocs-core": "14.3.1", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "fumadocs-mdx": "11.1.1", - "lucide-react": "^0.456.0", - "fumadocs-openapi": "5.5.9", - "shiki": "1.22.2", - "@next/third-parties": "16.0.7" + "react": "^19.2.0", + "react-dom": "^19.2.0", + "shiki": "3.19.0", + "tailwind-merge": "^2.5.4" }, "devDependencies": { - "tsx": "^4.19.2", - "@types/node": "22.9.0", - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "typescript": "^5.6.3", + "@tailwindcss/postcss": "^4.1.16", "@types/mdx": "^2.0.13", - "autoprefixer": "^10.4.20", - "postcss": "^8.4.47", - "tailwindcss": "^3.4.14" + "@types/node": "^24.10.0", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", + "postcss": "^8.5.6", + "tailwindcss": "^4.1.16", + "tw-animate-css": "^1.4.0", + "typescript": "^5.9.3" } } diff --git a/apps/docs/postcss.config.js b/apps/docs/postcss.config.js deleted file mode 100644 index e873f1a..0000000 --- a/apps/docs/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/apps/docs/postcss.config.mjs b/apps/docs/postcss.config.mjs new file mode 100644 index 0000000..017b34b --- /dev/null +++ b/apps/docs/postcss.config.mjs @@ -0,0 +1,5 @@ +export default { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; diff --git a/apps/docs/public/openapi.json b/apps/docs/public/openapi.json index 1bee42e..6649a35 100644 --- a/apps/docs/public/openapi.json +++ b/apps/docs/public/openapi.json @@ -21911,4 +21911,4 @@ "apiKey": [] } ] -} \ No newline at end of file +} diff --git a/apps/docs/scripts/api.yaml b/apps/docs/scripts/api.yaml deleted file mode 100644 index ab0f9ea..0000000 --- a/apps/docs/scripts/api.yaml +++ /dev/null @@ -1,806 +0,0 @@ -openapi: 3.0.3 -info: - title: Swagger Petstore - OpenAPI 3.0 - description: |- - This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about - Swagger at [https://swagger.io](https://swagger.io). In the third iteration of the pet store, we've switched to the design first approach! - You can now help us improve the API whether it's by making changes to the definition itself or to the code. - That way, with time, we can improve the API in general, and expose some of the new features in OAS3. - - _If you're looking for the Swagger 2.0/OAS 2.0 version of Petstore, then click [here](https://editor.swagger.io/?url=https://petstore.swagger.io/v2/swagger.yaml). Alternatively, you can load via the `Edit > Load Petstore OAS 2.0` menu option!_ - - Some useful links: - - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore) - - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml) - termsOfService: http://swagger.io/terms/ - contact: - email: apiteam@swagger.io - license: - name: Apache 2.0 - url: http://www.apache.org/licenses/LICENSE-2.0.html - version: 1.0.11 -externalDocs: - description: Find out more about Swagger - url: http://swagger.io -servers: - - url: https://petstore3.swagger.io/api/v3 -tags: - - name: pet - description: Everything about your Pets - externalDocs: - description: Find out more - url: http://swagger.io - - name: store - description: Access to Petstore orders - externalDocs: - description: Find out more about our store - url: http://swagger.io - - name: user - description: Operations about user -paths: - /pet: - put: - tags: - - pet - summary: Update an existing pet - description: Update an existing pet by Id - operationId: updatePet - requestBody: - description: Update an existent pet in the store - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/Pet' - required: true - responses: - '200': - description: Successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid ID supplied - '404': - description: Pet not found - '422': - description: Validation exception - security: - - petstore_auth: - - write:pets - - read:pets - post: - tags: - - pet - summary: Add a new pet to the store - description: Add a new pet to the store - operationId: addPet - requestBody: - description: Create a new pet in the store - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/Pet' - required: true - responses: - '200': - description: Successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid input - '422': - description: Validation exception - security: - - petstore_auth: - - write:pets - - read:pets - /pet/findByStatus: - get: - tags: - - pet - summary: Finds Pets by status - description: Multiple status values can be provided with comma separated strings - operationId: findPetsByStatus - parameters: - - name: status - in: query - description: Status values that need to be considered for filter - required: false - explode: true - schema: - type: string - default: available - enum: - - available - - pending - - sold - responses: - '200': - description: successful operation - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid status value - security: - - petstore_auth: - - write:pets - - read:pets - /pet/findByTags: - get: - tags: - - pet - summary: Finds Pets by tags - description: Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. - operationId: findPetsByTags - parameters: - - name: tags - in: query - description: Tags to filter by - required: false - explode: true - schema: - type: array - items: - type: string - responses: - '200': - description: successful operation - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid tag value - security: - - petstore_auth: - - write:pets - - read:pets - /pet/{petId}: - get: - tags: - - pet - summary: Find pet by ID - description: Returns a single pet - operationId: getPetById - parameters: - - name: petId - in: path - description: ID of pet to return - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid ID supplied - '404': - description: Pet not found - security: - - api_key: [] - - petstore_auth: - - write:pets - - read:pets - post: - tags: - - pet - summary: Updates a pet in the store with form data - description: '' - operationId: updatePetWithForm - parameters: - - name: petId - in: path - description: ID of pet that needs to be updated - required: true - schema: - type: integer - format: int64 - - name: name - in: query - description: Name of pet that needs to be updated - schema: - type: string - - name: status - in: query - description: Status of pet that needs to be updated - schema: - type: string - responses: - '400': - description: Invalid input - security: - - petstore_auth: - - write:pets - - read:pets - delete: - tags: - - pet - summary: Deletes a pet - description: delete a pet - operationId: deletePet - parameters: - - name: api_key - in: header - description: '' - required: false - schema: - type: string - - name: petId - in: path - description: Pet id to delete - required: true - schema: - type: integer - format: int64 - responses: - '400': - description: Invalid pet value - security: - - petstore_auth: - - write:pets - - read:pets - /pet/{petId}/uploadImage: - post: - tags: - - pet - summary: uploads an image - description: '' - operationId: uploadFile - parameters: - - name: petId - in: path - description: ID of pet to update - required: true - schema: - type: integer - format: int64 - - name: additionalMetadata - in: query - description: Additional Metadata - required: false - schema: - type: string - requestBody: - content: - application/octet-stream: - schema: - type: string - format: binary - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/ApiResponse' - security: - - petstore_auth: - - write:pets - - read:pets - /store/inventory: - get: - tags: - - store - summary: Returns pet inventories by status - description: Returns a map of status codes to quantities - operationId: getInventory - responses: - '200': - description: successful operation - content: - application/json: - schema: - type: object - additionalProperties: - type: integer - format: int32 - security: - - api_key: [] - /store/order: - post: - tags: - - store - summary: Place an order for a pet - description: Place a new order in the store - operationId: placeOrder - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/Order' - application/xml: - schema: - $ref: '#/components/schemas/Order' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/Order' - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Order' - '400': - description: Invalid input - '422': - description: Validation exception - /store/order/{orderId}: - get: - tags: - - store - summary: Find purchase order by ID - description: For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions. - operationId: getOrderById - parameters: - - name: orderId - in: path - description: ID of order that needs to be fetched - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Order' - application/xml: - schema: - $ref: '#/components/schemas/Order' - '400': - description: Invalid ID supplied - '404': - description: Order not found - delete: - tags: - - store - summary: Delete purchase order by ID - description: For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - operationId: deleteOrder - parameters: - - name: orderId - in: path - description: ID of the order that needs to be deleted - required: true - schema: - type: integer - format: int64 - responses: - '400': - description: Invalid ID supplied - '404': - description: Order not found - /user: - post: - tags: - - user - summary: Create user - description: This can only be done by the logged in user. - operationId: createUser - requestBody: - description: Created user object - content: - application/json: - schema: - $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/User' - responses: - default: - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - /user/createWithList: - post: - tags: - - user - summary: Creates list of users with given input array - description: Creates list of users with given input array - operationId: createUsersWithListInput - requestBody: - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/User' - responses: - '200': - description: Successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - default: - description: successful operation - /user/login: - get: - tags: - - user - summary: Logs user into the system - description: '' - operationId: loginUser - parameters: - - name: username - in: query - description: The user name for login - required: false - schema: - type: string - - name: password - in: query - description: The password for login in clear text - required: false - schema: - type: string - responses: - '200': - description: successful operation - headers: - X-Rate-Limit: - description: calls per hour allowed by the user - schema: - type: integer - format: int32 - X-Expires-After: - description: date in UTC when token expires - schema: - type: string - format: date-time - content: - application/xml: - schema: - type: string - application/json: - schema: - type: string - '400': - description: Invalid username/password supplied - /user/logout: - get: - tags: - - user - summary: Logs out current logged in user session - description: '' - operationId: logoutUser - parameters: [] - responses: - default: - description: successful operation - /user/{username}: - get: - tags: - - user - summary: Get user by user name - description: '' - operationId: getUserByName - parameters: - - name: username - in: path - description: 'The name that needs to be fetched. Use user1 for testing. ' - required: true - schema: - type: string - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - '400': - description: Invalid username supplied - '404': - description: User not found - put: - tags: - - user - summary: Update user - description: This can only be done by the logged in user. - operationId: updateUser - parameters: - - name: username - in: path - description: name that need to be deleted - required: true - schema: - type: string - requestBody: - description: Update an existent user in the store - content: - application/json: - schema: - $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/User' - responses: - default: - description: successful operation - delete: - tags: - - user - summary: Delete user - description: This can only be done by the logged in user. - operationId: deleteUser - parameters: - - name: username - in: path - description: The name that needs to be deleted - required: true - schema: - type: string - responses: - '400': - description: Invalid username supplied - '404': - description: User not found -components: - schemas: - Order: - type: object - properties: - id: - type: integer - format: int64 - example: 10 - petId: - type: integer - format: int64 - example: 198772 - quantity: - type: integer - format: int32 - example: 7 - shipDate: - type: string - format: date-time - status: - type: string - description: Order Status - example: approved - enum: - - placed - - approved - - delivered - complete: - type: boolean - xml: - name: order - Customer: - type: object - properties: - id: - type: integer - format: int64 - example: 100000 - username: - type: string - example: fehguy - address: - type: array - xml: - name: addresses - wrapped: true - items: - $ref: '#/components/schemas/Address' - xml: - name: customer - Address: - type: object - properties: - street: - type: string - example: 437 Lytton - city: - type: string - example: Palo Alto - state: - type: string - example: CA - zip: - type: string - example: '94301' - xml: - name: address - Category: - type: object - properties: - id: - type: integer - format: int64 - example: 1 - name: - type: string - example: Dogs - xml: - name: category - User: - type: object - properties: - id: - type: integer - format: int64 - example: 10 - username: - type: string - example: theUser - firstName: - type: string - example: John - lastName: - type: string - example: James - email: - type: string - example: john@email.com - password: - type: string - example: '12345' - phone: - type: string - example: '12345' - userStatus: - type: integer - description: User Status - format: int32 - example: 1 - xml: - name: user - Tag: - type: object - properties: - id: - type: integer - format: int64 - name: - type: string - xml: - name: tag - Pet: - required: - - name - - photoUrls - type: object - properties: - id: - type: integer - format: int64 - example: 10 - name: - type: string - example: doggie - category: - $ref: '#/components/schemas/Category' - photoUrls: - type: array - xml: - wrapped: true - items: - type: string - xml: - name: photoUrl - tags: - type: array - xml: - wrapped: true - items: - $ref: '#/components/schemas/Tag' - status: - type: string - description: pet status in the store - enum: - - available - - pending - - sold - xml: - name: pet - ApiResponse: - type: object - properties: - code: - type: integer - format: int32 - type: - type: string - message: - type: string - xml: - name: '##default' - requestBodies: - Pet: - description: Pet object that needs to be added to the store - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - UserArray: - description: List of user object - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/User' - securitySchemes: - petstore_auth: - type: oauth2 - flows: - implicit: - authorizationUrl: https://petstore3.swagger.io/oauth/authorize - scopes: - write:pets: modify pets in your account - read:pets: read your pets - api_key: - type: apiKey - name: api_key - in: header \ No newline at end of file diff --git a/apps/docs/scripts/fix-openapi.mjs b/apps/docs/scripts/fix-openapi.mjs index 1c0a417..a95b153 100644 --- a/apps/docs/scripts/fix-openapi.mjs +++ b/apps/docs/scripts/fix-openapi.mjs @@ -1,47 +1,83 @@ -import { readFileSync, writeFileSync } from 'fs'; -import { join } from 'path'; +import { readFileSync, writeFileSync } from "fs"; +import { join } from "path"; -const openapiPath = join(process.cwd(), 'public', 'openapi.json'); +const openapiPath = join(process.cwd(), "public", "openapi.json"); -console.log('Fixing OpenAPI schema...'); +console.log("Fixing OpenAPI schema..."); try { - const openapi = JSON.parse(readFileSync(openapiPath, 'utf8')); + const openapi = JSON.parse(readFileSync(openapiPath, "utf8")); let fixed = 0; let securityFixed = false; - - // Fix missing Authorization security scheme + + // Remove Authorization security scheme and add x-api-key if (!openapi.components) { openapi.components = {}; } if (!openapi.components.securitySchemes) { openapi.components.securitySchemes = {}; } - if (!openapi.components.securitySchemes.Authorization) { - openapi.components.securitySchemes.Authorization = { - type: 'apiKey', - in: 'header', - name: 'Authorization', - description: 'API key authentication using Authorization header' - }; + + // Remove old Authorization scheme + if (openapi.components.securitySchemes["Authorization"]) { + delete openapi.components.securitySchemes["Authorization"]; securityFixed = true; } - + + // Add x-api-key scheme + openapi.components.securitySchemes["x-api-key"] = { + type: "apiKey", + in: "header", + name: "x-api-key", + description: "API key authentication. Use YOUR-GENERATED-API-KEY", + "x-default": "your-key", + }; + securityFixed = true; + + // Replace global security from Authorization to x-api-key + if (openapi.security) { + openapi.security = openapi.security.filter((sec) => !sec["Authorization"]); + } else { + openapi.security = []; + } + + const hasApiKeySecurity = openapi.security.some((sec) => sec["x-api-key"]); + if (!hasApiKeySecurity) { + openapi.security.push({ "x-api-key": [] }); + securityFixed = true; + } + + // Replace Authorization with x-api-key in all operation security + for (const [path, pathItem] of Object.entries(openapi.paths || {})) { + for (const [method, operation] of Object.entries(pathItem)) { + if (operation && operation.security) { + // Replace Authorization with x-api-key + operation.security = operation.security.map((sec) => { + if (sec["Authorization"] !== undefined) { + securityFixed = true; + return { "x-api-key": [] }; + } + return sec; + }); + } + } + } + // Fix empty response schemas for (const [path, pathItem] of Object.entries(openapi.paths || {})) { for (const [method, operation] of Object.entries(pathItem)) { if (operation.responses) { for (const [status, response] of Object.entries(operation.responses)) { - if (response.content && response.content['application/json']) { - const content = response.content['application/json']; + if (response.content && response.content["application/json"]) { + const content = response.content["application/json"]; // Check if schema is completely empty or missing if (Object.keys(content).length === 0 || !content.schema) { - response.content['application/json'] = { + response.content["application/json"] = { schema: { - type: 'object', - description: 'Successful response' - } + type: "object", + description: "Successful response", + }, }; fixed++; } @@ -54,12 +90,11 @@ try { if (fixed > 0 || securityFixed) { writeFileSync(openapiPath, JSON.stringify(openapi, null, 2)); if (fixed > 0) console.log(`✓ Fixed ${fixed} empty response schemas`); - if (securityFixed) console.log(`✓ Added missing Authorization security scheme`); + if (securityFixed) console.log("✓ Added x-api-key security scheme"); } else { - console.log('✓ No fixes needed'); + console.log("✓ No fixes needed"); } } catch (error) { - console.error('Error fixing OpenAPI schema:', error.message); + console.error("Error fixing OpenAPI schema:", error.message); process.exit(1); } - diff --git a/apps/docs/scripts/generate-docs.mts b/apps/docs/scripts/generate-docs.mts deleted file mode 100644 index 623a288..0000000 --- a/apps/docs/scripts/generate-docs.mts +++ /dev/null @@ -1,38 +0,0 @@ -import * as path from "node:path"; -import * as OpenAPI from "fumadocs-openapi"; - -export async function generateDocs() { - // await rimraf("./content/docs/api", { - // filter(v) { - // return !v.endsWith("index.mdx") && !v.endsWith("meta.json"); - // }, - // }); - - const demoRegex = - /^---type-table-demo---\r?\n(?.+)\r?\n---end---$/gm; - - await Promise.all([ - OpenAPI.generateFiles({ - input: ["./api.yaml"], - output: "./content/docs/api", - per: "operation", - cwd: path.resolve(process.cwd(), ".."), - name: (type, name) => "index", - }).then(() => { - console.log("OpenAPI done"); - }), - // Typescript.generateFiles({ - // input: ['./content/docs/**/*.model.mdx'], - // transformOutput(_, content) { - // return content.replace(demoRegex, '---type-table---\n$1\n---end---'); - // }, - // output: (file) => - // path.resolve( - // path.dirname(file), - // `${path.basename(file).split('.')[0]}.mdx`, - // ), - // }), - ]); - - console.log("Done"); -} diff --git a/apps/docs/scripts/pre-build.mts b/apps/docs/scripts/pre-build.mts deleted file mode 100644 index 8df2afd..0000000 --- a/apps/docs/scripts/pre-build.mts +++ /dev/null @@ -1,9 +0,0 @@ -import { generateDocs } from "./generate-docs.mjs"; -async function main() { - await Promise.all([generateDocs()]); - console.log("Pre build script completed"); -} - -await main().catch((e) => { - console.error("Failed to run pre build script", e); -}); diff --git a/apps/docs/source.config.ts b/apps/docs/source.config.ts index 443d9d3..a65e66a 100644 --- a/apps/docs/source.config.ts +++ b/apps/docs/source.config.ts @@ -1,7 +1,27 @@ -import { defineConfig, defineDocs } from "fumadocs-mdx/config"; +import { + defineConfig, + defineDocs, + frontmatterSchema, + metaSchema, +} from "fumadocs-mdx/config"; -export const { docs, meta } = defineDocs({ - dir: "content/docs", +// You can customise Zod schemas for frontmatter and `meta.json` here +// see https://fumadocs.dev/docs/mdx/collections +export const docs = defineDocs({ + dir: "content/docs", + docs: { + schema: frontmatterSchema, + postprocess: { + includeProcessedMarkdown: true, + }, + }, + meta: { + schema: metaSchema, + }, }); -export default defineConfig(); +export default defineConfig({ + mdxOptions: { + // MDX options + }, +}); diff --git a/apps/docs/tailwind.config.js b/apps/docs/tailwind.config.js deleted file mode 100644 index 414fa6a..0000000 --- a/apps/docs/tailwind.config.js +++ /dev/null @@ -1,21 +0,0 @@ -import { createPreset } from "fumadocs-ui/tailwind-plugin"; - -/** @type {import('tailwindcss').Config} */ -export default { - content: [ - "./components/**/*.{ts,tsx}", - "./app/**/*.{ts,tsx}", - "./content/**/*.{md,mdx}", - "./mdx-components.{ts,tsx}", - "./node_modules/fumadocs-ui/dist/**/*.js", - "./node_modules/fumadocs-openapi/dist/**/*.js", - ], - darkMode: "class", - presets: [ - createPreset({ - // preset: 'neutral', - layoutWidth: 1400, - addGlobalColors: true, - }), - ], -}; diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json index 412bf5a..488f9a0 100644 --- a/apps/docs/tsconfig.json +++ b/apps/docs/tsconfig.json @@ -13,10 +13,11 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "paths": { - "@/*": ["./*"] + "@/*": ["./*"], + "fumadocs-mdx:collections/*": [".source/*"] }, "plugins": [ { @@ -24,6 +25,12 @@ } ] }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], "exclude": ["node_modules"] } diff --git a/apps/docs/utils/metadata.ts b/apps/docs/utils/metadata.ts deleted file mode 100644 index 8bc700d..0000000 --- a/apps/docs/utils/metadata.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { Metadata } from "next"; - -export const baseUrl = - process.env.NODE_ENV === "development" - ? "http://localhost:3000" - : "https://docs.dokploy.com"; - -export const url = (path: string): string => new URL(path, baseUrl).toString(); - -export function createMetadata(override: Metadata): Metadata { - return { - ...override, - openGraph: { - title: override.title ?? undefined, - description: override.description ?? undefined, - url: "https://fumadocs.vercel.app", - images: "/og.png", - siteName: "Fumadocs", - ...override.openGraph, - }, - twitter: { - card: "summary_large_image", - creator: "@money_is_shark", - title: override.title ?? undefined, - description: override.description ?? undefined, - images: "/banner.png", - ...override.twitter, - }, - }; -} diff --git a/apps/website/app/api/contact/route.ts b/apps/website/app/api/contact/route.ts index 1322171..a489115 100644 --- a/apps/website/app/api/contact/route.ts +++ b/apps/website/app/api/contact/route.ts @@ -1,31 +1,31 @@ -import type { NextRequest } from 'next/server' -import { NextResponse } from 'next/server' -import { Resend } from 'resend' -import { submitToHubSpot, getHubSpotUTK } from '@/lib/hubspot' +import { getHubSpotUTK, submitToHubSpot } from "@/lib/hubspot"; +import type { NextRequest } from "next/server"; +import { NextResponse } from "next/server"; +import { Resend } from "resend"; interface ContactFormData { - inquiryType: 'support' | 'sales' | 'other' - firstName: string - lastName: string - email: string - company: string - message: string + inquiryType: "support" | "sales" | "other"; + firstName: string; + lastName: string; + email: string; + company: string; + message: string; } export async function POST(request: NextRequest) { try { // Initialize Resend with API key check - const apiKey = process.env.RESEND_API_KEY + const apiKey = process.env.RESEND_API_KEY; if (!apiKey) { - console.error('RESEND_API_KEY is not configured') + console.error("RESEND_API_KEY is not configured"); return NextResponse.json( - { error: 'Email service not configured' }, + { error: "Email service not configured" }, { status: 500 }, - ) + ); } - const resend = new Resend(apiKey) - const body: ContactFormData = await request.json() + const resend = new Resend(apiKey); + const body: ContactFormData = await request.json(); // Validate required fields if ( @@ -37,45 +37,41 @@ export async function POST(request: NextRequest) { !body.message ) { return NextResponse.json( - { error: 'All fields are required' }, + { error: "All fields are required" }, { status: 400 }, - ) + ); } // Validate email format - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(body.email)) { return NextResponse.json( - { error: 'Invalid email format' }, + { error: "Invalid email format" }, { status: 400 }, - ) + ); } // Submit to HubSpot if it's a sales inquiry - if (body.inquiryType === 'sales') { + if (body.inquiryType === "sales") { try { - const hutk = getHubSpotUTK( - request.headers.get('cookie') || undefined, - ) - const hubspotSuccess = await submitToHubSpot(body, hutk) + const hutk = getHubSpotUTK(request.headers.get("cookie") || undefined); + const hubspotSuccess = await submitToHubSpot(body, hutk); if (hubspotSuccess) { - console.log( - 'Successfully submitted sales inquiry to HubSpot', - ) + console.log("Successfully submitted sales inquiry to HubSpot"); } else { console.warn( - 'Failed to submit sales inquiry to HubSpot, but continuing with email', - ) + "Failed to submit sales inquiry to HubSpot, but continuing with email", + ); } } catch (error) { - console.error('Error submitting to HubSpot:', error) + console.error("Error submitting to HubSpot:", error); // Continue with email even if HubSpot fails } } // Format email content - const emailSubject = `[${body.inquiryType.toUpperCase()}] New contact form submission from ${body.firstName} ${body.lastName}` + const emailSubject = `[${body.inquiryType.toUpperCase()}] New contact form submission from ${body.firstName} ${body.lastName}`; const emailBody = ` New contact form submission: @@ -90,23 +86,23 @@ ${body.message} --- Sent from Dokploy website contact form - `.trim() + `.trim(); // Send email to Dokploy team await resend.emails.send({ - from: 'Dokploy Contact Form ', + from: "Dokploy Contact Form ", to: - body.inquiryType === 'sales' - ? ['sales@dokploy.com', 'contact@dokploy.com'] - : ['contact@dokploy.com'], + body.inquiryType === "sales" + ? ["sales@dokploy.com", "contact@dokploy.com"] + : ["contact@dokploy.com"], subject: emailSubject, text: emailBody, replyTo: body.email, - }) + }); // Send confirmation email to the user const confirmationSubject = - 'Thank you for contacting Dokploy - We received your message' + "Thank you for contacting Dokploy - We received your message"; const confirmationBody = ` Hello ${body.firstName} ${body.lastName}, @@ -126,24 +122,24 @@ The Dokploy Team --- This is an automated confirmation email. Please do not reply to this email. If you need immediate assistance, contact us at contact@dokploy.com - `.trim() + `.trim(); await resend.emails.send({ - from: 'Dokploy Team ', + from: "Dokploy Team ", to: [body.email], subject: confirmationSubject, text: confirmationBody, - }) + }); return NextResponse.json( - { message: 'Contact form submitted successfully' }, + { message: "Contact form submitted successfully" }, { status: 200 }, - ) + ); } catch (error) { - console.error('Error processing contact form:', error) + console.error("Error processing contact form:", error); return NextResponse.json( - { error: 'Internal server error' }, + { error: "Internal server error" }, { status: 500 }, - ) + ); } } diff --git a/apps/website/app/api/github-stars/route.ts b/apps/website/app/api/github-stars/route.ts index 9426ff5..13c8afe 100644 --- a/apps/website/app/api/github-stars/route.ts +++ b/apps/website/app/api/github-stars/route.ts @@ -1,19 +1,19 @@ -import { NextResponse } from 'next/server' +import { NextResponse } from "next/server"; // Cache the result for 5 minutes to avoid rate limiting -let cachedStars: { count: number; timestamp: number } | null = null -const CACHE_DURATION = 5 * 60 * 1000 // 5 minutes in milliseconds +let cachedStars: { count: number; timestamp: number } | null = null; +const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes in milliseconds export async function GET(request: Request) { - const { searchParams } = new URL(request.url) - const owner = searchParams.get('owner') - const repo = searchParams.get('repo') + const { searchParams } = new URL(request.url); + const owner = searchParams.get("owner"); + const repo = searchParams.get("repo"); if (!owner || !repo) { return NextResponse.json( - { error: 'Owner and repo parameters are required' }, + { error: "Owner and repo parameters are required" }, { status: 400 }, - ) + ); } // Check if we have a valid cached result @@ -22,11 +22,10 @@ export async function GET(request: Request) { { stargazers_count: cachedStars.count }, { headers: { - 'Cache-Control': - 'public, s-maxage=300, stale-while-revalidate=600', + "Cache-Control": "public, s-maxage=300, stale-while-revalidate=600", }, }, - ) + ); } try { @@ -34,42 +33,41 @@ export async function GET(request: Request) { `https://api.github.com/repos/${owner}/${repo}`, { headers: { - Accept: 'application/vnd.github.v3+json', - 'User-Agent': 'Dokploy-Website', + Accept: "application/vnd.github.v3+json", + "User-Agent": "Dokploy-Website", }, }, - ) + ); if (!response.ok) { return NextResponse.json( - { error: 'Failed to fetch repository data' }, + { error: "Failed to fetch repository data" }, { status: response.status }, - ) + ); } - const data = await response.json() - const starCount = data.stargazers_count + const data = await response.json(); + const starCount = data.stargazers_count; // Cache the result cachedStars = { count: starCount, timestamp: Date.now(), - } + }; return NextResponse.json( { stargazers_count: starCount }, { headers: { - 'Cache-Control': - 'public, s-maxage=300, stale-while-revalidate=600', + "Cache-Control": "public, s-maxage=300, stale-while-revalidate=600", }, }, - ) + ); } catch (error) { - console.error('Error fetching GitHub stars:', error) + console.error("Error fetching GitHub stars:", error); return NextResponse.json( - { error: 'Internal server error' }, + { error: "Internal server error" }, { status: 500 }, - ) + ); } } diff --git a/apps/website/app/api/og/route.ts b/apps/website/app/api/og/route.ts index 2bbbddd..a232e71 100644 --- a/apps/website/app/api/og/route.ts +++ b/apps/website/app/api/og/route.ts @@ -1,34 +1,34 @@ -import { getPost } from '@/lib/ghost' -import { generateOGImage } from '@/lib/og-image' -import type { NextRequest } from 'next/server' +import { getPost } from "@/lib/ghost"; +import { generateOGImage } from "@/lib/og-image"; +import type { NextRequest } from "next/server"; export async function GET(request: NextRequest) { try { - const { searchParams } = new URL(request.url) - const slug = searchParams.get('slug') + const { searchParams } = new URL(request.url); + const slug = searchParams.get("slug"); - console.log('Generating OG image for slug:', slug) + console.log("Generating OG image for slug:", slug); if (!slug) { - console.error('Missing slug parameter') - return new Response('Missing slug parameter', { status: 400 }) + console.error("Missing slug parameter"); + return new Response("Missing slug parameter", { status: 400 }); } - const post = await getPost(slug) + const post = await getPost(slug); if (!post) { - console.error('Post not found for slug:', slug) - return new Response('Post not found', { status: 404 }) + console.error("Post not found for slug:", slug); + return new Response("Post not found", { status: 404 }); } const formattedDate = new Date(post.published_at).toLocaleDateString( - 'en-US', + "en-US", { - year: 'numeric', - month: 'long', - day: 'numeric', + year: "numeric", + month: "long", + day: "numeric", }, - ) + ); const ogImage = await generateOGImage({ title: post.title, @@ -40,16 +40,16 @@ export async function GET(request: NextRequest) { : undefined, date: formattedDate, readingTime: post.reading_time, - }) + }); return new Response(ogImage, { headers: { - 'Content-Type': 'image/png', - 'Cache-Control': 'public, max-age=31536000, immutable', + "Content-Type": "image/png", + "Cache-Control": "public, max-age=31536000, immutable", }, - }) + }); } catch (error) { - console.error('Error generating OG image:', error) - return new Response(`Error generating image: ${error}`, { status: 500 }) + console.error("Error generating OG image:", error); + return new Response(`Error generating image: ${error}`, { status: 500 }); } } diff --git a/apps/website/app/blog/[slug]/components/CodeBlock.tsx b/apps/website/app/blog/[slug]/components/CodeBlock.tsx index ac8ea91..f426044 100644 --- a/apps/website/app/blog/[slug]/components/CodeBlock.tsx +++ b/apps/website/app/blog/[slug]/components/CodeBlock.tsx @@ -1,39 +1,39 @@ -'use client' +"use client"; -import { CopyButton } from '@/components/ui/copy-button' -import * as babel from 'prettier/plugins/babel' -import * as estree from 'prettier/plugins/estree' -import * as yaml from 'prettier/plugins/yaml' -import * as prettier from 'prettier/standalone' -import { type JSX, useLayoutEffect, useState } from 'react' -import type { BundledLanguage } from 'shiki/bundle/web' -import { highlight } from './shared' +import { CopyButton } from "@/components/ui/copy-button"; +import * as babel from "prettier/plugins/babel"; +import * as estree from "prettier/plugins/estree"; +import * as yaml from "prettier/plugins/yaml"; +import * as prettier from "prettier/standalone"; +import { type JSX, useLayoutEffect, useState } from "react"; +import type { BundledLanguage } from "shiki/bundle/web"; +import { highlight } from "./shared"; interface CodeBlockProps { - code: string - lang: BundledLanguage - initial?: JSX.Element + code: string; + lang: BundledLanguage; + initial?: JSX.Element; } async function formatCode(code: string, lang: string) { try { - let parser: string - let plugins = [] as any[] + let parser: string; + let plugins = [] as any[]; switch (lang.toLowerCase()) { - case 'yaml': - case 'yml': - parser = 'yaml' - plugins = [yaml] - break - case 'javascript': - case 'typescript': - case 'jsx': - case 'tsx': - parser = 'babel-ts' - plugins = [babel, estree] - break + case "yaml": + case "yml": + parser = "yaml"; + plugins = [yaml]; + break; + case "javascript": + case "typescript": + case "jsx": + case "tsx": + parser = "babel-ts"; + plugins = [babel, estree]; + break; default: - return code + return code; } const formatted = await prettier.format(code, { parser, @@ -43,32 +43,32 @@ async function formatCode(code: string, lang: string) { tabWidth: 2, useTabs: false, printWidth: 120, - }) - return formatted + }); + return formatted; } catch (error) { - console.error('Error formatting code:', error) - return code + console.error("Error formatting code:", error); + return code; } } export function CodeBlock({ code, lang, initial }: CodeBlockProps) { - const [nodes, setNodes] = useState(initial) - const [formattedCode, setFormattedCode] = useState(code) + const [nodes, setNodes] = useState(initial); + const [formattedCode, setFormattedCode] = useState(code); useLayoutEffect(() => { async function formatAndHighlight() { try { - const formatted = await formatCode(code, lang) - setFormattedCode(formatted) - const highlighted = await highlight(formatted, lang) - setNodes(highlighted) + const formatted = await formatCode(code, lang); + setFormattedCode(formatted); + const highlighted = await highlight(formatted, lang); + setNodes(highlighted); } catch (error) { - const highlighted = await highlight(code, lang) - setNodes(highlighted) + const highlighted = await highlight(code, lang); + setNodes(highlighted); } } - void formatAndHighlight() - }, [code, lang]) + void formatAndHighlight(); + }, [code, lang]); if (!nodes) { return ( @@ -78,7 +78,7 @@ export function CodeBlock({ code, lang, initial }: CodeBlockProps) {
    - ) + ); } return ( @@ -88,5 +88,5 @@ export function CodeBlock({ code, lang, initial }: CodeBlockProps) { {nodes} - ) + ); } diff --git a/apps/website/app/blog/[slug]/components/Headings.tsx b/apps/website/app/blog/[slug]/components/Headings.tsx index 7385214..5ce0421 100644 --- a/apps/website/app/blog/[slug]/components/Headings.tsx +++ b/apps/website/app/blog/[slug]/components/Headings.tsx @@ -1,13 +1,13 @@ -'use client' +"use client"; -import { useRouter } from 'next/navigation' -import type { DetailedHTMLProps, HTMLAttributes } from 'react' -import slugify from 'slugify' +import { useRouter } from "next/navigation"; +import type { DetailedHTMLProps, HTMLAttributes } from "react"; +import slugify from "slugify"; type HeadingProps = DetailedHTMLProps< HTMLAttributes, HTMLHeadingElement -> +>; function LinkIcon() { return ( @@ -24,18 +24,18 @@ function LinkIcon() { d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" /> - ) + ); } export function H1({ children, ...props }: HeadingProps) { - const router = useRouter() - const id = slugify(children?.toString() || '', { + const router = useRouter(); + const id = slugify(children?.toString() || "", { lower: true, strict: true, - }) + }); const handleClick = () => { - router.push(`#${id}`) - } + router.push(`#${id}`); + }; return (

    - ) + ); } export function H2({ children, ...props }: HeadingProps) { - const router = useRouter() - const id = slugify(children?.toString() || '', { + const router = useRouter(); + const id = slugify(children?.toString() || "", { lower: true, strict: true, - }) + }); const handleClick = () => { - router.push(`#${id}`) - } + router.push(`#${id}`); + }; return (

    - ) + ); } export function H3({ children, ...props }: HeadingProps) { - const router = useRouter() - const id = slugify(children?.toString() || '', { + const router = useRouter(); + const id = slugify(children?.toString() || "", { lower: true, strict: true, - }) + }); const handleClick = () => { - router.push(`#${id}`) - } + router.push(`#${id}`); + }; return (

    - ) + ); } diff --git a/apps/website/app/blog/[slug]/components/TableOfContents.tsx b/apps/website/app/blog/[slug]/components/TableOfContents.tsx index 099d3db..9c72f44 100644 --- a/apps/website/app/blog/[slug]/components/TableOfContents.tsx +++ b/apps/website/app/blog/[slug]/components/TableOfContents.tsx @@ -1,45 +1,45 @@ -'use client' +"use client"; -import { useEffect, useState } from 'react' +import { useEffect, useState } from "react"; interface Heading { - id: string - text: string - level: number + id: string; + text: string; + level: number; } export function TableOfContents() { - const [headings, setHeadings] = useState([]) - const [activeId, setActiveId] = useState() + const [headings, setHeadings] = useState([]); + const [activeId, setActiveId] = useState(); useEffect(() => { - const elements = Array.from(document.querySelectorAll('h1, h2, h3')) + const elements = Array.from(document.querySelectorAll("h1, h2, h3")) .filter((element) => element.id) .map((element) => ({ id: element.id, - text: element.textContent || '', + text: element.textContent || "", level: Number(element.tagName.charAt(1)), - })) - setHeadings(elements) + })); + setHeadings(elements); const observer = new IntersectionObserver( (entries) => { for (const entry of entries) { if (entry.isIntersecting) { - setActiveId(entry.target.id) + setActiveId(entry.target.id); } } }, - { rootMargin: '-100px 0px -66%' }, - ) + { rootMargin: "-100px 0px -66%" }, + ); for (const { id } of elements) { - const element = document.getElementById(id) - if (element) observer.observe(element) + const element = document.getElementById(id); + if (element) observer.observe(element); } - return () => observer.disconnect() - }, []) + return () => observer.disconnect(); + }, []); return ( - ) + ); } diff --git a/apps/website/app/blog/[slug]/components/ZoomableImage.tsx b/apps/website/app/blog/[slug]/components/ZoomableImage.tsx index cbcc66e..7b97960 100644 --- a/apps/website/app/blog/[slug]/components/ZoomableImage.tsx +++ b/apps/website/app/blog/[slug]/components/ZoomableImage.tsx @@ -1,25 +1,21 @@ -'use client' +"use client"; -import { cn } from '@/lib/utils' -import { PhotoProvider, PhotoView } from 'react-photo-view' -import 'react-photo-view/dist/react-photo-view.css' +import { cn } from "@/lib/utils"; +import { PhotoProvider, PhotoView } from "react-photo-view"; +import "react-photo-view/dist/react-photo-view.css"; interface ZoomableImageProps { - src: string - alt: string - className?: string + src: string; + alt: string; + className?: string; } export function ZoomableImage({ src, alt, className }: ZoomableImageProps) { return ( - {alt} + {alt} - ) + ); } diff --git a/apps/website/app/blog/[slug]/components/shared.ts b/apps/website/app/blog/[slug]/components/shared.ts index a2daa08..4e6096b 100644 --- a/apps/website/app/blog/[slug]/components/shared.ts +++ b/apps/website/app/blog/[slug]/components/shared.ts @@ -1,14 +1,14 @@ -import { toJsxRuntime } from 'hast-util-to-jsx-runtime' -import type { JSX } from 'react' -import { Fragment } from 'react' -import { jsx, jsxs } from 'react/jsx-runtime' -import type { BundledLanguage } from 'shiki/bundle/web' -import { codeToHast } from 'shiki/bundle/web' +import { toJsxRuntime } from "hast-util-to-jsx-runtime"; +import type { JSX } from "react"; +import { Fragment } from "react"; +import { jsx, jsxs } from "react/jsx-runtime"; +import type { BundledLanguage } from "shiki/bundle/web"; +import { codeToHast } from "shiki/bundle/web"; export async function highlight(code: string, lang: BundledLanguage) { const out = await codeToHast(code, { lang, - theme: 'houston', - }) - return toJsxRuntime(out, { Fragment, jsx, jsxs }) as JSX.Element + theme: "houston", + }); + return toJsxRuntime(out, { Fragment, jsx, jsxs }) as JSX.Element; } diff --git a/apps/website/app/blog/[slug]/page.tsx b/apps/website/app/blog/[slug]/page.tsx index 4bad59b..4604ff7 100644 --- a/apps/website/app/blog/[slug]/page.tsx +++ b/apps/website/app/blog/[slug]/page.tsx @@ -1,47 +1,47 @@ -import { getPost, getPosts } from '@/lib/ghost' -import type { Metadata, ResolvingMetadata } from 'next' -import Image from 'next/image' -import Link from 'next/link' -import { notFound } from 'next/navigation' -import type React from 'react' -import ReactMarkdown from 'react-markdown' -import type { Components } from 'react-markdown' -import rehypeRaw from 'rehype-raw' -import remarkGfm from 'remark-gfm' -import remarkToc from 'remark-toc' -import type { BundledLanguage } from 'shiki/bundle/web' -import TurndownService from 'turndown' +import { getPost, getPosts } from "@/lib/ghost"; +import type { Metadata, ResolvingMetadata } from "next"; +import Image from "next/image"; +import Link from "next/link"; +import { notFound } from "next/navigation"; +import type React from "react"; +import ReactMarkdown from "react-markdown"; +import type { Components } from "react-markdown"; +import rehypeRaw from "rehype-raw"; +import remarkGfm from "remark-gfm"; +import remarkToc from "remark-toc"; +import type { BundledLanguage } from "shiki/bundle/web"; +import TurndownService from "turndown"; // @ts-ignore -import * as turndownPluginGfm from 'turndown-plugin-gfm' -import { CodeBlock } from './components/CodeBlock' -import { H1, H2, H3 } from './components/Headings' -import { TableOfContents } from './components/TableOfContents' -import { ZoomableImage } from './components/ZoomableImage' +import * as turndownPluginGfm from "turndown-plugin-gfm"; +import { CodeBlock } from "./components/CodeBlock"; +import { H1, H2, H3 } from "./components/Headings"; +import { TableOfContents } from "./components/TableOfContents"; +import { ZoomableImage } from "./components/ZoomableImage"; type Props = { - params: { slug: string } -} + params: { slug: string }; +}; export async function generateMetadata( { params }: Props, parent: ResolvingMetadata, ): Promise { - const { slug } = await params - const post = await getPost(slug) + const { slug } = await params; + const post = await getPost(slug); if (!post) { return { - title: 'Post Not Found', - } + title: "Post Not Found", + }; } const ogUrl = new URL( - `/api/og`, - process.env.NODE_ENV === 'production' - ? 'https://dokploy.com' - : 'http://localhost:3000', - ) - ogUrl.searchParams.set('slug', slug) + "/api/og", + process.env.NODE_ENV === "production" + ? "https://dokploy.com" + : "http://localhost:3000", + ); + ogUrl.searchParams.set("slug", slug); return { title: post.title, @@ -49,7 +49,7 @@ export async function generateMetadata( openGraph: { title: post.title, description: post.custom_excerpt || post.excerpt, - type: 'article', + type: "article", url: `${process.env.NEXT_PUBLIC_APP_URL}/blog/${post.slug}`, images: [ { @@ -61,66 +61,66 @@ export async function generateMetadata( ], }, twitter: { - card: 'summary_large_image', + card: "summary_large_image", title: post.title, description: post.custom_excerpt || post.excerpt, images: [ogUrl.toString()], }, - } + }; } export default async function BlogPostPage({ params }: Props) { - const { slug } = await params - const post = await getPost(slug) - const allPosts = await getPosts() + const { slug } = await params; + const post = await getPost(slug); + const allPosts = await getPosts(); - const relatedPosts = allPosts.filter((p) => p.id !== post?.id).slice(0, 3) + const relatedPosts = allPosts.filter((p) => p.id !== post?.id).slice(0, 3); if (!post) { - notFound() + notFound(); } const cleanHtml = (html: string) => { - if (typeof window !== 'undefined') { - const parser = new DOMParser() - const doc = parser.parseFromString(html, 'text/html') + if (typeof window !== "undefined") { + const parser = new DOMParser(); + const doc = parser.parseFromString(html, "text/html"); const scripts = doc.querySelectorAll( 'script[type="application/ld+json"], script', - ) - scripts.forEach((script) => script.remove()) - const unwantedElements = doc.querySelectorAll('style, meta, link') - unwantedElements.forEach((el) => el.remove()) - return doc.body.innerHTML + ); + scripts.forEach((script) => script.remove()); + const unwantedElements = doc.querySelectorAll("style, meta, link"); + unwantedElements.forEach((el) => el.remove()); + return doc.body.innerHTML; } else { return html .replace( /]*type="application\/ld\+json"[^>]*>[\s\S]*?<\/script>/gi, - '', + "", ) - .replace(/]*>[\s\S]*?<\/script>/gi, '') - .replace(/]*>[\s\S]*?<\/style>/gi, '') - .replace(/]*>/gi, '') - .replace(/]*>/gi, '') + .replace(/]*>[\s\S]*?<\/script>/gi, "") + .replace(/]*>[\s\S]*?<\/style>/gi, "") + .replace(/]*>/gi, "") + .replace(/]*>/gi, ""); } - } + }; const turndownService = new TurndownService({ - headingStyle: 'atx', - codeBlockStyle: 'fenced', - }) - const gfm = turndownPluginGfm.gfm - const tables = turndownPluginGfm.tables - const strikethrough = turndownPluginGfm.strikethrough - turndownService.use([tables, strikethrough, gfm, remarkToc]) + headingStyle: "atx", + codeBlockStyle: "fenced", + }); + const gfm = turndownPluginGfm.gfm; + const tables = turndownPluginGfm.tables; + const strikethrough = turndownPluginGfm.strikethrough; + turndownService.use([tables, strikethrough, gfm, remarkToc]); - const cleanedHtml = cleanHtml(post.html) - const markdown = turndownService.turndown(cleanedHtml) + const cleanedHtml = cleanHtml(post.html); + const markdown = turndownService.turndown(cleanedHtml); - const formattedDate = new Date(post.published_at).toLocaleDateString('en', { - year: 'numeric', - month: 'long', - day: 'numeric', - }) + const formattedDate = new Date(post.published_at).toLocaleDateString("en", { + year: "numeric", + month: "long", + day: "numeric", + }); const components: Partial = { h1: H1, @@ -186,8 +186,8 @@ export default async function BlogPostPage({ params }: Props) { ), img: ({ node, src, alt }) => ( ), @@ -196,26 +196,26 @@ export default async function BlogPostPage({ params }: Props) { children, inline, }: { - className: string - children: React.ReactNode - inline: boolean + className: string; + children: React.ReactNode; + inline: boolean; }) => { if (inline || !className || !/language-(\w+)/.test(className)) { return ( {children} - ) + ); } - const match = /language-(\w+)/.exec(className) + const match = /language-(\w+)/.exec(className); return ( - ) + ); }, - } + }; return (
    @@ -255,20 +255,14 @@ export default async function BlogPostPage({ params }: Props) { className="block cursor-pointer transition-opacity hover:opacity-90" > {post.primary_author.name} ) : ( {post.primary_author.name} @@ -284,17 +278,14 @@ export default async function BlogPostPage({ params }: Props) { rel="noopener noreferrer" className="transition-colors hover:text-primary" > - {post.primary_author.name || - 'Unknown Author'} + {post.primary_author.name || "Unknown Author"} ) : ( - post.primary_author?.name || - 'Unknown Author' + post.primary_author?.name || "Unknown Author" )}

    - {formattedDate} • {post.reading_time} min - read + {formattedDate} • {post.reading_time} min read

    @@ -354,11 +345,11 @@ export default async function BlogPostPage({ params }: Props) { {relatedPosts.map((relatedPost) => { const relatedPostDate = new Date( relatedPost.published_at, - ).toLocaleDateString('en', { - year: 'numeric', - month: 'long', - day: 'numeric', - }) + ).toLocaleDateString("en", { + year: "numeric", + month: "long", + day: "numeric", + }); return ( {relatedPost.title} @@ -384,9 +372,7 @@ export default async function BlogPostPage({ params }: Props) { {relatedPost.title}

    - {relatedPostDate} •{' '} - {relatedPost.reading_time} min - read + {relatedPostDate} • {relatedPost.reading_time} min read

    {relatedPost.excerpt} @@ -394,11 +380,11 @@ export default async function BlogPostPage({ params }: Props) { - ) + ); })} )}

    - ) + ); } diff --git a/apps/website/app/blog/components/BlogPostCard.tsx b/apps/website/app/blog/components/BlogPostCard.tsx index a67968f..64e36d4 100644 --- a/apps/website/app/blog/components/BlogPostCard.tsx +++ b/apps/website/app/blog/components/BlogPostCard.tsx @@ -1,28 +1,28 @@ -'use client' +"use client"; -import type { Post } from '@/lib/ghost' -import Link from 'next/link' -import { useRouter } from 'next/navigation' +import type { Post } from "@/lib/ghost"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; interface BlogPostCardProps { - post: Post + post: Post; } export function BlogPostCard({ post }: BlogPostCardProps) { - const router = useRouter() - const formattedDate = new Date(post.published_at).toLocaleDateString('en', { - year: 'numeric', - month: 'long', - day: 'numeric', - }) + const router = useRouter(); + const formattedDate = new Date(post.published_at).toLocaleDateString("en", { + year: "numeric", + month: "long", + day: "numeric", + }); const handleTwitterClick = (e: React.MouseEvent) => { if (post.primary_author?.twitter) { - router.push(`https://twitter.com/${post.primary_author.twitter}`) + router.push(`https://twitter.com/${post.primary_author.twitter}`); } - e.preventDefault() - e.stopPropagation() - } + e.preventDefault(); + e.stopPropagation(); + }; return (
    {post.feature_image
    @@ -55,20 +55,14 @@ export function BlogPostCard({ post }: BlogPostCardProps) { type="button" > {post.primary_author.name} ) : ( {post.primary_author.name} @@ -81,18 +75,14 @@ export function BlogPostCard({ post }: BlogPostCardProps) { onClick={handleTwitterClick} type="button" > - {post.primary_author.name || - 'Unknown Author'} + {post.primary_author.name || "Unknown Author"} ) : ( - - {post.primary_author?.name || - 'Unknown Author'} - + {post.primary_author?.name || "Unknown Author"} )} in - {post.primary_tag?.name || 'General'} + {post.primary_tag?.name || "General"} {post.reading_time} min read @@ -101,5 +91,5 @@ export function BlogPostCard({ post }: BlogPostCardProps) { - ) + ); } diff --git a/apps/website/app/blog/components/SearchAndFilter.tsx b/apps/website/app/blog/components/SearchAndFilter.tsx index 26b2596..a96ef14 100644 --- a/apps/website/app/blog/components/SearchAndFilter.tsx +++ b/apps/website/app/blog/components/SearchAndFilter.tsx @@ -1,4 +1,4 @@ -'use client' +"use client"; import { Select, @@ -6,27 +6,27 @@ import { SelectItem, SelectTrigger, SelectValue, -} from '@/components/ui/select' -import { useDebounce } from '@/lib/hooks/use-debounce' -import { Search } from 'lucide-react' -import { useRouter } from 'next/navigation' -import { useCallback, useTransition } from 'react' +} from "@/components/ui/select"; +import { useDebounce } from "@/lib/hooks/use-debounce"; +import { Search } from "lucide-react"; +import { useRouter } from "next/navigation"; +import { useCallback, useTransition } from "react"; interface Tag { - id: string - name: string - slug: string + id: string; + name: string; + slug: string; } interface SearchAndFilterProps { - tags: Tag[] - initialSearch: string - initialTag: string - searchPlaceholder: string - allTagsText: string + tags: Tag[]; + initialSearch: string; + initialTag: string; + searchPlaceholder: string; + allTagsText: string; } -const ALL_TAGS_VALUE = 'all' +const ALL_TAGS_VALUE = "all"; export function SearchAndFilter({ tags, @@ -35,39 +35,39 @@ export function SearchAndFilter({ searchPlaceholder, allTagsText, }: SearchAndFilterProps) { - const router = useRouter() - const [isPending, startTransition] = useTransition() + const router = useRouter(); + const [isPending, startTransition] = useTransition(); const handleTagChange = (value: string) => { - const searchParams = new URLSearchParams(window.location.search) + const searchParams = new URLSearchParams(window.location.search); if (value && value !== ALL_TAGS_VALUE) { - searchParams.set('tag', value) + searchParams.set("tag", value); } else { - searchParams.delete('tag') + searchParams.delete("tag"); } startTransition(() => { - router.push(`?${searchParams.toString()}`) - }) - } + router.push(`?${searchParams.toString()}`); + }); + }; const debouncedCallback = useDebounce((value: string) => { - const searchParams = new URLSearchParams(window.location.search) + const searchParams = new URLSearchParams(window.location.search); if (value) { - searchParams.set('search', value) + searchParams.set("search", value); } else { - searchParams.delete('search') + searchParams.delete("search"); } startTransition(() => { - router.push(`?${searchParams.toString()}`) - }) - }, 300) + router.push(`?${searchParams.toString()}`); + }); + }, 300); const handleSearch = useCallback( (e: React.ChangeEvent) => { - debouncedCallback(e.target.value) + debouncedCallback(e.target.value); }, [debouncedCallback], - ) + ); return (
    @@ -92,9 +92,7 @@ export function SearchAndFilter({ - - {allTagsText} - + {allTagsText} {tags.map((tag) => ( {tag.name} @@ -104,5 +102,5 @@ export function SearchAndFilter({
    - ) + ); } diff --git a/apps/website/app/blog/page.tsx b/apps/website/app/blog/page.tsx index 5ba5212..d7afdf3 100644 --- a/apps/website/app/blog/page.tsx +++ b/apps/website/app/blog/page.tsx @@ -1,47 +1,46 @@ -import { getPosts, getTags } from '@/lib/ghost' -import type { Post } from '@/lib/ghost' -import { RssIcon } from 'lucide-react' -import type { Metadata } from 'next' -import Link from 'next/link' -import { BlogPostCard } from './components/BlogPostCard' -import { SearchAndFilter } from './components/SearchAndFilter' +import { getPosts, getTags } from "@/lib/ghost"; +import type { Post } from "@/lib/ghost"; +import { RssIcon } from "lucide-react"; +import type { Metadata } from "next"; +import Link from "next/link"; +import { BlogPostCard } from "./components/BlogPostCard"; +import { SearchAndFilter } from "./components/SearchAndFilter"; interface Tag { - id: string - name: string - slug: string + id: string; + name: string; + slug: string; } export const metadata: Metadata = { - title: 'Blog', - description: 'Latest news, updates, and articles from Dokploy', -} + title: "Blog", + description: "Latest news, updates, and articles from Dokploy", +}; export default async function BlogPage({ searchParams, }: { - searchParams: { [key: string]: string | string[] | undefined } + searchParams: { [key: string]: string | string[] | undefined }; }) { - const searchParams2 = await searchParams - const posts = await getPosts() - const tags = (await getTags()) as Tag[] + const searchParams2 = await searchParams; + const posts = await getPosts(); + const tags = (await getTags()) as Tag[]; const search = - typeof searchParams2.search === 'string' ? searchParams2.search : '' + typeof searchParams2.search === "string" ? searchParams2.search : ""; const selectedTag = - typeof searchParams2.tag === 'string' ? searchParams2.tag : '' + typeof searchParams2.tag === "string" ? searchParams2.tag : ""; const filteredPosts = posts.filter((post) => { const matchesSearch = - search === '' || + search === "" || post.title.toLowerCase().includes(search.toLowerCase()) || - post.excerpt.toLowerCase().includes(search.toLowerCase()) + post.excerpt.toLowerCase().includes(search.toLowerCase()); const matchesTag = - selectedTag === '' || - post.tags?.some((tag) => tag.slug === selectedTag) + selectedTag === "" || post.tags?.some((tag) => tag.slug === selectedTag); - return matchesSearch && matchesTag - }) + return matchesSearch && matchesTag; + }); return (
    @@ -50,9 +49,7 @@ export default async function BlogPage({

    BLOG

    -

    - Dokploy Latest News & Updates -

    +

    Dokploy Latest News & Updates

    {search || selectedTag - ? 'No posts found matching your criteria' - : 'No posts available'} + ? "No posts found matching your criteria" + : "No posts available"}

    ) : ( @@ -86,5 +83,5 @@ export default async function BlogPage({ )} - ) + ); } diff --git a/apps/website/app/blog/tag/[tag]/page.tsx b/apps/website/app/blog/tag/[tag]/page.tsx index b36a11c..2d344c5 100644 --- a/apps/website/app/blog/tag/[tag]/page.tsx +++ b/apps/website/app/blog/tag/[tag]/page.tsx @@ -1,51 +1,49 @@ -import { getPostsByTag, getTags } from '@/lib/ghost' -import type { Post } from '@/lib/ghost' -import type { Metadata } from 'next' -import Image from 'next/image' -import Link from 'next/link' -import { notFound } from 'next/navigation' +import { getPostsByTag, getTags } from "@/lib/ghost"; +import type { Post } from "@/lib/ghost"; +import type { Metadata } from "next"; +import Image from "next/image"; +import Link from "next/link"; +import { notFound } from "next/navigation"; type Props = { - params: { tag: string } -} + params: { tag: string }; +}; export async function generateMetadata({ params }: Props): Promise { - const { tag } = await params - const posts = await getPostsByTag(tag) + const { tag } = await params; + const posts = await getPostsByTag(tag); if (!posts || posts.length === 0) { return { - title: 'Tag Not Found', - description: 'The requested tag could not be found', - } + title: "Tag Not Found", + description: "The requested tag could not be found", + }; } const tagName = - posts[0].tags?.find((t: { slug: string }) => t.slug === tag)?.name || - tag + posts[0].tags?.find((t: { slug: string }) => t.slug === tag)?.name || tag; return { title: `${tagName} Posts`, description: `Browse all posts tagged with ${tagName}`, - } + }; } export async function generateStaticParams() { - const tags = await getTags() - return tags.map((tag: { slug: string }) => ({ tag: tag.slug })) + const tags = await getTags(); + return tags.map((tag: { slug: string }) => ({ tag: tag.slug })); } export default async function TagPage({ params }: Props) { - const { tag } = await params - const posts = await getPostsByTag(tag) + const { tag } = await params; + const posts = await getPostsByTag(tag); if (!posts || posts.length === 0) { - notFound() + notFound(); } const tagName = - posts[0].tags?.find((t: { slug: string }) => t.slug === tag)?.name || - tag + posts[0].tags?.find((t: { slug: string }) => t.slug === tag)?.name || tag; return (
    @@ -70,11 +68,11 @@ export default async function TagPage({ params }: Props) {

    - Posts tagged with{' '} + Posts tagged with{" "} "{tagName}"

    - {posts.length} {posts.length === 1 ? 'post' : 'posts'} found + {posts.length} {posts.length === 1 ? "post" : "posts"} found

    @@ -84,15 +82,15 @@ export default async function TagPage({ params }: Props) { ))}
    - ) + ); } function BlogPostCard({ post }: { post: Post }) { - const formattedDate = new Date(post.published_at).toLocaleDateString('en', { - year: 'numeric', - month: 'long', - day: 'numeric', - }) + const formattedDate = new Date(post.published_at).toLocaleDateString("en", { + year: "numeric", + month: "long", + day: "numeric", + }); return ( @@ -130,12 +128,12 @@ function BlogPostCard({ post }: { post: Post }) { )}

    - {post.primary_author?.name || 'Unknown Author'} + {post.primary_author?.name || "Unknown Author"}

    - ) + ); } diff --git a/apps/website/app/changelog/page.tsx b/apps/website/app/changelog/page.tsx index 5fbd963..f421387 100644 --- a/apps/website/app/changelog/page.tsx +++ b/apps/website/app/changelog/page.tsx @@ -1,61 +1,66 @@ -import type { Metadata } from 'next' +import type { Metadata } from "next"; export const metadata: Metadata = { - title: 'Changelog', + title: "Changelog", description: - 'Stay updated with the latest changes, improvements, and features in Dokploy', -} + "Stay updated with the latest changes, improvements, and features in Dokploy", +}; const changelogEntries = [ { - date: '2023-11-01', - title: 'Versión 2.1.0', + date: "2023-11-01", + title: "Versión 2.1.0", changes: [ - 'Añadido soporte para modo oscuro en todas las páginas', - 'Mejorado el rendimiento para grandes conjuntos de datos', - 'Corregido error en el flujo de autenticación de usuarios', + "Añadido soporte para modo oscuro en todas las páginas", + "Mejorado el rendimiento para grandes conjuntos de datos", + "Corregido error en el flujo de autenticación de usuarios", ], - image: 'https://g-ndmbkfuhw2w.vusercontent.net/placeholder.svg?height=200&width=400', + image: + "https://g-ndmbkfuhw2w.vusercontent.net/placeholder.svg?height=200&width=400", }, { - date: '2023-10-15', - title: 'Versión 2.0.1', + date: "2023-10-15", + title: "Versión 2.0.1", changes: [ - 'Corrección urgente para vulnerabilidad crítica de seguridad', - 'Actualizadas las dependencias a las últimas versiones', + "Corrección urgente para vulnerabilidad crítica de seguridad", + "Actualizadas las dependencias a las últimas versiones", ], - image: 'https://g-ndmbkfuhw2w.vusercontent.net/placeholder.svg?height=200&width=400', + image: + "https://g-ndmbkfuhw2w.vusercontent.net/placeholder.svg?height=200&width=400", }, { - date: '2023-10-01', - title: 'Versión 2.0.0', + date: "2023-10-01", + title: "Versión 2.0.0", changes: [ - 'Rediseño completo de la UI para mejorar la experiencia de usuario', - 'Introducidas nuevas características en el panel de control', - 'Añadido soporte para temas personalizados', - 'Mejorada la accesibilidad en toda la aplicación', + "Rediseño completo de la UI para mejorar la experiencia de usuario", + "Introducidas nuevas características en el panel de control", + "Añadido soporte para temas personalizados", + "Mejorada la accesibilidad en toda la aplicación", ], - image: 'https://g-ndmbkfuhw2w.vusercontent.net/placeholder.svg?height=200&width=400', + image: + "https://g-ndmbkfuhw2w.vusercontent.net/placeholder.svg?height=200&width=400", }, { - date: '2023-09-15', - title: 'Versión 1.9.5', + date: "2023-09-15", + title: "Versión 1.9.5", changes: [ - 'Optimización de rendimiento en la carga inicial', - 'Nuevas opciones de personalización para usuarios premium', + "Optimización de rendimiento en la carga inicial", + "Nuevas opciones de personalización para usuarios premium", ], - image: 'https://g-ndmbkfuhw2w.vusercontent.net/placeholder.svg?height=200&width=400', + image: + "https://g-ndmbkfuhw2w.vusercontent.net/placeholder.svg?height=200&width=400", }, { - date: '2023-08-01', - title: 'Versión 1.9.0', + date: "2023-08-01", + title: "Versión 1.9.0", changes: [ - 'Lanzamiento de la API pública para desarrolladores', - 'Mejoras en la sincronización de datos entre dispositivos', + "Lanzamiento de la API pública para desarrolladores", + "Mejoras en la sincronización de datos entre dispositivos", ], - image: 'https://g-ndmbkfuhw2w.vusercontent.net/placeholder.svg?height=200&width=400', + image: + "https://g-ndmbkfuhw2w.vusercontent.net/placeholder.svg?height=200&width=400", }, -] +]; export default function ChangelogPage() { return ( @@ -66,21 +71,12 @@ export default function ChangelogPage() { - + - + @@ -99,9 +95,7 @@ export default function ChangelogPage() { {entry.date} -

    - {entry.title} -

    +

    {entry.title}

    @@ -113,16 +107,11 @@ export default function ChangelogPage() {
      - {entry.changes.map( - (change, changeIndex) => ( -
    • - {change} -
    • - ), - )} + {entry.changes.map((change, changeIndex) => ( +
    • + {change} +
    • + ))}
    @@ -130,5 +119,5 @@ export default function ChangelogPage() { - ) + ); } diff --git a/apps/website/app/contact/layout.tsx b/apps/website/app/contact/layout.tsx index b26fc24..d2e786d 100644 --- a/apps/website/app/contact/layout.tsx +++ b/apps/website/app/contact/layout.tsx @@ -1,12 +1,12 @@ -import type { Metadata } from 'next' -import type { ReactNode } from 'react' +import type { Metadata } from "next"; +import type { ReactNode } from "react"; export const metadata: Metadata = { - title: 'Contact Us', + title: "Contact Us", description: "Get in touch with our team. We're here to help with any questions about Dokploy.", -} +}; export default function ContactLayout({ children }: { children: ReactNode }) { - return <>{children} + return <>{children}; } diff --git a/apps/website/app/contact/page.tsx b/apps/website/app/contact/page.tsx index df8ad26..f821b43 100644 --- a/apps/website/app/contact/page.tsx +++ b/apps/website/app/contact/page.tsx @@ -1,144 +1,13 @@ -'use client' +"use client"; -import { useState } from 'react' -import { Container } from '@/components/Container' -import { Button } from '@/components/ui/button' -import { Input } from '@/components/ui/input' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select' -import { trackGAEvent } from '@/components/analitycs' -import AnimatedGridPattern from '@/components/ui/animated-grid-pattern' -import { cn } from '@/lib/utils' - -interface ContactFormData { - inquiryType: '' | 'support' | 'sales' | 'other' - deploymentType: '' | 'cloud' | 'self-hosted' - firstName: string - lastName: string - email: string - company: string - message: string -} +import { Container } from "@/components/Container"; +import { ContactForm } from "@/components/ContactForm"; +import AnimatedGridPattern from "@/components/ui/animated-grid-pattern"; +import { cn } from "@/lib/utils"; +import { useState } from "react"; export default function ContactPage() { - const [isSubmitting, setIsSubmitting] = useState(false) - const [isSubmitted, setIsSubmitted] = useState(false) - const [formData, setFormData] = useState({ - inquiryType: '', - deploymentType: '', - firstName: '', - lastName: '', - email: '', - company: '', - message: '', - }) - const [errors, setErrors] = useState>({}) - - const validateForm = (): boolean => { - const newErrors: Record = {} - - if (!formData.inquiryType) { - newErrors.inquiryType = 'Please select what we can help you with' - } - if (formData.inquiryType === 'support' && !formData.deploymentType) { - newErrors.deploymentType = 'Please select your deployment type' - } - if (!formData.firstName.trim()) { - newErrors.firstName = 'First name is required' - } - if (!formData.lastName.trim()) { - newErrors.lastName = 'Last name is required' - } - if (!formData.email.trim()) { - newErrors.email = 'Email is required' - } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) { - newErrors.email = 'Please enter a valid email address' - } - if (!formData.company.trim()) { - newErrors.company = 'Company name is required' - } - if (!formData.message.trim()) { - newErrors.message = 'Message is required' - } - - setErrors(newErrors) - return Object.keys(newErrors).length === 0 - } - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault() - - if (!validateForm()) { - return - } - - // Prevent submission for self-hosted support requests - if (formData.inquiryType === 'support' && formData.deploymentType === 'self-hosted') { - return - } - - setIsSubmitting(true) - - try { - const response = await fetch('/api/contact', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(formData), - }) - - if (response.ok) { - trackGAEvent({ - action: 'Contact Form Submitted', - category: 'Contact', - label: formData.inquiryType, - }) - - setFormData({ - inquiryType: '', - deploymentType: '', - firstName: '', - lastName: '', - email: '', - company: '', - message: '', - }) - setErrors({}) - setIsSubmitted(true) - } else { - throw new Error('Failed to submit form') - } - } catch (error) { - console.error('Error submitting form:', error) - alert('There was an error sending your message. Please try again.') - } finally { - setIsSubmitting(false) - } - } - - const handleInputChange = (field: keyof ContactFormData, value: any) => { - setFormData((prev) => { - const updated = { ...prev, [field]: value } - // Reset deploymentType when inquiryType changes and is not support - if (field === 'inquiryType' && value !== 'support') { - updated.deploymentType = '' - } - return updated - }) - if (errors[field]) { - setErrors((prev) => { - const newErrors = { ...prev } - delete newErrors[field] - return newErrors - }) - } - } + const [isSubmitted, setIsSubmitted] = useState(false); if (isSubmitted) { return ( @@ -149,21 +18,22 @@ export default function ContactPage() { Thank you for contacting us!

    - We've received your message and will get back to you - as soon as possible. + We've received your message and will get back to you as soon as + possible.

    - +
    - ) + ); } return ( @@ -176,8 +46,8 @@ export default function ContactPage() { duration={3} repeatDelay={1} className={cn( - '[mask-image:radial-gradient(800px_circle_at_center,white,transparent)]', - 'absolute inset-x-0 inset-y-[-30%] h-[200%] skew-y-12', + "[mask-image:radial-gradient(800px_circle_at_center,white,transparent)]", + "absolute inset-x-0 inset-y-[-30%] h-[200%] skew-y-12", )} /> @@ -187,270 +57,16 @@ export default function ContactPage() { Contact Us

    - Get in touch with our team. We're here to help with - any questions about Dokploy. + Get in touch with our team. We're here to help with any questions + about Dokploy.

    -
    -
    - - - {errors.inquiryType && ( -

    - {errors.inquiryType} -

    - )} -
    - - {formData.inquiryType === 'support' && ( -
    - - - {errors.deploymentType && ( -

    - {errors.deploymentType} -

    - )} - - {formData.deploymentType === 'self-hosted' && ( -
    -

    - Self-Hosted Support -

    -

    - We currently don't provide direct support for self-hosted deployments through this form. However, our community is here to help! -

    -
    -

    - Please use one of these channels to get assistance: -

    - -
    -
    - )} -
    - )} - -
    -
    - - - handleInputChange( - 'firstName', - e.target.value, - ) - } - placeholder="Your first name" - /> - {errors.firstName && ( -

    - {errors.firstName} -

    - )} -
    - -
    - - - handleInputChange( - 'lastName', - e.target.value, - ) - } - placeholder="Your last name" - /> - {errors.lastName && ( -

    - {errors.lastName} -

    - )} -
    -
    - -
    - - - handleInputChange('email', e.target.value) - } - placeholder="your.email@company.com" - /> - {errors.email && ( -

    - {errors.email} -

    - )} -
    - -
    - - - handleInputChange('company', e.target.value) - } - placeholder="Your company name" - /> - {errors.company && ( -

    - {errors.company} -

    - )} -
    - -
    - -