feat: Implement database migration framework with initial migrations for organizations, workspaces, agents, virtual hosts, upstreams, certificates, and users
This commit is contained in:
35
Cargo.lock
generated
35
Cargo.lock
generated
@@ -1708,7 +1708,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower-service",
|
||||
"webpki-roots",
|
||||
"webpki-roots 1.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2225,6 +2225,14 @@ version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "migration"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"sea-orm-migration",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
@@ -2480,11 +2488,12 @@ dependencies = [
|
||||
"handlebars",
|
||||
"hex",
|
||||
"jsonwebtoken",
|
||||
"migration",
|
||||
"mockall",
|
||||
"nxmesh-core",
|
||||
"nxmesh-proto",
|
||||
"sea-orm",
|
||||
"sea-orm-migration 2.0.0-rc.35",
|
||||
"sea-orm-migration",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
@@ -3272,7 +3281,7 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"webpki-roots",
|
||||
"webpki-roots 1.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3593,15 +3602,6 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sea-orm-migration"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"sea-orm",
|
||||
"sea-orm-migration 2.0.0-rc.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sea-orm-migration"
|
||||
version = "2.0.0-rc.35"
|
||||
@@ -3961,6 +3961,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"rust_decimal",
|
||||
"rustls",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
@@ -3972,6 +3973,7 @@ dependencies = [
|
||||
"tracing",
|
||||
"url",
|
||||
"uuid",
|
||||
"webpki-roots 0.26.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5075,6 +5077,15 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.26.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
|
||||
dependencies = [
|
||||
"webpki-roots 1.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "1.0.6"
|
||||
|
||||
12
Cargo.toml
12
Cargo.toml
@@ -5,7 +5,7 @@ members = [
|
||||
"crates/nxmesh-master",
|
||||
"crates/nxmesh-agent",
|
||||
"crates/nxmesh-cli",
|
||||
"migrations/sea-orm",
|
||||
"migration",
|
||||
]
|
||||
resolver = "3"
|
||||
|
||||
@@ -36,7 +36,10 @@ tonic = "0.11"
|
||||
prost = "0.12"
|
||||
|
||||
# Database
|
||||
sea-orm = { version = "2.0.0-rc", features = ["sqlx-postgres", "runtime-tokio-native-tls"] }
|
||||
sea-orm = { version = "2.0.0-rc", features = [
|
||||
"sqlx-postgres",
|
||||
"runtime-tokio-native-tls",
|
||||
] }
|
||||
sea-orm-migration = "2.0.0-rc"
|
||||
|
||||
# Async
|
||||
@@ -48,7 +51,10 @@ toml = "0.8"
|
||||
config = "0.14"
|
||||
|
||||
# HTTP client
|
||||
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] }
|
||||
reqwest = { version = "0.12", default-features = false, features = [
|
||||
"rustls-tls",
|
||||
"json",
|
||||
] }
|
||||
|
||||
# Crypto
|
||||
sha2 = "0.10"
|
||||
|
||||
@@ -173,10 +173,9 @@ nxmesh/
|
||||
│ # Build output (dist/) is embedded into master binary
|
||||
│ # Master serves static files at root path ("/")
|
||||
│
|
||||
├── migrations/ # Database migrations
|
||||
│ └── sea-orm/
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
├── migration/ # Database migrations
|
||||
│ ├── Cargo.toml
|
||||
│ └── src/
|
||||
│
|
||||
├── tests/ # Integration tests
|
||||
│ ├── integration/
|
||||
|
||||
52
justfile
52
justfile
@@ -102,8 +102,8 @@ db-migrate:
|
||||
|
||||
# Create new database migration
|
||||
db-new-migration name:
|
||||
@echo "📝 Creating new migration: {{name}}"
|
||||
sea-orm-cli migrate generate {{name}}
|
||||
@echo "📝 Creating new migration: {{ name }}"
|
||||
sea-orm-cli migrate generate {{ name }}
|
||||
|
||||
# Reset database (drop and recreate)
|
||||
db-reset:
|
||||
@@ -115,6 +115,17 @@ db-console:
|
||||
@echo "🐘 Connecting to PostgreSQL..."
|
||||
psql $DATABASE_URL
|
||||
|
||||
# Generate SeaORM entities from database schema
|
||||
db-generate:
|
||||
@echo "⚙️ Generating SeaORM entities from database..."
|
||||
sea-orm-cli generate entity \
|
||||
--database-url $DATABASE_URL \
|
||||
--output-dir crates/nxmesh-master/src/db/entities \
|
||||
--with-serde both \
|
||||
--with-copy-enums \
|
||||
--date-time-crate chrono
|
||||
@echo "✅ Entities generated at crates/nxmesh-master/src/db/entities/"
|
||||
|
||||
# =============================================================================
|
||||
# Testing Commands
|
||||
# =============================================================================
|
||||
@@ -195,9 +206,10 @@ nginx-reload:
|
||||
bash .devcontainer/scripts/nginx-reload.sh
|
||||
|
||||
# Full nginx control via shared PID namespace
|
||||
|
||||
# Usage: just nginx-ctl <reload|stop|quit|reopen|upgrade|status>
|
||||
nginx-ctl cmd="reload":
|
||||
@bash .devcontainer/scripts/nginx-ctl.sh {{cmd}}
|
||||
@bash .devcontainer/scripts/nginx-ctl.sh {{ cmd }}
|
||||
|
||||
# Quick status check
|
||||
nginx-status:
|
||||
@@ -264,3 +276,37 @@ logs:
|
||||
docs:
|
||||
@echo "📚 Generating documentation..."
|
||||
cargo doc --open 2>/dev/null || cargo doc
|
||||
|
||||
# =============================================================================
|
||||
# API Client Generation Commands
|
||||
# =============================================================================
|
||||
|
||||
# Generate OpenAPI spec from backend (requires backend to be running)
|
||||
gen-openapi:
|
||||
@echo "📋 Generating OpenAPI spec from backend..."
|
||||
@curl -s http://localhost:8080/api/openapi.json > /tmp/openapi.json
|
||||
@echo "✅ OpenAPI spec saved to /tmp/openapi.json"
|
||||
|
||||
# Generate TypeScript API client from OpenAPI spec
|
||||
gen-api-client:
|
||||
@echo "⚡ Generating TypeScript API client..."
|
||||
@if [ ! -f /tmp/openapi.json ]; then \
|
||||
echo "❌ OpenAPI spec not found. Run 'just gen-openapi' first (backend must be running)."; \
|
||||
exit 1; \
|
||||
fi
|
||||
cd frontend && bunx openapi-typescript /tmp/openapi.json -o src/api/schema.ts
|
||||
@echo "✅ API client generated at frontend/src/api/schema.ts"
|
||||
|
||||
# Full API generation workflow (start backend, generate spec, generate client, stop backend)
|
||||
gen-api: start-backend-temp
|
||||
@just gen-openapi
|
||||
@just gen-api-client
|
||||
@echo "✅ API client generation complete!"
|
||||
|
||||
# Internal: Start backend temporarily for API generation
|
||||
start-backend-temp:
|
||||
@echo "🔧 Starting backend temporarily..."
|
||||
@cargo build --package nxmesh-master
|
||||
@cargo run --package nxmesh-master &
|
||||
@sleep 5
|
||||
@echo "✅ Backend ready"
|
||||
|
||||
19
migration/Cargo.toml
Normal file
19
migration/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "migration"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "migration"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
async-std = { version = "1", features = ["attributes", "tokio1"] }
|
||||
|
||||
[dependencies.sea-orm-migration]
|
||||
version = "2.0.0-rc"
|
||||
features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlx-postgres",
|
||||
]
|
||||
41
migration/README.md
Normal file
41
migration/README.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Running Migrator CLI
|
||||
|
||||
- Generate a new migration file
|
||||
```sh
|
||||
cargo run -- generate MIGRATION_NAME
|
||||
```
|
||||
- Apply all pending migrations
|
||||
```sh
|
||||
cargo run
|
||||
```
|
||||
```sh
|
||||
cargo run -- up
|
||||
```
|
||||
- Apply first 10 pending migrations
|
||||
```sh
|
||||
cargo run -- up -n 10
|
||||
```
|
||||
- Rollback last applied migrations
|
||||
```sh
|
||||
cargo run -- down
|
||||
```
|
||||
- Rollback last 10 applied migrations
|
||||
```sh
|
||||
cargo run -- down -n 10
|
||||
```
|
||||
- Drop all tables from the database, then reapply all migrations
|
||||
```sh
|
||||
cargo run -- fresh
|
||||
```
|
||||
- Rollback all applied migrations, then reapply all migrations
|
||||
```sh
|
||||
cargo run -- refresh
|
||||
```
|
||||
- Rollback all applied migrations
|
||||
```sh
|
||||
cargo run -- reset
|
||||
```
|
||||
- Check the status of all migrations
|
||||
```sh
|
||||
cargo run -- status
|
||||
```
|
||||
26
migration/src/lib.rs
Normal file
26
migration/src/lib.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
pub use sea_orm_migration::prelude::*;
|
||||
|
||||
mod m20240301_000001_create_organizations;
|
||||
mod m20240301_000002_create_workspaces;
|
||||
mod m20240301_000003_create_agents;
|
||||
mod m20240301_000004_create_virtual_hosts;
|
||||
mod m20240301_000005_create_upstreams;
|
||||
mod m20240301_000006_create_certificates;
|
||||
mod m20240301_000007_create_users;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigratorTrait for Migrator {
|
||||
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||
vec![
|
||||
Box::new(m20240301_000001_create_organizations::Migration),
|
||||
Box::new(m20240301_000002_create_workspaces::Migration),
|
||||
Box::new(m20240301_000003_create_agents::Migration),
|
||||
Box::new(m20240301_000004_create_virtual_hosts::Migration),
|
||||
Box::new(m20240301_000005_create_upstreams::Migration),
|
||||
Box::new(m20240301_000006_create_certificates::Migration),
|
||||
Box::new(m20240301_000007_create_users::Migration),
|
||||
]
|
||||
}
|
||||
}
|
||||
59
migration/src/m20240301_000001_create_organizations.rs
Normal file
59
migration/src/m20240301_000001_create_organizations.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Organizations::Table)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Organizations::Id)
|
||||
.uuid()
|
||||
.not_null()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(Organizations::Name).string().not_null())
|
||||
.col(
|
||||
ColumnDef::new(Organizations::Slug)
|
||||
.string()
|
||||
.not_null()
|
||||
.unique_key(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Organizations::CreatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Organizations::UpdatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.col(ColumnDef::new(Organizations::Settings).json())
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(Organizations::Table).to_owned())
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Organizations {
|
||||
Table,
|
||||
Id,
|
||||
Name,
|
||||
Slug,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
Settings,
|
||||
}
|
||||
88
migration/src/m20240301_000002_create_workspaces.rs
Normal file
88
migration/src/m20240301_000002_create_workspaces.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Workspaces::Table)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Workspaces::Id)
|
||||
.uuid()
|
||||
.not_null()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Workspaces::OrganizationId)
|
||||
.uuid()
|
||||
.not_null(),
|
||||
)
|
||||
.col(ColumnDef::new(Workspaces::Name).string().not_null())
|
||||
.col(
|
||||
ColumnDef::new(Workspaces::Slug)
|
||||
.string()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Workspaces::CreatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Workspaces::UpdatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_workspace_organization")
|
||||
.from(Workspaces::Table, Workspaces::OrganizationId)
|
||||
.to(Organizations::Table, Organizations::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Create unique index on organization_id + slug
|
||||
manager
|
||||
.create_index(
|
||||
Index::create()
|
||||
.unique()
|
||||
.name("idx_workspaces_org_slug")
|
||||
.table(Workspaces::Table)
|
||||
.col(Workspaces::OrganizationId)
|
||||
.col(Workspaces::Slug)
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(Workspaces::Table).to_owned())
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Workspaces {
|
||||
Table,
|
||||
Id,
|
||||
OrganizationId,
|
||||
Name,
|
||||
Slug,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Organizations {
|
||||
Table,
|
||||
Id,
|
||||
}
|
||||
90
migration/src/m20240301_000003_create_agents.rs
Normal file
90
migration/src/m20240301_000003_create_agents.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Agents::Table)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Agents::Id)
|
||||
.uuid()
|
||||
.not_null()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Agents::WorkspaceId)
|
||||
.uuid()
|
||||
.not_null(),
|
||||
)
|
||||
.col(ColumnDef::new(Agents::Name).string().not_null())
|
||||
.col(ColumnDef::new(Agents::Hostname).string().not_null())
|
||||
.col(ColumnDef::new(Agents::IpAddress).string())
|
||||
.col(ColumnDef::new(Agents::Version).string())
|
||||
.col(ColumnDef::new(Agents::State).string().not_null())
|
||||
.col(ColumnDef::new(Agents::DeploymentMode).string())
|
||||
.col(
|
||||
ColumnDef::new(Agents::LastSeenAt)
|
||||
.timestamp_with_time_zone(),
|
||||
)
|
||||
.col(ColumnDef::new(Agents::Capabilities).json())
|
||||
.col(ColumnDef::new(Agents::Labels).json())
|
||||
.col(ColumnDef::new(Agents::TokenHash).string())
|
||||
.col(
|
||||
ColumnDef::new(Agents::CreatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Agents::UpdatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_agent_workspace")
|
||||
.from(Agents::Table, Agents::WorkspaceId)
|
||||
.to(Workspaces::Table, Workspaces::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(Agents::Table).to_owned())
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Agents {
|
||||
Table,
|
||||
Id,
|
||||
WorkspaceId,
|
||||
Name,
|
||||
Hostname,
|
||||
IpAddress,
|
||||
Version,
|
||||
State,
|
||||
DeploymentMode,
|
||||
LastSeenAt,
|
||||
Capabilities,
|
||||
Labels,
|
||||
TokenHash,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Workspaces {
|
||||
Table,
|
||||
Id,
|
||||
}
|
||||
115
migration/src/m20240301_000004_create_virtual_hosts.rs
Normal file
115
migration/src/m20240301_000004_create_virtual_hosts.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(VirtualHosts::Table)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(VirtualHosts::Id)
|
||||
.uuid()
|
||||
.not_null()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(VirtualHosts::WorkspaceId)
|
||||
.uuid()
|
||||
.not_null(),
|
||||
)
|
||||
.col(ColumnDef::new(VirtualHosts::Name).string().not_null())
|
||||
.col(
|
||||
ColumnDef::new(VirtualHosts::ServerName)
|
||||
.string()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(VirtualHosts::ListenPort)
|
||||
.integer()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(VirtualHosts::SslEnabled)
|
||||
.boolean()
|
||||
.not_null()
|
||||
.default(false),
|
||||
)
|
||||
.col(ColumnDef::new(VirtualHosts::SslCertificateId).uuid())
|
||||
.col(ColumnDef::new(VirtualHosts::Locations).json())
|
||||
.col(
|
||||
ColumnDef::new(VirtualHosts::Http2Enabled)
|
||||
.boolean()
|
||||
.not_null()
|
||||
.default(false),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(VirtualHosts::Http3Enabled)
|
||||
.boolean()
|
||||
.not_null()
|
||||
.default(false),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(VirtualHosts::GzipEnabled)
|
||||
.boolean()
|
||||
.not_null()
|
||||
.default(true),
|
||||
)
|
||||
.col(ColumnDef::new(VirtualHosts::TargetAgents).json())
|
||||
.col(
|
||||
ColumnDef::new(VirtualHosts::CreatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(VirtualHosts::UpdatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_vh_workspace")
|
||||
.from(VirtualHosts::Table, VirtualHosts::WorkspaceId)
|
||||
.to(Workspaces::Table, Workspaces::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(VirtualHosts::Table).to_owned())
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum VirtualHosts {
|
||||
Table,
|
||||
Id,
|
||||
WorkspaceId,
|
||||
Name,
|
||||
ServerName,
|
||||
ListenPort,
|
||||
SslEnabled,
|
||||
SslCertificateId,
|
||||
Locations,
|
||||
Http2Enabled,
|
||||
Http3Enabled,
|
||||
GzipEnabled,
|
||||
TargetAgents,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Workspaces {
|
||||
Table,
|
||||
Id,
|
||||
}
|
||||
83
migration/src/m20240301_000005_create_upstreams.rs
Normal file
83
migration/src/m20240301_000005_create_upstreams.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Upstreams::Table)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Upstreams::Id)
|
||||
.uuid()
|
||||
.not_null()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Upstreams::WorkspaceId)
|
||||
.uuid()
|
||||
.not_null(),
|
||||
)
|
||||
.col(ColumnDef::new(Upstreams::Name).string().not_null())
|
||||
.col(
|
||||
ColumnDef::new(Upstreams::Algorithm)
|
||||
.string()
|
||||
.not_null(),
|
||||
)
|
||||
.col(ColumnDef::new(Upstreams::Servers).json())
|
||||
.col(ColumnDef::new(Upstreams::HealthCheck).json())
|
||||
.col(ColumnDef::new(Upstreams::KeepaliveConnections).integer())
|
||||
.col(ColumnDef::new(Upstreams::KeepaliveTimeout).integer())
|
||||
.col(
|
||||
ColumnDef::new(Upstreams::CreatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Upstreams::UpdatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_upstream_workspace")
|
||||
.from(Upstreams::Table, Upstreams::WorkspaceId)
|
||||
.to(Workspaces::Table, Workspaces::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(Upstreams::Table).to_owned())
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Upstreams {
|
||||
Table,
|
||||
Id,
|
||||
WorkspaceId,
|
||||
Name,
|
||||
Algorithm,
|
||||
Servers,
|
||||
HealthCheck,
|
||||
KeepaliveConnections,
|
||||
KeepaliveTimeout,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Workspaces {
|
||||
Table,
|
||||
Id,
|
||||
}
|
||||
99
migration/src/m20240301_000006_create_certificates.rs
Normal file
99
migration/src/m20240301_000006_create_certificates.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Certificates::Table)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Certificates::Id)
|
||||
.uuid()
|
||||
.not_null()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Certificates::WorkspaceId)
|
||||
.uuid()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Certificates::Domain)
|
||||
.string()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Certificates::IsWildcard)
|
||||
.boolean()
|
||||
.not_null()
|
||||
.default(false),
|
||||
)
|
||||
.col(ColumnDef::new(Certificates::Provider).string())
|
||||
.col(ColumnDef::new(Certificates::Status).string())
|
||||
.col(ColumnDef::new(Certificates::IssuedAt).timestamp_with_time_zone())
|
||||
.col(ColumnDef::new(Certificates::ExpiresAt).timestamp_with_time_zone())
|
||||
.col(
|
||||
ColumnDef::new(Certificates::AutoRenew)
|
||||
.boolean()
|
||||
.not_null()
|
||||
.default(true),
|
||||
)
|
||||
.col(ColumnDef::new(Certificates::CertificatePem).text())
|
||||
.col(ColumnDef::new(Certificates::PrivateKeyPem).text())
|
||||
.col(
|
||||
ColumnDef::new(Certificates::CreatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Certificates::UpdatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_certificate_workspace")
|
||||
.from(Certificates::Table, Certificates::WorkspaceId)
|
||||
.to(Workspaces::Table, Workspaces::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(Certificates::Table).to_owned())
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Certificates {
|
||||
Table,
|
||||
Id,
|
||||
WorkspaceId,
|
||||
Domain,
|
||||
IsWildcard,
|
||||
Provider,
|
||||
Status,
|
||||
IssuedAt,
|
||||
ExpiresAt,
|
||||
AutoRenew,
|
||||
CertificatePem,
|
||||
PrivateKeyPem,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Workspaces {
|
||||
Table,
|
||||
Id,
|
||||
}
|
||||
74
migration/src/m20240301_000007_create_users.rs
Normal file
74
migration/src/m20240301_000007_create_users.rs
Normal file
@@ -0,0 +1,74 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Users::Table)
|
||||
.if_not_exists()
|
||||
.col(
|
||||
ColumnDef::new(Users::Id)
|
||||
.uuid()
|
||||
.not_null()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(Users::Email).string().not_null().unique_key())
|
||||
.col(ColumnDef::new(Users::PasswordHash).string().not_null())
|
||||
.col(ColumnDef::new(Users::Name).string())
|
||||
.col(ColumnDef::new(Users::Role).string().not_null())
|
||||
.col(
|
||||
ColumnDef::new(Users::OrganizationId)
|
||||
.uuid(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Users::CreatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.col(
|
||||
ColumnDef::new(Users::UpdatedAt)
|
||||
.timestamp_with_time_zone()
|
||||
.not_null(),
|
||||
)
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk_user_organization")
|
||||
.from(Users::Table, Users::OrganizationId)
|
||||
.to(Organizations::Table, Organizations::Id)
|
||||
.on_delete(ForeignKeyAction::SetNull),
|
||||
)
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(Users::Table).to_owned())
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Users {
|
||||
Table,
|
||||
Id,
|
||||
Email,
|
||||
PasswordHash,
|
||||
Name,
|
||||
Role,
|
||||
OrganizationId,
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
}
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
enum Organizations {
|
||||
Table,
|
||||
Id,
|
||||
}
|
||||
6
migration/src/main.rs
Normal file
6
migration/src/main.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
cli::run_cli(migration::Migrator).await;
|
||||
}
|
||||
Reference in New Issue
Block a user