cauldron/cauldron/templates/me.html
Kayos 1540c2f436 v0.2: household-shared picks pool + /plan with lock button + scoreboard + streak
DB:
- migration 006 — cauldron_households (mirrors Mealie household), members
- migration 007 — cauldron_meal_plans (per household per week, lock state)
- new helpers: upsert_household, add_household_member, get_user_household_id,
  list_household_member_subs, get_or_create_plan, lock_plan,
  auto_lock_past_unlocked_plans, household_scoreboard, household_streak,
  list_household_pick_slugs, list_household_picks_with_pickers

Backend:
- sync_user_household() — pulls Mealie's /api/users/self, upserts the
  household row, ensures membership. Fires on /connect-mealie POST and
  lazy on every /me / /picks / /plan / /recipes load.
- current_household_id() helper used by all user-facing routes
- /recipes + /api/recipes.json now mark items.picked=True if ANYONE in the
  household has pinned (shared pool, not per-user)
- /picks now renders household-pooled view with attribution (who pinned what)
- /plan replaces stub: shows current week's lock state + lock button +
  scoreboard + streak. POST /api/plan/lock locks this week's plan with
  reason='user'. Past unlocked weeks auto-lock on read with reason='auto'.
- /list still stub (v0.3 territory)

UI:
- picks.html: each pick shows '🍄 pinned by <name(s)>' attribution row,
  unpin button only on your own picks, household_size in lede
- plan.html: NEW. Lock state pill, lock button (open weeks only), scoreboard
  table with rank/wins/last_win, streak ribbon ('🔥 abby on a 3-week run')
  if streak >= 2
- me.html: shows household name + member count

Locking semantics match Cobb's pick:
- (c) both — user-lock = scoreboard win, auto-lock past calendar = no win.
  Auto-lock fires lazily on /plan view (no cron needed for v0.2).
- Picks pool = (a) shared across household.
- Game shape = medium (locked-by + tally + streak counter, room for richer
  badges/notifs in v0.4).
2026-04-28 21:11:11 -07:00

57 lines
2.2 KiB
HTML

{% extends "_base.html" %}
{% block title %}{{ user.name or user.email }} · Cauldron{% endblock %}
{% block content %}
<div class="page-head">
<div class="crumb">// account</div>
<h1><span class="accent">{{ user.name or user.email.split('@')[0] }}</span></h1>
<div class="lede">welcome back to the coven.</div>
</div>
<section class="panel">
<div class="panel-head">
<h2>identity</h2>
<span class="ctx">authentik</span>
</div>
<dl class="kv">
<dt>email</dt><dd>{{ user.email }}</dd>
<dt>subject</dt><dd>{{ user.sub }}</dd>
</dl>
</section>
<section class="panel green">
<div class="panel-head">
<h2>mealie</h2>
{% if connected %}<span class="pill pill-ok">connected</span>{% else %}<span class="pill pill-warn">not connected</span>{% endif %}
</div>
{% if connected and mealie_user %}
<dl class="kv">
<dt>logged in as</dt><dd>{{ mealie_user.username or mealie_user.email }}</dd>
<dt>full name</dt><dd>{{ mealie_user.fullName or '—' }}</dd>
<dt>role</dt><dd>{{ 'admin' if mealie_user.admin else 'member' }}</dd>
{% if mealie_user.household %}
<dt>household</dt><dd>{{ mealie_user.household.name or mealie_user.household.slug }} · {{ household_size }} {% if household_size == 1 %}member{% else %}members{% endif %}</dd>
{% endif %}
</dl>
<form method="post" action="/disconnect-mealie" class="btn-row">
<button class="btn btn-purple" type="submit">Disconnect</button>
<span class="muted">revoking on mealie's side also works.</span>
</form>
{% elif connected %}
<p class="muted">token stored, but mealie didn't return profile data. probably revoked or rotated.</p>
<form method="post" action="/disconnect-mealie" class="btn-row">
<button class="btn btn-purple" type="submit">Reset</button>
</form>
{% else %}
<p>connect mealie so cauldron can act on your behalf — your recipes, your meal plan, your shopping list. one-time, ~30 seconds.</p>
<p><a class="btn btn-primary" href="/connect-mealie">Connect mealie →</a></p>
{% endif %}
</section>
<hr>
<form method="post" action="/logout">
<button class="btn" type="submit">Sign out</button>
</form>
{% endblock %}