feat: initial commit - Phase 1 & 2 core features

This commit is contained in:
hiderfong
2026-04-22 17:07:33 +08:00
commit 1773bda06b
25005 changed files with 6252106 additions and 0 deletions
View File
+45
View File
@@ -0,0 +1,45 @@
from logging.config import fileConfig
from sqlalchemy import engine_from_config, pool
from alembic import context
from app.core.database import Base
from app.core.config import settings
from app.models import *
config = context.config
config.set_main_option("sqlalchemy.url", settings.DATABASE_URL)
if config.config_file_name is not None:
fileConfig(config.config_file_name)
target_metadata = Base.metadata
def run_migrations_offline() -> None:
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online() -> None:
connectable = engine_from_config(
config.get_section(config.config_ini_section, {}),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(connection=connection, target_metadata=target_metadata)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
+26
View File
@@ -0,0 +1,26 @@
"""${message}
Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}
# revision identifiers, used by Alembic.
revision: str = ${repr(up_revision)}
down_revision: Union[str, None] = ${repr(down_revision)}
branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
def upgrade() -> None:
${upgrades if upgrades else "pass"}
def downgrade() -> None:
${downgrades if downgrades else "pass"}
+303
View File
@@ -0,0 +1,303 @@
"""Initial migration
Revision ID: 001
Revises:
Create Date: 2024-01-01 00:00:00.000000
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = "001"
down_revision: Union[str, None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# sys_dept
op.create_table(
"sys_dept",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("name", sa.String(100), nullable=False),
sa.Column("parent_id", sa.Integer(), sa.ForeignKey("sys_dept.id"), nullable=True),
sa.Column("sort_order", sa.Integer(), default=0),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
)
# sys_role
op.create_table(
"sys_role",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("name", sa.String(50), unique=True, nullable=False),
sa.Column("code", sa.String(50), unique=True, nullable=False),
sa.Column("description", sa.String(200)),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
)
# sys_user
op.create_table(
"sys_user",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("username", sa.String(50), unique=True, nullable=False, index=True),
sa.Column("email", sa.String(100), unique=True, nullable=True),
sa.Column("hashed_password", sa.String(255), nullable=False),
sa.Column("real_name", sa.String(50)),
sa.Column("phone", sa.String(20)),
sa.Column("is_active", sa.Boolean(), default=True),
sa.Column("is_superuser", sa.Boolean(), default=False),
sa.Column("dept_id", sa.Integer(), sa.ForeignKey("sys_dept.id"), nullable=True),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
sa.Column("updated_at", sa.DateTime(), default=sa.func.now(), onupdate=sa.func.now()),
)
# sys_user_role
op.create_table(
"sys_user_role",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("user_id", sa.Integer(), sa.ForeignKey("sys_user.id"), nullable=False),
sa.Column("role_id", sa.Integer(), sa.ForeignKey("sys_role.id"), nullable=False),
)
# data_source
op.create_table(
"data_source",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("name", sa.String(100), nullable=False),
sa.Column("source_type", sa.String(50), nullable=False),
sa.Column("host", sa.String(200)),
sa.Column("port", sa.Integer()),
sa.Column("database_name", sa.String(100)),
sa.Column("username", sa.String(100)),
sa.Column("encrypted_password", sa.Text()),
sa.Column("extra_params", sa.Text()),
sa.Column("status", sa.String(20), default="active"),
sa.Column("dept_id", sa.Integer(), sa.ForeignKey("sys_dept.id"), nullable=True),
sa.Column("created_by", sa.Integer(), sa.ForeignKey("sys_user.id")),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
sa.Column("updated_at", sa.DateTime(), default=sa.func.now(), onupdate=sa.func.now()),
)
# meta_database
op.create_table(
"meta_database",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("source_id", sa.Integer(), sa.ForeignKey("data_source.id"), nullable=False),
sa.Column("name", sa.String(100), nullable=False),
sa.Column("charset", sa.String(50)),
sa.Column("table_count", sa.Integer(), default=0),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
)
# meta_table
op.create_table(
"meta_table",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("database_id", sa.Integer(), sa.ForeignKey("meta_database.id"), nullable=False),
sa.Column("name", sa.String(200), nullable=False),
sa.Column("comment", sa.String(500)),
sa.Column("row_count", sa.BigInteger(), default=0),
sa.Column("column_count", sa.Integer(), default=0),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
)
# meta_column
op.create_table(
"meta_column",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("table_id", sa.Integer(), sa.ForeignKey("meta_table.id"), nullable=False),
sa.Column("name", sa.String(200), nullable=False),
sa.Column("data_type", sa.String(100)),
sa.Column("length", sa.Integer()),
sa.Column("comment", sa.String(500)),
sa.Column("is_nullable", sa.Boolean(), default=True),
sa.Column("sample_data", sa.Text()),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
)
# unstructured_file
op.create_table(
"unstructured_file",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("original_name", sa.String(255), nullable=False),
sa.Column("file_type", sa.String(50)),
sa.Column("file_size", sa.BigInteger()),
sa.Column("storage_path", sa.String(500)),
sa.Column("extracted_text", sa.Text()),
sa.Column("status", sa.String(20), default="pending"),
sa.Column("created_by", sa.Integer(), sa.ForeignKey("sys_user.id")),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
)
# category
op.create_table(
"category",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("parent_id", sa.Integer(), sa.ForeignKey("category.id"), nullable=True),
sa.Column("level", sa.Integer(), default=1),
sa.Column("code", sa.String(50), unique=True, nullable=False),
sa.Column("name", sa.String(100), nullable=False),
sa.Column("description", sa.Text()),
sa.Column("sort_order", sa.Integer(), default=0),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
)
# data_level
op.create_table(
"data_level",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("code", sa.String(20), unique=True, nullable=False),
sa.Column("name", sa.String(50), nullable=False),
sa.Column("description", sa.Text()),
sa.Column("color", sa.String(20), default="#999999"),
sa.Column("control_requirements", sa.JSON()),
sa.Column("sort_order", sa.Integer(), default=0),
)
# classification_template
op.create_table(
"classification_template",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("name", sa.String(100), nullable=False),
sa.Column("industry_type", sa.String(50), default="insurance_property"),
sa.Column("version", sa.String(20), default="1.0"),
sa.Column("description", sa.Text()),
sa.Column("is_builtin", sa.Boolean(), default=False),
sa.Column("is_active", sa.Boolean(), default=True),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
)
# recognition_rule
op.create_table(
"recognition_rule",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("template_id", sa.Integer(), sa.ForeignKey("classification_template.id"), nullable=False),
sa.Column("category_id", sa.Integer(), sa.ForeignKey("category.id"), nullable=True),
sa.Column("level_id", sa.Integer(), sa.ForeignKey("data_level.id"), nullable=True),
sa.Column("rule_type", sa.String(20), nullable=False),
sa.Column("rule_name", sa.String(100)),
sa.Column("rule_content", sa.Text(), nullable=False),
sa.Column("target_field", sa.String(20), default="column_name"),
sa.Column("priority", sa.Integer(), default=100),
sa.Column("hit_count", sa.Integer(), default=0),
sa.Column("is_active", sa.Boolean(), default=True),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
)
# classification_project
op.create_table(
"classification_project",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("name", sa.String(200), nullable=False),
sa.Column("template_id", sa.Integer(), sa.ForeignKey("classification_template.id")),
sa.Column("description", sa.Text()),
sa.Column("status", sa.String(20), default="created"),
sa.Column("target_source_ids", sa.Text()),
sa.Column("target_database_ids", sa.Text()),
sa.Column("target_table_ids", sa.Text()),
sa.Column("planned_start", sa.DateTime()),
sa.Column("planned_end", sa.DateTime()),
sa.Column("created_by", sa.Integer(), sa.ForeignKey("sys_user.id"), nullable=False),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
sa.Column("updated_at", sa.DateTime(), default=sa.func.now(), onupdate=sa.func.now()),
)
# classification_task
op.create_table(
"classification_task",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("project_id", sa.Integer(), sa.ForeignKey("classification_project.id"), nullable=False),
sa.Column("name", sa.String(200)),
sa.Column("assigner_id", sa.Integer(), sa.ForeignKey("sys_user.id")),
sa.Column("assignee_id", sa.Integer(), sa.ForeignKey("sys_user.id")),
sa.Column("target_type", sa.String(20), default="table"),
sa.Column("target_ids", sa.Text()),
sa.Column("status", sa.String(20), default="pending"),
sa.Column("deadline", sa.DateTime()),
sa.Column("completed_at", sa.DateTime()),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
)
# classification_result
op.create_table(
"classification_result",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("project_id", sa.Integer(), sa.ForeignKey("classification_project.id"), nullable=False),
sa.Column("column_id", sa.Integer(), sa.ForeignKey("meta_column.id"), nullable=True),
sa.Column("file_id", sa.Integer(), sa.ForeignKey("unstructured_file.id"), nullable=True),
sa.Column("category_id", sa.Integer(), sa.ForeignKey("category.id")),
sa.Column("level_id", sa.Integer(), sa.ForeignKey("data_level.id")),
sa.Column("source", sa.String(20), default="auto"),
sa.Column("confidence", sa.Float(), default=0.0),
sa.Column("labeler_id", sa.Integer(), sa.ForeignKey("sys_user.id")),
sa.Column("reviewer_id", sa.Integer(), sa.ForeignKey("sys_user.id")),
sa.Column("status", sa.String(20), default="auto"),
sa.Column("label_time", sa.DateTime()),
sa.Column("review_time", sa.DateTime()),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
sa.Column("updated_at", sa.DateTime(), default=sa.func.now(), onupdate=sa.func.now()),
)
# classification_change
op.create_table(
"classification_change",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("result_id", sa.Integer(), sa.ForeignKey("classification_result.id"), nullable=False),
sa.Column("change_type", sa.String(20), nullable=False),
sa.Column("old_category_id", sa.Integer(), sa.ForeignKey("category.id")),
sa.Column("new_category_id", sa.Integer(), sa.ForeignKey("category.id")),
sa.Column("old_level_id", sa.Integer(), sa.ForeignKey("data_level.id")),
sa.Column("new_level_id", sa.Integer(), sa.ForeignKey("data_level.id")),
sa.Column("reason", sa.Text()),
sa.Column("applicant_id", sa.Integer(), sa.ForeignKey("sys_user.id")),
sa.Column("approver_id", sa.Integer(), sa.ForeignKey("sys_user.id")),
sa.Column("approval_status", sa.String(20), default="pending"),
sa.Column("approval_comment", sa.Text()),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
)
# sys_operation_log
op.create_table(
"sys_operation_log",
sa.Column("id", sa.Integer(), primary_key=True, index=True),
sa.Column("user_id", sa.Integer(), sa.ForeignKey("sys_user.id"), nullable=True),
sa.Column("username", sa.String(50)),
sa.Column("module", sa.String(50)),
sa.Column("action", sa.String(50)),
sa.Column("method", sa.String(10)),
sa.Column("path", sa.String(500)),
sa.Column("ip", sa.String(50)),
sa.Column("request_body", sa.Text()),
sa.Column("response_body", sa.Text()),
sa.Column("status_code", sa.Integer()),
sa.Column("duration_ms", sa.Integer()),
sa.Column("created_at", sa.DateTime(), default=sa.func.now()),
)
def downgrade() -> None:
tables = [
"sys_operation_log",
"classification_change",
"classification_result",
"classification_task",
"classification_project",
"recognition_rule",
"classification_template",
"data_level",
"category",
"unstructured_file",
"meta_column",
"meta_table",
"meta_database",
"data_source",
"sys_user_role",
"sys_user",
"sys_role",
"sys_dept",
]
for t in tables:
op.drop_table(t)