fix: focus_areas column name + goal progress calculation
All checks were successful
Deploy Development / deploy (push) Successful in 49s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 13s

Fixed 2 critical placeholder issues:

1. focus_areas_weighted_json was empty:
   - Query used 'area_key' but column is 'key' in focus_area_definitions
   - Changed to SELECT key, not area_key

2. Goal progress placeholders showed "nicht verfügbar":
   - progress_pct in goals table is NULL (not auto-calculated)
   - Added manual calculation in all 3 formatter functions:
     * _format_goals_as_markdown() - shows % in table
     * _format_goals_behind() - finds lowest progress
     * _format_goals_on_track() - finds >= 50% progress

All placeholders should now return proper values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-03-28 12:43:54 +01:00
parent 112226938d
commit befc310958

View File

@ -686,11 +686,11 @@ def _get_focus_areas_weighted_json(profile_id: str) -> str:
with get_db() as conn: with get_db() as conn:
cur = get_cursor(conn) cur = get_cursor(conn)
cur.execute(""" cur.execute("""
SELECT area_key, name_de, name_en, category SELECT key, name_de, name_en, category
FROM focus_area_definitions FROM focus_area_definitions
WHERE is_active = true WHERE is_active = true
""") """)
definitions = {row['area_key']: row for row in cur.fetchall()} definitions = {row['key']: row for row in cur.fetchall()}
# Build weighted list # Build weighted list
result = [] result = []
@ -726,12 +726,33 @@ def _format_goals_as_markdown(profile_id: str) -> str:
for goal in goals: for goal in goals:
name = goal.get('name') or goal.get('goal_type', 'Unbekannt') name = goal.get('name') or goal.get('goal_type', 'Unbekannt')
current = f"{goal.get('current_value', '-')}" current = goal.get('current_value')
target = f"{goal.get('target_value', '-')}" target = goal.get('target_value')
progress = f"{goal.get('progress_pct', '-')}%" if goal.get('progress_pct') else '-' start = goal.get('start_value')
# Calculate progress if possible
progress_str = '-'
if None not in [current, target, start]:
try:
current_f = float(current)
target_f = float(target)
start_f = float(start)
if target_f == start_f:
progress_pct = 100 if current_f == target_f else 0
else:
progress_pct = ((current_f - start_f) / (target_f - start_f)) * 100
progress_pct = max(0, min(100, progress_pct))
progress_str = f"{int(progress_pct)}%"
except (ValueError, ZeroDivisionError):
progress_str = '-'
current_str = f"{current}" if current is not None else '-'
target_str = f"{target}" if target is not None else '-'
status = '🎯' if goal.get('is_primary') else '' status = '🎯' if goal.get('is_primary') else ''
lines.append(f"| {name} | {current} | {target} | {progress} | {status} |") lines.append(f"| {name} | {current_str} | {target_str} | {progress_str} | {status} |")
return '\n'.join(lines) return '\n'.join(lines)
except Exception: except Exception:
@ -793,19 +814,43 @@ def _format_goals_behind(profile_id: str, n: int = 3) -> str:
if not goals: if not goals:
return 'Keine Ziele definiert' return 'Keine Ziele definiert'
# Filter goals with progress_pct available, sort by lowest progress # Calculate progress for each goal
goals_with_progress = [g for g in goals if g.get('progress_pct') is not None] goals_with_progress = []
for g in goals:
current = g.get('current_value')
target = g.get('target_value')
start = g.get('start_value')
if None in [current, target, start]:
continue
# Calculate progress percentage
try:
current = float(current)
target = float(target)
start = float(start)
if target == start:
progress_pct = 100 if current == target else 0
else:
progress_pct = ((current - start) / (target - start)) * 100
progress_pct = max(0, min(100, progress_pct))
g['_calc_progress_pct'] = int(progress_pct)
goals_with_progress.append(g)
except (ValueError, ZeroDivisionError):
continue
if not goals_with_progress: if not goals_with_progress:
return 'Keine Ziele mit Fortschritt' return 'Keine Ziele mit Fortschritt'
# Sort by progress ascending (lowest first) and take top N # Sort by progress ascending (lowest first) and take top N
sorted_goals = sorted(goals_with_progress, key=lambda x: x.get('progress_pct', 0))[:n] sorted_goals = sorted(goals_with_progress, key=lambda x: x.get('_calc_progress_pct', 0))[:n]
lines = [] lines = []
for goal in sorted_goals: for goal in sorted_goals:
name = goal.get('name') or goal.get('goal_type', 'Unbekannt') name = goal.get('name') or goal.get('goal_type', 'Unbekannt')
progress = goal.get('progress_pct', 0) progress = goal.get('_calc_progress_pct', 0)
lines.append(f"{name} ({progress}%)") lines.append(f"{name} ({progress}%)")
return ', '.join(lines) return ', '.join(lines)
@ -822,19 +867,46 @@ def _format_goals_on_track(profile_id: str, n: int = 3) -> str:
if not goals: if not goals:
return 'Keine Ziele definiert' return 'Keine Ziele definiert'
# Filter goals with progress >= 50%, sort by highest progress # Calculate progress for each goal
goals_on_track = [g for g in goals if g.get('progress_pct') is not None and g.get('progress_pct', 0) >= 50] goals_with_progress = []
for g in goals:
current = g.get('current_value')
target = g.get('target_value')
start = g.get('start_value')
if None in [current, target, start]:
continue
# Calculate progress percentage
try:
current = float(current)
target = float(target)
start = float(start)
if target == start:
progress_pct = 100 if current == target else 0
else:
progress_pct = ((current - start) / (target - start)) * 100
progress_pct = max(0, min(100, progress_pct))
g['_calc_progress_pct'] = int(progress_pct)
goals_with_progress.append(g)
except (ValueError, ZeroDivisionError):
continue
# Filter goals with progress >= 50%
goals_on_track = [g for g in goals_with_progress if g.get('_calc_progress_pct', 0) >= 50]
if not goals_on_track: if not goals_on_track:
return 'Keine Ziele auf gutem Weg' return 'Keine Ziele auf gutem Weg'
# Sort by progress descending (highest first) and take top N # Sort by progress descending (highest first) and take top N
sorted_goals = sorted(goals_on_track, key=lambda x: x.get('progress_pct', 0), reverse=True)[:n] sorted_goals = sorted(goals_on_track, key=lambda x: x.get('_calc_progress_pct', 0), reverse=True)[:n]
lines = [] lines = []
for goal in sorted_goals: for goal in sorted_goals:
name = goal.get('name') or goal.get('goal_type', 'Unbekannt') name = goal.get('name') or goal.get('goal_type', 'Unbekannt')
progress = goal.get('progress_pct', 0) progress = goal.get('_calc_progress_pct', 0)
lines.append(f"{name} ({progress}%)") lines.append(f"{name} ({progress}%)")
return ', '.join(lines) return ', '.join(lines)