20251227_0841_2affe85d6033_initial_schema.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. """Initial schema
  2. Revision ID: 2affe85d6033
  3. Revises:
  4. Create Date: 2025-12-27 08:41:03.191770+00:00
  5. """
  6. from typing import Sequence, Union
  7. from alembic import op
  8. import sqlalchemy as sa
  9. from sqlalchemy.dialects import postgresql
  10. # revision identifiers, used by Alembic.
  11. revision: str = '2affe85d6033'
  12. down_revision: Union[str, None] = None
  13. branch_labels: Union[str, Sequence[str], None] = None
  14. depends_on: Union[str, Sequence[str], None] = None
  15. def upgrade() -> None:
  16. # ### commands auto generated by Alembic - please adjust! ###
  17. # Create sequence for device simple_id (auto-increment, never reused)
  18. op.execute('CREATE SEQUENCE device_simple_id_seq START 1')
  19. op.create_table('organizations',
  20. sa.Column('id', sa.Integer(), nullable=False),
  21. sa.Column('name', sa.String(length=255), nullable=False),
  22. sa.Column('contact_email', sa.String(length=255), nullable=False),
  23. sa.Column('contact_phone', sa.String(length=50), nullable=True),
  24. sa.Column('wifi_enabled', sa.Boolean(), nullable=False),
  25. sa.Column('ble_enabled', sa.Boolean(), nullable=False),
  26. sa.Column('status', sa.String(length=20), nullable=False),
  27. sa.Column('notes', sa.String(), nullable=True),
  28. sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
  29. sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
  30. sa.PrimaryKeyConstraint('id', name=op.f('pk_organizations'))
  31. )
  32. op.create_table('devices',
  33. sa.Column('id', sa.Integer(), nullable=False),
  34. sa.Column('simple_id', sa.Integer(), server_default=sa.text("nextval('device_simple_id_seq')"), nullable=False),
  35. sa.Column('mac_address', sa.String(length=17), nullable=False),
  36. sa.Column('serial_number', sa.String(length=100), nullable=True),
  37. sa.Column('device_type', sa.String(length=50), nullable=False),
  38. sa.Column('model', sa.String(length=50), nullable=True),
  39. sa.Column('firmware_version', sa.String(length=50), nullable=True),
  40. sa.Column('organization_id', sa.Integer(), nullable=True),
  41. sa.Column('status', sa.String(length=20), nullable=False),
  42. sa.Column('last_seen_at', sa.DateTime(timezone=True), nullable=True),
  43. sa.Column('last_ip', postgresql.INET(), nullable=True),
  44. sa.Column('config', postgresql.JSONB(astext_type=sa.Text()), nullable=False),
  45. sa.Column('notes', sa.String(), nullable=True),
  46. sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
  47. sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
  48. sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], name=op.f('fk_devices_organization_id_organizations'), ondelete='SET NULL'),
  49. sa.PrimaryKeyConstraint('id', name=op.f('pk_devices')),
  50. sa.UniqueConstraint('mac_address', name=op.f('uq_devices_mac_address')),
  51. sa.UniqueConstraint('simple_id', name=op.f('uq_devices_simple_id'))
  52. )
  53. op.create_table('users',
  54. sa.Column('id', sa.Integer(), nullable=False),
  55. sa.Column('email', sa.String(length=255), nullable=False),
  56. sa.Column('hashed_password', sa.String(length=255), nullable=False),
  57. sa.Column('full_name', sa.String(length=255), nullable=True),
  58. sa.Column('phone', sa.String(length=50), nullable=True),
  59. sa.Column('role', sa.String(length=20), nullable=False),
  60. sa.Column('status', sa.String(length=20), nullable=False),
  61. sa.Column('organization_id', sa.Integer(), nullable=True),
  62. sa.Column('email_verified', sa.Boolean(), nullable=False),
  63. sa.Column('email_verification_token', sa.String(length=255), nullable=True),
  64. sa.Column('email_verified_at', sa.DateTime(timezone=True), nullable=True),
  65. sa.Column('password_reset_token', sa.String(length=255), nullable=True),
  66. sa.Column('password_reset_expires', sa.DateTime(timezone=True), nullable=True),
  67. sa.Column('last_login_at', sa.DateTime(timezone=True), nullable=True),
  68. sa.Column('last_login_ip', postgresql.INET(), nullable=True),
  69. sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
  70. sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
  71. sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], name=op.f('fk_users_organization_id_organizations'), ondelete='CASCADE'),
  72. sa.PrimaryKeyConstraint('id', name=op.f('pk_users')),
  73. sa.UniqueConstraint('email', name=op.f('uq_users_email'))
  74. )
  75. op.create_table('audit_logs',
  76. sa.Column('id', sa.BigInteger(), nullable=False),
  77. sa.Column('user_id', sa.Integer(), nullable=True),
  78. sa.Column('user_email', sa.String(length=255), nullable=True),
  79. sa.Column('organization_id', sa.Integer(), nullable=True),
  80. sa.Column('action', sa.String(length=50), nullable=False),
  81. sa.Column('resource_type', sa.String(length=50), nullable=True),
  82. sa.Column('resource_id', sa.Integer(), nullable=True),
  83. sa.Column('description', sa.String(), nullable=True),
  84. sa.Column('changes', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
  85. sa.Column('ip_address', postgresql.INET(), nullable=True),
  86. sa.Column('user_agent', sa.String(), nullable=True),
  87. sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
  88. sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
  89. sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], name=op.f('fk_audit_logs_organization_id_organizations'), ondelete='SET NULL'),
  90. sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_audit_logs_user_id_users'), ondelete='SET NULL'),
  91. sa.PrimaryKeyConstraint('id', name=op.f('pk_audit_logs'))
  92. )
  93. op.create_table('refresh_tokens',
  94. sa.Column('id', sa.Integer(), nullable=False),
  95. sa.Column('user_id', sa.Integer(), nullable=False),
  96. sa.Column('token', sa.String(length=512), nullable=False),
  97. sa.Column('expires_at', sa.DateTime(timezone=True), nullable=False),
  98. sa.Column('device_info', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
  99. sa.Column('revoked_at', sa.DateTime(timezone=True), nullable=True),
  100. sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
  101. sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
  102. sa.ForeignKeyConstraint(['user_id'], ['users.id'], name=op.f('fk_refresh_tokens_user_id_users'), ondelete='CASCADE'),
  103. sa.PrimaryKeyConstraint('id', name=op.f('pk_refresh_tokens')),
  104. sa.UniqueConstraint('token', name=op.f('uq_refresh_tokens_token'))
  105. )
  106. # ### end Alembic commands ###
  107. def downgrade() -> None:
  108. # ### commands auto generated by Alembic - please adjust! ###
  109. op.drop_table('refresh_tokens')
  110. op.drop_table('audit_logs')
  111. op.drop_table('users')
  112. op.drop_table('devices')
  113. op.drop_table('organizations')
  114. # Drop sequence
  115. op.execute('DROP SEQUENCE IF EXISTS device_simple_id_seq')
  116. # ### end Alembic commands ###