Remove HR completely: delete hr API; baseline alembic without HR tables

This commit is contained in:
Abhimanyu Saharan
2026-02-02 16:51:06 +05:30
parent 1bbc65c983
commit a678180d07
7 changed files with 121 additions and 201 deletions

View File

@@ -1,35 +0,0 @@
"""remove hr module
Revision ID: 4dffc5312eb8
Revises: bacd5e6a253d
Create Date: 2026-02-02 16:46:47.579836
"""
from typing import Sequence, Union
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision: str = "4dffc5312eb8"
down_revision: Union[str, Sequence[str], None] = "bacd5e6a253d"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# Drop HR tables. If they don't exist (fresh db + baseline changed later), be safe.
op.execute("DROP TABLE IF EXISTS headcount_requests CASCADE")
op.execute("DROP TABLE IF EXISTS employment_actions CASCADE")
op.execute("DROP TABLE IF EXISTS agent_onboardings CASCADE")
def downgrade() -> None:
"""Downgrade schema."""
# We intentionally do not recreate the HR tables; HR module is removed.
# If ever needed, re-introduce with a new migration.
pass

View File

@@ -1,19 +1,19 @@
"""baseline schema """baseline schema (no HR module)
Revision ID: bacd5e6a253d Revision ID: bacd5e6a253d
Revises: Revises:
Create Date: 2026-02-02 16:37:34.122971 Create Date: 2026-02-02 16:37:34.122971
""" """
from typing import Sequence, Union from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
import sqlmodel import sqlmodel
from alembic import op
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision: str = 'bacd5e6a253d' revision: str = "bacd5e6a253d"
down_revision: Union[str, Sequence[str], None] = None down_revision: Union[str, Sequence[str], None] = None
branch_labels: Union[str, Sequence[str], None] = None branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None
@@ -21,159 +21,130 @@ depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None: def upgrade() -> None:
"""Upgrade schema.""" """Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('departments', # Departments (FK to employees added after employees table exists)
sa.Column('id', sa.Integer(), nullable=False), op.create_table(
sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), "departments",
sa.Column('head_employee_id', sa.Integer(), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.PrimaryKeyConstraint('id') sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("head_employee_id", sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint("id"),
) )
op.create_index(op.f('ix_departments_name'), 'departments', ['name'], unique=True) op.create_index(op.f("ix_departments_name"), "departments", ["name"], unique=True)
op.create_table('employees',
sa.Column('id', sa.Integer(), nullable=False), # Employees
sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), op.create_table(
sa.Column('employee_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False), "employees",
sa.Column('department_id', sa.Integer(), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('manager_id', sa.Integer(), nullable=True), sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('title', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("employee_type", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column("department_id", sa.Integer(), nullable=True),
sa.Column('openclaw_session_key', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("manager_id", sa.Integer(), nullable=True),
sa.Column('notify_enabled', sa.Boolean(), nullable=False), sa.Column("title", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.ForeignKeyConstraint(['department_id'], ['departments.id'], ), sa.Column("status", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.ForeignKeyConstraint(['manager_id'], ['employees.id'], ), sa.Column("openclaw_session_key", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.PrimaryKeyConstraint('id') sa.Column("notify_enabled", sa.Boolean(), nullable=False),
sa.ForeignKeyConstraint(["department_id"], ["departments.id"]),
sa.ForeignKeyConstraint(["manager_id"], ["employees.id"]),
sa.PrimaryKeyConstraint("id"),
) )
op.create_foreign_key(None, 'departments', 'employees', ['head_employee_id'], ['id'])
op.create_table('projects', # Break the departments<->employees cycle: add this FK after both tables exist
sa.Column('id', sa.Integer(), nullable=False), op.create_foreign_key(None, "departments", "employees", ["head_employee_id"], ["id"])
sa.Column('name', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False), # Projects
sa.PrimaryKeyConstraint('id') op.create_table(
"projects",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("name", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("status", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.PrimaryKeyConstraint("id"),
) )
op.create_index(op.f('ix_projects_name'), 'projects', ['name'], unique=True) op.create_index(op.f("ix_projects_name"), "projects", ["name"], unique=True)
op.create_table('activities',
sa.Column('id', sa.Integer(), nullable=False), # Activities
sa.Column('actor_employee_id', sa.Integer(), nullable=True), op.create_table(
sa.Column('entity_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False), "activities",
sa.Column('entity_id', sa.Integer(), nullable=True), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('verb', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column("actor_employee_id", sa.Integer(), nullable=True),
sa.Column('payload_json', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("entity_type", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False), sa.Column("entity_id", sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['actor_employee_id'], ['employees.id'], ), sa.Column("verb", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.PrimaryKeyConstraint('id') sa.Column("payload_json", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(["actor_employee_id"], ["employees.id"]),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('agent_onboardings',
sa.Column('id', sa.Integer(), nullable=False), # Project members
sa.Column('agent_name', sqlmodel.sql.sqltypes.AutoString(), nullable=False), op.create_table(
sa.Column('role_title', sqlmodel.sql.sqltypes.AutoString(), nullable=False), "project_members",
sa.Column('prompt', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('cron_interval_ms', sa.Integer(), nullable=True), sa.Column("project_id", sa.Integer(), nullable=False),
sa.Column('tools_json', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("employee_id", sa.Integer(), nullable=False),
sa.Column('owner_hr_id', sa.Integer(), nullable=True), sa.Column("role", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('employee_id', sa.Integer(), nullable=True), sa.ForeignKeyConstraint(["employee_id"], ["employees.id"]),
sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.ForeignKeyConstraint(["project_id"], ["projects.id"]),
sa.Column('spawned_agent_id', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.PrimaryKeyConstraint("id"),
sa.Column('session_key', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('notes', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['employee_id'], ['employees.id'], ),
sa.ForeignKeyConstraint(['owner_hr_id'], ['employees.id'], ),
sa.PrimaryKeyConstraint('id')
) )
op.create_table('employment_actions',
sa.Column('id', sa.Integer(), nullable=False), # Tasks
sa.Column('employee_id', sa.Integer(), nullable=False), op.create_table(
sa.Column('issued_by_employee_id', sa.Integer(), nullable=False), "tasks",
sa.Column('action_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False), sa.Column("id", sa.Integer(), nullable=False),
sa.Column('notes', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("project_id", sa.Integer(), nullable=False),
sa.Column('idempotency_key', sqlmodel.sql.sqltypes.AutoString(), nullable=True), sa.Column("title", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False), sa.Column("description", sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.ForeignKeyConstraint(['employee_id'], ['employees.id'], ), sa.Column("status", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.ForeignKeyConstraint(['issued_by_employee_id'], ['employees.id'], ), sa.Column("assignee_employee_id", sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id') sa.Column("reviewer_employee_id", sa.Integer(), nullable=True),
sa.Column("created_by_employee_id", sa.Integer(), nullable=True),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.Column("updated_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(["assignee_employee_id"], ["employees.id"]),
sa.ForeignKeyConstraint(["created_by_employee_id"], ["employees.id"]),
sa.ForeignKeyConstraint(["project_id"], ["projects.id"]),
sa.ForeignKeyConstraint(["reviewer_employee_id"], ["employees.id"]),
sa.PrimaryKeyConstraint("id"),
) )
op.create_index(op.f('ix_employment_actions_idempotency_key'), 'employment_actions', ['idempotency_key'], unique=True) op.create_index(op.f("ix_tasks_project_id"), "tasks", ["project_id"], unique=False)
op.create_table('project_members', op.create_index(op.f("ix_tasks_status"), "tasks", ["status"], unique=False)
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('project_id', sa.Integer(), nullable=False), # Task comments
sa.Column('employee_id', sa.Integer(), nullable=False), op.create_table(
sa.Column('role', sqlmodel.sql.sqltypes.AutoString(), nullable=True), "task_comments",
sa.ForeignKeyConstraint(['employee_id'], ['employees.id'], ), sa.Column("id", sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['project_id'], ['projects.id'], ), sa.Column("task_id", sa.Integer(), nullable=False),
sa.PrimaryKeyConstraint('id') sa.Column("author_employee_id", sa.Integer(), nullable=True),
sa.Column("reply_to_comment_id", sa.Integer(), nullable=True),
sa.Column("body", sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column("created_at", sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(["author_employee_id"], ["employees.id"]),
sa.ForeignKeyConstraint(["reply_to_comment_id"], ["task_comments.id"]),
sa.ForeignKeyConstraint(["task_id"], ["tasks.id"]),
sa.PrimaryKeyConstraint("id"),
) )
op.create_table('tasks', op.create_index(op.f("ix_task_comments_task_id"), "task_comments", ["task_id"], unique=False)
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('project_id', sa.Integer(), nullable=False),
sa.Column('title', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('description', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('assignee_employee_id', sa.Integer(), nullable=True),
sa.Column('reviewer_employee_id', sa.Integer(), nullable=True),
sa.Column('created_by_employee_id', sa.Integer(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['assignee_employee_id'], ['employees.id'], ),
sa.ForeignKeyConstraint(['created_by_employee_id'], ['employees.id'], ),
sa.ForeignKeyConstraint(['project_id'], ['projects.id'], ),
sa.ForeignKeyConstraint(['reviewer_employee_id'], ['employees.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_tasks_project_id'), 'tasks', ['project_id'], unique=False)
op.create_index(op.f('ix_tasks_status'), 'tasks', ['status'], unique=False)
op.create_table('headcount_requests',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('department_id', sa.Integer(), nullable=False),
sa.Column('requested_by_manager_id', sa.Integer(), nullable=False),
sa.Column('role_title', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('employee_type', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('quantity', sa.Integer(), nullable=False),
sa.Column('justification', sqlmodel.sql.sqltypes.AutoString(), nullable=True),
sa.Column('status', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('fulfilled_employee_id', sa.Integer(), nullable=True),
sa.Column('fulfilled_onboarding_id', sa.Integer(), nullable=True),
sa.Column('fulfilled_at', sa.DateTime(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['department_id'], ['departments.id'], ),
sa.ForeignKeyConstraint(['fulfilled_employee_id'], ['employees.id'], ),
sa.ForeignKeyConstraint(['fulfilled_onboarding_id'], ['agent_onboardings.id'], ),
sa.ForeignKeyConstraint(['requested_by_manager_id'], ['employees.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('task_comments',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('task_id', sa.Integer(), nullable=False),
sa.Column('author_employee_id', sa.Integer(), nullable=True),
sa.Column('reply_to_comment_id', sa.Integer(), nullable=True),
sa.Column('body', sqlmodel.sql.sqltypes.AutoString(), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['author_employee_id'], ['employees.id'], ),
sa.ForeignKeyConstraint(['reply_to_comment_id'], ['task_comments.id'], ),
sa.ForeignKeyConstraint(['task_id'], ['tasks.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_task_comments_task_id'), 'task_comments', ['task_id'], unique=False)
# ### end Alembic commands ###
def downgrade() -> None: def downgrade() -> None:
"""Downgrade schema.""" """Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_task_comments_task_id'), table_name='task_comments') op.drop_index(op.f("ix_task_comments_task_id"), table_name="task_comments")
op.drop_table('task_comments') op.drop_table("task_comments")
op.drop_table('headcount_requests')
op.drop_index(op.f('ix_tasks_status'), table_name='tasks') op.drop_index(op.f("ix_tasks_status"), table_name="tasks")
op.drop_index(op.f('ix_tasks_project_id'), table_name='tasks') op.drop_index(op.f("ix_tasks_project_id"), table_name="tasks")
op.drop_table('tasks') op.drop_table("tasks")
op.drop_table('project_members')
op.drop_index(op.f('ix_employment_actions_idempotency_key'), table_name='employment_actions') op.drop_table("project_members")
op.drop_table('employment_actions')
op.drop_table('agent_onboardings') op.drop_table("activities")
op.drop_table('activities')
op.drop_index(op.f('ix_projects_name'), table_name='projects') op.drop_index(op.f("ix_projects_name"), table_name="projects")
op.drop_table('projects') op.drop_table("projects")
op.drop_table('employees')
op.drop_index(op.f('ix_departments_name'), table_name='departments') op.drop_table("employees")
op.drop_table('departments')
# ### end Alembic commands ### op.drop_index(op.f("ix_departments_name"), table_name="departments")
op.drop_table("departments")

View File

@@ -1,16 +0,0 @@
"""HR module removed.
Mission Control now uses the org/people module (employees) for provisioning.
"""
from fastapi import APIRouter
router = APIRouter(prefix="/hr", tags=["hr"])
@router.get("/")
def hr_removed():
return {
"ok": False,
"error": "HR module removed; use /employees endpoints for provisioning",
}