feat(route-sections): add dynamic route sections
Replace hardcoded homepage featured route groups with a fully managed dynamic system: - add database models RouteSection and RouteSectionProduct for storing route groups and their associated products - create Alembic migration 0004_route_sections for the new tables - extend SiteConfigPatchIn schema with subtitle and productIds fields - refactor shared site_config utility to load dynamic route sections instead of fixed groups - implement admin CRUD API with validation for duplicate/conflicting product associations - update public and admin API documentation to reflect the new system - add default route section seed data and comprehensive test coverage
This commit is contained in:
@@ -149,6 +149,7 @@ class Product(Base):
|
||||
destination: Mapped[Destination | None] = relationship(back_populates="products")
|
||||
images: Mapped[list["ProductImage"]] = relationship(back_populates="product", cascade="all, delete-orphan")
|
||||
campaignLinks: Mapped[list["CampaignProduct"]] = relationship(back_populates="product", cascade="all, delete-orphan")
|
||||
routeSectionLinks: Mapped[list["RouteSectionProduct"]] = relationship(back_populates="product", cascade="all, delete-orphan")
|
||||
leads: Mapped[list["Lead"]] = relationship(back_populates="sourceProduct")
|
||||
orders: Mapped[list["Order"]] = relationship(back_populates="product")
|
||||
|
||||
@@ -196,6 +197,31 @@ class CampaignProduct(Base):
|
||||
product: Mapped[Product] = relationship(back_populates="campaignLinks")
|
||||
|
||||
|
||||
class RouteSection(Base):
|
||||
__tablename__ = "RouteSection"
|
||||
|
||||
id: Mapped[str] = mapped_column(String, primary_key=True, default=new_id)
|
||||
title: Mapped[str] = mapped_column(String, nullable=False)
|
||||
subtitle: Mapped[str | None] = mapped_column(Text)
|
||||
sortOrder: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||
isActive: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
||||
createdAt: Mapped[datetime] = mapped_column(DateTime, default=utc_now, nullable=False)
|
||||
updatedAt: Mapped[datetime] = mapped_column(DateTime, default=utc_now, onupdate=utc_now, nullable=False)
|
||||
|
||||
products: Mapped[list["RouteSectionProduct"]] = relationship(back_populates="section", cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class RouteSectionProduct(Base):
|
||||
__tablename__ = "RouteSectionProduct"
|
||||
|
||||
sectionId: Mapped[str] = mapped_column(String, ForeignKey("RouteSection.id", ondelete="CASCADE"), primary_key=True)
|
||||
productId: Mapped[str] = mapped_column(String, ForeignKey("Product.id", ondelete="CASCADE"), primary_key=True)
|
||||
sortOrder: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||
|
||||
section: Mapped[RouteSection] = relationship(back_populates="products")
|
||||
product: Mapped[Product] = relationship(back_populates="routeSectionLinks")
|
||||
|
||||
|
||||
class Lead(Base):
|
||||
__tablename__ = "Lead"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user