POL-126: Fix critical backend bugs — Championship model/DB mismatch, broken imports

- Restore judges/categories TEXT columns to Championship model (were in DB but missing from model)
- Remove phantom columns not in DB: org_id, subtitle, venue, accent_color
- Remove broken relationships to unmigrated tables (Organization, Discipline, Style, Fee, Rule, Judge)
- Remove broken instagram_service import from lifespan (file doesn't exist)
- Add http://localhost:3000 to default CORS origins (web frontend)

Model files for unmigrated tables kept on disk for future migration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dianaka123
2026-02-28 22:33:24 +03:00
parent 0716f09e3f
commit 96e02bf64a
5 changed files with 5 additions and 41 deletions

View File

@@ -18,7 +18,7 @@ class Settings(BaseSettings):
EXPO_ACCESS_TOKEN: str = ""
CORS_ORIGINS: str = "http://localhost:8081,exp://"
CORS_ORIGINS: str = "http://localhost:3000,http://localhost:8081,exp://"
@property
def cors_origins_list(self) -> list[str]:

View File

@@ -1,5 +1,3 @@
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
@@ -7,19 +5,7 @@ from app.config import settings
from app.routers import auth, championships, registrations, participant_lists, users
@asynccontextmanager
async def lifespan(app: FastAPI):
# Start Instagram sync scheduler if configured
if settings.INSTAGRAM_USER_ID and settings.INSTAGRAM_ACCESS_TOKEN:
from app.services.instagram_service import start_scheduler
scheduler = start_scheduler()
yield
scheduler.shutdown()
else:
yield
app = FastAPI(title="Pole Dance Championships API", version="1.0.0", lifespan=lifespan)
app = FastAPI(title="Pole Dance Championships API", version="1.0.0")
app.add_middleware(
CORSMiddleware,

View File

@@ -1,26 +1,14 @@
from app.models.user import User, RefreshToken
from app.models.organization import Organization
from app.models.championship import Championship
from app.models.registration import Registration
from app.models.participant import ParticipantList
from app.models.notification import NotificationLog
from app.models.discipline import Discipline
from app.models.style import Style
from app.models.fee import Fee
from app.models.rule import Rule
from app.models.judge import Judge
__all__ = [
"User",
"RefreshToken",
"Organization",
"Championship",
"Registration",
"ParticipantList",
"NotificationLog",
"Discipline",
"Style",
"Fee",
"Rule",
"Judge",
]

View File

@@ -1,7 +1,7 @@
import uuid
from datetime import datetime
from sqlalchemy import DateTime, Float, ForeignKey, Integer, String, Text, Uuid, func
from sqlalchemy import DateTime, Float, Integer, String, Text, Uuid, func
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.database import Base
@@ -11,21 +11,18 @@ class Championship(Base):
__tablename__ = "championships"
id: Mapped[uuid.UUID] = mapped_column(Uuid(as_uuid=True), primary_key=True, default=uuid.uuid4)
org_id: Mapped[uuid.UUID | None] = mapped_column(Uuid(as_uuid=True), ForeignKey("organizations.id", ondelete="SET NULL"))
title: Mapped[str] = mapped_column(String(255), nullable=False)
subtitle: Mapped[str | None] = mapped_column(String(255))
description: Mapped[str | None] = mapped_column(Text)
location: Mapped[str | None] = mapped_column(String(500))
venue: Mapped[str | None] = mapped_column(String(255))
event_date: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
registration_open_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
registration_close_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
accent_color: Mapped[str | None] = mapped_column(String(20)) # hex color e.g. #FF5CA8
# Legacy flat fields (kept for backwards compat, replaced by relational tables in POL-7 to POL-11)
form_url: Mapped[str | None] = mapped_column(String(2048))
entry_fee: Mapped[float | None] = mapped_column(Float)
video_max_duration: Mapped[int | None] = mapped_column(Integer) # seconds
judges: Mapped[str | None] = mapped_column(Text) # JSON string: [{name, bio, instagram}]
categories: Mapped[str | None] = mapped_column(Text) # JSON string: ["cat1", "cat2"]
# Status: 'draft' | 'open' | 'closed' | 'completed'
status: Mapped[str] = mapped_column(String(20), nullable=False, default="draft")
@@ -40,11 +37,5 @@ class Championship(Base):
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)
organization: Mapped["Organization | None"] = relationship(back_populates="championships") # type: ignore[name-defined]
registrations: Mapped[list["Registration"]] = relationship(back_populates="championship", cascade="all, delete-orphan") # type: ignore[name-defined]
participant_list: Mapped["ParticipantList | None"] = relationship(back_populates="championship", uselist=False, cascade="all, delete-orphan") # type: ignore[name-defined]
disciplines: Mapped[list["Discipline"]] = relationship(back_populates="championship", cascade="all, delete-orphan") # type: ignore[name-defined]
styles: Mapped[list["Style"]] = relationship(back_populates="championship", cascade="all, delete-orphan") # type: ignore[name-defined]
fees: Mapped["Fee | None"] = relationship(back_populates="championship", uselist=False, cascade="all, delete-orphan") # type: ignore[name-defined]
rules: Mapped[list["Rule"]] = relationship(back_populates="championship", cascade="all, delete-orphan") # type: ignore[name-defined]
judges_list: Mapped[list["Judge"]] = relationship(back_populates="championship", cascade="all, delete-orphan") # type: ignore[name-defined]

View File

@@ -30,7 +30,6 @@ class User(Base):
refresh_tokens: Mapped[list["RefreshToken"]] = relationship(back_populates="user", cascade="all, delete-orphan")
registrations: Mapped[list["Registration"]] = relationship(back_populates="user") # type: ignore[name-defined]
notification_logs: Mapped[list["NotificationLog"]] = relationship(back_populates="user") # type: ignore[name-defined]
organization: Mapped["Organization | None"] = relationship(back_populates="user", uselist=False) # type: ignore[name-defined]
class RefreshToken(Base):