Skip to content

Commit eb91df2

Browse files
committed
Add model constraints and safe defaults
1 parent 0ba527c commit eb91df2

File tree

2 files changed

+33
-10
lines changed

2 files changed

+33
-10
lines changed

Backend/app/models/models.py

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@
1010
DateTime,
1111
Boolean,
1212
TIMESTAMP,
13+
UniqueConstraint,
14+
CheckConstraint,
15+
Index,
16+
Enum,
1317
)
14-
from sqlalchemy.orm import relationship
18+
from sqlalchemy.orm import relationship, backref
1519
from datetime import datetime, timezone
1620
from app.db.db import Base
1721
import uuid
@@ -167,8 +171,10 @@ class SponsorshipPayment(Base):
167171
# ============================================================================
168172

169173
# Brand Profile Table (Extended brand information)
170-
class BrandProfile(Base):
171174
__tablename__ = "brand_profiles"
175+
__table_args__ = (
176+
UniqueConstraint("user_id", name="uq_brand_profiles_user_id"),
177+
)
172178

173179
id = Column(String, primary_key=True, default=generate_uuid)
174180
user_id = Column(String, ForeignKey("users.id"), nullable=False)
@@ -182,7 +188,7 @@ class BrandProfile(Base):
182188
)
183189

184190
# Relationships
185-
user = relationship("User", backref="brand_profile")
191+
user = relationship("User", backref=backref("brand_profile", uselist=False))
186192

187193

188194
# Campaign Metrics Table (Performance tracking)
@@ -205,15 +211,27 @@ class CampaignMetrics(Base):
205211

206212

207213
# Contracts Table (Contract management)
214+
# Contracts Table (Contract management)
215+
from enum import Enum as PyEnum
216+
217+
class ContractStatus(PyEnum):
218+
DRAFT = "draft"
219+
SIGNED = "signed"
220+
COMPLETED = "completed"
221+
CANCELLED = "cancelled"
222+
208223
class Contract(Base):
209224
__tablename__ = "contracts"
225+
__table_args__ = (
226+
UniqueConstraint("sponsorship_id", "creator_id", name="uq_sponsorship_creator_contract"),
227+
)
210228

211229
id = Column(String, primary_key=True, default=generate_uuid)
212-
sponsorship_id = Column(String, ForeignKey("sponsorships.id"), nullable=False)
213-
creator_id = Column(String, ForeignKey("users.id"), nullable=False)
214-
brand_id = Column(String, ForeignKey("users.id"), nullable=False)
230+
sponsorship_id = Column(String, ForeignKey("sponsorships.id", ondelete="CASCADE"), nullable=False)
231+
creator_id = Column(String, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
232+
brand_id = Column(String, ForeignKey("users.id", ondelete="RESTRICT"), nullable=False)
215233
contract_url = Column(String, nullable=True)
216-
status = Column(String, default="draft") # draft, signed, completed, cancelled
234+
status = Column(Enum(ContractStatus), default=ContractStatus.DRAFT, nullable=False)
217235
created_at = Column(
218236
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
219237
)
@@ -227,6 +245,11 @@ class Contract(Base):
227245
# Creator Matches Table (AI-powered matching)
228246
class CreatorMatch(Base):
229247
__tablename__ = "creator_matches"
248+
__table_args__ = (
249+
UniqueConstraint("brand_id", "creator_id", name="uq_brand_creator"),
250+
CheckConstraint("match_score >= 0 AND match_score <= 1", name="ck_match_score_bounds"),
251+
Index("ix_brand_creator", "brand_id", "creator_id"),
252+
)
230253

231254
id = Column(String, primary_key=True, default=generate_uuid)
232255
brand_id = Column(String, ForeignKey("users.id"), nullable=False)

Backend/app/routes/ai_query.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from fastapi import APIRouter, HTTPException, Query, Depends, Request
22
from typing import Dict, Any, Optional
3-
from pydantic import BaseModel
3+
from pydantic import BaseModel, Field
44
import logging
55
from ..services.ai_router import ai_router
66
from ..services.redis_client import get_session_state, save_session_state
@@ -22,7 +22,7 @@ class AIQueryRequest(BaseModel):
2222
class AIQueryResponse(BaseModel):
2323
intent: str
2424
route: Optional[str] = None
25-
parameters: Dict[str, Any] = {}
25+
parameters: Dict[str, Any] = Field(default_factory=dict)
2626
follow_up_needed: bool = False
2727
follow_up_question: Optional[str] = None
2828
explanation: str
@@ -89,7 +89,7 @@ def get_api_args(intent, params):
8989
missing_params = []
9090
if intent in intent_param_map:
9191
for param in intent_param_map[intent]["required"]:
92-
if not params.get(param):
92+
if params.get(param) is None:
9393
all_params_present = False
9494
missing_params.append(param)
9595

0 commit comments

Comments
 (0)