fix: Prevent manual progress entries for automatic goals
All checks were successful
Deploy Development / deploy (push) Successful in 43s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s

**Backend Safeguards:**
- get_goals_grouped: Added source_table, source_column, direction to SELECT
- create_goal_progress: Check source_table before allowing manual entry
- Returns HTTP 400 if user tries to log progress for automatic goals (weight, activity, etc.)

**Prevents:**
- Data confusion: Manual entries in goal_progress_log for weight/activity/etc.
- Dual tracking: Same data in multiple tables
- User error: Wrong data entry location

**Result:**
- Frontend filter (!goal.source_table) now works correctly
- CustomGoalsPage shows ONLY custom goals (flexibility, strength, etc.)
- Clear error message if manual entry attempted via API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-03-27 17:00:53 +01:00
parent 1960ae4924
commit 217990d417

View File

@ -561,15 +561,25 @@ def create_goal_progress(goal_id: str, data: GoalProgressCreate, session: dict =
with get_db() as conn:
cur = get_cursor(conn)
# Verify ownership
cur.execute(
"SELECT id, unit FROM goals WHERE id = %s AND profile_id = %s",
(goal_id, pid)
)
# Verify ownership and check if manual entry is allowed
cur.execute("""
SELECT g.id, g.unit, gt.source_table
FROM goals g
LEFT JOIN goal_type_definitions gt ON g.goal_type = gt.type_key
WHERE g.id = %s AND g.profile_id = %s
""", (goal_id, pid))
goal = cur.fetchone()
if not goal:
raise HTTPException(status_code=404, detail="Ziel nicht gefunden")
# Prevent manual entries for goals with automatic data sources
if goal['source_table']:
raise HTTPException(
status_code=400,
detail=f"Manuelle Einträge nicht erlaubt für automatisch erfasste Ziele. "
f"Bitte nutze die entsprechende Erfassungsseite (z.B. Gewicht, Aktivität)."
)
# Insert progress entry
try:
cur.execute("""
@ -660,7 +670,8 @@ def get_goals_grouped(session: dict = Depends(require_auth)):
g.unit, g.target_date, g.status, g.is_primary, g.category, g.priority,
g.name, g.description, g.progress_pct, g.on_track, g.projection_date,
g.created_at, g.updated_at,
gt.label_de, gt.icon, gt.category as type_category
gt.label_de, gt.icon, gt.category as type_category,
gt.source_table, gt.source_column, gt.direction
FROM goals g
LEFT JOIN goal_type_definitions gt ON g.goal_type = gt.type_key
WHERE g.profile_id = %s