diff --git a/.env.example b/.env.example
index ebda3b0..9a305b5 100644
--- a/.env.example
+++ b/.env.example
@@ -2,6 +2,7 @@
# cp .env.example .env
# ── MySQL ─────────────────────────────────────────────────────────────────────
+# Use strong random passwords — generate with: openssl rand -hex 16
MYSQL_ROOT_PASSWORD=change_me
MYSQL_DATABASE=eggtracker
MYSQL_USER=eggtracker
@@ -9,6 +10,7 @@ MYSQL_PASSWORD=change_me
# ── Super admin ───────────────────────────────────────────────────────────────
# This account is created (and its password synced) automatically on every startup.
+# Use a strong password of at least 10 characters.
ADMIN_USERNAME=admin
ADMIN_PASSWORD=change_me
diff --git a/backend/main.py b/backend/main.py
index 60615bf..252291c 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -91,6 +91,15 @@ def _run_migrations():
except Exception:
db.rollback() # index already exists — safe to ignore
+ # v2.3 — unique constraint on flock_history (user_id, date)
+ try:
+ db.execute(text(
+ "ALTER TABLE flock_history ADD CONSTRAINT uq_flock_user_date UNIQUE (user_id, date)"
+ ))
+ db.commit()
+ except Exception:
+ db.rollback() # constraint already exists — safe to ignore
+
@asynccontextmanager
async def lifespan(app: FastAPI):
diff --git a/backend/models.py b/backend/models.py
index 48020b1..7f40f42 100644
--- a/backend/models.py
+++ b/backend/models.py
@@ -30,7 +30,10 @@ class EggCollection(Base):
class FlockHistory(Base):
__tablename__ = "flock_history"
- __table_args__ = (Index("ix_flock_history_user_date", "user_id", "date"),)
+ __table_args__ = (
+ UniqueConstraint("user_id", "date", name="uq_flock_user_date"),
+ 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)
diff --git a/nginx/html/404.html b/nginx/html/404.html
index caf2a51..fe3bbb0 100644
--- a/nginx/html/404.html
+++ b/nginx/html/404.html
@@ -30,6 +30,6 @@
Go to Dashboard
-
+