Add project scaffolding and documentation
Add .env.example with configuration for database, Redis, security, SMTP, workers, and plugins. Add .gitignore for Python, Node.js, Next.js, Docker volumes, and IDE files. Add MIT License. Update README.md with feature overview, quick start guide, architecture description, plugin system documentation, security details, backup/restore instructions, and developer setup. Add Alembic configuration files and placeholder directories for API, web, worker, and plugin components
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class AuditLogResponse(BaseModel):
|
||||
id: uuid.UUID
|
||||
user_id: uuid.UUID | None
|
||||
action: str
|
||||
resource_type: str
|
||||
resource_id: str | None
|
||||
ip_address: str | None
|
||||
user_agent: str | None
|
||||
details: dict[str, Any]
|
||||
severity: str
|
||||
timestamp: datetime
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -0,0 +1,31 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, EmailStr
|
||||
|
||||
|
||||
class LoginRequest(BaseModel):
|
||||
email: EmailStr
|
||||
password: str
|
||||
|
||||
|
||||
class TokenResponse(BaseModel):
|
||||
access_token: str
|
||||
refresh_token: str
|
||||
token_type: str = "bearer"
|
||||
expires_at: datetime
|
||||
|
||||
|
||||
class RefreshRequest(BaseModel):
|
||||
refresh_token: str
|
||||
|
||||
|
||||
class SetupRequest(BaseModel):
|
||||
email: EmailStr
|
||||
password: str
|
||||
first_name: str | None = None
|
||||
last_name: str | None = None
|
||||
locale: str = "en"
|
||||
|
||||
|
||||
class SetupStatusResponse(BaseModel):
|
||||
setup_required: bool
|
||||
@@ -0,0 +1,22 @@
|
||||
from typing import Any, Generic, TypeVar
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class PaginatedResponse(BaseModel, Generic[T]):
|
||||
items: list[T]
|
||||
total: int
|
||||
page: int
|
||||
page_size: int
|
||||
pages: int
|
||||
|
||||
|
||||
class MessageResponse(BaseModel):
|
||||
message: str
|
||||
|
||||
|
||||
class ErrorResponse(BaseModel):
|
||||
detail: str
|
||||
errors: dict[str, Any] | None = None
|
||||
@@ -0,0 +1,105 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class DashboardWidgetBase(BaseModel):
|
||||
plugin_id: str
|
||||
widget_type: str
|
||||
title: str
|
||||
description: str | None = None
|
||||
position_x: int = 0
|
||||
position_y: int = 0
|
||||
width: int = 2
|
||||
height: int = 2
|
||||
min_width: int | None = None
|
||||
min_height: int | None = None
|
||||
max_width: int | None = None
|
||||
max_height: int | None = None
|
||||
order_index: int = 0
|
||||
settings: dict = Field(default_factory=dict)
|
||||
instance_id: uuid.UUID | None = None
|
||||
is_visible: bool = True
|
||||
is_static: bool = False
|
||||
|
||||
|
||||
class DashboardWidgetCreate(DashboardWidgetBase):
|
||||
pass
|
||||
|
||||
|
||||
class DashboardWidgetUpdate(BaseModel):
|
||||
title: str | None = None
|
||||
description: str | None = None
|
||||
position_x: int | None = None
|
||||
position_y: int | None = None
|
||||
width: int | None = None
|
||||
height: int | None = None
|
||||
min_width: int | None = None
|
||||
min_height: int | None = None
|
||||
max_width: int | None = None
|
||||
max_height: int | None = None
|
||||
order_index: int | None = None
|
||||
settings: dict | None = None
|
||||
instance_id: uuid.UUID | None = None
|
||||
is_visible: bool | None = None
|
||||
is_static: bool | None = None
|
||||
|
||||
|
||||
class DashboardWidgetResponse(DashboardWidgetBase):
|
||||
id: uuid.UUID
|
||||
dashboard_id: uuid.UUID
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class DashboardBase(BaseModel):
|
||||
title: str
|
||||
description: str | None = None
|
||||
icon: str | None = None
|
||||
folder: str = "default"
|
||||
is_favorite: bool = False
|
||||
is_public: bool = False
|
||||
refresh_interval_seconds: int | None = 60
|
||||
order_index: int = 0
|
||||
tags: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class DashboardCreate(DashboardBase):
|
||||
layout: dict = Field(default_factory=dict)
|
||||
layouts_by_breakpoint: dict = Field(default_factory=lambda: {"lg": [], "md": [], "sm": [], "xs": [], "xxs": []})
|
||||
|
||||
|
||||
class DashboardUpdate(BaseModel):
|
||||
title: str | None = None
|
||||
description: str | None = None
|
||||
icon: str | None = None
|
||||
folder: str | None = None
|
||||
is_favorite: bool | None = None
|
||||
is_public: bool | None = None
|
||||
refresh_interval_seconds: int | None = None
|
||||
order_index: int | None = None
|
||||
tags: list[str] | None = None
|
||||
layout: dict | None = None
|
||||
layouts_by_breakpoint: dict | None = None
|
||||
|
||||
|
||||
class DashboardResponse(DashboardBase):
|
||||
id: uuid.UUID
|
||||
owner_id: uuid.UUID
|
||||
layout: dict
|
||||
layouts_by_breakpoint: dict
|
||||
widgets: list[DashboardWidgetResponse]
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class DashboardLayoutUpdate(BaseModel):
|
||||
layout: dict
|
||||
layouts_by_breakpoint: dict
|
||||
@@ -0,0 +1,32 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class NotificationBase(BaseModel):
|
||||
title: str
|
||||
message: str | None = None
|
||||
type: str = "info"
|
||||
link: str | None = None
|
||||
metadata: dict[str, Any] = {}
|
||||
|
||||
|
||||
class NotificationCreate(NotificationBase):
|
||||
pass
|
||||
|
||||
|
||||
class NotificationUpdate(BaseModel):
|
||||
is_read: bool
|
||||
|
||||
|
||||
class NotificationResponse(NotificationBase):
|
||||
id: uuid.UUID
|
||||
user_id: uuid.UUID
|
||||
is_read: bool
|
||||
read_at: datetime | None
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -0,0 +1,117 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class PluginManifest(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
version: str
|
||||
nexadashPluginApi: str
|
||||
description: str | None = None
|
||||
author: str | None = None
|
||||
category: str = "Generic"
|
||||
permissions: list[str] = Field(default_factory=list)
|
||||
settingsSchema: dict = Field(default_factory=dict)
|
||||
credentialsSchema: dict = Field(default_factory=dict)
|
||||
widgets: list[dict] = Field(default_factory=list)
|
||||
|
||||
|
||||
class PluginBase(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
version: str
|
||||
description: str | None = None
|
||||
author: str | None = None
|
||||
category: str = "Generic"
|
||||
icon: str | None = None
|
||||
is_active: bool = False
|
||||
is_builtin: bool = False
|
||||
is_installed: bool = False
|
||||
permissions: list[str] = Field(default_factory=list)
|
||||
settings_schema: dict = Field(default_factory=dict)
|
||||
credentials_schema: dict = Field(default_factory=dict)
|
||||
widget_types: list[dict] = Field(default_factory=list)
|
||||
healthcheck_definition: dict = Field(default_factory=dict)
|
||||
api_routes: list[str] = Field(default_factory=list)
|
||||
has_frontend: bool = True
|
||||
|
||||
|
||||
class PluginResponse(PluginBase):
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class PluginCreate(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
version: str
|
||||
description: str | None = None
|
||||
author: str | None = None
|
||||
category: str = "Generic"
|
||||
icon: str | None = None
|
||||
is_builtin: bool = False
|
||||
permissions: list[str] = Field(default_factory=list)
|
||||
settings_schema: dict = Field(default_factory=dict)
|
||||
credentials_schema: dict = Field(default_factory=dict)
|
||||
widget_types: list[dict] = Field(default_factory=list)
|
||||
healthcheck_definition: dict = Field(default_factory=dict)
|
||||
api_routes: list[str] = Field(default_factory=list)
|
||||
has_frontend: bool = True
|
||||
manifest: dict = Field(default_factory=dict)
|
||||
path: str
|
||||
|
||||
|
||||
class PluginUpdate(BaseModel):
|
||||
is_active: bool | None = None
|
||||
is_installed: bool | None = None
|
||||
|
||||
|
||||
class PluginInstanceBase(BaseModel):
|
||||
plugin_id: str
|
||||
service_connection_id: uuid.UUID | None = None
|
||||
name: str
|
||||
settings: dict = Field(default_factory=dict)
|
||||
is_enabled: bool = True
|
||||
|
||||
|
||||
class PluginInstanceCreate(PluginInstanceBase):
|
||||
pass
|
||||
|
||||
|
||||
class PluginInstanceUpdate(BaseModel):
|
||||
name: str | None = None
|
||||
service_connection_id: uuid.UUID | None = None
|
||||
settings: dict | None = None
|
||||
is_enabled: bool | None = None
|
||||
|
||||
|
||||
class PluginInstanceResponse(PluginInstanceBase):
|
||||
id: uuid.UUID
|
||||
health_status: str
|
||||
health_message: str | None = None
|
||||
last_sync_at: datetime | None
|
||||
last_error: str | None
|
||||
error_count: int
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class PluginLogResponse(BaseModel):
|
||||
id: uuid.UUID
|
||||
plugin_id: str
|
||||
instance_id: uuid.UUID | None
|
||||
level: str
|
||||
message: str
|
||||
context: dict
|
||||
timestamp: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -0,0 +1,27 @@
|
||||
import uuid
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class RoleBase(BaseModel):
|
||||
name: str
|
||||
description: str | None = None
|
||||
permissions: list[str]
|
||||
|
||||
|
||||
class RoleCreate(RoleBase):
|
||||
pass
|
||||
|
||||
|
||||
class RoleUpdate(BaseModel):
|
||||
name: str | None = None
|
||||
description: str | None = None
|
||||
permissions: list[str] | None = None
|
||||
|
||||
|
||||
class RoleResponse(RoleBase):
|
||||
id: uuid.UUID
|
||||
is_system: bool
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -0,0 +1,31 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class SecretBase(BaseModel):
|
||||
name: str
|
||||
secret_type: str
|
||||
scope: str
|
||||
metadata: dict[str, Any] = {}
|
||||
|
||||
|
||||
class SecretCreate(SecretBase):
|
||||
value: str
|
||||
|
||||
|
||||
class SecretUpdate(BaseModel):
|
||||
name: str | None = None
|
||||
value: str | None = None
|
||||
metadata: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class SecretResponse(SecretBase):
|
||||
id: uuid.UUID
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -0,0 +1,49 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class ServiceConnectionBase(BaseModel):
|
||||
name: str
|
||||
plugin_id: str
|
||||
base_url: str
|
||||
verify_tls: bool = True
|
||||
timeout_seconds: int = 30
|
||||
extra_headers: dict = Field(default_factory=dict)
|
||||
is_enabled: bool = True
|
||||
|
||||
|
||||
class ServiceConnectionCreate(ServiceConnectionBase):
|
||||
credentials: dict = Field(default_factory=dict)
|
||||
|
||||
|
||||
class ServiceConnectionUpdate(BaseModel):
|
||||
name: str | None = None
|
||||
base_url: str | None = None
|
||||
verify_tls: bool | None = None
|
||||
timeout_seconds: int | None = None
|
||||
extra_headers: dict | None = None
|
||||
is_enabled: bool | None = None
|
||||
credentials: dict | None = None
|
||||
|
||||
|
||||
class ServiceConnectionResponse(ServiceConnectionBase):
|
||||
id: uuid.UUID
|
||||
credentials_id: uuid.UUID | None
|
||||
health_status: str
|
||||
health_message: str | None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ServiceConnectionTestRequest(BaseModel):
|
||||
plugin_id: str
|
||||
base_url: str
|
||||
verify_tls: bool = True
|
||||
timeout_seconds: int = 30
|
||||
credentials: dict = Field(default_factory=dict)
|
||||
extra_headers: dict = Field(default_factory=dict)
|
||||
@@ -0,0 +1,19 @@
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class SystemSettingBase(BaseModel):
|
||||
key: str
|
||||
value: dict[str, Any]
|
||||
description: str | None = None
|
||||
is_sensitive: bool = False
|
||||
|
||||
|
||||
class SystemSettingUpdate(BaseModel):
|
||||
value: dict[str, Any]
|
||||
|
||||
|
||||
class SystemSettingResponse(SystemSettingBase):
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -0,0 +1,79 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, EmailStr, Field
|
||||
|
||||
|
||||
class UserBase(BaseModel):
|
||||
email: EmailStr
|
||||
first_name: str | None = None
|
||||
last_name: str | None = None
|
||||
locale: str = "en"
|
||||
theme: str = "system"
|
||||
timezone: str = "UTC"
|
||||
|
||||
|
||||
class UserCreate(UserBase):
|
||||
password: str = Field(..., min_length=12, max_length=128)
|
||||
role_id: uuid.UUID | None = None
|
||||
|
||||
|
||||
class UserUpdate(BaseModel):
|
||||
email: EmailStr | None = None
|
||||
first_name: str | None = None
|
||||
last_name: str | None = None
|
||||
locale: str | None = None
|
||||
theme: str | None = None
|
||||
timezone: str | None = None
|
||||
role_id: uuid.UUID | None = None
|
||||
is_active: bool | None = None
|
||||
|
||||
|
||||
class UserResponse(UserBase):
|
||||
id: uuid.UUID
|
||||
is_active: bool
|
||||
is_superuser: bool
|
||||
is_owner: bool
|
||||
email_verified: bool
|
||||
last_login_at: datetime | None
|
||||
avatar_url: str | None
|
||||
role: "RoleResponse" | None = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class UserInviteRequest(BaseModel):
|
||||
email: EmailStr
|
||||
role_id: uuid.UUID
|
||||
|
||||
|
||||
class UserInviteAccept(BaseModel):
|
||||
token: str
|
||||
password: str = Field(..., min_length=12, max_length=128)
|
||||
|
||||
|
||||
class PasswordChangeRequest(BaseModel):
|
||||
current_password: str
|
||||
new_password: str = Field(..., min_length=12, max_length=128)
|
||||
|
||||
|
||||
class PasswordResetRequest(BaseModel):
|
||||
email: EmailStr
|
||||
|
||||
|
||||
class PasswordResetConfirm(BaseModel):
|
||||
token: str
|
||||
new_password: str = Field(..., min_length=12, max_length=128)
|
||||
|
||||
|
||||
class ProfileUpdate(BaseModel):
|
||||
first_name: str | None = None
|
||||
last_name: str | None = None
|
||||
locale: str | None = None
|
||||
theme: str | None = None
|
||||
timezone: str | None = None
|
||||
preferences: dict[str, Any] | None = None
|
||||
Reference in New Issue
Block a user