Skip to content

Backend should write digest_tasks.user_id directly (remove n8n back-fill dependency) #7

@nmogil

Description

@nmogil

Summary

The backend writes digest_tasks rows without a user_id. The n8n orchestrator (workflow 3) later back-fills digest_tasks.user_id by matching task_id to a profiles row. The frontend Dashboard queries digest_tasks by user_id, so this out-of-band back-fill is load-bearing yet invisible from either repo. The backend should own user_id and write it directly.

Current state (verified)

  • src/state_supabase.py create_task / create_task_with_source_date (lines 27-40, 177-199) write task_id, status, message, result, user_info, timestamps — never user_id.
  • /generate-digest (src/main.py:301-310) builds user_info from the request body (name, title, goals, etc.) but receives no user identifier.
  • Per paperboy_all/CLAUDE.md: workflow 3 (3_Send_Digest_Email_v2, id GwegBjHAUPQO3380) "looks up the profile by task_id, back-fills digest_tasks.user_id from that profile" before the frontend can show the digest. n8n workflow 2 writes task_id back to profiles when it kicks off generation, which is what makes the later match possible.

Why this matters

  • The link between a digest and the user who owns it is reconstructed in n8n, not asserted by the system that creates the digest. Break that n8n step and the frontend silently shows nothing — no error, just missing digests.
  • It's fragile coupling across three systems (backend, n8n, Supabase) for what should be a single foreign key written at creation time.
  • It blocks the backend from ever serving user-scoped queries itself.

Proposed approach

  1. Add an optional user_id (uuid) to the /generate-digest request model (src/api_models.py) and to the n8n workflow 2 HTTP node so the orchestrator forwards profiles.id (it already has the profile in hand when it POSTs).
  2. Thread user_id through to create_task_with_source_date and persist it on the digest_tasks row (src/state_supabase.py). Add the column via the migrations workflow if it isn't already present (see schema-migrations issue).
  3. Keep the n8n back-fill temporarily as a fallback for rows that arrive without user_id, then remove it once all callers send user_id. Coordinate the cutover so digests never go dark.
  4. Update paperboy_all/CLAUDE.md to reflect that the backend now owns user_id.

Files likely involved

  • src/api_models.py (add user_id to the generate-digest request)
  • src/main.py:289-361 (accept + pass through)
  • src/state_supabase.py:177-199 (persist user_id)
  • n8n workflow 2_Generate_Digest (id ilWr3k5rSwCHRFXc) HTTP node — forward profiles.id as user_id. Use mcp__n8n-mcp__* to inspect/edit.
  • n8n workflow 3_Send_Digest_Email_v2 (id GwegBjHAUPQO3380) — back-fill becomes a fallback, then is retired.
  • paperboy-frontend/src/integrations/supabase/types.ts if the column shape changes.

Acceptance criteria

  • digest_tasks rows created by the backend include user_id when the caller supplies it.
  • n8n workflow 2 forwards profiles.id as user_id.
  • The frontend Dashboard finds digests by user_id for newly generated digests without relying on the workflow-3 back-fill.
  • Migration safety: existing rows and the fallback path are not broken during cutover.

Gotchas

  • Sequencing is critical. If you remove the workflow-3 back-fill before workflow 2 starts sending user_id, every new digest disappears from the UI. Land backend + workflow 2 first, verify, then retire the back-fill.
  • This spans two repos + n8n. Treat it as coordinated changes, not one PR (per paperboy_all/CLAUDE.md "two repos, two commits" rule).
  • Confirm digest_tasks.user_id type matches profiles.id type exactly to avoid join/filter mismatches.

Metadata

Metadata

Assignees

No one assigned

    Labels

    architectureArchitectural / structural changereliabilityReliability / operational robustness

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions