feat: Phase 2 — saved recipes, browser, accessibility, level UX #69

Merged
pyr0ball merged 17 commits from feature/orch-auto-lifecycle into main 2026-04-08 15:13:45 -07:00
3 changed files with 22 additions and 5 deletions
Showing only changes of commit 6a59c8dfd1 - Show all commits

View file

@ -6,6 +6,8 @@ import os
import secrets
from datetime import datetime, timedelta, timezone
import sqlite3
import requests
from fastapi import APIRouter, Depends, HTTPException
@ -42,11 +44,14 @@ def _require_household_owner(session: CloudUser = Depends(_require_premium)) ->
def _household_store(household_id: str) -> Store:
"""Open the household DB directly (used during invite acceptance)."""
from pathlib import Path
"""Open the household DB directly (used during invite acceptance).
Sets row_factory so dict-style column access works on raw conn queries.
"""
db_path = CLOUD_DATA_ROOT / f"household_{household_id}" / "kiwi.db"
db_path.parent.mkdir(parents=True, exist_ok=True)
return Store(db_path)
store = Store(db_path)
store.conn.row_factory = sqlite3.Row
return store
def _heimdall_post(path: str, body: dict) -> dict:
@ -74,7 +79,13 @@ async def create_household(session: CloudUser = Depends(_require_premium)):
if session.household_id:
raise HTTPException(status_code=409, detail="You are already in a household.")
data = _heimdall_post("/admin/household/create", {"owner_user_id": session.user_id})
household_id = data.get("household_id", "local-household")
household_id = data.get("household_id")
if not household_id:
# Heimdall returned OK but without a household_id — treat as server error.
# Fall back to a local stub only when HEIMDALL_ADMIN_TOKEN is unset (dev mode).
if HEIMDALL_ADMIN_TOKEN:
raise HTTPException(status_code=500, detail="Heimdall did not return a household_id.")
household_id = "local-household"
return HouseholdCreateResponse(
household_id=household_id,
message="Household created. Share an invite link to add members.",

View file

@ -13,6 +13,7 @@ services:
environment:
CLOUD_MODE: "true"
CLOUD_DATA_ROOT: /devl/kiwi-cloud-data
KIWI_BASE_URL: https://menagerie.circuitforge.tech/kiwi
# DIRECTUS_JWT_SECRET, HEIMDALL_URL, HEIMDALL_ADMIN_TOKEN — set in .env
# DEV ONLY: comma-separated IPs that bypass JWT auth (LAN testing without Caddy).
# Production deployments must NOT set this. Leave blank or omit entirely.

View file

@ -86,8 +86,13 @@ def test_invite_generates_token():
app.dependency_overrides.clear()
def test_accept_invalid_token_returns_404():
def test_accept_invalid_token_returns_404(tmp_path, monkeypatch):
"""Accepting a non-existent token returns 404."""
import app.api.endpoints.household as hh_ep
import app.cloud_session as cs
monkeypatch.setattr(hh_ep, "CLOUD_DATA_ROOT", tmp_path)
monkeypatch.setattr(cs, "CLOUD_DATA_ROOT", tmp_path)
from app.main import app
from app.cloud_session import get_session
import tempfile, pathlib