fix(db): resolve migration bugs preventing fresh database initialization

- Fix composite primary keys in role_permissions and user_roles tables
  (PostgreSQL does not allow multiple PRIMARY KEY constraints)
- Fix FK table name mismatch: tasks → tokens (was wf_tokens)
- Fix FK table name mismatch: messages → message_templates (was message_templates_ref)
- Fix tenant table name in main.rs SQL: tenant (not tenants)
- Fix React Router nested routes: add /* wildcard for child route matching
This commit is contained in:
iven
2026-04-12 16:58:47 +08:00
parent 3b41e73f82
commit 9557c9ca16
6 changed files with 21 additions and 31 deletions

View File

@@ -39,7 +39,7 @@ export default function App() {
<Routes> <Routes>
<Route path="/login" element={<Login />} /> <Route path="/login" element={<Login />} />
<Route <Route
path="/" path="/*"
element={ element={
<PrivateRoute> <PrivateRoute>
<MainLayout> <MainLayout>

View File

@@ -11,18 +11,8 @@ impl MigrationTrait for Migration {
Table::create() Table::create()
.table(RolePermissions::Table) .table(RolePermissions::Table)
.if_not_exists() .if_not_exists()
.col( .col(ColumnDef::new(RolePermissions::RoleId).uuid().not_null())
ColumnDef::new(RolePermissions::RoleId) .col(ColumnDef::new(RolePermissions::PermissionId).uuid().not_null())
.uuid()
.not_null()
.primary_key(),
)
.col(
ColumnDef::new(RolePermissions::PermissionId)
.uuid()
.not_null()
.primary_key(),
)
.col(ColumnDef::new(RolePermissions::TenantId).uuid().not_null()) .col(ColumnDef::new(RolePermissions::TenantId).uuid().not_null())
.col( .col(
ColumnDef::new(RolePermissions::CreatedAt) ColumnDef::new(RolePermissions::CreatedAt)
@@ -49,6 +39,11 @@ impl MigrationTrait for Migration {
.not_null() .not_null()
.default(1), .default(1),
) )
.primary_key(
Index::create()
.col(RolePermissions::RoleId)
.col(RolePermissions::PermissionId),
)
.foreign_key( .foreign_key(
&mut ForeignKey::create() &mut ForeignKey::create()
.name("fk_role_permissions_role_id") .name("fk_role_permissions_role_id")

View File

@@ -11,18 +11,8 @@ impl MigrationTrait for Migration {
Table::create() Table::create()
.table(UserRoles::Table) .table(UserRoles::Table)
.if_not_exists() .if_not_exists()
.col( .col(ColumnDef::new(UserRoles::UserId).uuid().not_null())
ColumnDef::new(UserRoles::UserId) .col(ColumnDef::new(UserRoles::RoleId).uuid().not_null())
.uuid()
.not_null()
.primary_key(),
)
.col(
ColumnDef::new(UserRoles::RoleId)
.uuid()
.not_null()
.primary_key(),
)
.col(ColumnDef::new(UserRoles::TenantId).uuid().not_null()) .col(ColumnDef::new(UserRoles::TenantId).uuid().not_null())
.col( .col(
ColumnDef::new(UserRoles::CreatedAt) ColumnDef::new(UserRoles::CreatedAt)
@@ -49,6 +39,11 @@ impl MigrationTrait for Migration {
.not_null() .not_null()
.default(1), .default(1),
) )
.primary_key(
Index::create()
.col(UserRoles::UserId)
.col(UserRoles::RoleId),
)
.foreign_key( .foreign_key(
&mut ForeignKey::create() &mut ForeignKey::create()
.name("fk_user_roles_user_id") .name("fk_user_roles_user_id")

View File

@@ -108,7 +108,7 @@ impl MigrationTrait for Migration {
ForeignKey::create() ForeignKey::create()
.name("fk_tasks_token") .name("fk_tasks_token")
.from(Tasks::Table, Tasks::TokenId) .from(Tasks::Table, Tasks::TokenId)
.to(WfTokens::Table, WfTokens::Id) .to(Tokens::Table, Tokens::Id)
.to_owned(), .to_owned(),
) )
.await?; .await?;
@@ -154,7 +154,7 @@ enum ProcessInstances {
} }
#[derive(DeriveIden)] #[derive(DeriveIden)]
enum WfTokens { enum Tokens {
Table, Table,
Id, Id,
} }

View File

@@ -93,7 +93,7 @@ impl MigrationTrait for Migration {
ForeignKey::create() ForeignKey::create()
.name("fk_messages_template") .name("fk_messages_template")
.from(Messages::Table, Messages::TemplateId) .from(Messages::Table, Messages::TemplateId)
.to(MessageTemplatesRef::Table, MessageTemplatesRef::Id) .to(MessageTemplates::Table, MessageTemplates::Id)
.to_owned(), .to_owned(),
) )
.await?; .await?;
@@ -137,7 +137,7 @@ enum Messages {
} }
#[derive(DeriveIden)] #[derive(DeriveIden)]
enum MessageTemplatesRef { enum MessageTemplates {
Table, Table,
Id, Id,
} }

View File

@@ -62,7 +62,7 @@ async fn main() -> anyhow::Result<()> {
let existing = TenantId::find_by_statement(sea_orm::Statement::from_string( let existing = TenantId::find_by_statement(sea_orm::Statement::from_string(
sea_orm::DatabaseBackend::Postgres, sea_orm::DatabaseBackend::Postgres,
"SELECT id FROM tenants WHERE deleted_at IS NULL LIMIT 1".to_string(), "SELECT id FROM tenant WHERE deleted_at IS NULL LIMIT 1".to_string(),
)) ))
.one(&db) .one(&db)
.await .await
@@ -79,7 +79,7 @@ async fn main() -> anyhow::Result<()> {
// Insert default tenant using raw SQL (no tenant entity in erp-server) // Insert default tenant using raw SQL (no tenant entity in erp-server)
db.execute(sea_orm::Statement::from_sql_and_values( db.execute(sea_orm::Statement::from_sql_and_values(
sea_orm::DatabaseBackend::Postgres, sea_orm::DatabaseBackend::Postgres,
"INSERT INTO tenants (id, name, code, status, created_at, updated_at) VALUES ($1, $2, $3, $4, NOW(), NOW())", "INSERT INTO tenant (id, name, code, status, created_at, updated_at) VALUES ($1, $2, $3, $4, NOW(), NOW())",
[ [
new_tenant_id.into(), new_tenant_id.into(),
"Default Tenant".into(), "Default Tenant".into(),