diff --git a/public/database/src/generated/entities/access_list.rs b/public/database/src/generated/entities/access_list.rs new file mode 100644 index 0000000..93fd0e5 --- /dev/null +++ b/public/database/src/generated/entities/access_list.rs @@ -0,0 +1,34 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0.0-rc.18 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "access_list")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub name: String, + #[sea_orm(column_type = "Text", nullable)] + pub description: Option, + pub created_by: Option, + pub created_at: DateTimeUtc, + pub updated_at: DateTimeUtc, + #[sea_orm(has_many)] + pub access_list_entries: HasMany, + #[sea_orm(has_many)] + pub proxy_host_access_lists: HasMany, + #[sea_orm(has_many)] + pub stream_service_access_lists: HasMany, + #[sea_orm( + belongs_to, + from = "created_by", + to = "id", + on_update = "Cascade", + on_delete = "SetNull" + )] + pub user: HasOne, +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/public/database/src/generated/entities/access_list_entry.rs b/public/database/src/generated/entities/access_list_entry.rs new file mode 100644 index 0000000..403ae92 --- /dev/null +++ b/public/database/src/generated/entities/access_list_entry.rs @@ -0,0 +1,28 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0.0-rc.18 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "access_list_entry")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub access_list_id: Uuid, + pub entry_type: String, + pub value: String, + #[sea_orm(column_type = "Text", nullable)] + pub comment: Option, + pub created_at: DateTimeUtc, + #[sea_orm( + belongs_to, + from = "access_list_id", + to = "id", + on_update = "Cascade", + on_delete = "Cascade" + )] + pub access_list: HasOne, +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/public/database/src/generated/entities/audit_log.rs b/public/database/src/generated/entities/audit_log.rs new file mode 100644 index 0000000..960aee7 --- /dev/null +++ b/public/database/src/generated/entities/audit_log.rs @@ -0,0 +1,29 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0.0-rc.18 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "audit_log")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub actor_id: Option, + pub action: String, + pub resource_type: String, + pub resource_id: String, + #[sea_orm(column_type = "JsonBinary", nullable)] + pub details: Option, + pub created_at: DateTimeUtc, + #[sea_orm( + belongs_to, + from = "actor_id", + to = "id", + on_update = "Cascade", + on_delete = "SetNull" + )] + pub user: HasOne, +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/public/database/src/generated/entities/location.rs b/public/database/src/generated/entities/location.rs new file mode 100644 index 0000000..99f1c32 --- /dev/null +++ b/public/database/src/generated/entities/location.rs @@ -0,0 +1,45 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0.0-rc.18 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "location")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub host_id: Uuid, + pub path: String, + pub match_type: String, + pub order: i64, + pub upstream_id: Option, + pub proxy_pass_host: Option, + pub proxy_pass_port: Option, + pub preserve_host_header: Option, + #[sea_orm(column_type = "JsonBinary", nullable)] + pub allowed_methods: Option, + #[sea_orm(column_type = "Text", nullable)] + pub custom_config: Option, + pub enabled: bool, + pub created_at: DateTimeUtc, + pub updated_at: DateTimeUtc, + #[sea_orm( + belongs_to, + from = "host_id", + to = "id", + on_update = "Cascade", + on_delete = "Cascade" + )] + pub proxy_host: HasOne, + #[sea_orm( + belongs_to, + from = "upstream_id", + to = "id", + on_update = "Cascade", + on_delete = "SetNull" + )] + pub upstream: HasOne, +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/public/database/src/generated/entities/mod.rs b/public/database/src/generated/entities/mod.rs index 1917343..33598a4 100644 --- a/public/database/src/generated/entities/mod.rs +++ b/public/database/src/generated/entities/mod.rs @@ -2,6 +2,15 @@ pub mod prelude; +pub mod access_list; +pub mod access_list_entry; pub mod config; +pub mod location; +pub mod proxy_host; +pub mod proxy_host_access_list; +pub mod stream_service; +pub mod stream_service_access_list; +pub mod upstream; +pub mod upstream_target; pub mod user; pub mod user_identity; diff --git a/public/database/src/generated/entities/prelude.rs b/public/database/src/generated/entities/prelude.rs index f0df089..d09f1c3 100644 --- a/public/database/src/generated/entities/prelude.rs +++ b/public/database/src/generated/entities/prelude.rs @@ -1,5 +1,14 @@ //! `SeaORM` Entity, @generated by sea-orm-codegen 2.0.0-rc.18 +pub use super::access_list::Entity as AccessList; +pub use super::access_list_entry::Entity as AccessListEntry; pub use super::config::Entity as Config; +pub use super::location::Entity as Location; +pub use super::proxy_host::Entity as ProxyHost; +pub use super::proxy_host_access_list::Entity as ProxyHostAccessList; +pub use super::stream_service::Entity as StreamService; +pub use super::stream_service_access_list::Entity as StreamServiceAccessList; +pub use super::upstream::Entity as Upstream; +pub use super::upstream_target::Entity as UpstreamTarget; pub use super::user::Entity as User; pub use super::user_identity::Entity as UserIdentity; diff --git a/public/database/src/generated/entities/proxy_host.rs b/public/database/src/generated/entities/proxy_host.rs new file mode 100644 index 0000000..b521b02 --- /dev/null +++ b/public/database/src/generated/entities/proxy_host.rs @@ -0,0 +1,50 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0.0-rc.18 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "proxy_host")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub name: Option, + pub domain: String, + pub scheme: String, + pub listen_port: i64, + pub forward_scheme: String, + pub forward_host: Option, + pub forward_port: Option, + pub preserve_host_header: bool, + pub enable_websocket: bool, + pub enabled: bool, + #[sea_orm(column_type = "JsonBinary", nullable)] + pub meta: Option, + pub default_upstream_id: Option, + pub created_by: Option, + pub created_at: DateTimeUtc, + pub updated_at: DateTimeUtc, + #[sea_orm(has_many)] + pub locations: HasMany, + #[sea_orm(has_many)] + pub proxy_host_access_lists: HasMany, + #[sea_orm( + belongs_to, + from = "default_upstream_id", + to = "id", + on_update = "Cascade", + on_delete = "SetNull" + )] + pub upstream: HasOne, + #[sea_orm( + belongs_to, + from = "created_by", + to = "id", + on_update = "Cascade", + on_delete = "SetNull" + )] + pub user: HasOne, +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/public/database/src/generated/entities/proxy_host_access_list.rs b/public/database/src/generated/entities/proxy_host_access_list.rs new file mode 100644 index 0000000..0818588 --- /dev/null +++ b/public/database/src/generated/entities/proxy_host_access_list.rs @@ -0,0 +1,33 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0.0-rc.18 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "proxy_host_access_list")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub proxy_host_id: Uuid, + pub access_list_id: Uuid, + pub created_at: DateTimeUtc, + #[sea_orm( + belongs_to, + from = "access_list_id", + to = "id", + on_update = "Cascade", + on_delete = "Cascade" + )] + pub access_list: HasOne, + #[sea_orm( + belongs_to, + from = "proxy_host_id", + to = "id", + on_update = "Cascade", + on_delete = "Cascade" + )] + pub proxy_host: HasOne, +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/public/database/src/generated/entities/stream_service.rs b/public/database/src/generated/entities/stream_service.rs new file mode 100644 index 0000000..08a92fe --- /dev/null +++ b/public/database/src/generated/entities/stream_service.rs @@ -0,0 +1,47 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0.0-rc.18 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "stream_service")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub name: Option, + pub listen_host: String, + pub listen_port: i64, + pub protocol: String, + pub mode: String, + pub forward_host: Option, + pub forward_port: Option, + pub upstream_id: Option, + pub preserved_client_ip: bool, + pub enabled: bool, + #[sea_orm(column_type = "JsonBinary", nullable)] + pub meta: Option, + pub created_by: Option, + pub created_at: DateTimeUtc, + pub updated_at: DateTimeUtc, + #[sea_orm(has_many)] + pub stream_service_access_lists: HasMany, + #[sea_orm( + belongs_to, + from = "upstream_id", + to = "id", + on_update = "Cascade", + on_delete = "SetNull" + )] + pub upstream: HasOne, + #[sea_orm( + belongs_to, + from = "created_by", + to = "id", + on_update = "Cascade", + on_delete = "SetNull" + )] + pub user: HasOne, +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/public/database/src/generated/entities/stream_service_access_list.rs b/public/database/src/generated/entities/stream_service_access_list.rs new file mode 100644 index 0000000..9ec8043 --- /dev/null +++ b/public/database/src/generated/entities/stream_service_access_list.rs @@ -0,0 +1,33 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0.0-rc.18 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "stream_service_access_list")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub stream_service_id: Uuid, + pub access_list_id: Uuid, + pub created_at: DateTimeUtc, + #[sea_orm( + belongs_to, + from = "access_list_id", + to = "id", + on_update = "Cascade", + on_delete = "Cascade" + )] + pub access_list: HasOne, + #[sea_orm( + belongs_to, + from = "stream_service_id", + to = "id", + on_update = "Cascade", + on_delete = "Cascade" + )] + pub stream_service: HasOne, +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/public/database/src/generated/entities/upstream.rs b/public/database/src/generated/entities/upstream.rs new file mode 100644 index 0000000..3490112 --- /dev/null +++ b/public/database/src/generated/entities/upstream.rs @@ -0,0 +1,29 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0.0-rc.18 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "upstream")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub name: String, + pub protocol: String, + pub algorithm: String, + pub sticky_session: bool, + pub created_by: Option, + pub created_at: DateTimeUtc, + pub updated_at: DateTimeUtc, + #[sea_orm(has_many)] + pub locations: HasMany, + #[sea_orm(has_many)] + pub proxy_hosts: HasMany, + #[sea_orm(has_many)] + pub stream_services: HasMany, + #[sea_orm(has_many)] + pub upstream_targets: HasMany, +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/public/database/src/generated/entities/upstream_target.rs b/public/database/src/generated/entities/upstream_target.rs new file mode 100644 index 0000000..a35acf7 --- /dev/null +++ b/public/database/src/generated/entities/upstream_target.rs @@ -0,0 +1,30 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 2.0.0-rc.18 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[sea_orm::model] +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] +#[sea_orm(table_name = "upstream_target")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub upstream_id: Uuid, + pub target_host: String, + pub target_port: i64, + pub weight: i64, + pub is_backup: bool, + pub enabled: bool, + pub created_at: DateTimeUtc, + pub updated_at: DateTimeUtc, + #[sea_orm( + belongs_to, + from = "upstream_id", + to = "id", + on_update = "Cascade", + on_delete = "Cascade" + )] + pub upstream: HasOne, +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/public/database/src/generated/entities/user.rs b/public/database/src/generated/entities/user.rs index ab2edb2..6e043f4 100644 --- a/public/database/src/generated/entities/user.rs +++ b/public/database/src/generated/entities/user.rs @@ -18,6 +18,12 @@ pub struct Model { pub last_login_at: Option, pub deleted_at: Option, #[sea_orm(has_many)] + pub access_lists: HasMany, + #[sea_orm(has_many)] + pub proxy_hosts: HasMany, + #[sea_orm(has_many)] + pub stream_services: HasMany, + #[sea_orm(has_many)] pub user_identities: HasMany, } diff --git a/public/migration/doc/nginx-tables.md b/public/migration/doc/nginx-tables.md new file mode 100644 index 0000000..2e09164 --- /dev/null +++ b/public/migration/doc/nginx-tables.md @@ -0,0 +1,208 @@ +# Migration Tables → nginx mapping + +This document explains the purpose of each migration table added under `public/migration/src/migrations` and how the rows map to generated nginx configuration (HTTP `http {}` and `stream {}` contexts). + +Summary of tables covered: + +- `upstream` +- `upstream_target` +- `proxy_host` +- `location` +- `stream_service` +- `access_list` +- `access_list_entry` +- `audit_log` + +--- + +## `upstream` + +Purpose: A named backend pool of servers. Shared by HTTP and stream services. + +Key fields: + +- `id`: UUID primary key +- `name`: identifier used when generating nginx `upstream {}` +- `protocol`: `http` | `tcp` | `udp` — determines how nginx will use the pool +- `algorithm`: load balancing strategy (`round_robin`, `least_conn`, `ip_hash`) +- `sticky_session`: whether to enable sticky behavior when supported +- `health_check`: optional JSON describing health probes + +nginx mapping (HTTP): + +```nginx +upstream { + server 10.0.0.5:8080 weight=2; + server 10.0.0.6:8080 backup; + # optional LB settings generated from `algorithm` and `sticky_session` +} + +server { + listen 80; + server_name example.com; + + location / { + proxy_pass http://; + } +} +``` + +nginx mapping (stream): + +```nginx +stream { + upstream { + server 10.0.0.5:3306; + server 10.0.0.6:3306 backup; + } + + server { + listen 3306; + proxy_pass ; + } +} +``` + +Notes: `upstream.protocol` selects which block and directive forms to generate; + +--- + +## `upstream_target` + +Purpose: One row per backend server in an `upstream` pool. + +Key fields: + +- `upstream_id`: FK to `upstream` +- `target_host`, `target_port` +- `weight`, `is_backup`, `enabled` + +nginx mapping: each row becomes a `server` line in the generated `upstream` block (weights and backup flags applied). Disabled targets are omitted. + +Example generated line: + +```nginx +server 10.0.0.5:8080 weight=3; +server 10.0.0.6:8080 backup; +``` + +--- + +## `proxy_host` + +Purpose: Represents an HTTP(S) host (a top-level `server` block in nginx `http` context). + +Key fields: + +- `domain`: `server_name` value (may be a wildcard) +- `listen_port`: port to listen on (80/443) +- `scheme`: http|https (informs UI; TLS handled elsewhere) +- `forward_host/forward_port` or `default_upstream_id`: host-level forwarding fallback +- `preserve_host_header`: whether to forward original `Host` header +- `enable_websocket`: toggles websocket header handling +- `meta`: JSON for optional host-level settings (timeouts, client_max_body_size, custom snippets) + +nginx mapping (host-level default): + +```nginx +server { + listen ; + server_name ; + + # host-level fallback if no matching location + location / { + proxy_pass http://; + } +} +``` + +If `forward_host`/`forward_port` is set instead of `default_upstream_id`, generate `proxy_pass http://forward_host:forward_port;`. + +`meta` entries are injected into the `server` block (careful: snippets can break reloads). + +--- + +## `location` + +Purpose: Path-level routing (`location` blocks inside a `server`). More specific than `proxy_host` default. + +Key fields: + +- `host_id`: FK to `proxy_host` +- `path`: `location` match (e.g., `/api`, `~^/assets/`) +- `match_type`: `prefix` | `exact` | `regex` +- `upstream_id` or `proxy_pass_host`/`proxy_pass_port` +- `allowed_methods`: optional method whitelist +- `custom_config`: raw nginx snippet inserted inside the `location` + +nginx mapping: + +```nginx +location /api { + proxy_pass http://api_upstream; + # optional custom_config injected here +} +``` + +Ordering and match type produce correct nginx `location` selection semantics; `order` field can break ties for equal specificity. + +--- + +## `stream_service` + +Purpose: A TCP/UDP service in nginx `stream` context — corresponds to a `server` block inside `stream {}`. + +Key fields: + +- `listen_host`, `listen_port` +- `protocol`: `tcp` | `udp` +- `mode`: `direct` | `upstream` (direct forwards to `forward_host:forward_port`, `upstream` uses `upstream_id` pool) +- `preserved_client_ip`: whether to enable proxy_protocol or other client-ip forwarding +- `meta`: JSON for advanced stream options (ssl_preread, proxy_timeout, buffer sizes) + +nginx mapping (stream): + +```nginx +stream { + upstream { + server 10.0.0.5:3306; + } + + server { + listen 3306; + proxy_pass ; # or proxy_pass 10.0.0.10:3306 for direct + } +} +``` + +Notes: Stream services bypass HTTP processing. Use `meta` for `proxy_protocol` and `ssl_preread` toggles. + +--- + +## `access_list` and `access_list_entry` + +Purpose: Nameable allow/deny lists for IP/CIDR or other entry types that can be applied to hosts/locations/stream services. + +Key fields (access_list): `id`, `name`, `description`. +Key fields (entry): `access_list_id`, `entry_type` (e.g., `allow`, `deny`, `note`), `value` (IP or CIDR), `comment`. + +nginx mapping (HTTP example): + +```nginx +location /admin { + allow 10.0.0.0/24; + deny all; + proxy_pass http://admin_upstream; +} +``` + +nginx mapping (stream example): + +```nginx +server { + listen 3306; + allow 10.0.0.0/24; + deny all; + proxy_pass backend_pool; +} +``` diff --git a/public/migration/src/lib.rs b/public/migration/src/lib.rs index 83e0779..920a97d 100644 --- a/public/migration/src/lib.rs +++ b/public/migration/src/lib.rs @@ -13,6 +13,15 @@ impl MigratorTrait for Migrator { Box::new(m20251011_000001_create_config_table::Migration), Box::new(m20251011_000002_create_user_table::Migration), Box::new(m20251011_000003_create_user_identity_table::Migration), + Box::new(m20251223_000004_create_upstream_table::Migration), + Box::new(m20251223_000005_create_upstream_target_table::Migration), + Box::new(m20251223_000006_create_proxy_host_table::Migration), + Box::new(m20251223_000007_create_location_table::Migration), + Box::new(m20251223_000008_create_stream_service_table::Migration), + Box::new(m20251223_000009_create_access_list_table::Migration), + Box::new(m20251223_000010_create_access_list_entry_table::Migration), + Box::new(m20251223_000011_create_proxy_host_access_list_table::Migration), + Box::new(m20251223_000012_create_stream_service_access_list_table::Migration), ] } } diff --git a/public/migration/src/migrations.rs b/public/migration/src/migrations.rs index 2ff1c48..1501f2a 100644 --- a/public/migration/src/migrations.rs +++ b/public/migration/src/migrations.rs @@ -1,3 +1,12 @@ pub mod m20251011_000001_create_config_table; pub mod m20251011_000002_create_user_table; pub mod m20251011_000003_create_user_identity_table; +pub mod m20251223_000004_create_upstream_table; +pub mod m20251223_000005_create_upstream_target_table; +pub mod m20251223_000006_create_proxy_host_table; +pub mod m20251223_000007_create_location_table; +pub mod m20251223_000008_create_stream_service_table; +pub mod m20251223_000009_create_access_list_table; +pub mod m20251223_000010_create_access_list_entry_table; +pub mod m20251223_000011_create_proxy_host_access_list_table; +pub mod m20251223_000012_create_stream_service_access_list_table; diff --git a/public/migration/src/migrations/m20251223_000004_create_upstream_table.rs b/public/migration/src/migrations/m20251223_000004_create_upstream_table.rs new file mode 100644 index 0000000..e6df994 --- /dev/null +++ b/public/migration/src/migrations/m20251223_000004_create_upstream_table.rs @@ -0,0 +1,66 @@ +use sea_orm_migration::{prelude::*, schema::*}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[forbid(dead_code)] +#[derive(DeriveIden)] +pub enum Upstream { + Table, + Id, + Name, + Protocol, + Algorithm, + StickySession, + CreatedBy, + CreatedAt, + UpdatedAt, +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(Upstream::Table) + .if_not_exists() + .col(pk_uuid(Upstream::Id)) + .col(ColumnDef::new(Upstream::Name).string().not_null()) + .col(ColumnDef::new(Upstream::Protocol).string().not_null()) + .col( + ColumnDef::new(Upstream::Algorithm) + .string() + .default("round_robin") + .not_null(), + ) + .col( + ColumnDef::new(Upstream::StickySession) + .boolean() + .default(false) + .not_null(), + ) + .col(ColumnDef::new(Upstream::CreatedBy).uuid().null()) + .col( + ColumnDef::new(Upstream::CreatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .col( + ColumnDef::new(Upstream::UpdatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(Upstream::Table).to_owned()) + .await + } +} diff --git a/public/migration/src/migrations/m20251223_000005_create_upstream_target_table.rs b/public/migration/src/migrations/m20251223_000005_create_upstream_target_table.rs new file mode 100644 index 0000000..0d1567a --- /dev/null +++ b/public/migration/src/migrations/m20251223_000005_create_upstream_target_table.rs @@ -0,0 +1,92 @@ +use sea_orm_migration::{prelude::*, schema::*}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[forbid(dead_code)] +#[derive(DeriveIden)] +pub enum UpstreamTarget { + Table, + Id, + UpstreamId, + TargetHost, + TargetPort, + Weight, + IsBackup, + Enabled, + CreatedAt, + UpdatedAt, +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(UpstreamTarget::Table) + .if_not_exists() + .col(pk_uuid(UpstreamTarget::Id)) + .col(ColumnDef::new(UpstreamTarget::UpstreamId).uuid().not_null()) + .foreign_key( + ForeignKey::create() + .name("fk-upstream-target-upstream-id") + .from(UpstreamTarget::Table, UpstreamTarget::UpstreamId) + .to( + super::m20251223_000004_create_upstream_table::Upstream::Table, + super::m20251223_000004_create_upstream_table::Upstream::Id, + ) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .col( + ColumnDef::new(UpstreamTarget::TargetHost) + .string() + .not_null(), + ) + .col( + ColumnDef::new(UpstreamTarget::TargetPort) + .integer() + .not_null(), + ) + .col( + ColumnDef::new(UpstreamTarget::Weight) + .integer() + .default(1) + .not_null(), + ) + .col( + ColumnDef::new(UpstreamTarget::IsBackup) + .boolean() + .default(false) + .not_null(), + ) + .col( + ColumnDef::new(UpstreamTarget::Enabled) + .boolean() + .default(true) + .not_null(), + ) + .col( + ColumnDef::new(UpstreamTarget::CreatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .col( + ColumnDef::new(UpstreamTarget::UpdatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(UpstreamTarget::Table).to_owned()) + .await + } +} diff --git a/public/migration/src/migrations/m20251223_000006_create_proxy_host_table.rs b/public/migration/src/migrations/m20251223_000006_create_proxy_host_table.rs new file mode 100644 index 0000000..bcdd3fa --- /dev/null +++ b/public/migration/src/migrations/m20251223_000006_create_proxy_host_table.rs @@ -0,0 +1,124 @@ +use sea_orm_migration::{prelude::*, schema::*}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[forbid(dead_code)] +#[derive(DeriveIden)] +pub enum ProxyHost { + Table, + Id, + Name, + Domain, + Scheme, + ListenPort, + ForwardScheme, + ForwardHost, + ForwardPort, + PreserveHostHeader, + EnableWebsocket, + Enabled, + Meta, + DefaultUpstreamId, + CreatedBy, + CreatedAt, + UpdatedAt, +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(ProxyHost::Table) + .if_not_exists() + .col(pk_uuid(ProxyHost::Id)) + .col(ColumnDef::new(ProxyHost::Name).string().null()) + .col(ColumnDef::new(ProxyHost::Domain).string().not_null()) + .col( + ColumnDef::new(ProxyHost::Scheme) + .string() + .default("http") + .not_null(), + ) + .col( + ColumnDef::new(ProxyHost::ListenPort) + .integer() + .default(80) + .not_null(), + ) + .col( + ColumnDef::new(ProxyHost::ForwardScheme) + .string() + .default("http") + .not_null(), + ) + .col(ColumnDef::new(ProxyHost::ForwardHost).string().null()) + .col(ColumnDef::new(ProxyHost::ForwardPort).integer().null()) + .col( + ColumnDef::new(ProxyHost::PreserveHostHeader) + .boolean() + .default(false) + .not_null(), + ) + .col( + ColumnDef::new(ProxyHost::EnableWebsocket) + .boolean() + .default(false) + .not_null(), + ) + .col( + ColumnDef::new(ProxyHost::Enabled) + .boolean() + .default(true) + .not_null(), + ) + .col(ColumnDef::new(ProxyHost::Meta).json_binary().null()) + .col(ColumnDef::new(ProxyHost::DefaultUpstreamId).uuid().null()) + .foreign_key( + ForeignKey::create() + .name("fk-proxy-host-default-upstream-id") + .from(ProxyHost::Table, ProxyHost::DefaultUpstreamId) + .to( + super::m20251223_000004_create_upstream_table::Upstream::Table, + super::m20251223_000004_create_upstream_table::Upstream::Id, + ) + .on_delete(ForeignKeyAction::SetNull) + .on_update(ForeignKeyAction::Cascade), + ) + .col(ColumnDef::new(ProxyHost::CreatedBy).uuid().null()) + .foreign_key( + ForeignKey::create() + .name("fk-proxy-host-created-by") + .from(ProxyHost::Table, ProxyHost::CreatedBy) + .to( + super::m20251011_000002_create_user_table::User::Table, + super::m20251011_000002_create_user_table::User::Id, + ) + .on_delete(ForeignKeyAction::SetNull) + .on_update(ForeignKeyAction::Cascade), + ) + .col( + ColumnDef::new(ProxyHost::CreatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .col( + ColumnDef::new(ProxyHost::UpdatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(ProxyHost::Table).to_owned()) + .await + } +} diff --git a/public/migration/src/migrations/m20251223_000007_create_location_table.rs b/public/migration/src/migrations/m20251223_000007_create_location_table.rs new file mode 100644 index 0000000..5da97d4 --- /dev/null +++ b/public/migration/src/migrations/m20251223_000007_create_location_table.rs @@ -0,0 +1,100 @@ +use sea_orm_migration::{prelude::*, schema::*}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[forbid(dead_code)] +#[derive(DeriveIden)] +pub enum Location { + Table, + Id, + HostId, + Path, + MatchType, + Order, + UpstreamId, + ProxyPassHost, + ProxyPassPort, + PreserveHostHeader, + AllowedMethods, + CustomConfig, + Enabled, + CreatedAt, + UpdatedAt, +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(Location::Table) + .if_not_exists() + .col(pk_uuid(Location::Id)) + .col(ColumnDef::new(Location::HostId).uuid().not_null()) + .foreign_key( + ForeignKey::create() + .name("fk-location-host-id") + .from(Location::Table, Location::HostId) + .to( + super::m20251223_000006_create_proxy_host_table::ProxyHost::Table, + super::m20251223_000006_create_proxy_host_table::ProxyHost::Id, + ) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .col(ColumnDef::new(Location::Path).string().not_null()) + .col( + ColumnDef::new(Location::MatchType) + .string() + .default("prefix") + .not_null(), + ) + .col(ColumnDef::new(Location::Order).integer().default(0).not_null()) + .col(ColumnDef::new(Location::UpstreamId).uuid().null()) + .foreign_key( + ForeignKey::create() + .name("fk-location-upstream-id") + .from(Location::Table, Location::UpstreamId) + .to( + super::m20251223_000004_create_upstream_table::Upstream::Table, + super::m20251223_000004_create_upstream_table::Upstream::Id, + ) + .on_delete(ForeignKeyAction::SetNull) + .on_update(ForeignKeyAction::Cascade), + ) + .col(ColumnDef::new(Location::ProxyPassHost).string().null()) + .col(ColumnDef::new(Location::ProxyPassPort).integer().null()) + .col(ColumnDef::new(Location::PreserveHostHeader).boolean().null()) + .col(ColumnDef::new(Location::AllowedMethods).json_binary().null()) + .col(ColumnDef::new(Location::CustomConfig).text().null()) + .col( + ColumnDef::new(Location::Enabled) + .boolean() + .default(true) + .not_null(), + ) + .col( + ColumnDef::new(Location::CreatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .col( + ColumnDef::new(Location::UpdatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(Location::Table).to_owned()) + .await + } +} diff --git a/public/migration/src/migrations/m20251223_000008_create_stream_service_table.rs b/public/migration/src/migrations/m20251223_000008_create_stream_service_table.rs new file mode 100644 index 0000000..e99ae60 --- /dev/null +++ b/public/migration/src/migrations/m20251223_000008_create_stream_service_table.rs @@ -0,0 +1,112 @@ +use sea_orm_migration::{prelude::*, schema::*}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[forbid(dead_code)] +#[derive(DeriveIden)] +pub enum StreamService { + Table, + Id, + Name, + ListenHost, + ListenPort, + Protocol, + Mode, + ForwardHost, + ForwardPort, + UpstreamId, + PreservedClientIp, + Enabled, + Meta, + CreatedBy, + CreatedAt, + UpdatedAt, +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(StreamService::Table) + .if_not_exists() + .col(pk_uuid(StreamService::Id)) + .col(ColumnDef::new(StreamService::Name).string().null()) + .col( + ColumnDef::new(StreamService::ListenHost) + .string() + .default("0.0.0.0") + .not_null(), + ) + .col(ColumnDef::new(StreamService::ListenPort).integer().not_null()) + .col(ColumnDef::new(StreamService::Protocol).string().not_null()) + .col( + ColumnDef::new(StreamService::Mode) + .string() + .default("direct") + .not_null(), + ) + .col(ColumnDef::new(StreamService::ForwardHost).string().null()) + .col(ColumnDef::new(StreamService::ForwardPort).integer().null()) + .col(ColumnDef::new(StreamService::UpstreamId).uuid().null()) + .foreign_key( + ForeignKey::create() + .name("fk-stream-service-upstream-id") + .from(StreamService::Table, StreamService::UpstreamId) + .to( + super::m20251223_000004_create_upstream_table::Upstream::Table, + super::m20251223_000004_create_upstream_table::Upstream::Id, + ) + .on_delete(ForeignKeyAction::SetNull) + .on_update(ForeignKeyAction::Cascade), + ) + .col( + ColumnDef::new(StreamService::PreservedClientIp) + .boolean() + .default(false) + .not_null(), + ) + .col( + ColumnDef::new(StreamService::Enabled) + .boolean() + .default(true) + .not_null(), + ) + .col(ColumnDef::new(StreamService::Meta).json_binary().null()) + .col(ColumnDef::new(StreamService::CreatedBy).uuid().null()) + .foreign_key( + ForeignKey::create() + .name("fk-stream-service-created-by") + .from(StreamService::Table, StreamService::CreatedBy) + .to( + super::m20251011_000002_create_user_table::User::Table, + super::m20251011_000002_create_user_table::User::Id, + ) + .on_delete(ForeignKeyAction::SetNull) + .on_update(ForeignKeyAction::Cascade), + ) + .col( + ColumnDef::new(StreamService::CreatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .col( + ColumnDef::new(StreamService::UpdatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(StreamService::Table).to_owned()) + .await + } +} diff --git a/public/migration/src/migrations/m20251223_000009_create_access_list_table.rs b/public/migration/src/migrations/m20251223_000009_create_access_list_table.rs new file mode 100644 index 0000000..7d947b7 --- /dev/null +++ b/public/migration/src/migrations/m20251223_000009_create_access_list_table.rs @@ -0,0 +1,63 @@ +use sea_orm_migration::{prelude::*, schema::*}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[forbid(dead_code)] +#[derive(DeriveIden)] +pub enum AccessList { + Table, + Id, + Name, + Description, + CreatedBy, + CreatedAt, + UpdatedAt, +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(AccessList::Table) + .if_not_exists() + .col(pk_uuid(AccessList::Id)) + .col(ColumnDef::new(AccessList::Name).string().not_null()) + .col(ColumnDef::new(AccessList::Description).text().null()) + .col(ColumnDef::new(AccessList::CreatedBy).uuid().null()) + .foreign_key( + ForeignKey::create() + .name("fk-access-list-created-by") + .from(AccessList::Table, AccessList::CreatedBy) + .to( + super::m20251011_000002_create_user_table::User::Table, + super::m20251011_000002_create_user_table::User::Id, + ) + .on_delete(ForeignKeyAction::SetNull) + .on_update(ForeignKeyAction::Cascade), + ) + .col( + ColumnDef::new(AccessList::CreatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .col( + ColumnDef::new(AccessList::UpdatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(AccessList::Table).to_owned()) + .await + } +} diff --git a/public/migration/src/migrations/m20251223_000010_create_access_list_entry_table.rs b/public/migration/src/migrations/m20251223_000010_create_access_list_entry_table.rs new file mode 100644 index 0000000..2dea34e --- /dev/null +++ b/public/migration/src/migrations/m20251223_000010_create_access_list_entry_table.rs @@ -0,0 +1,58 @@ +use sea_orm_migration::{prelude::*, schema::*}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[forbid(dead_code)] +#[derive(DeriveIden)] +pub enum AccessListEntry { + Table, + Id, + AccessListId, + EntryType, + Value, + Comment, + CreatedAt, +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(AccessListEntry::Table) + .if_not_exists() + .col(pk_uuid(AccessListEntry::Id)) + .col(ColumnDef::new(AccessListEntry::AccessListId).uuid().not_null()) + .foreign_key( + ForeignKey::create() + .name("fk-access-list-entry-access-list-id") + .from(AccessListEntry::Table, AccessListEntry::AccessListId) + .to( + super::m20251223_000009_create_access_list_table::AccessList::Table, + super::m20251223_000009_create_access_list_table::AccessList::Id, + ) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .col(ColumnDef::new(AccessListEntry::EntryType).string().not_null()) + .col(ColumnDef::new(AccessListEntry::Value).string().not_null()) + .col(ColumnDef::new(AccessListEntry::Comment).text().null()) + .col( + ColumnDef::new(AccessListEntry::CreatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(AccessListEntry::Table).to_owned()) + .await + } +} diff --git a/public/migration/src/migrations/m20251223_000011_create_proxy_host_access_list_table.rs b/public/migration/src/migrations/m20251223_000011_create_proxy_host_access_list_table.rs new file mode 100644 index 0000000..27f085e --- /dev/null +++ b/public/migration/src/migrations/m20251223_000011_create_proxy_host_access_list_table.rs @@ -0,0 +1,65 @@ +use sea_orm_migration::{prelude::*, schema::*}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[forbid(dead_code)] +#[derive(DeriveIden)] +pub enum ProxyHostAccessList { + Table, + Id, + ProxyHostId, + AccessListId, + CreatedAt, +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(ProxyHostAccessList::Table) + .if_not_exists() + .col(pk_uuid(ProxyHostAccessList::Id)) + .col(ColumnDef::new(ProxyHostAccessList::ProxyHostId).uuid().not_null()) + .foreign_key( + ForeignKey::create() + .name("fk-proxy-host-access-list-host-id") + .from(ProxyHostAccessList::Table, ProxyHostAccessList::ProxyHostId) + .to( + super::m20251223_000006_create_proxy_host_table::ProxyHost::Table, + super::m20251223_000006_create_proxy_host_table::ProxyHost::Id, + ) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .col(ColumnDef::new(ProxyHostAccessList::AccessListId).uuid().not_null()) + .foreign_key( + ForeignKey::create() + .name("fk-proxy-host-access-list-access-list-id") + .from(ProxyHostAccessList::Table, ProxyHostAccessList::AccessListId) + .to( + super::m20251223_000009_create_access_list_table::AccessList::Table, + super::m20251223_000009_create_access_list_table::AccessList::Id, + ) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .col( + ColumnDef::new(ProxyHostAccessList::CreatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(ProxyHostAccessList::Table).to_owned()) + .await + } +} diff --git a/public/migration/src/migrations/m20251223_000012_create_stream_service_access_list_table.rs b/public/migration/src/migrations/m20251223_000012_create_stream_service_access_list_table.rs new file mode 100644 index 0000000..84d8b41 --- /dev/null +++ b/public/migration/src/migrations/m20251223_000012_create_stream_service_access_list_table.rs @@ -0,0 +1,65 @@ +use sea_orm_migration::{prelude::*, schema::*}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[forbid(dead_code)] +#[derive(DeriveIden)] +pub enum StreamServiceAccessList { + Table, + Id, + StreamServiceId, + AccessListId, + CreatedAt, +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(StreamServiceAccessList::Table) + .if_not_exists() + .col(pk_uuid(StreamServiceAccessList::Id)) + .col(ColumnDef::new(StreamServiceAccessList::StreamServiceId).uuid().not_null()) + .foreign_key( + ForeignKey::create() + .name("fk-stream-service-access-list-service-id") + .from(StreamServiceAccessList::Table, StreamServiceAccessList::StreamServiceId) + .to( + super::m20251223_000008_create_stream_service_table::StreamService::Table, + super::m20251223_000008_create_stream_service_table::StreamService::Id, + ) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .col(ColumnDef::new(StreamServiceAccessList::AccessListId).uuid().not_null()) + .foreign_key( + ForeignKey::create() + .name("fk-stream-service-access-list-access-list-id") + .from(StreamServiceAccessList::Table, StreamServiceAccessList::AccessListId) + .to( + super::m20251223_000009_create_access_list_table::AccessList::Table, + super::m20251223_000009_create_access_list_table::AccessList::Id, + ) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) + .col( + ColumnDef::new(StreamServiceAccessList::CreatedAt) + .timestamp() + .default(SimpleExpr::Keyword(Keyword::CurrentTimestamp)) + .not_null(), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(StreamServiceAccessList::Table).to_owned()) + .await + } +}