mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Fix migrations
This commit is contained in:
@@ -19,6 +19,9 @@ def run_migrations():
|
|||||||
This function will upgrade the database to the latest migration.
|
This function will upgrade the database to the latest migration.
|
||||||
Fully automated - handles all scenarios automatically.
|
Fully automated - handles all scenarios automatically.
|
||||||
"""
|
"""
|
||||||
|
# Get the directory where this script is located
|
||||||
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# FIRST: Check if database has any application tables (excluding alembic_version)
|
# FIRST: Check if database has any application tables (excluding alembic_version)
|
||||||
engine = create_engine(DATABASE_URL)
|
engine = create_engine(DATABASE_URL)
|
||||||
@@ -35,9 +38,6 @@ def run_migrations():
|
|||||||
Base.metadata.create_all(bind=engine)
|
Base.metadata.create_all(bind=engine)
|
||||||
logger.info("All tables created successfully from models.")
|
logger.info("All tables created successfully from models.")
|
||||||
|
|
||||||
# Get the directory where this script is located
|
|
||||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
|
|
||||||
# Note: Problematic migrations are now cleaned up during Docker build
|
# Note: Problematic migrations are now cleaned up during Docker build
|
||||||
|
|
||||||
# Create Alembic configuration
|
# Create Alembic configuration
|
||||||
@@ -488,6 +488,8 @@ def _create_database_directly():
|
|||||||
from backend.shared.db import get_engine
|
from backend.shared.db import get_engine
|
||||||
from sqlalchemy import text, inspect
|
from sqlalchemy import text, inspect
|
||||||
|
|
||||||
|
engine = get_engine()
|
||||||
|
|
||||||
# Check existing tables and update schema
|
# Check existing tables and update schema
|
||||||
with engine.connect() as connection:
|
with engine.connect() as connection:
|
||||||
inspector = inspect(connection)
|
inspector = inspect(connection)
|
||||||
@@ -569,9 +571,9 @@ def _create_database_directly():
|
|||||||
revision_match = re.search(r"revision: str = '([^']+)'", content)
|
revision_match = re.search(r"revision: str = '([^']+)'", content)
|
||||||
if revision_match:
|
if revision_match:
|
||||||
revision_id = revision_match.group(1)
|
revision_id = revision_match.group(1)
|
||||||
connection.execute(text(f"INSERT OR IGNORE INTO alembic_version (version_num) VALUES ('{revision_id}')"))
|
connection.execute(text(f"INSERT INTO alembic_version (version_num) VALUES ('{revision_id}') ON CONFLICT DO NOTHING"))
|
||||||
else:
|
else:
|
||||||
connection.execute(text("INSERT OR IGNORE INTO alembic_version (version_num) VALUES ('direct_creation')"))
|
connection.execute(text("INSERT INTO alembic_version (version_num) VALUES ('direct_creation') ON CONFLICT DO NOTHING"))
|
||||||
else:
|
else:
|
||||||
connection.execute(text("INSERT OR IGNORE INTO alembic_version (version_num) VALUES ('direct_creation')"))
|
connection.execute(text("INSERT OR IGNORE INTO alembic_version (version_num) VALUES ('direct_creation')"))
|
||||||
|
|
||||||
|
|||||||
+13
-13
@@ -155,7 +155,7 @@ class MessageFile(Base):
|
|||||||
__tablename__ = "message_file"
|
__tablename__ = "message_file"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
message_id = Column(Integer, ForeignKey("message.id"), nullable=False, index=True)
|
message_id = Column(BigInteger, ForeignKey("messages.id"), nullable=False, index=True)
|
||||||
path = Column(Text, nullable=False)
|
path = Column(Text, nullable=False)
|
||||||
name = Column(Text, nullable=False)
|
name = Column(Text, nullable=False)
|
||||||
|
|
||||||
@@ -166,7 +166,7 @@ class CryptoPublicKey(Base):
|
|||||||
__tablename__ = "crypto_public_key"
|
__tablename__ = "crypto_public_key"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
user_id = Column(Integer, ForeignKey("user.id"), nullable=False, unique=True)
|
user_id = Column(BigInteger, ForeignKey("users.id"), nullable=False, unique=True)
|
||||||
public_key_b64 = Column(Text, nullable=False)
|
public_key_b64 = Column(Text, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ class CryptoBackup(Base):
|
|||||||
__tablename__ = "crypto_backup"
|
__tablename__ = "crypto_backup"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
user_id = Column(Integer, ForeignKey("user.id"), nullable=False, unique=True)
|
user_id = Column(BigInteger, ForeignKey("users.id"), nullable=False, unique=True)
|
||||||
blob_json = Column(Text, nullable=False)
|
blob_json = Column(Text, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
@@ -182,8 +182,8 @@ class DMEnvelope(Base):
|
|||||||
__tablename__ = "dm_envelope"
|
__tablename__ = "dm_envelope"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
sender_id = Column(Integer, ForeignKey("user.id"), nullable=False)
|
sender_id = Column(BigInteger, ForeignKey("users.id"), nullable=False)
|
||||||
recipient_id = Column(Integer, ForeignKey("user.id"), nullable=False)
|
recipient_id = Column(BigInteger, ForeignKey("users.id"), nullable=False)
|
||||||
iv_b64 = Column(Text, nullable=False)
|
iv_b64 = Column(Text, nullable=False)
|
||||||
ciphertext_b64 = Column(Text, nullable=False)
|
ciphertext_b64 = Column(Text, nullable=False)
|
||||||
salt_b64 = Column(Text, nullable=False)
|
salt_b64 = Column(Text, nullable=False)
|
||||||
@@ -200,8 +200,8 @@ class DMFile(Base):
|
|||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
message_id = Column(Integer, ForeignKey("dm_envelope.id"), nullable=False, index=True)
|
message_id = Column(Integer, ForeignKey("dm_envelope.id"), nullable=False, index=True)
|
||||||
sender_id = Column(Integer, ForeignKey("user.id"), nullable=False)
|
sender_id = Column(BigInteger, ForeignKey("users.id"), nullable=False)
|
||||||
recipient_id = Column(Integer, ForeignKey("user.id"), nullable=False)
|
recipient_id = Column(BigInteger, ForeignKey("users.id"), nullable=False)
|
||||||
name = Column(Text, nullable=False)
|
name = Column(Text, nullable=False)
|
||||||
path = Column(Text, nullable=False)
|
path = Column(Text, nullable=False)
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ class FcmToken(Base):
|
|||||||
__tablename__ = "fcm_token"
|
__tablename__ = "fcm_token"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
user_id = Column(Integer, ForeignKey("user.id"), nullable=False, index=True)
|
user_id = Column(BigInteger, ForeignKey("users.id"), nullable=False, index=True)
|
||||||
token = Column(Text, nullable=False, unique=True)
|
token = Column(Text, nullable=False, unique=True)
|
||||||
created_at = Column(DateTime, default=datetime.now)
|
created_at = Column(DateTime, default=datetime.now)
|
||||||
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
|
||||||
@@ -222,8 +222,8 @@ class Reaction(Base):
|
|||||||
__tablename__ = "reaction"
|
__tablename__ = "reaction"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
message_id = Column(Integer, ForeignKey("message.id"), nullable=False, index=True)
|
message_id = Column(BigInteger, ForeignKey("messages.id"), nullable=False, index=True)
|
||||||
user_id = Column(Integer, ForeignKey("user.id"), nullable=False)
|
user_id = Column(BigInteger, ForeignKey("users.id"), nullable=False)
|
||||||
emoji = Column(String(10), nullable=False) # Store emoji as string
|
emoji = Column(String(10), nullable=False) # Store emoji as string
|
||||||
timestamp = Column(DateTime, default=datetime.now)
|
timestamp = Column(DateTime, default=datetime.now)
|
||||||
|
|
||||||
@@ -239,7 +239,7 @@ class DMReaction(Base):
|
|||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
dm_envelope_id = Column(Integer, ForeignKey("dm_envelope.id"), nullable=False, index=True)
|
dm_envelope_id = Column(Integer, ForeignKey("dm_envelope.id"), nullable=False, index=True)
|
||||||
user_id = Column(Integer, ForeignKey("user.id"), nullable=False)
|
user_id = Column(BigInteger, ForeignKey("users.id"), nullable=False)
|
||||||
emoji = Column(String(10), nullable=False) # Store emoji as string
|
emoji = Column(String(10), nullable=False) # Store emoji as string
|
||||||
timestamp = Column(DateTime, default=datetime.now)
|
timestamp = Column(DateTime, default=datetime.now)
|
||||||
|
|
||||||
@@ -256,7 +256,7 @@ class DeviceSession(Base):
|
|||||||
__tablename__ = "device_session"
|
__tablename__ = "device_session"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
user_id = Column(Integer, ForeignKey("user.id"), nullable=False, index=True)
|
user_id = Column(BigInteger, ForeignKey("users.id"), nullable=False, index=True)
|
||||||
|
|
||||||
# Raw User-Agent for reference/debugging
|
# Raw User-Agent for reference/debugging
|
||||||
raw_user_agent = Column(Text, nullable=True)
|
raw_user_agent = Column(Text, nullable=True)
|
||||||
@@ -394,7 +394,7 @@ class UpdateLog(Base):
|
|||||||
__tablename__ = "update_log"
|
__tablename__ = "update_log"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
user_id = Column(Integer, ForeignKey("user.id"), nullable=False, index=True)
|
user_id = Column(BigInteger, ForeignKey("users.id"), nullable=False, index=True)
|
||||||
sequence = Column(Integer, nullable=False, index=True)
|
sequence = Column(Integer, nullable=False, index=True)
|
||||||
updates = Column(Text, nullable=False) # JSON array of updates
|
updates = Column(Text, nullable=False) # JSON array of updates
|
||||||
timestamp = Column(DateTime, default=datetime.now, index=True)
|
timestamp = Column(DateTime, default=datetime.now, index=True)
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
services:
|
services:
|
||||||
# Database service
|
# Database service
|
||||||
db:
|
database:
|
||||||
image: postgres:15
|
image: postgres:15
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: fromchat
|
POSTGRES_DB: fromchat
|
||||||
POSTGRES_USER: fromchat_admin
|
POSTGRES_USER: fromchat_admin
|
||||||
POSTGRES_PASSWORD: ${DB_PASSWORD:-changeme}
|
POSTGRES_PASSWORD: ${DB_PASSWORD:-changeme}
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data
|
- database:/var/lib/postgresql/data
|
||||||
- ./db-init:/docker-entrypoint-initdb.d
|
- ./db-init:/docker-entrypoint-initdb.d
|
||||||
networks:
|
networks:
|
||||||
- fromchat_internal
|
- fromchat_internal
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U fromchat_admin -d fromchat"]
|
test: ["CMD-SHELL", "pg_isready -U fromchat_admin -d fromchat"]
|
||||||
interval: 10s
|
interval: 1s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
|
|
||||||
@@ -25,10 +25,10 @@ services:
|
|||||||
dockerfile: docker/Dockerfile.multi
|
dockerfile: docker/Dockerfile.multi
|
||||||
target: migration_runner
|
target: migration_runner
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql://fromchat_admin:${DB_PASSWORD:-changeme}@db:5432/fromchat
|
DATABASE_URL: postgresql://fromchat_admin:${DB_PASSWORD:-changeme}@database:5432/fromchat
|
||||||
JWT_SECRET: ${JWT_SECRET:-changeme}
|
JWT_SECRET: ${JWT_SECRET:-changeme}
|
||||||
depends_on:
|
depends_on:
|
||||||
db:
|
database:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
networks:
|
networks:
|
||||||
- fromchat_internal
|
- fromchat_internal
|
||||||
@@ -57,7 +57,7 @@ services:
|
|||||||
dockerfile: docker/Dockerfile.multi
|
dockerfile: docker/Dockerfile.multi
|
||||||
target: gateway
|
target: gateway
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql://gateway_user:${DB_PASSWORD:-changeme}@db:5432/fromchat
|
DATABASE_URL: postgresql://gateway_user:${DB_PASSWORD:-changeme}@database:5432/fromchat
|
||||||
depends_on:
|
depends_on:
|
||||||
migration_runner:
|
migration_runner:
|
||||||
condition: service_completed_successfully
|
condition: service_completed_successfully
|
||||||
@@ -93,7 +93,7 @@ services:
|
|||||||
dockerfile: docker/Dockerfile.multi
|
dockerfile: docker/Dockerfile.multi
|
||||||
target: account_service
|
target: account_service
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql://account_service_user:${DB_PASSWORD:-changeme}@db:5432/fromchat
|
DATABASE_URL: postgresql://account_service_user:${DB_PASSWORD:-changeme}@database:5432/fromchat
|
||||||
JWT_SECRET: ${JWT_SECRET:-changeme}
|
JWT_SECRET: ${JWT_SECRET:-changeme}
|
||||||
depends_on:
|
depends_on:
|
||||||
migration_runner:
|
migration_runner:
|
||||||
@@ -120,7 +120,7 @@ services:
|
|||||||
dockerfile: docker/Dockerfile.multi
|
dockerfile: docker/Dockerfile.multi
|
||||||
target: profile_service
|
target: profile_service
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql://profile_service_user:${DB_PASSWORD:-changeme}@db:5432/fromchat
|
DATABASE_URL: postgresql://profile_service_user:${DB_PASSWORD:-changeme}@database:5432/fromchat
|
||||||
FIREBASE_CERT: ${FIREBASE_CERT:-}
|
FIREBASE_CERT: ${FIREBASE_CERT:-}
|
||||||
VAPID_PRIVATE_KEY: ${VAPID_PRIVATE_KEY:-}
|
VAPID_PRIVATE_KEY: ${VAPID_PRIVATE_KEY:-}
|
||||||
VAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY:-}
|
VAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY:-}
|
||||||
@@ -150,7 +150,7 @@ services:
|
|||||||
dockerfile: docker/Dockerfile.multi
|
dockerfile: docker/Dockerfile.multi
|
||||||
target: device_service
|
target: device_service
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql://device_service_user:${DB_PASSWORD:-changeme}@db:5432/fromchat
|
DATABASE_URL: postgresql://device_service_user:${DB_PASSWORD:-changeme}@database:5432/fromchat
|
||||||
depends_on:
|
depends_on:
|
||||||
migration_runner:
|
migration_runner:
|
||||||
condition: service_completed_successfully
|
condition: service_completed_successfully
|
||||||
@@ -176,7 +176,7 @@ services:
|
|||||||
dockerfile: docker/Dockerfile.multi
|
dockerfile: docker/Dockerfile.multi
|
||||||
target: messaging_service
|
target: messaging_service
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql://messaging_service_user:${DB_PASSWORD:-changeme}@db:5432/fromchat
|
DATABASE_URL: postgresql://messaging_service_user:${DB_PASSWORD:-changeme}@database:5432/fromchat
|
||||||
FIREBASE_CERT: ${FIREBASE_CERT:-}
|
FIREBASE_CERT: ${FIREBASE_CERT:-}
|
||||||
VAPID_PRIVATE_KEY: ${VAPID_PRIVATE_KEY:-}
|
VAPID_PRIVATE_KEY: ${VAPID_PRIVATE_KEY:-}
|
||||||
VAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY:-}
|
VAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY:-}
|
||||||
@@ -209,7 +209,7 @@ services:
|
|||||||
dockerfile: docker/Dockerfile.multi
|
dockerfile: docker/Dockerfile.multi
|
||||||
target: push_service
|
target: push_service
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql://push_service_user:${DB_PASSWORD:-changeme}@db:5432/fromchat
|
DATABASE_URL: postgresql://push_service_user:${DB_PASSWORD:-changeme}@database:5432/fromchat
|
||||||
FIREBASE_CERT: ${FIREBASE_CERT:-}
|
FIREBASE_CERT: ${FIREBASE_CERT:-}
|
||||||
VAPID_PRIVATE_KEY: ${VAPID_PRIVATE_KEY:-}
|
VAPID_PRIVATE_KEY: ${VAPID_PRIVATE_KEY:-}
|
||||||
VAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY:-}
|
VAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY:-}
|
||||||
@@ -242,7 +242,7 @@ services:
|
|||||||
dockerfile: docker/Dockerfile.multi
|
dockerfile: docker/Dockerfile.multi
|
||||||
target: webrtc_service
|
target: webrtc_service
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql://webrtc_service_user:${DB_PASSWORD:-changeme}@db:5432/fromchat
|
DATABASE_URL: postgresql://webrtc_service_user:${DB_PASSWORD:-changeme}@database:5432/fromchat
|
||||||
depends_on:
|
depends_on:
|
||||||
migration_runner:
|
migration_runner:
|
||||||
condition: service_completed_successfully
|
condition: service_completed_successfully
|
||||||
@@ -268,7 +268,7 @@ services:
|
|||||||
dockerfile: docker/Dockerfile.multi
|
dockerfile: docker/Dockerfile.multi
|
||||||
target: moderation_service
|
target: moderation_service
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql://moderation_service_user:${DB_PASSWORD:-changeme}@db:5432/fromchat
|
DATABASE_URL: postgresql://moderation_service_user:${DB_PASSWORD:-changeme}@database:5432/fromchat
|
||||||
depends_on:
|
depends_on:
|
||||||
migration_runner:
|
migration_runner:
|
||||||
condition: service_completed_successfully
|
condition: service_completed_successfully
|
||||||
@@ -295,24 +295,35 @@ services:
|
|||||||
|
|
||||||
# Caddy reverse proxy
|
# Caddy reverse proxy
|
||||||
caddy:
|
caddy:
|
||||||
image: caddy:2
|
build:
|
||||||
|
context: ./caddy
|
||||||
|
dockerfile: Dockerfile
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
- "443:443"
|
- "443:443"
|
||||||
volumes:
|
volumes:
|
||||||
- ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
|
- certs:/root/site/certs
|
||||||
- caddy_data:/data
|
|
||||||
- caddy_config:/config
|
|
||||||
networks:
|
networks:
|
||||||
- fromchat_external
|
- fromchat_external
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
environment:
|
||||||
|
- XDG_DATA_HOME=/root/site/certs
|
||||||
|
- XDG_CONFIG_HOME=/root/site/certs
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- gateway
|
- gateway
|
||||||
|
profiles: ["prod"]
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
database:
|
||||||
caddy_data:
|
name: fromchat-database
|
||||||
caddy_config:
|
certs:
|
||||||
|
name: fromchat-certs
|
||||||
|
logs:
|
||||||
|
name: fromchat-logs
|
||||||
|
data:
|
||||||
|
name: fromchat-data
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
fromchat_internal:
|
fromchat_internal:
|
||||||
|
|||||||
Reference in New Issue
Block a user