Agents Builders

Standard Studio::Link model: /l/<token>, branded mailer, managed email image (engine foundation)

Archived
task-f2ca3e97a730

Created

Jun 21, 05:39

Started

Jun 21, 05:40

Completed

Jun 22, 01:54

DevOps handoff

Type

Feature

Shape

library

Worktree Slug

standard-link-model

Repositories

studio-engine, mcritchie-studio, turf-monster

Release Train

Branch

feat/standard-link-model

Local URL

QA URL

Production URL

auth email shared-engine referral migration

Acceptance Criteria

  • Studio::Link model in engine: short urlsafe token (~16 chars), kind (magic_link|referral), optional polymorphic linkable, metadata jsonb (email/return_to/etc), nullable expires_at, consumed_at for single-use kinds; engine-owned migration
  • /l/<token> route + controller in engine dispatches by kind: magic_link keeps GET-inert confirm + POST-consume; referral sets attribution cookie + redirects to metadata target; /magic_link/<token> kept as a one-release alias
  • Branded mailer (layout + magic-link body + managed header image) lifted into the engine so both apps render the same branded email
  • Shared admin email-image page built on existing image-upload host + Studio::S3/ImageCache, per-purpose (magic-link header wired now, extensible); linkable from each app admin hub
  • Consumer CI green in BOTH mcritchie-studio and turf-monster against the new engine version

Expected Test Plan

  • unit
  • integration

Checks Run

  • [unit] engine: test/lib/studio/link_token_test.rb (8 runs, 23 assertions) + full pure suite 157 runs/531 assertions, 0 failures
  • [integration] mcritchie-studio (engine branch, store=:database): 22 assertions green — /l magic-link flow (7) + email-image admin (6) + legacy magic-link (9)

Stage Timeline

Who handled each stage, the time it took (measured), and the model / tokens / cost reported (best-effort) — plus who's on it right now. means the agent didn't report that metric.

No stage changes recorded yet.

Conversation

QA review feedback, agent handoffs, and follow-up notes for this task.

Handoff 6 days ago

Engine PR #7 (studio-engine). Foundation for the standard /l/<token> link scheme + branded mailer + admin email-image. Fully back-compat (magic_link_store defaults :signed). Verified via mcritchie integration on the branch (22 assertions). GATED: gem publish is the conductor/operator lane — app adoption PRs (mcritchie task-0a09e3a0b60e, turf-monster) depend on this releasing first.

QA Feedback 6 days ago

QA APPROVE-WITH-NITS -> reviewed. Security-correct: URL-safe token (route-constraint trap tested), GET-inert/POST-consume scanner-safe flow, atomic single-use burn, same-origin redirect sanitize, additive+reversible migration, fresh studio_links table (no collision with turf magic_links). Not draft, MERGEABLE, not behind. Non-blocking nits: (1) LinksController not table-guarded — Studio::Link.find_by raises StatementInvalid/500 on a consumer that bumps the gem before migrating; mirror EmailImage.table_ready?. (2) expired/consumed link shows spinner before error (UX polish). Owed at publish lane (NOT this PR): bump Studio::VERSION 0.7.0->0.8.0 + promote CHANGELOG Unreleased. Carry-forward to first consumer-adoption task: atomic burn/expiry untestable in engine harness -> gate integration coverage there; turf-monster must set Studio.draw_link_routes=false; mcritchie-studio must ship the migration in the SAME change as the gem bump.

Comment 5 days ago

GEM PUBLISHED: studio-engine 0.8.0 live on RubyGems (gem registered), PR #7 squash-merged to studio-engine main, tagged v0.8.0. Version bumped 0.7.0→0.8.0 + CHANGELOG promoted at publish. Consumers can now pin 'studio-engine','~> 0.8'. Unblocks the adoption tasks (task-0a09e3a0b60e mcr, task-a54f8e18a68f turf).

Sealed-bid sizing

Edit →

Alex (PM)

Avi (PO)

Dev

Actual