Pydantic v2 + FastAPI serializes Field(alias="_id") as _id in JSON,
so client.id was always undefined on the frontend — causing option
values to fall back to text content ("3M") and firing /clients/3M/teams 404s.
- Remove Field(alias="_id") from Client/Team/Project models; id is now a
plain string field populated explicitly in _client_from_doc etc.
- API now returns id not _id, matching the TypeScript Client interface
- Add clientId !== "undefined" guard to useTeams, usePMs, useProjects
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
71 lines
1.4 KiB
Python
71 lines
1.4 KiB
Python
from datetime import datetime
|
|
from typing import Optional, Annotated
|
|
|
|
from bson import ObjectId
|
|
from pydantic import BaseModel, BeforeValidator
|
|
|
|
|
|
def validate_object_id(v) -> str:
|
|
if isinstance(v, ObjectId):
|
|
return str(v)
|
|
if isinstance(v, str):
|
|
return v
|
|
raise ValueError("Invalid ObjectId")
|
|
|
|
|
|
PyObjectId = Annotated[str, BeforeValidator(validate_object_id)]
|
|
|
|
|
|
class Client(BaseModel):
|
|
id: Optional[str] = None
|
|
name: str
|
|
slug: str
|
|
is_active: bool = True
|
|
created_at: Optional[datetime] = None
|
|
updated_at: Optional[datetime] = None
|
|
|
|
|
|
class ClientCreate(BaseModel):
|
|
name: str
|
|
slug: str
|
|
|
|
|
|
class ClientUpdate(BaseModel):
|
|
name: Optional[str] = None
|
|
slug: Optional[str] = None
|
|
is_active: Optional[bool] = None
|
|
|
|
|
|
class Team(BaseModel):
|
|
id: Optional[str] = None
|
|
name: str
|
|
client_id: str
|
|
member_user_ids: list[str] = []
|
|
created_at: Optional[datetime] = None
|
|
updated_at: Optional[datetime] = None
|
|
|
|
|
|
class TeamCreate(BaseModel):
|
|
name: str
|
|
|
|
|
|
class TeamUpdate(BaseModel):
|
|
name: Optional[str] = None
|
|
|
|
|
|
class Project(BaseModel):
|
|
id: Optional[str] = None
|
|
name: str
|
|
client_id: str
|
|
is_active: bool = True
|
|
created_at: Optional[datetime] = None
|
|
updated_at: Optional[datetime] = None
|
|
|
|
|
|
class ProjectCreate(BaseModel):
|
|
name: str
|
|
|
|
|
|
class ProjectUpdate(BaseModel):
|
|
name: Optional[str] = None
|
|
is_active: Optional[bool] = None
|