Implement performance improvements across backend and frontend

- models.py: add composite (user_id, date) indexes to flock_history,
  feed_purchases, and other_purchases for faster date-filtered queries
  (egg_collections already had one via its unique constraint)
- main.py: add v2.2 migration to create the three composite indexes on
  existing installs at startup
- stats.py: fix N+1 query in monthly_stats — flock history is now fetched
  once and looked up per month using bisect_right instead of one DB query
  per month row; also remove unnecessary Decimal(str(...)) round-trips
  since SQLAlchemy already returns Numeric columns as Decimal
- eggs.py: add limit parameter (default 500, max 1000) to list_eggs to
  cap unbounded fetches on large datasets
- dashboard.js: pass start= (30 days ago) when fetching eggs so the
  dashboard only loads the data it actually needs for the chart and
  recent collections list

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-18 00:02:58 -07:00
parent 37f19a83ed
commit 60fed6d464
5 changed files with 46 additions and 18 deletions

View File

@@ -1,5 +1,5 @@
from datetime import date, datetime
from sqlalchemy import Boolean, Integer, Date, DateTime, Text, Numeric, String, ForeignKey, UniqueConstraint, func
from sqlalchemy import Boolean, Integer, Date, DateTime, Text, Numeric, String, ForeignKey, UniqueConstraint, Index, func
from sqlalchemy.orm import Mapped, mapped_column
from database import Base
@@ -30,6 +30,7 @@ class EggCollection(Base):
class FlockHistory(Base):
__tablename__ = "flock_history"
__table_args__ = (Index("ix_flock_history_user_date", "user_id", "date"),)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
@@ -41,6 +42,7 @@ class FlockHistory(Base):
class FeedPurchase(Base):
__tablename__ = "feed_purchases"
__table_args__ = (Index("ix_feed_purchases_user_date", "user_id", "date"),)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
@@ -53,6 +55,7 @@ class FeedPurchase(Base):
class OtherPurchase(Base):
__tablename__ = "other_purchases"
__table_args__ = (Index("ix_other_purchases_user_date", "user_id", "date"),)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)