{
  "schema_version": "1.1",
  "selection_rules": {
    "component": {
      "field": "kind",
      "match": "includes"
    },
    "ui_preference": {
      "field": "ui",
      "match": "equals"
    },
    "static_hosting": {
      "field": "host",
      "values": [
        "static"
      ]
    },
    "offline_browser": {
      "field": "ui",
      "values": [
        "client",
        "full"
      ]
    },
    "native_both": [
      "ios",
      "android"
    ],
    "unknown_is_supported": false
  },
  "reviewed": "2026-10-10",
  "evidence_status": "documentation-reviewed",
  "selection_guide": "/choose.md",
  "agent_entry": "/llms.txt",
  "requirements": [
    {
      "key": "existing_stack",
      "label": "Existing project",
      "description": "Repository, chosen stack and conventions; whether a new stack is actually requested."
    },
    {
      "key": "deliverables",
      "label": "Target surfaces",
      "description": "Browser, API, command line, automation, iOS, Android; a product may combine several."
    },
    {
      "key": "native_ui",
      "label": "Native platform UI",
      "description": "Native controls and platform integration versus browser UI."
    },
    {
      "key": "offline",
      "label": "Offline behavior",
      "description": "Read-only cache, offline edits, synchronization and conflict policy."
    },
    {
      "key": "integrations",
      "label": "Required integrations",
      "description": "Vendor SDKs, data/AI libraries, payments and platform APIs."
    },
    {
      "key": "runtime",
      "label": "Runtime constraints",
      "description": "Latency, throughput, concurrency, memory, persistent connections and background work."
    },
    {
      "key": "deployment",
      "label": "Deployment",
      "description": "Allowed host/runtime, data residency, OS, native toolchains and operational constraints."
    },
    {
      "key": "data_security",
      "label": "Data and access",
      "description": "Tenancy, authorization, durability, retention, backups and recovery."
    },
    {
      "key": "maintenance",
      "label": "Maintenance",
      "description": "Team experience, delivery constraints, licensing, support and budget."
    }
  ],
  "coverage_gaps": [
    "Desktop stack preparation",
    "C# and .NET stack preparation",
    "Embedded and game development preparation",
    "Exact dependency compatibility qualification",
    "Executable starter projects",
    "Representative cross-stack agent delivery comparisons"
  ],
  "field_semantics": {
    "kind": "Recommended application component; not exhaustive language capability.",
    "host": "Deployment class for this profile; runtime adapters need separate qualification.",
    "ui": "Recommended UI architecture. none means this profile provides no client UI.",
    "best_practices": "Editorial summary of the linked research guide; verify installed-version documentation."
  },
  "profiles": [
    {
      "id": "elixir-phoenix-liveview",
      "name": "Elixir: Phoenix + LiveView + Ecto/PostgreSQL, with Oban when needed",
      "use_cases": [
        "Connected browser products and portals",
        "Real-time collaboration interfaces",
        "JSON APIs for native clients",
        "Durable application background work"
      ],
      "choose_when": [
        "Server-owned state and business rules dominate a connected product.",
        "Phoenix conventions and OTP process lifecycles match the service requirements.",
        "A relational store can also support durable background jobs."
      ],
      "avoid_when": [
        "The main deliverable is a platform-native mobile UI or offline-first client.",
        "The application depends on a library, accelerator or vendor SDK unsupported by the intended Elixir deployment.",
        "A small static site, simple script or CLI does not need a running web application."
      ],
      "tools": [
        {
          "job": "Web application",
          "default": "Phoenix + its generated HTTP/asset defaults",
          "alternatives": [
            "Phoenix API-only",
            "Plain supervised Mix application for non-web services"
          ],
          "reason": "Coherent routing, contexts and generated application structure.",
          "limits": "Phoenix is unnecessary for a CLI or a service without HTTP; preserve existing architecture.",
          "source_urls": [
            "https://hexdocs.pm/phoenix/Mix.Tasks.Phx.New.html",
            "https://hexdocs.pm/phoenix/json_and_apis.html"
          ]
        },
        {
          "job": "Dependency documentation and agent guidance",
          "default": "usage_rules for selected dependency guidance",
          "alternatives": [
            "Installed-version HexDocs and maintained repository guidance"
          ],
          "reason": "Discover dependency documentation and synchronize selected upstream usage rules for agents",
          "limits": "Development-only tool; inspect installed-version options and review generated content. Preserve Phoenix-generated guidance by default. An explicit README-only repository may configure file: \"docs/dependency-rules.md\" in mix.exs and link it from README; this destination is an optional project convention, not an upstream default.",
          "source_urls": [
            "https://hexdocs.pm/usage_rules/readme.html",
            "https://hexdocs.pm/usage_rules/Mix.Tasks.UsageRules.Sync.html"
          ]
        },
        {
          "job": "Browser UI",
          "default": "LiveView + HEEx components",
          "alternatives": [
            "Server-rendered Phoenix HTML",
            "JavaScript hooks for isolated client behavior",
            "Separate TypeScript browser application over Phoenix APIs"
          ],
          "reason": "Shared server-side business operations and interactive screens suit connected forms, portals and collaboration.",
          "limits": "Offline-first state, high-frequency local interactions and rich canvas editors can justify a dedicated client. LiveView does not remove HTML/CSS or all JavaScript.",
          "source_urls": [
            "https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html",
            "https://hexdocs.pm/phoenix_live_view/js-interop.html",
            "https://hexdocs.pm/phoenix/json_and_apis.html"
          ]
        },
        {
          "job": "Shared relational persistence",
          "default": "Ecto + PostgreSQL",
          "alternatives": [
            "Another Ecto adapter when an actual persistence requirement warrants it"
          ],
          "reason": "Explicit queries, changesets and database transactions fit shared application data.",
          "limits": "Changeset validation is not a replacement for database constraints or authorization; database operations and migrations need operational ownership. Current Ecto documentation deprecates Repo.transaction/2 in favor of Repo.transact/2. Follow the installed-version API and callback/result semantics; do not mechanically rename an existing transaction without tests.",
          "source_urls": [
            "https://hexdocs.pm/ecto/Ecto.html",
            "https://hexdocs.pm/ecto/Ecto.Repo.html#c:transact/2"
          ]
        },
        {
          "job": "Accounts and access control",
          "default": "phx.gen.auth + scoped context authorization",
          "alternatives": [
            "External identity integration for SSO requirements"
          ],
          "reason": "Generated first-party authentication keeps application-owned code; contexts authorize operations.",
          "limits": "Check permission both on mount/navigation and each operation. Test revoked access and reconnect behavior; magic-link delivery needs a configured mail provider.",
          "source_urls": [
            "https://hexdocs.pm/phoenix/mix_phx_gen_auth.html",
            "https://hexdocs.pm/phoenix_live_view/security-model.html"
          ]
        },
        {
          "job": "Durable background work",
          "default": "Oban with the existing Ecto/PostgreSQL database",
          "alternatives": [
            "Another supported Oban SQL engine after engine-specific qualification; retain the existing datastore when it meets requirements"
          ],
          "reason": "Persist jobs and enqueue alongside domain changes in one transaction.",
          "limits": "Task is only for explicitly disposable work and does not satisfy crash-durable delivery. Oban engine support and guarantees must be checked against the selected version; Redis is not a shipped Oban persistence engine. Oban Pro is an optional licensed extension, not a replacement for persistence.",
          "source_urls": [
            "https://hexdocs.pm/oban/Oban.html",
            "https://hexdocs.pm/oban/testing.html"
          ]
        },
        {
          "job": "Behavior and persistence tests",
          "default": "ExUnit + Ecto SQL Sandbox + LiveViewTest",
          "alternatives": [
            "Oban.Testing when jobs exist"
          ],
          "reason": "Test contexts, data invariants, denied access and server-side UI behavior.",
          "limits": "LiveViewTest does not establish browser JavaScript, accessibility or visual correctness. Inline/manual job tests are not a production recovery simulation.",
          "source_urls": [
            "https://hexdocs.pm/ex_unit/ExUnit.html",
            "https://hexdocs.pm/ecto_sql/Ecto.Adapters.SQL.Sandbox.html",
            "https://hexdocs.pm/phoenix_live_view/Phoenix.LiveViewTest.html",
            "https://hexdocs.pm/oban/testing.html"
          ]
        },
        {
          "job": "Real-browser checks",
          "default": "PhoenixTest.Playwright for critical browser flows",
          "alternatives": [
            "A separately maintained Playwright suite"
          ],
          "reason": "Exercise hooks, navigation, reconnects and actual browser behavior omitted by server-side tests.",
          "limits": "Adds Node/package-manager/browser binaries and sandbox configuration; verify supported wrapper features. It is an editorial extension, not a Phoenix generator default.",
          "source_urls": [
            "https://hexdocs.pm/phoenix_test_playwright/readme.html",
            "https://hexdocs.pm/phoenix_live_view/Phoenix.LiveViewTest.html"
          ]
        },
        {
          "job": "Code quality",
          "default": "Mix formatter and compiler warnings; Credo when selected",
          "alternatives": [
            "Dialyxir for additional success-typing analysis"
          ],
          "reason": "Fast local feedback plus consistency checks; select checks appropriate to project size.",
          "limits": "Static analysis does not prove domain correctness. Dialyxir adds analysis/PLT maintenance and is not a mandatory starter dependency.",
          "source_urls": [
            "https://hexdocs.pm/credo/overview.html",
            "https://hexdocs.pm/dialyxir/readme.html"
          ]
        },
        {
          "job": "Security checks",
          "default": "Hex audit + Sobelow, alongside permission tests",
          "alternatives": [],
          "reason": "Hex reports retired packages and known advisories; Sobelow finds common risky code patterns.",
          "limits": "Use the installed Hex version’s behavior. Scan findings need review; configure a non-zero Sobelow exit threshold and do not blanket-suppress findings. Neither proves the application secure.",
          "source_urls": [
            "https://hexdocs.pm/hex/Mix.Tasks.Hex.Audit.html",
            "https://hexdocs.pm/sobelow/readme.html",
            "https://hexdocs.pm/phoenix_live_view/security-model.html"
          ]
        },
        {
          "job": "Deployment",
          "default": "Mix release + runtime configuration",
          "alternatives": [
            "Containerized release when the host benefits"
          ],
          "reason": "Package application and runtime with explicit migration/server entry points.",
          "limits": "Build for the target OS/architecture and native libraries. Host choice, secrets, migrations, TLS, backups, restore and rollback remain separate responsibilities.",
          "source_urls": [
            "https://hexdocs.pm/phoenix/releases.html"
          ]
        },
        {
          "job": "Native mobile client boundary",
          "default": "Platform-native clients consuming Phoenix APIs",
          "alternatives": [
            "Evaluate LiveView Native separately for an explicitly suitable connected client"
          ],
          "reason": "Preserve native UI/platform ownership while sharing server-side domain operations.",
          "limits": "Do not advertise Elixir as a complete native mobile default: LiveView Native’s inspected README uses release-candidate dependencies and platform-specific clients. Validate target support, offline behavior, accessibility and signing independently.",
          "source_urls": [
            "https://hexdocs.pm/phoenix/json_and_apis.html",
            "https://github.com/liveview-native/live_view_native"
          ]
        },
        {
          "job": "Project instructions",
          "default": "README navigation + generated Phoenix agent guidance",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Keep generated stack conventions available to coding agents",
          "limits": "Preserve maintained repository rules; --no-agents-md is an optional project choice, not the Phoenix default.",
          "source_urls": [
            "https://hexdocs.pm/phoenix/Mix.Tasks.Phx.New.html"
          ]
        },
        {
          "job": "Transactional email",
          "default": "Swoosh + selected provider adapter",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Mailer adapters and test delivery fit generated Phoenix account flows",
          "limits": "Configure adapter/client dependencies and sender credentials; keep test/local adapters in development only. Use Oban for required queued delivery; a Task has no durable retry guarantee.",
          "source_urls": [
            "https://hexdocs.pm/swoosh/Swoosh.html"
          ]
        },
        {
          "job": "Uploads",
          "default": "LiveView uploads",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Built-in upload configuration and consumption fit connected forms",
          "limits": "Configure allow_upload limits and authorize attachment association; persist consumed files before temp cleanup. External storage integration and content validation remain application work.",
          "source_urls": [
            "https://hexdocs.pm/phoenix_live_view/uploads.html"
          ]
        },
        {
          "job": "Realtime application events",
          "default": "Phoenix.PubSub",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Local/distributed publication updates connected views and channels",
          "limits": "Supervise PubSub and subscribe to scoped topics; authorize each subscription/action and test reconnect. PubSub is transient broadcast, not durable replay or a message queue.",
          "source_urls": [
            "https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html"
          ]
        }
      ],
      "setup_steps": [
        "Read README.md, mix.exs, mix.lock and runtime pins; preserve existing applications. This is a recipe, not executed setup evidence.",
        "For a new project, choose an empty source directory in a local development workspace. Check elixir --version, mix --version, mix phx.new --version and actual PostgreSQL connectivity; install only missing prerequisites using official instructions.",
        "Resolve and record a compatible Elixir/OTP pair and Phoenix generator. Generate with mix phx.new my_app --database postgres; honor generated guidance. Use --no-agents-md only when the repository explicitly adopts a README-only instruction policy.",
        "If dependency guidance synchronization is useful, add usage_rules as a development dependency, configure selected rules in mix.exs and review mix usage_rules.sync output. Honor generated Phoenix guidance; configure an alternate file only for an explicit repository policy.",
        "Enter my_app; configure development database credentials outside committed secrets; inspect and run mix setup. For API-only creation use the documented --no-html --no-assets options instead.",
        "If accounts are required, run mix phx.gen.auth Accounts User users --live, then mix deps.get and mix ecto.migrate; review generated instructions and email setup.",
        "If jobs are required, follow the installed Oban installation/migration instructions, supervise Oban and configure bounded queues; write idempotent workers and tests.",
        "Add selected development/test checks only. For PhoenixTest.Playwright install its JS dependency and matching browsers, configure test endpoint and SQL sandbox as documented.",
        "Run the checks below and actual browser flows. Fix failures in place, retaining logs; never regenerate over work to hide a failure.",
        "For deployment qualification, follow Phoenix releases: generate release helpers, compile production assets and build a target-compatible release. Rehearse migration, startup, reconnect, job retry and backup/restore on the selected host before claiming production readiness.",
        "Completion: record exact versions, lockfile, checks and observed flows in README-linked evidence; report untested deployment/mobile paths explicitly."
      ],
      "verification_commands": [
        "mix hex.audit",
        "mix format --check-formatted",
        "mix compile --warnings-as-errors",
        "mix test",
        "mix credo --strict  # only after installing/configuring Credo",
        "mix sobelow --strict --exit low  # only after installing/configuring Sobelow; review findings",
        "mix dialyzer  # optional, after Dialyxir/PLT configuration",
        "mix phx.server  # interactive smoke check, not an automated assertion",
        "MIX_ENV=prod mix assets.deploy  # release qualification, after production prerequisites",
        "MIX_ENV=prod mix release  # after release configuration; not deployment proof"
      ],
      "evidence_status": "documentation-reviewed",
      "sources": [
        {
          "url": "https://hexdocs.pm/phoenix/Mix.Tasks.Phx.New.html",
          "title": "Phoenix application generator",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html",
          "title": "Phoenix LiveView",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/phoenix_live_view/js-interop.html",
          "title": "LiveView JavaScript interoperability",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/ecto/Ecto.html",
          "title": "Ecto",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/phoenix/mix_phx_gen_auth.html",
          "title": "Phoenix authentication generator",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/phoenix_live_view/security-model.html",
          "title": "LiveView security model",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/oban/Oban.html",
          "title": "Oban",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/oban/testing.html",
          "title": "Oban testing",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/ex_unit/ExUnit.html",
          "title": "ExUnit",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/phoenix_live_view/Phoenix.LiveViewTest.html",
          "title": "LiveViewTest",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/ecto_sql/Ecto.Adapters.SQL.Sandbox.html",
          "title": "Ecto SQL Sandbox",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/phoenix_test_playwright/readme.html",
          "title": "PhoenixTest.Playwright",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/credo/overview.html",
          "title": "Credo",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/dialyxir/readme.html",
          "title": "Dialyxir",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/sobelow/readme.html",
          "title": "Sobelow",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/hex/Mix.Tasks.Hex.Audit.html",
          "title": "Hex dependency audit",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/phoenix/releases.html",
          "title": "Phoenix releases",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/phoenix/json_and_apis.html",
          "title": "Phoenix JSON and APIs",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/liveview-native/live_view_native",
          "title": "LiveView Native source README",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/swoosh/Swoosh.html",
          "title": "Swoosh",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/phoenix_live_view/uploads.html",
          "title": "LiveView uploads",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html",
          "title": "Phoenix PubSub",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/usage_rules/readme.html",
          "title": "usage_rules README",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/usage_rules/Mix.Tasks.UsageRules.Sync.html",
          "title": "usage_rules sync task",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://hexdocs.pm/ecto/Ecto.Repo.html#c:transact/2",
          "title": "Ecto current transaction API and semantics",
          "checked_date": "2026-10-13"
        }
      ],
      "open_questions": [
        "Does the product fit connected server-owned UI, or need a separate offline/native client?",
        "Which account/tenant permissions and email recovery requirements apply?",
        "Which work needs durable retries and duplicate-effect protection?",
        "Which host, object storage, observability and backup/restore requirements apply?"
      ],
      "title": "Phoenix + LiveView",
      "language": "Elixir",
      "group": "Web applications",
      "kind": [
        "web",
        "api"
      ],
      "ui": "server",
      "host": "server",
      "summary": "Connected products, live updates and background work in one application.",
      "shape": "Phoenix · LiveView · Ecto · PostgreSQL",
      "tradeoff": "A persistent server owns the UI state. Use a separate client for substantial offline work.",
      "research_file": "elixir.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Keep business operations in contexts shared by controllers, LiveViews and workers. Contexts are not automatically processes.",
        "Enforce authorization on every protected operation, including direct context calls and after access is revoked.",
        "Use ordinary functions first. Add processes for state ownership or lifecycle; add durable storage for work that must survive a restart.",
        "Give retried external effects stable idempotency keys. Exercise reconnects, failed jobs and cross-account access."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://phoenix.hexdocs.pm/overview.html",
          "https://phoenix.hexdocs.pm/installation.html",
          "https://hexdocs.pm/ecto/Ecto.Repo.html#c:transact/2"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/elixir-phoenix-liveview/",
      "markdown_url": "/stacks/elixir-phoenix-liveview/guide.md",
      "json_url": "/stacks/elixir-phoenix-liveview/record.json",
      "architecture_and_migration": {
        "id": "elixir-phoenix-liveview",
        "version_scope": "Fetched documentation: Phoenix 1.8.15, LiveView 1.2.12, PubSub 2.4.1, Plug 1.20.3, Ecto 3.14.2 / Ecto SQL 3.14.0, Oban 2.24.1, Exq 0.25.0 and OTP 29.1.1 ETS. Installed dependency compatibility is unqualified; pin the actual application before using version-specific APIs.",
        "operating_model": "Phoenix web modules call application contexts; Ecto supplies persistence boundaries. LiveView maintains connected server-side interaction, while Channels expose a client-facing realtime protocol. Recommendation: model domain operations through contexts and supervised responsibilities rather than translating every old controller, global singleton or database serialization bottleneck literally.",
        "architecture": [
          "Recommendation: contexts own business operations, Ecto Repo owns database access and explicit transactions join related writes. A single GenServer around all queries is an application choice, not a Phoenix requirement.",
          "Phoenix PubSub has a distributed-Elixir adapter and a Redis adapter. Redis can remain appropriate when deployment or interoperability requires it. Recommendation: identify the required delivery boundary before selecting the topology.",
          "Oban requires an Ecto-backed supported SQL engine. Its installation documents PostgreSQL, SQLite and MySQL; selecting PostgreSQL is this catalogue's target composition, not a universal Oban prerequisite. Recommendation: preserve durable external effects through idempotency and recovery checks."
        ],
        "developer_workflow": [
          "For a disposable target, mix phx.new PATH generates a Phoenix application with selectable database and HTML/LiveView options. In an existing project, inspect mix.lock, generated modules and maintained conventions before regenerating anything.",
          "When manually installing the selected Oban version, adapt mix ecto.gen.migration add_oban_jobs_table and mix ecto.migrate from its installation guide; configure the engine, Repo and supervised Oban child. Do not copy PostgreSQL settings into a SQLite or MySQL target.",
          "Use mix test for application tests and the generated Phoenix connection/channel fixtures. Recommendation: add mixed-version payload, authorization and restart scenarios; a passing formatter or compiler does not establish those contracts.",
          "For a release build, adapt MIX_ENV=prod mix assets.deploy and mix release from the Phoenix deployment workflow; runtime.exs owns runtime configuration. Recommendation: verify database migrations, job supervision and cluster/PubSub connectivity separately from HTTP startup."
        ],
        "avoid": [
          "Avoid replacing a durable queue with spawned tasks or an in-memory notification list while calling the change equivalent. Recommendation: explicitly accept the changed crash and retry behavior or retain a persistent queue.",
          "Avoid treating Exq's Resque/Sidekiq-compatible transport format as proof that Ruby Active Job wrappers, classes and serializers execute in Elixir. The exact consumer and payload contract still needs qualification.",
          "Avoid assuming Plug cookies decode Rails cookies: Plug exposes its own serializer, salts and cryptographic options. Avoid relying only on HTTP plugs for LiveView authorization; mount and events require checks.",
          "Avoid using ETS as a shared session or global lock store. Tables are local to their node and normally disappear with their owner unless an heir takes ownership. Recommendation: reserve ETS for explicitly reconstructible local state."
        ],
        "transitions": [
          {
            "capability": "data",
            "existing_contract": "Inventory schema, constraints, record identifiers and callbacks previously triggered by writes. Ecto schemas and changesets must preserve the intended domain semantics, not simply the old table shapes.",
            "coexistence": "Recommendation: keep the source application as the authoritative writer while Phoenix contexts read fixtures; move a tenant or domain operation with one named writer. Use additive schema changes and a single migration runner during shared-table operation.",
            "target": "Contexts calling Ecto Repo with explicit validation and transaction boundaries. Ecto.Multi composes related Repo operations in one database transaction; cross-store side effects require a separate delivery design.",
            "benefits": [
              {
                "benefit": "Recommendation: a context boundary can expose one reusable domain operation to LiveView, controllers and workers.",
                "prerequisites": "Resource authorization, constraints and side effects moved with that operation.",
                "tradeoffs": "Shared-schema coexistence limits schema changes; external effects do not become part of a database transaction."
              }
            ],
            "checks": [
              "Write a fixture through each allowed writer and read it from both runtimes; compare IDs, enum/null values, timestamps and constraint failures.",
              "Fail the second operation in an Ecto.Multi and verify the first database operation is absent; prove old readers still accept successful new writes."
            ],
            "rollback": "Recommendation: return the domain writer to the source while preserving additive schema and reconciling accepted new writes; delay destructive contractions until the rollback window closes.",
            "sources": [
              "https://hexdocs.pm/phoenix/contexts.html",
              "https://hexdocs.pm/ecto/Ecto.Multi.html",
              "https://hexdocs.pm/ecto_sql/Ecto.Migrator.html"
            ],
            "id": "data-1"
          },
          {
            "capability": "jobs",
            "existing_contract": "Rails workers currently own Ruby job execution, including Active Job/GlobalID serializers and backend retry/scheduling behavior. Record the actual Redis-backed backend and every backlog state rather than inferring it from the word Rails.",
            "coexistence": "Recommendation, retain/wrap path: keep Ruby workers and their broker; expose a narrow producer endpoint or durable outbox relay for Phoenix. Ruby remains the only consumer and scheduler for retained categories, and the interface names payload version, business idempotency key and enqueue acknowledgement.",
            "target": "Phoenix web/domain code with retained Ruby worker ownership is a valid permanent composition when queue interoperability or Ruby libraries remain necessary.",
            "benefits": [
              {
                "benefit": "Recommendation: the web layer can transfer before job execution without transforming the old backlog.",
                "prerequisites": "Defined producer interface, monitored delivery and retained worker deployment.",
                "tradeoffs": "Two runtimes and the broker remain operated; domain write plus broker enqueue is not a shared SQL transaction."
              }
            ],
            "checks": [
              "Submit a captured serializer/GlobalID case through the interface and confirm the intended Ruby class executes with its normal failure policy.",
              "Interrupt delivery after domain commit; recover it without duplicating a business effect. Verify only the Ruby scheduler owns the retained category."
            ],
            "rollback": "Recommendation: restore the old web producer while retaining the same workers; reconcile accepted interface/outbox entries before disabling the relay.",
            "sources": [
              "https://guides.rubyonrails.org/active_job_basics.html",
              "https://github.com/sidekiq/sidekiq/wiki/Job-Format",
              "https://github.com/sidekiq/sidekiq/wiki/Best-Practices"
            ],
            "id": "jobs-1",
            "option_title": "Retain Ruby workers behind an interface"
          },
          {
            "capability": "jobs",
            "existing_contract": "A retained Redis broker may carry Sidekiq/Resque-shaped jobs; framework wrappers, class names, serializer tags and version-sensitive timestamps are still part of the execution contract.",
            "coexistence": "Recommendation, broker-retaining replacement path: qualify Exq for selected job types on isolated queues. Keep unsupported Ruby types on Ruby consumers; map only deliberately supported payload versions, and give each category one consumer family and schedule owner.",
            "target": "Selected Elixir workers using Exq's documented Redis-backed Resque/Sidekiq-compatible format. This is a candidate for qualification, not a claim that arbitrary Active Job payloads are interoperable.",
            "benefits": [
              {
                "benefit": "Recommendation: selected job execution can move to Elixir while preserving the broker boundary.",
                "prerequisites": "Fixture-tested serialization, queue isolation, retry mapping and scheduler ownership.",
                "tradeoffs": "Redis remains; compatibility and unsupported Ruby argument types require explicit maintenance."
              }
            ],
            "checks": [
              "Replay ordinary arguments, an Active Job wrapper, serializer edge cases and scheduled/retry payloads; reject unsupported cases without consuming them silently.",
              "Crash after a business effect before acknowledgement and verify replay safety; confirm old and new consumers never race for an unqualified category."
            ],
            "rollback": "Recommendation: stop new consumption and return only backward-readable queued work to Ruby; preserve both consumers for payloads accepted during the transition.",
            "sources": [
              "https://exq.hexdocs.pm/readme.html",
              "https://github.com/sidekiq/sidekiq/wiki/Job-Format",
              "https://guides.rubyonrails.org/active_job_basics.html"
            ],
            "id": "jobs-2",
            "option_title": "Keep Redis and qualify Exq consumers"
          },
          {
            "capability": "jobs",
            "existing_contract": "Legacy Redis jobs and a proposed SQL queue have distinct payload/storage formats and retry/schedule state. A backend change does not copy the backlog or the recurring schedule.",
            "coexistence": "Recommendation, SQL replacement path: run Oban alongside the legacy broker and route selected categories exclusively to one system. Keep old ready, retry, delayed, failed and running work accounted for. Transfer each schedule once; use a recoverable relay/outbox while domain data and queue insertion span stores.",
            "target": "Oban workers on the chosen supported SQL engine. With the same Repo/transaction, Oban.insert in Ecto.Multi can join domain changes; a separate database cannot gain that atomicity merely from both databases being SQL.",
            "benefits": [
              {
                "benefit": "Atomic domain-write-and-job-insert is available within a shared transaction.",
                "prerequisites": "One supported database transaction/Repo for both writes and business idempotency for execution.",
                "tradeoffs": "Queue load shares the database; SQL atomic insertion does not guarantee exactly-once external effects."
              },
              {
                "benefit": "Recommendation: broker retirement can reduce the operated service inventory.",
                "prerequisites": "All Redis uses transferred, all backlog states reconciled and recovery/rollback checks passed.",
                "tradeoffs": "Redis plus SQL coexistence temporarily adds operational work; no service reduction occurs while Redis remains needed."
              }
            ],
            "checks": [
              "Rollback the combined transaction and confirm neither domain change nor executable Oban job remains.",
              "Pause a selected Oban queue, reconcile running work and inspect retained backlog; resume without duplicated effects.",
              "Restart during a job and validate the selected engine's configured recovery policy, including a failure after an external side effect."
            ],
            "rollback": "Recommendation: pause new producers/consumption, keep accepted Oban payloads executable, and reconcile effects before moving routing back. Do not blindly copy all rows into the old broker.",
            "sources": [
              "https://oban.hexdocs.pm/installation.html",
              "https://oban.hexdocs.pm/Oban.html",
              "https://hexdocs.pm/ecto/Ecto.Multi.html"
            ],
            "id": "jobs-3",
            "option_title": "Run Oban SQL workers alongside legacy queues"
          },
          {
            "capability": "identity",
            "existing_contract": "Record old cookie encoding, serializer, keys/salts, expiration and session revocation; shared account IDs alone do not establish cookie compatibility. Plug COOKIE defaults its serializer to external_term_format and exposes rotating cryptographic options.",
            "coexistence": "Recommendation: retain the existing identity authority through a qualified session exchange or compatibility decoder. Map authorization rules into Phoenix contexts and LiveView mount/events; keep account and revocation ownership explicit.",
            "target": "Phoenix identity with the selected session store and LiveView authorization in mount/on_mount and actions. Recommendation: choose planned reauthentication when cookie compatibility is not worth maintaining.",
            "benefits": [
              {
                "benefit": "Recommendation: users can preserve access while a connected feature moves.",
                "prerequisites": "Qualified decoder/exchange, shared revocation and event-level authorization.",
                "tradeoffs": "Long-lived sockets need explicit disconnect/recheck behavior when access changes; sharing secrets alone is insufficient."
              }
            ],
            "checks": [
              "Login through the old runtime, access the target feature, revoke the account/session and confirm HTTP plus existing/reconnected LiveView access follows the required policy.",
              "Send a forged delete event for another tenant despite a hidden UI control; confirm the server rejects it."
            ],
            "rollback": "Recommendation: retain the old decoder/exchange until routing can return; never reverse revocation merely to restore traffic.",
            "sources": [
              "https://hexdocs.pm/plug/Plug.Session.COOKIE.html",
              "https://hexdocs.pm/phoenix_live_view/security-model.html",
              "https://guides.rubyonrails.org/security.html"
            ],
            "id": "identity-1"
          },
          {
            "capability": "realtime",
            "existing_contract": "Action Cable, Phoenix Channels and LiveView are different protocols. Capture subscription identity, event envelope, authorization, ordering and missed-message recovery. Channels documents at-most-once client delivery without server persistence.",
            "coexistence": "Recommendation: retain old client endpoints and bridge versioned domain events into each renderer. A room/tenant cohort owns its subscriptions and reconnects. Choose Redis PubSub or a qualified distributed-Elixir cluster deliberately; sharing Redis does not translate the wire protocol.",
            "target": "LiveView for connected server-owned screens or Channels for explicit realtime clients, with durable domain state and an application catch-up mechanism when missed events matter.",
            "benefits": [
              {
                "benefit": "Recommendation: connected UI and domain operations can share Phoenix contexts.",
                "prerequisites": "Authorized subscriptions, working multi-node fanout and persisted state/cursors for recovery requirements.",
                "tradeoffs": "Live protocol/client changes and cluster operations remain; PubSub does not supply a durable user-message history."
              }
            ],
            "checks": [
              "Place old/new subscribers on separate nodes; commit through either permitted path and verify every authorized recipient converges once.",
              "Disconnect before an event, restart a node, reconnect with the chosen cursor/state mechanism and verify missed domain changes recover; test revocation while connected."
            ],
            "rollback": "Recommendation: preserve the old endpoint/event envelope and cohort routing through reconnects; rebuild UI from persisted state instead of duplicating broadcasts.",
            "sources": [
              "https://hexdocs.pm/phoenix/channels.html",
              "https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html",
              "https://hexdocs.pm/phoenix_live_view/security-model.html"
            ],
            "id": "realtime-1"
          },
          {
            "capability": "cache",
            "existing_contract": "Classify every Redis use as cache, session, limiter, lock, job or PubSub. ETS tables are node-local and their ownership lifetime matters; they do not provide Redis's cross-node boundary.",
            "coexistence": "Recommendation: move only reconstructible cache entries into supervised local ownership, with explicit TTL/invalidation and bounded memory. Keep shared identity, coordination, queues and broadcast infrastructure until their own transitions qualify.",
            "target": "ETS for deliberately local reconstructed values, or a retained shared cache where consistency across nodes is required. Recommendation: state stale-read tolerance and rebuilding behavior in the application contract.",
            "benefits": [
              {
                "benefit": "Recommendation: a local cache can remove a remote dependency from selected reads.",
                "prerequisites": "Acceptable node-local semantics, bounded memory and verified invalidation/rebuild behavior.",
                "tradeoffs": "Each node maintains separate contents; owner/node failure loses local state. Performance benefit requires measurement."
              }
            ],
            "checks": [
              "Warm two nodes, update the authoritative record and verify their documented staleness/invalidation policy.",
              "Terminate the table owner or restart the node; verify the application rebuilds and no durable job/session/lock state was stored there."
            ],
            "rollback": "Recommendation: switch those reads back to the qualified shared store or authoritative data; retain Redis until every remaining capability is reconciled.",
            "sources": [
              "https://www.erlang.org/doc/apps/stdlib/ets.html",
              "https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html"
            ],
            "id": "cache-1"
          },
          {
            "capability": "operations",
            "existing_contract": "Record endpoint, worker, scheduler, Repo, assets and cluster/PubSub ownership. Phoenix runtime configuration, release build and schema migrations have distinct deployment steps.",
            "coexistence": "Recommendation: maintain both releases with stable cohort routing and a single schedule/writer owner per responsibility. Monitor queue age, retry effects, node connectivity and authorization failures against application-specific promotion thresholds.",
            "target": "A Phoenix release with runtime.exs configuration, built assets, named migration runner and supervised workers. Recommendation: make cluster formation, backups and restore ordering explicit instead of assuming VM startup establishes them.",
            "benefits": [
              {
                "benefit": "Recommendation: explicit supervised roles and release inputs make restart behavior reviewable.",
                "prerequisites": "Configured children, deployment inventory and exercised recovery procedures.",
                "tradeoffs": "Durable recovery still depends on the chosen databases/queues; supervision alone cannot recreate lost external state."
              }
            ],
            "checks": [
              "Start the actual release with a disposable restored database and confirm assets, authenticated routes, a queued job and cross-node broadcast work.",
              "Stop a worker/node, observe detection and recovery, and verify no second schedule owner activates during rollback."
            ],
            "rollback": "Recommendation: retain the previous release and compatible database reads; return cohort routing and role ownership separately, reconciling new jobs and external effects.",
            "sources": [
              "https://hexdocs.pm/phoenix/deployment.html",
              "https://oban.hexdocs.pm/installation.html",
              "https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html"
            ],
            "id": "operations-1"
          }
        ],
        "sources": [
          {
            "url": "https://hexdocs.pm/phoenix/contexts.html",
            "title": "Phoenix Intro to Contexts",
            "claim": "Contexts separate web features from application operations."
          },
          {
            "url": "https://hexdocs.pm/phoenix/Mix.Tasks.Phx.New.html",
            "title": "mix phx.new",
            "claim": "Phoenix generator syntax and selectable target options."
          },
          {
            "url": "https://hexdocs.pm/ecto/Ecto.Multi.html",
            "title": "Ecto.Multi",
            "claim": "Composes related database operations within a transaction."
          },
          {
            "url": "https://hexdocs.pm/ecto_sql/Ecto.Migrator.html",
            "title": "Ecto.Migrator",
            "claim": "Migration execution, repository connection and release migration concerns."
          },
          {
            "url": "https://oban.hexdocs.pm/installation.html",
            "title": "Oban Installation",
            "claim": "PostgreSQL, SQLite and MySQL engine setup; migrations, configuration and supervision."
          },
          {
            "url": "https://oban.hexdocs.pm/Oban.html",
            "title": "Oban API",
            "claim": "Transactional Ecto.Multi insertion and queue pause/resume APIs; uniqueness is an enqueue feature."
          },
          {
            "url": "https://exq.hexdocs.pm/readme.html",
            "title": "Exq README",
            "claim": "Redis persistence, retrying and Resque/Sidekiq-format compatibility."
          },
          {
            "url": "https://github.com/sidekiq/sidekiq/wiki/Job-Format",
            "title": "Sidekiq Job Format",
            "claim": "Job envelopes and Active Job wrapper/version-sensitive payload details."
          },
          {
            "url": "https://github.com/sidekiq/sidekiq/wiki/Best-Practices",
            "title": "Sidekiq Best Practices",
            "claim": "Idempotent jobs and at-least-once execution."
          },
          {
            "url": "https://guides.rubyonrails.org/active_job_basics.html",
            "title": "Rails Active Job Basics",
            "claim": "Active Job serializers/GlobalID, adapter abstraction and scheduled/retry execution."
          },
          {
            "url": "https://guides.rubyonrails.org/security.html",
            "title": "Rails Security",
            "claim": "Rails cookie/session contract and rotation considerations."
          },
          {
            "url": "https://hexdocs.pm/plug/Plug.Session.COOKIE.html",
            "title": "Plug cookie session store",
            "claim": "Cookie serializer, signing/encryption configuration and rotating options."
          },
          {
            "url": "https://hexdocs.pm/phoenix_live_view/security-model.html",
            "title": "LiveView Security",
            "claim": "Authorization on mount/events and stateful connection revocation."
          },
          {
            "url": "https://hexdocs.pm/phoenix/channels.html",
            "title": "Phoenix Channels",
            "claim": "Channel protocol, joins and at-most-once non-persistent client delivery with application catch-up options."
          },
          {
            "url": "https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html",
            "title": "Phoenix PubSub",
            "claim": "Distributed-Elixir and Redis adapters, pool configuration and migration."
          },
          {
            "url": "https://www.erlang.org/doc/apps/stdlib/ets.html",
            "title": "OTP ETS",
            "claim": "Node-local tables, owner/heir lifetime and table options."
          },
          {
            "url": "https://hexdocs.pm/phoenix/testing.html",
            "title": "Phoenix Testing",
            "claim": "mix test and generated web test helpers."
          },
          {
            "url": "https://hexdocs.pm/phoenix/deployment.html",
            "title": "Phoenix Deployment",
            "claim": "Runtime configuration, assets.deploy, release and production build responsibilities."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "extended_reference": {
        "stack": {
          "name": "elixir.menu — Web application stack",
          "edition": "01",
          "reviewed": "2026-10-06",
          "status": "Documentation-based recommendations; verify the selected dependencies together in your application.",
          "scope": "Database-backed web products built by individuals and small teams",
          "principle": "One default per job. Add a dependency when its job exists. Revisit a choice when a concrete requirement warrants it.",
          "groups": [
            {
              "id": "foundation",
              "title": "Application",
              "description": "A Phoenix application, a database, and familiar conventions.",
              "items": [
                {
                  "id": "web",
                  "job": "Web framework",
                  "tool": "Phoenix",
                  "stage": "Start here",
                  "summary": "Routes, controllers, HTML and application conventions in one place.",
                  "why": "Start with one Phoenix application and its generated structure. Keep the standard HTTP server and asset setup until a measured requirement calls for a change.",
                  "boundary": "Phoenix does not choose every application policy for you. This guide supplies the next layer of defaults; it does not replace Phoenix.",
                  "next": "Use the official getting-started guide and a supported Elixir/OTP pair. Commit the resolved dependency lockfile.",
                  "sources": [
                    [
                      "Phoenix getting started",
                      "https://hexdocs.pm/phoenix/up_and_running.html"
                    ]
                  ]
                },
                {
                  "id": "ui",
                  "job": "Interactive interfaces",
                  "tool": "Phoenix LiveView",
                  "stage": "Start here",
                  "summary": "Build forms, dashboards and live updates alongside your Elixir code.",
                  "why": "Use HEEx and function components for markup, with LiveView for interactive screens. Start ordinary content pages as server-rendered HTML when they need no live process.",
                  "boundary": "Offline-first products, rich canvas editors and heavy local interaction can justify a dedicated client application. Add small JavaScript hooks for isolated browser behavior.",
                  "next": "Keep business rules in contexts; use LiveView for interaction and presentation.",
                  "sources": [
                    [
                      "LiveView documentation",
                      "https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html"
                    ]
                  ]
                },
                {
                  "id": "styling",
                  "job": "Styling and components",
                  "tool": "Tailwind CSS + HEEx components",
                  "stage": "Start here",
                  "summary": "Own a small set of reusable components and the visual language around them.",
                  "why": "Use Tailwind for styling and HEEx function components to share markup and behavior. Keep theme tokens and application components in your project, where you can shape them around the product.",
                  "boundary": "Phoenix 1.8 includes daisyUI, but its generators do not require it. Keep daisyUI when its component classes and themes save useful work; it is optional, not the design system every product must adopt.",
                  "next": "Define the product’s type, spacing and color rules, then build the components repeated across its screens.",
                  "sources": [
                    [
                      "Phoenix 1.8 release",
                      "https://phoenixframework.org/blog/phoenix-1-8-released"
                    ],
                    [
                      "daisyUI customization",
                      "https://daisyui.com/docs/customize/"
                    ]
                  ]
                },
                {
                  "id": "data",
                  "job": "Database and queries",
                  "tool": "PostgreSQL + Ecto",
                  "stage": "Start here",
                  "summary": "One durable store, explicit queries, changesets and migrations.",
                  "why": "Use Ecto for data access and changesets, backed by PostgreSQL. Database constraints enforce invariants; transactions keep related writes together.",
                  "boundary": "Ecto is not Active Record: queries and persistence remain explicit. SQLite is reasonable for a genuinely embedded or single-file application, outside this web-product default.",
                  "next": "Use Ecto.Multi for multi-step transactions. Inspect slow queries and their plans before adding caches.",
                  "sources": [
                    [
                      "Ecto documentation",
                      "https://hexdocs.pm/ecto/Ecto.html"
                    ],
                    [
                      "Ecto.Multi",
                      "https://hexdocs.pm/ecto/Ecto.Multi.html"
                    ]
                  ]
                },
                {
                  "id": "domain",
                  "job": "Business logic",
                  "tool": "Phoenix contexts",
                  "stage": "Start here",
                  "summary": "Plain Elixir modules around the language of your product.",
                  "why": "Give related business operations a clear public API. Both LiveViews and controllers should call that API instead of implementing separate versions of the same rules.",
                  "boundary": "A context is an organizational boundary, not a process. Do not turn ordinary CRUD or pure business logic into a GenServer.",
                  "next": "Define public operations around the application’s domain. Call those operations from controllers, LiveViews and workers; keep database access behind the context boundary.",
                  "sources": [
                    [
                      "Phoenix contexts",
                      "https://hexdocs.pm/phoenix/contexts.html"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "accounts",
              "title": "Accounts and permissions",
              "description": "Authentication establishes identity. Your application still owns permissions.",
              "items": [
                {
                  "id": "auth",
                  "job": "Accounts and sign-in",
                  "tool": "phx.gen.auth",
                  "stage": "When needed",
                  "summary": "Start with Phoenix’s generated authentication.",
                  "why": "Use the authentication generator for a first-party web application. Phoenix 1.8 includes magic-link authentication and sudo-mode conventions; the generated code lives in your application.",
                  "boundary": "Authentication is not authorization. Enterprise SSO, external identity or complex organization requirements need their own deliberate integration.",
                  "next": "Read the generated code and current security guidance. Configure real email delivery before relying on magic links.",
                  "sources": [
                    [
                      "Authentication generator",
                      "https://hexdocs.pm/phoenix/mix_phx_gen_auth.html"
                    ]
                  ]
                },
                {
                  "id": "authorization",
                  "job": "Authorization",
                  "tool": "Scopes + context checks",
                  "stage": "When needed",
                  "summary": "Carry the actor into business operations and constrain data access.",
                  "why": "Pass the authenticated scope through context functions. Apply ownership and permission rules to reads and writes; test denied access as deliberately as the successful path.",
                  "boundary": "Scopes carry identity and context; they are not an automatic policy engine. Hidden buttons and client parameters are never sufficient access control.",
                  "next": "Pass the current scope into context operations. Test that another user cannot read or modify the protected resource, including through direct context calls.",
                  "sources": [
                    [
                      "Phoenix scopes",
                      "https://hexdocs.pm/phoenix/scopes.html"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "work",
              "title": "Jobs and integrations",
              "description": "Reliable background work and the integrations most products need.",
              "items": [
                {
                  "id": "jobs",
                  "job": "Durable background jobs",
                  "tool": "Oban",
                  "stage": "When needed",
                  "summary": "Retries and persistent jobs using the database you already run.",
                  "why": "Use Oban with PostgreSQL for work that must survive a process or application restart. Insert related jobs and domain changes within the same transaction.",
                  "boundary": "Jobs may be retried. Make side effects idempotent; uniqueness is not an exactly-once guarantee. Some advanced orchestration features belong to paid Oban Pro.",
                  "next": "Use separate queues for distinct workloads and monitor retries. An ordinary Task is suitable for disposable concurrent work, not a durable queue.",
                  "sources": [
                    [
                      "Oban documentation",
                      "https://hexdocs.pm/oban/Oban.html"
                    ]
                  ]
                },
                {
                  "id": "schedule",
                  "job": "Recurring tasks",
                  "tool": "Oban Cron",
                  "stage": "When needed",
                  "summary": "Put scheduled work in the same queue as other durable jobs.",
                  "why": "Use Oban.Cron for periodic job insertion. Keep execution, retries and operational visibility in the job system.",
                  "boundary": "A schedule is not a catch-up policy for time when the app is down. Define missed-run behavior explicitly; dynamic scheduling has different requirements.",
                  "next": "Set the intended timezone, check daylight-saving behavior where applicable, and keep workers idempotent.",
                  "sources": [
                    [
                      "Oban.Cron",
                      "https://hexdocs.pm/oban/Oban.Cron.html"
                    ]
                  ]
                },
                {
                  "id": "email",
                  "job": "Transactional email",
                  "tool": "Swoosh",
                  "stage": "When needed",
                  "summary": "Compose mail in Elixir and send through a delivery adapter.",
                  "why": "Use Swoosh, included in generated Phoenix applications, for account mail and product notifications. Use Oban when delivery needs durable retries.",
                  "boundary": "Swoosh is a library, not an email delivery service. The provider, verified domain and deliverability setup are separate operational choices.",
                  "next": "Keep development mail local. Test message content and recipient selection before enabling production delivery.",
                  "sources": [
                    [
                      "Swoosh documentation",
                      "https://hexdocs.pm/swoosh/Swoosh.html"
                    ]
                  ]
                },
                {
                  "id": "http",
                  "job": "Outgoing HTTP",
                  "tool": "Req",
                  "stage": "When needed",
                  "summary": "A readable client for calling external APIs.",
                  "why": "Use Req for request construction, response handling and client features rather than assembling a new HTTP abstraction for each integration.",
                  "boundary": "Timeouts, retries and error handling are part of the integration design. A retried payment or other side effect needs an idempotency strategy.",
                  "next": "Wrap each external service behind a small module. Use Req.Test for deterministic request tests.",
                  "sources": [
                    [
                      "Req documentation",
                      "https://hexdocs.pm/req/Req.html"
                    ],
                    [
                      "Req.Test",
                      "https://hexdocs.pm/req/Req.Test.html"
                    ]
                  ]
                },
                {
                  "id": "realtime",
                  "job": "Realtime notifications",
                  "tool": "Phoenix PubSub",
                  "stage": "When needed",
                  "summary": "Broadcast changes to connected parts of your application.",
                  "why": "Use Phoenix.PubSub to notify subscribed LiveViews or processes of a change. Persist important facts in PostgreSQL and load their current state when clients reconnect.",
                  "boundary": "PubSub is not a persistent message log. Multiple nodes require a suitable cluster or adapter configuration.",
                  "next": "Use Presence only when you actually need to track who is connected.",
                  "sources": [
                    [
                      "Phoenix.PubSub",
                      "https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html"
                    ]
                  ]
                },
                {
                  "id": "uploads",
                  "job": "File uploads",
                  "tool": "LiveView uploads",
                  "stage": "When needed",
                  "summary": "Progress, validation and direct-to-cloud upload support.",
                  "why": "Start with LiveView’s upload flow. For durable production attachments, pair it with object storage and store ownership and file metadata in PostgreSQL.",
                  "boundary": "An upload widget does not supply permanent storage. Ephemeral application disks are not a durable attachment store; client metadata does not establish file safety.",
                  "next": "Set size/type limits, authorize downloads, and implement the storage provider’s documented signing flow.",
                  "sources": [
                    [
                      "LiveView uploads",
                      "https://hexdocs.pm/phoenix_live_view/uploads.html"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "grow",
              "title": "Queries and APIs",
              "description": "Start with the tools already in the application or runtime.",
              "items": [
                {
                  "id": "search",
                  "job": "Product text search",
                  "tool": "PostgreSQL full-text search",
                  "stage": "When needed",
                  "summary": "Search your product’s data before operating another service.",
                  "why": "For ordinary application search, start with PostgreSQL text-search features and an appropriate index. Keep the query and ranking logic close to your data model.",
                  "boundary": "Advanced relevance, typo tolerance or specialist search scale can justify a dedicated engine. Evaluate against actual queries and user expectations.",
                  "next": "Build representative search cases and inspect query plans; avoid claiming that an unindexed text scan will scale.",
                  "sources": [
                    [
                      "PostgreSQL text search",
                      "https://www.postgresql.org/docs/current/textsearch-intro.html"
                    ]
                  ]
                },
                {
                  "id": "pagination",
                  "job": "Filtering and pagination",
                  "tool": "Flop",
                  "stage": "When needed",
                  "summary": "Validated filter, sort and page parameters for Ecto queries.",
                  "why": "Use Flop when product lists need reusable sorting, filtering and pagination. Keep the allowed fields explicit and restrict the base query to authorized records first.",
                  "boundary": "For one simple bounded list, an explicit Ecto query may be enough. Pagination does not replace tenant or ownership checks.",
                  "next": "Use cursor pagination when the list and ordering warrant it; add Flop Phoenix only for the corresponding UI helpers.",
                  "sources": [
                    [
                      "Flop documentation",
                      "https://hexdocs.pm/flop/readme.html"
                    ]
                  ]
                },
                {
                  "id": "cache",
                  "job": "Local read caching",
                  "tool": "ETS",
                  "stage": "After measuring",
                  "summary": "Use the runtime’s in-memory tables for disposable cached data.",
                  "why": "First measure and improve database queries. When a local cache earns its keep, ETS provides concurrent in-memory storage without another service.",
                  "boundary": "ETS is node-local, loses data when its owner dies, and does not supply an automatic TTL or invalidation policy. It is never the source of truth.",
                  "next": "Define table ownership, expiry and invalidation. Shared durable state requires a different design.",
                  "sources": [
                    [
                      "ETS documentation",
                      "https://www.erlang.org/doc/apps/stdlib/ets.html"
                    ]
                  ]
                },
                {
                  "id": "api",
                  "job": "JSON APIs",
                  "tool": "Phoenix controllers",
                  "stage": "When needed",
                  "summary": "Expose your existing contexts through explicit HTTP endpoints.",
                  "why": "Use Phoenix controllers and JSON rendering when a mobile client, partner or external integration needs an API. Share the business API with your web interface.",
                  "boundary": "Do not build an API simply to connect LiveView to its own server. Add GraphQL only when clients need that query model; Absinthe is the established Elixir option.",
                  "next": "Define authentication, authorization, error shapes, pagination and versioning as part of the API contract.",
                  "sources": [
                    [
                      "Phoenix JSON and APIs",
                      "https://hexdocs.pm/phoenix/json_and_apis.html"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "ship",
              "title": "Testing and deployment",
              "description": "Fast feedback, observable behavior and a repeatable deployment artifact.",
              "items": [
                {
                  "id": "test",
                  "job": "Application tests",
                  "tool": "ExUnit + LiveViewTest",
                  "stage": "Start here",
                  "summary": "Test business behavior, persistence and server-driven interaction.",
                  "why": "Use ExUnit and Phoenix’s generated test setup. Test contexts with the database sandbox and interactive screens with Phoenix.LiveViewTest.",
                  "boundary": "Server-side LiveView tests do not execute browser JavaScript or prove the final visual layout. Avoid asserting incidental markup when behavior is the contract.",
                  "next": "Prioritize permission boundaries, data invariants, job behavior and core user journeys.",
                  "sources": [
                    [
                      "ExUnit",
                      "https://hexdocs.pm/ex_unit/ExUnit.html"
                    ],
                    [
                      "LiveViewTest",
                      "https://hexdocs.pm/phoenix_live_view/Phoenix.LiveViewTest.html"
                    ]
                  ]
                },
                {
                  "id": "browser",
                  "job": "Browser integration tests",
                  "tool": "PhoenixTest.Playwright",
                  "stage": "When needed",
                  "summary": "Exercise the small set of flows that need a real browser.",
                  "why": "Use the Playwright-backed PhoenixTest driver for JavaScript hooks, browser navigation and integrations that server-side tests cannot cover.",
                  "boundary": "This adds browser tooling and setup cost. Keep most application tests in ExUnit; this is an editorial extension, not a Phoenix-generated default.",
                  "next": "Cover representative critical flows and keep browser tests focused on observable behavior.",
                  "sources": [
                    [
                      "PhoenixTest.Playwright",
                      "https://hexdocs.pm/phoenix_test_playwright/readme.html"
                    ]
                  ]
                },
                {
                  "id": "observability",
                  "job": "Instrumentation",
                  "tool": "Telemetry + Logger",
                  "stage": "Start here",
                  "summary": "Expose timings, failures and structured operational events.",
                  "why": "Use Telemetry events and Logger as the instrumentation foundation. Track request latency, database time, job failures and the product operations that matter.",
                  "boundary": "Instrumentation is not a hosted monitoring backend. Choose collection, storage and alerting separately; restrict any production LiveDashboard access.",
                  "next": "Make logs useful without exposing secrets. Establish alerts and retention before calling the production system operationally complete.",
                  "sources": [
                    [
                      "Telemetry",
                      "https://hexdocs.pm/telemetry/readme.html"
                    ],
                    [
                      "Logger",
                      "https://hexdocs.pm/logger/Logger.html"
                    ]
                  ]
                },
                {
                  "id": "deployment",
                  "job": "Deployment artifact",
                  "tool": "Mix releases",
                  "stage": "When shipping",
                  "summary": "Package the application and runtime in a repeatable release.",
                  "why": "Use Mix releases with runtime configuration. A container is a practical transport when the chosen host supports it; Phoenix documents the release and Dockerfile path.",
                  "boundary": "A release is not a hosting platform. Database backups, migrations, TLS, monitoring and rollback remain production responsibilities.",
                  "next": "Choose a host that fits the team. Rehearse migrations and restoration, and keep secrets out of the build artifact.",
                  "sources": [
                    [
                      "Phoenix releases",
                      "https://hexdocs.pm/phoenix/releases.html"
                    ]
                  ]
                }
              ]
            }
          ]
        },
        "optional": {
          "reviewed": "2026-10-11",
          "status": "Choose and configure each library against its installed-version documentation.",
          "instruction": "Select an optional tool only when the application's requirements match its use case. Explain the selection, check compatibility with the project's lockfile, and follow its installed-version documentation. Do not install the whole menu.",
          "groups": [
            {
              "id": "optional-accounts",
              "title": "Accounts and product controls",
              "items": [
                {
                  "id": "social-login",
                  "job": "Social login and OIDC",
                  "tool": "Assent",
                  "when": "Users need to sign in with Google, GitHub, Apple or an OpenID Connect provider.",
                  "use": "Integrate provider authentication with the application's existing accounts and sessions.",
                  "boundary": "Account linking, session management and permissions remain application concerns. SAML is a separate requirement.",
                  "sources": [
                    [
                      "Assent",
                      "https://github.com/pow-auth/assent"
                    ]
                  ]
                },
                {
                  "id": "rate-limits",
                  "job": "Rate limiting",
                  "tool": "Hammer",
                  "when": "Login attempts, API calls, uploads or expensive actions need limits.",
                  "use": "Define limits by actor, operation and time window; choose a backend that matches the deployment.",
                  "boundary": "A node-local counter does not automatically enforce a cluster-wide quota. Choose the algorithm's burst behavior deliberately.",
                  "sources": [
                    [
                      "Hammer",
                      "https://hexdocs.pm/hammer/readme.html"
                    ]
                  ]
                },
                {
                  "id": "feature-flags",
                  "job": "Feature flags",
                  "tool": "FunWithFlags",
                  "when": "Features need gradual rollout, per-customer access or an operational off switch.",
                  "use": "Choose an Ecto or Redis persistence adapter and configure synchronization between nodes.",
                  "boundary": "Keep permission checks separate from rollout flags. Remove expired flags and restrict the management interface.",
                  "sources": [
                    [
                      "FunWithFlags",
                      "https://hexdocs.pm/fun_with_flags/readme.html"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "optional-files",
              "title": "Files and documents",
              "items": [
                {
                  "id": "object-storage",
                  "job": "Object storage",
                  "tool": "ExAws.S3",
                  "when": "Uploads need to live in an S3 or compatible object store.",
                  "use": "Use ExAws with its S3 service module for object operations and signed URLs. In a LiveView app, connect it to the upload flow.",
                  "boundary": "The storage service, credentials, access rules and lifecycle policy are separate. Check which operations a compatible service actually supports.",
                  "sources": [
                    [
                      "ExAws.S3",
                      "https://hexdocs.pm/ex_aws_s3/ExAws.S3.html"
                    ]
                  ]
                },
                {
                  "id": "image-processing",
                  "job": "Image processing",
                  "tool": "Image",
                  "when": "The product needs thumbnails, resized uploads, image conversion or watermarks.",
                  "use": "Process images through the libvips-backed Image API; use Oban for work that needs retries.",
                  "boundary": "Vix/libvips introduces native runtime requirements. Check the deployment target and required codecs, and limit input dimensions and processing work.",
                  "sources": [
                    [
                      "Image",
                      "https://hexdocs.pm/image/readme.html"
                    ]
                  ]
                },
                {
                  "id": "markdown",
                  "job": "Markdown parsing and rendering",
                  "tool": "MDEx",
                  "when": "The application needs CommonMark parsing, rendered Markdown content or transformations over a Markdown document tree.",
                  "use": "Use MDEx to parse and transform a document or render HTML. Choose extensions and syntax highlighting deliberately; reserve HEEx components and expressions for trusted application-owned content.",
                  "boundary": "Treat user-authored Markdown as untrusted input: configure and verify HTML sanitization, link handling and size limits. Never evaluate its HEEx expressions. MDEx uses native Rust code; verify precompiled artifact support or a Rust build toolchain for the deployment target.",
                  "sources": [
                    [
                      "MDEx",
                      "https://github.com/leandrocp/mdex"
                    ]
                  ]
                },
                {
                  "id": "pdf-generation",
                  "job": "PDF generation",
                  "tool": "ChromicPDF",
                  "when": "Invoices, reports or other HTML documents need downloadable PDFs.",
                  "use": "Render application-owned HTML and CSS through a managed Chrome process.",
                  "boundary": "Chrome is an additional runtime dependency; PDF/A conversion also uses Ghostscript. Isolate rendering and control access to external resources.",
                  "sources": [
                    [
                      "ChromicPDF",
                      "https://hexdocs.pm/chromic_pdf/ChromicPDF.html"
                    ]
                  ]
                },
                {
                  "id": "csv",
                  "job": "CSV import and export",
                  "tool": "NimbleCSV",
                  "when": "Users need bulk uploads, data exports or integrations through CSV files.",
                  "use": "Parse and write streams; validate each imported row through the application's business rules.",
                  "boundary": "CSV parsing does not validate field types or business rules. Define malformed-row handling and spreadsheet formula escaping for exports.",
                  "sources": [
                    [
                      "NimbleCSV",
                      "https://hexdocs.pm/nimble_csv/NimbleCSV.html"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "optional-interfaces",
              "title": "APIs and collaboration",
              "items": [
                {
                  "id": "openapi",
                  "job": "Documented HTTP APIs",
                  "tool": "OpenApiSpex",
                  "when": "External consumers need an OpenAPI contract for the Phoenix API.",
                  "use": "Describe operations and schemas, validate requests, and test responses against the specification.",
                  "boundary": "A schema does not enforce ownership or authorization. Keep the published contract aligned with application behavior.",
                  "sources": [
                    [
                      "OpenApiSpex",
                      "https://hexdocs.pm/open_api_spex/readme.html"
                    ]
                  ]
                },
                {
                  "id": "graphql",
                  "job": "GraphQL APIs",
                  "tool": "Absinthe",
                  "when": "Clients specifically need GraphQL queries, mutations or subscriptions.",
                  "use": "Expose the existing business layer through a schema; use Dataloader where batching is needed.",
                  "boundary": "Resolvers still need authorization and query-cost limits. Ordinary JSON endpoints remain simpler when GraphQL adds no client benefit.",
                  "sources": [
                    [
                      "Absinthe",
                      "https://hexdocs.pm/absinthe/overview.html"
                    ]
                  ]
                },
                {
                  "id": "presence",
                  "job": "Who is online",
                  "tool": "Phoenix Presence",
                  "when": "Chat, collaborative screens or live rooms need connected-user state.",
                  "use": "Track presence metadata and broadcast joins and leaves through Phoenix's existing realtime infrastructure.",
                  "boundary": "Presence is ephemeral and eventually consistent. It is not a durable audit trail, access-control system or editing-conflict resolver.",
                  "sources": [
                    [
                      "Phoenix Presence",
                      "https://hexdocs.pm/phoenix/Phoenix.Presence.html"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "optional-international",
              "title": "Languages, locales and money",
              "items": [
                {
                  "id": "translations",
                  "job": "Translated interface text",
                  "tool": "Gettext",
                  "when": "The application needs interface copy in multiple languages.",
                  "use": "Use the Gettext integration already present in typical Phoenix projects; maintain translation catalogs and plural forms.",
                  "boundary": "It does not translate user-authored content automatically. Dates, amounts and units need locale-aware formatting too.",
                  "sources": [
                    [
                      "Gettext",
                      "https://hexdocs.pm/gettext/Gettext.html"
                    ]
                  ]
                },
                {
                  "id": "localization",
                  "job": "Localized dates and numbers",
                  "tool": "Localize",
                  "when": "Dates, numbers, currencies and units must follow the user's locale.",
                  "use": "Use CLDR-based formatting and parsing. For new projects, evaluate Localize as the documented successor to the ex_cldr family.",
                  "boundary": "Existing ex_cldr applications need a planned migration. Check runtime requirements and package locale data for deployment.",
                  "sources": [
                    [
                      "Localize",
                      "https://hexdocs.pm/localize/readme.html"
                    ],
                    [
                      "ex_cldr migration notice",
                      "https://hexdocs.pm/ex_cldr/readme.html"
                    ]
                  ]
                },
                {
                  "id": "money",
                  "job": "Currency amounts",
                  "tool": "Money (ex_money)",
                  "when": "Prices, invoices or balances need explicit currencies and decimal arithmetic.",
                  "use": "Represent amount and currency together and make rounding rules explicit.",
                  "boundary": "This is not payment processing, tax calculation or an accounting ledger. The package is ex_money; check its major-version migration notes.",
                  "sources": [
                    [
                      "Money",
                      "https://hexdocs.pm/ex_money/readme.html"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "optional-ai",
              "title": "AI features",
              "items": [
                {
                  "id": "llm-client",
                  "job": "Calling language models",
                  "tool": "ReqLLM",
                  "when": "The product needs text generation, streaming, structured outputs, embeddings or model tool calls through supported provider APIs.",
                  "use": "Use a common Elixir interface to supported providers, including schema-constrained output and embedding generation. Keep provider-specific settings explicit; store embeddings separately when retrieval needs persistence.",
                  "boundary": "Provider and model capabilities differ. Start here for direct model calls; add an agent framework only when orchestration needs it. Define application validation, permissions and representative evaluations separately.",
                  "sources": [
                    [
                      "ReqLLM",
                      "https://github.com/agentjido/req_llm"
                    ]
                  ]
                },
                {
                  "id": "ai-agents",
                  "job": "Tool-using AI agents",
                  "tool": "Jido.AI 2.x",
                  "when": "A language model must select tools, keep agent state or run a bounded multistep reasoning loop.",
                  "use": "Add Jido.AI to a Jido agent and use ReqLLM for provider access. Define tools as actions, and keep model selection, timeouts and tool policy explicit.",
                  "boundary": "Model output is untrusted and nondeterministic. Restrict tool permissions and side effects, set cost and step limits, require approval for high-risk operations, and test representative tasks.",
                  "sources": [
                    [
                      "Jido.AI documentation",
                      "https://hexdocs.pm/jido_ai/readme.html"
                    ],
                    [
                      "Jido ecosystem",
                      "https://jido.run/ecosystem"
                    ]
                  ]
                },
                {
                  "id": "structured-extraction",
                  "job": "Validated structured extraction",
                  "tool": "InstructorLite",
                  "when": "The main requirement is extracting typed fields from text into Ecto schemas, with casting, validation and retries.",
                  "use": "Define an instruction with an Ecto schema and use changeset validation to check the returned fields. Choose this alternative when its Ecto integration fits better than ReqLLM structured output.",
                  "boundary": "It is not an agent runtime and does not provide response streaming. Valid fields can still contain incorrect facts; handle failed validation, retry limits and domain checks explicitly.",
                  "sources": [
                    [
                      "InstructorLite",
                      "https://github.com/martosaur/instructor_lite"
                    ]
                  ]
                },
                {
                  "id": "llm-chains",
                  "job": "Conversational chains and tool loops",
                  "tool": "LangChain for Elixir",
                  "when": "The application is organized around message history, model responses and chained tool calls, or already uses the Elixir LangChain abstractions.",
                  "use": "Compose messages, model adapters and tools through LLMChain. Use its callbacks for streaming and inspect tool-call trajectories when evaluating a conversation workflow.",
                  "boundary": "This is an alternative orchestration approach, not an extra layer every ReqLLM or Jido application needs. Bound tool loops, authorize actions and implement persistence and retry behavior for the actual product.",
                  "sources": [
                    [
                      "LangChain for Elixir",
                      "https://github.com/brainlid/langchain"
                    ]
                  ]
                },
                {
                  "id": "ash-ai",
                  "job": "AI features for Ash applications",
                  "tool": "Ash AI",
                  "when": "An application already uses Ash resources and needs to expose selected actions as model tools or MCP tools, generate structured outputs or maintain embeddings.",
                  "use": "Add Ash AI to the existing Ash domains and resources. Select the actions to expose and carry the authenticated actor and tenant into their execution; configure model access only for features that require it.",
                  "boundary": "Choose Ash as an architecture first. Ash AI does not justify migrating an ordinary contexts application by itself. Test authorization for every exposed action and verify embedding updates, retrieval quality and model costs.",
                  "sources": [
                    [
                      "Ash AI",
                      "https://github.com/ash-project/ash_ai"
                    ]
                  ]
                },
                {
                  "id": "vector-search",
                  "job": "Vector similarity search",
                  "tool": "pgvector",
                  "when": "Embeddings are useful for semantic retrieval or recommendations alongside existing PostgreSQL data.",
                  "use": "Enable the PostgreSQL vector extension and use the Elixir pgvector integration with Ecto or Postgrex.",
                  "boundary": "The library does not generate embeddings. Verify database-extension support, dimensions, indexes and retrieval quality against representative queries.",
                  "sources": [
                    [
                      "pgvector for Elixir",
                      "https://hexdocs.pm/pgvector/readme.html"
                    ]
                  ]
                },
                {
                  "id": "local-models",
                  "job": "Running pretrained models",
                  "tool": "Bumblebee + Nx",
                  "when": "Inference should run on infrastructure you control, using a supported pretrained model.",
                  "use": "Load supported model architectures with Bumblebee and serve predictions through Nx.Serving.",
                  "boundary": "Plan model memory, a suitable numerical backend and hardware. Model compatibility and licensing need to be checked individually.",
                  "sources": [
                    [
                      "Bumblebee",
                      "https://hexdocs.pm/bumblebee/Bumblebee.html"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "optional-data",
              "title": "Data processing and machine learning",
              "items": [
                {
                  "id": "ingestion",
                  "job": "Message ingestion pipelines",
                  "tool": "Broadway",
                  "when": "The application consumes a stream from Kafka, RabbitMQ, SQS or another supported source.",
                  "use": "Build concurrent processing stages with batching, acknowledgements and back-pressure.",
                  "boundary": "The source connector determines delivery behavior. Keep handlers safe to retry; ordinary application jobs still fit Oban.",
                  "sources": [
                    [
                      "Broadway",
                      "https://hexdocs.pm/broadway/Broadway.html"
                    ]
                  ]
                },
                {
                  "id": "dataframes",
                  "job": "Tabular data analysis",
                  "tool": "Explorer",
                  "when": "Imports, analytics or reports need dataframe transformations over CSV, Parquet or similar datasets.",
                  "use": "Use typed series and dataframes for grouping, joining and transforming tabular data.",
                  "boundary": "The default Polars backend uses native code. Check deployment support and memory use; routine application queries still belong in Ecto.",
                  "sources": [
                    [
                      "Explorer",
                      "https://hexdocs.pm/explorer/Explorer.html"
                    ]
                  ]
                },
                {
                  "id": "neural-networks",
                  "job": "Building and training neural networks",
                  "tool": "Axon + Nx",
                  "when": "The project needs to define or train a neural network in Elixir rather than only run a supported pretrained model.",
                  "use": "Use Axon to build models and training loops on Nx, with a numerical compiler/backend suited to the target hardware. Use Bumblebee when loading a supported pretrained model meets the requirement.",
                  "boundary": "Check native backend support, hardware, memory and training data. Validate on held-out data and measure deployment behavior; adding Axon does not establish model quality or a performance advantage.",
                  "sources": [
                    [
                      "Axon",
                      "https://github.com/elixir-nx/axon"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "optional-performance",
              "title": "Performance and scaling",
              "items": [
                {
                  "id": "genstage",
                  "job": "Custom demand-driven pipelines",
                  "tool": "GenStage",
                  "when": "Producers and consumers need a custom event pipeline with demand-driven backpressure.",
                  "use": "Model stages around runtime concurrency and data transfer; keep business steps in functions.",
                  "boundary": "You own buffering, subscriptions and failure behavior. Use Task.async_stream for simpler bounded parallel work, or Broadway for its ingestion features.",
                  "sources": [
                    [
                      "GenStage",
                      "https://hexdocs.pm/gen_stage/GenStage.html"
                    ]
                  ]
                },
                {
                  "id": "flow",
                  "job": "Parallel dataset transformations",
                  "tool": "Flow",
                  "when": "A large enumerable needs parallel mapping, partitioned grouping, aggregation or windows.",
                  "use": "Build a Flow pipeline and choose partition keys, stages and windows for the workload.",
                  "boundary": "Coordination has overhead; small inputs can favor Enum or Task. Partitioning affects grouping and order; bound accumulating state.",
                  "sources": [
                    [
                      "Flow",
                      "https://hexdocs.pm/flow/Flow.html"
                    ]
                  ]
                },
                {
                  "id": "benchmarking",
                  "job": "Compare code performance",
                  "tool": "Benchee",
                  "when": "A measured hot path has alternative implementations to compare.",
                  "use": "Benchmark representative inputs with warmup, runtime, memory and reduction measurements.",
                  "boundary": "Microbenchmarks do not establish application throughput or production latency. Check correctness and end-to-end behavior separately.",
                  "sources": [
                    [
                      "Benchee",
                      "https://hexdocs.pm/benchee/readme.html"
                    ]
                  ]
                },
                {
                  "id": "profiling",
                  "job": "Locate runtime bottlenecks",
                  "tool": "Mix + OTP profilers",
                  "when": "The application is slow and you need to locate expensive calls or repeated work.",
                  "use": "Use the supported mix profile task or OTP profiler for the question; combine findings with the existing Telemetry events.",
                  "boundary": "Check installed runtime support for tprof, eprof and fprof. Tracing can change timing and add overhead; profile a representative bounded workload.",
                  "sources": [
                    [
                      "Mix + OTP profilers",
                      "https://hexdocs.pm/mix/Mix.Tasks.Profile.Tprof.html"
                    ]
                  ]
                },
                {
                  "id": "cache-management",
                  "job": "Managed in-memory caching",
                  "tool": "Cachex",
                  "when": "A node-local cache needs expiration, eviction or fallback loading beyond a small ETS implementation.",
                  "use": "Configure cache limits, expiration and loading behavior around the data lifecycle.",
                  "boundary": "Define invalidation and stale-data policy. A local cache is not a durable source of truth or a cluster-wide consistency guarantee.",
                  "sources": [
                    [
                      "Cachex",
                      "https://hexdocs.pm/cachex/Cachex.html"
                    ]
                  ]
                },
                {
                  "id": "native-rust",
                  "job": "Native computation and Rust integration",
                  "tool": "Rustler",
                  "when": "Profiling identifies CPU-heavy work suited to native code, or the product must call an existing Rust library.",
                  "use": "Expose a narrow NIF interface and select normal versus dirty scheduling appropriate to the work.",
                  "boundary": "Native faults can crash the VM. Validate target builds, scheduler impact and boundary-copying costs; consider a separate OS process when fault isolation is required.",
                  "sources": [
                    [
                      "Rustler",
                      "https://hexdocs.pm/rustler/readme.html"
                    ]
                  ]
                },
                {
                  "id": "numerical-compiler",
                  "job": "Compiled tensor computation",
                  "tool": "EXLA + Nx",
                  "when": "Nx numerical work needs a compiled backend on supported CPU or accelerator hardware.",
                  "use": "Use EXLA as the Nx compiler/backend and select the supported target, precision and memory settings.",
                  "boundary": "Compilation, data transfer and native dependencies have costs. Verify hardware/toolchain support and measure representative workloads; it is not a general accelerator for arbitrary Elixir functions.",
                  "sources": [
                    [
                      "EXLA + Nx",
                      "https://hexdocs.pm/exla/EXLA.html"
                    ]
                  ]
                },
                {
                  "id": "elastic-compute",
                  "job": "Elastic remote execution",
                  "tool": "FLAME",
                  "when": "Bursty expensive work should run on additional ephemeral nodes, such as media processing or model inference.",
                  "use": "Configure a bounded runner pool and an appropriate backend. Start only required application children and size runner database pools deliberately.",
                  "boundary": "Boot latency, network transfer and capacity costs matter. FLAME supplies compute execution, not a durable job queue; pair it with Oban when jobs must persist.",
                  "sources": [
                    [
                      "FLAME",
                      "https://hexdocs.pm/flame/FLAME.html"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "optional-development",
              "title": "Development tools",
              "items": [
                {
                  "id": "boundary-checks",
                  "job": "Module dependency rules",
                  "tool": "Boundary",
                  "when": "Domains or layers need explicit, compiler-checked dependencies and public module exports. Useful for agent-maintained applications as well as human-maintained code.",
                  "use": "Declare each boundary in its root module with use Boundary, explicit deps and a small exports list. Add the compile-time dependency and compiler below. A boundary always exports its root module; prefer explicit exports over exports: :all. Keep allowed calls aligned with the architecture.",
                  "boundary": "Violations are compiler warnings unless compilation uses --warnings-as-errors. External OTP application calls are allowed by default; opt into selected app checks or strict mode when required. Dynamic calls such as apply/3 are not checked. Boundary enforces static module references; it does not isolate an agent’s files, processes or network access. Libraries can limit the compiler to dev/test as the compiler documentation describes.",
                  "setup": "# In mix.exs deps/0:\n{:boundary, \"~> 0.11\", runtime: false}\n\n# In mix.exs project/0:\ncompilers: [:boundary] ++ Mix.compilers()\n\n# In each domain root module (adapt the names):\nuse Boundary, deps: [MyApp.Accounts], exports: []",
                  "check": "Run mix deps.get, then mix compile --warnings-as-errors in the environments your CI checks. Add a temporary forbidden static call to confirm the check fails, remove it, and rerun successfully. The dependency alone does not enforce boundaries.",
                  "sources": [
                    [
                      "Boundary reference",
                      "https://boundary.hexdocs.pm/Boundary.html"
                    ],
                    [
                      "Boundary installation",
                      "https://boundary.hexdocs.pm/readme.html"
                    ],
                    [
                      "Compiler and CI enforcement",
                      "https://boundary.hexdocs.pm/Mix.Tasks.Compile.Boundary.html"
                    ]
                  ]
                },
                {
                  "id": "ai-development",
                  "job": "AI-assisted Phoenix development",
                  "tool": "Tidewave",
                  "when": "A coding agent needs runtime context from a Phoenix application during development.",
                  "use": "Add the Tidewave Phoenix integration as a development-only dependency and plug. Connect your coding agent to inspect logs, evaluate code, query the development database and read installed-version documentation.",
                  "boundary": "This gives the agent access to the running development application. Use a trusted local environment and keep the dependency and endpoint out of production; this is tooling for building the app, not an AI feature for its users.",
                  "sources": [
                    [
                      "Tidewave Phoenix",
                      "https://github.com/tidewave-ai/tidewave_phoenix"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "optional-architecture",
              "title": "A different application architecture",
              "items": [
                {
                  "id": "ash-architecture",
                  "job": "Declarative business applications",
                  "tool": "Ash",
                  "when": "Resources, actions, policies and derived APIs form a substantial part of the application.",
                  "use": "Evaluate Ash early as the domain layer beneath Phoenix, with only the extensions the product needs.",
                  "boundary": "This changes how business logic is modeled. It is an architectural choice, not a small utility to install beside an unchanged contexts design.",
                  "sources": [
                    [
                      "What is Ash?",
                      "https://hexdocs.pm/ash/what-is-ash.html"
                    ]
                  ]
                },
                {
                  "id": "agent-runtime",
                  "job": "Stateful agent workflows",
                  "tool": "Jido 2.x",
                  "when": "The application needs cooperating agents that choose or coordinate steps, share reusable actions and react to routed signals.",
                  "use": "Model the system with agents, actions, signals and directives, and run long-lived agents through Jido's supervised runtime. AI is optional; add Jido.AI only when decisions need a language model.",
                  "boundary": "Prefer a plain GenServer, durable Oban jobs or an explicit function pipeline when behavior is fixed and simple. Supervision and in-memory state alone do not preserve progress across restarts; choose and verify persistence and resume behavior.",
                  "sources": [
                    [
                      "Jido documentation",
                      "https://hexdocs.pm/jido/readme.html"
                    ],
                    [
                      "Jido ecosystem",
                      "https://jido.run/ecosystem"
                    ]
                  ]
                }
              ]
            }
          ],
          "specialist_tracks": [
            {
              "tool": "Nerves",
              "job": "Embedded devices and firmware",
              "url": "https://hexdocs.pm/nerves/getting-started.html"
            },
            {
              "tool": "Membrane",
              "job": "Audio, video and streaming pipelines",
              "url": "https://membrane.stream/"
            }
          ]
        },
        "runtime": {
          "title": "OTP, concurrency and performance",
          "reviewed": "2026-10-06",
          "intro": "Start with functions. Add processes for state ownership, concurrency or lifecycle. Choose shared storage by its read/write pattern; measure before changing the architecture.",
          "status": "Built-in Elixir and Erlang tools need no extra package. Follow the installed Elixir/OTP documentation; node-local memory and supervision do not provide durable storage.",
          "groups": [
            {
              "id": "runtime-work",
              "title": "Computation and process state",
              "items": [
                {
                  "id": "runtime-functions",
                  "job": "Ordinary computation",
                  "tool": "Functions + Enum",
                  "when": "The work is business logic or a transformation that needs no independent lifecycle.",
                  "boundary": "Keep it in functions. Adding a process adds messaging and coordination costs; it does not make a function faster.",
                  "sources": [
                    [
                      "Functions + Enum documentation",
                      "https://hexdocs.pm/elixir/Enum.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-stream",
                  "job": "Lazy processing",
                  "tool": "Stream + File.stream!",
                  "when": "A file or collection should be processed incrementally, without building every intermediate result in memory.",
                  "boundary": "Streams are lazy: enumerate them to run the work. They are not parallel; collecting all results can still exhaust memory.",
                  "sources": [
                    [
                      "Stream + File.stream! documentation",
                      "https://hexdocs.pm/elixir/Stream.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-task",
                  "job": "One concurrent operation",
                  "tool": "Task",
                  "when": "Short-lived work can run alongside its caller, such as fetching independent inputs.",
                  "boundary": "Task.async links failures to the caller. Await the result and define timeout/cleanup behavior. Tasks do not survive node restarts as durable jobs.",
                  "sources": [
                    [
                      "Task documentation",
                      "https://hexdocs.pm/elixir/Task.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-task-supervisor",
                  "job": "Supervised concurrent work",
                  "tool": "Task.Supervisor",
                  "when": "Tasks need an application-owned supervisor or must fail independently of the requesting process.",
                  "boundary": "async still links to the caller; choose async_nolink when isolation is required and handle results/exits. max_children rejects excess starts; it is not a waiting queue or a rate limiter.",
                  "sources": [
                    [
                      "Task.Supervisor documentation",
                      "https://hexdocs.pm/elixir/Task.Supervisor.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-async-stream",
                  "job": "Bounded parallel batches",
                  "tool": "Task.async_stream",
                  "when": "Independent items can be processed concurrently with a bounded number of tasks.",
                  "boundary": "Enumerate the stream; set concurrency and timeout policy. ordered: false avoids buffering for input order when order is unnecessary. Task.Supervisor.async_stream_nolink adds supervised, unlinked task execution.",
                  "sources": [
                    [
                      "Task.async_stream documentation",
                      "https://hexdocs.pm/elixir/Task.html#async_stream/3"
                    ]
                  ]
                },
                {
                  "id": "runtime-agent",
                  "job": "Simple shared process state",
                  "tool": "Agent",
                  "when": "One process needs to hold a small value accessed through get/update functions.",
                  "boundary": "This is Elixir Agent, not an AI agent. Operations run serially inside its process. Choose GenServer for messages, timers or a richer lifecycle; ETS for concurrent table access.",
                  "sources": [
                    [
                      "Agent documentation",
                      "https://hexdocs.pm/elixir/Agent.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-genserver",
                  "job": "State and coordination",
                  "tool": "GenServer",
                  "when": "A long-lived process owns state or coordinates a resource, for example a connection or session.",
                  "boundary": "Callbacks execute serially. Keep slow work out of callbacks when responsiveness matters; call timeouts do not cancel server work. In-memory state needs a separate persistence strategy.",
                  "sources": [
                    [
                      "GenServer documentation",
                      "https://hexdocs.pm/elixir/GenServer.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-statem",
                  "job": "Explicit runtime transitions",
                  "tool": ":gen_statem",
                  "when": "A protocol or connection has distinct states, state-specific events and transition/timeout rules.",
                  "boundary": "Use functions or a data model for ordinary business statuses. The behaviour models a running process; supervision does not make its state durable.",
                  "sources": [
                    [
                      ":gen_statem documentation",
                      "https://www.erlang.org/doc/apps/stdlib/gen_statem.html"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "runtime-lifecycle",
              "title": "Lifecycle, naming and coordination",
              "items": [
                {
                  "id": "runtime-supervisor",
                  "job": "Application lifecycle",
                  "tool": "Application + Supervisor",
                  "when": "Long-running children must start in order and recover according to their dependencies.",
                  "boundary": "Choose restart and shutdown policies deliberately. Restarts do not restore lost state, and terminate callbacks are not a durability guarantee. Slow child initialization delays later children.",
                  "sources": [
                    [
                      "Application + Supervisor documentation",
                      "https://hexdocs.pm/elixir/Supervisor.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-dynamic-supervisor",
                  "job": "Workers created at runtime",
                  "tool": "DynamicSupervisor",
                  "when": "The application starts and stops workers as demand changes, such as one worker per active room.",
                  "boundary": "Use Registry for discovery. A restarted supervisor does not remember the former dynamic child set; reconcile it from an authoritative source when required.",
                  "sources": [
                    [
                      "DynamicSupervisor documentation",
                      "https://hexdocs.pm/elixir/DynamicSupervisor.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-registry",
                  "job": "Find local processes",
                  "tool": "Registry",
                  "when": "Processes need names based on runtime keys, such as tenant/session IDs, or local duplicate-key dispatch.",
                  "boundary": "Use :via tuples rather than creating atoms from user input. Registry is node-local; it is neither cluster discovery nor durable storage.",
                  "sources": [
                    [
                      "Registry documentation",
                      "https://hexdocs.pm/elixir/Registry.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-partition",
                  "job": "Reduce supervisor contention",
                  "tool": "PartitionSupervisor",
                  "when": "Measurements show one process, such as a DynamicSupervisor or Task.Supervisor, bottlenecking concurrent starts.",
                  "boundary": "Route work across partitioned children. This reduces contention in that layer; it does not parallelize a single worker or distribute work across nodes.",
                  "sources": [
                    [
                      "PartitionSupervisor documentation",
                      "https://hexdocs.pm/elixir/PartitionSupervisor.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-process",
                  "job": "Observe failure and schedule messages",
                  "tool": "Process monitors + timers",
                  "when": "A process must observe another process exiting or receive a delayed message.",
                  "boundary": "Monitors report DOWN without coupling failures; links couple lifecycles. Process.send_after schedules a message, not a durable job. Account for stale timer messages and mailbox growth.",
                  "sources": [
                    [
                      "Process monitors + timers documentation",
                      "https://hexdocs.pm/elixir/Process.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-inspection",
                  "job": "Inspect a running process",
                  "tool": ":sys + Process.info",
                  "when": "A running server has unexpected state, memory growth or a growing mailbox.",
                  "boundary": "Use :sys for OTP process state and bounded debugging; Process.info reports process memory and queue length. Inspecting full state can expose sensitive values and allocate large results. These tools diagnose behavior; they do not repair it.",
                  "sources": [
                    [
                      "OTP sys",
                      "https://www.erlang.org/doc/apps/stdlib/sys.html"
                    ],
                    [
                      "Process.info",
                      "https://hexdocs.pm/elixir/Process.html#info/2"
                    ]
                  ]
                }
              ]
            },
            {
              "id": "runtime-storage",
              "title": "Shared data and hot paths",
              "items": [
                {
                  "id": "runtime-ets",
                  "job": "Mutable shared tables",
                  "tool": ":ets",
                  "when": "Many processes need concurrent lookups or updates to node-local in-memory data.",
                  "boundary": "Choose table type, ownership and access rights. Tune read/write concurrency against measurements. The table normally dies with its owner; TTL, invalidation and durability are separate.",
                  "sources": [
                    [
                      ":ets documentation",
                      "https://www.erlang.org/doc/apps/stdlib/ets.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-persistent-term",
                  "job": "Read-mostly shared values",
                  "tool": ":persistent_term",
                  "when": "Many processes repeatedly read a value that changes rarely, such as a static lookup or a stable resource reference. A stable :counters reference can be stored once while the counter array itself is updated.",
                  "boundary": "Reads avoid locks and copying the value onto the caller heap. Writes copy the key table; replacing/deleting complex terms triggers a node-wide GC scan. Avoid request-time updates and expiring caches. Persistent means VM lifetime, not disk durability.",
                  "sources": [
                    [
                      ":persistent_term documentation",
                      "https://www.erlang.org/doc/apps/erts/persistent_term.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-counters",
                  "job": "Frequent shared increments",
                  "tool": ":counters",
                  "when": "Many processes update numeric metrics without routing each increment through one server.",
                  "boundary": "write_concurrency favors add/sub throughput with weaker read consistency. Choose atomics mode when those semantics do not fit. Fixed-width integers wrap; this is node-local memory, not an accounting ledger.",
                  "sources": [
                    [
                      ":counters documentation",
                      "https://www.erlang.org/doc/apps/erts/counters.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-atomics",
                  "job": "Atomic numeric coordination",
                  "tool": ":atomics",
                  "when": "An integer operation needs an atomic result or compare-and-exchange, such as claiming a numeric slot.",
                  "boundary": "Individual operations are atomic and mutually ordered. A sequence of operations is not a transaction. Integers wrap on overflow, and these values are not cluster-wide.",
                  "sources": [
                    [
                      ":atomics documentation",
                      "https://www.erlang.org/doc/apps/erts/atomics.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-queue",
                  "job": "FIFO data structure",
                  "tool": ":queue",
                  "when": "A process holds a FIFO buffer and repeated list appends would be costly.",
                  "boundary": "A queue is a data structure, not a worker, backpressure mechanism or persistent job system. Bound its size and define overload behavior.",
                  "sources": [
                    [
                      ":queue documentation",
                      "https://www.erlang.org/doc/apps/stdlib/queue.html"
                    ]
                  ]
                },
                {
                  "id": "runtime-iodata",
                  "job": "Build output from fragments",
                  "tool": "iodata",
                  "when": "Output combines many byte fragments and its destination accepts iodata.",
                  "boundary": "Keep binaries and byte lists nested until a binary is required. Avoid repeated copying; benchmark the actual construction because BEAM binary appends can also be optimized.",
                  "sources": [
                    [
                      "iodata documentation",
                      "https://hexdocs.pm/elixir/IO.html#module-io-data"
                    ]
                  ]
                },
                {
                  "id": "runtime-binary",
                  "job": "Control retained binary memory",
                  "tool": ":binary",
                  "when": "Small slices of large payloads live in process state or another long-lived store.",
                  "boundary": "Inspect referenced_byte_size. Copy selected retained slices when they pin a much larger binary; copying every binary adds allocation and work.",
                  "sources": [
                    [
                      ":binary documentation",
                      "https://www.erlang.org/doc/apps/stdlib/binary.html"
                    ]
                  ]
                }
              ]
            }
          ],
          "pipeline_ids": [
            "genstage",
            "flow",
            "ingestion"
          ],
          "notes": [
            {
              "title": "Choose durability separately",
              "body": "Use Task for disposable work and Oban for application jobs that need persistence and retries. GenStage and Broadway regulate ingestion; source acknowledgements and retry-safe handlers determine delivery behavior.",
              "sources": [
                [
                  "Oban",
                  "https://hexdocs.pm/oban/Oban.html"
                ]
              ]
            },
            {
              "title": "Measure the limiting resource",
              "body": "Track latency, throughput, memory, mailbox growth, database queries and pool waits on representative traffic. Extra tasks can overload a database or an upstream API. Use Benchee for code comparisons and profilers to find where work accumulates.",
              "sources": [
                [
                  "Benchee",
                  "https://hexdocs.pm/benchee/readme.html"
                ],
                [
                  "OTP profiling",
                  "https://www.erlang.org/doc/apps/tools/tprof.html"
                ]
              ]
            },
            {
              "title": "Stream database exports deliberately",
              "body": "Use Ecto.Repo.stream for incremental row processing when the adapter supports it. SQL adapters require enumeration inside a transaction. Long streams occupy a database connection; batching and collecting results can change memory use.",
              "sources": [
                [
                  "Ecto.Repo.stream",
                  "https://hexdocs.pm/ecto/Ecto.Repo.html#c:stream/2"
                ]
              ]
            }
          ]
        },
        "app-types": {
          "reviewed": "2026-10-11",
          "title": "Choose an Elixir starting point",
          "status": "Choose tools by application requirements and preserve existing project decisions.",
          "types": [
            {
              "id": "command-line",
              "name": "Command-line tool",
              "short": "Developer tools, local automation and terminal applications.",
              "start": "Mix + OptionParser",
              "command": "mix new my_tool",
              "explanation": "Keep command parsing separate from the modules that perform the work. OptionParser handles flags; the application owns help text, subcommands, output and exit codes.",
              "boundary": "An escript needs Erlang/OTP on the target machine. Evaluate Burrito when distributing a bundled executable to users without that runtime, and test each supported OS and architecture.",
              "sources": [
                [
                  "Mix projects",
                  "https://hexdocs.pm/mix/Mix.Tasks.New.html"
                ],
                [
                  "OptionParser",
                  "https://hexdocs.pm/elixir/OptionParser.html"
                ],
                [
                  "Escript packaging",
                  "https://hexdocs.pm/mix/Mix.Tasks.Escript.Build.html"
                ],
                [
                  "Burrito",
                  "https://hexdocs.pm/burrito/readme.html"
                ]
              ]
            },
            {
              "id": "library-project",
              "name": "Library",
              "short": "Reusable modules used by other Elixir applications.",
              "start": "Mix",
              "command": "mix new my_library",
              "explanation": "Define a small public module API, examples and tests. Generate documentation with ExDoc; publish to Hex if the package is intended for reuse outside the project. Add a supervision tree only if the library owns long-lived processes.",
              "boundary": "Choose supported Elixir/OTP versions and dependency constraints for consumers. A library does not need an HTTP server or database unless that is its purpose.",
              "sources": [
                [
                  "Mix projects",
                  "https://hexdocs.pm/mix/Mix.Tasks.New.html"
                ],
                [
                  "ExDoc",
                  "https://hexdocs.pm/ex_doc/readme.html"
                ],
                [
                  "Publishing to Hex",
                  "https://hexdocs.pm/hex/Mix.Tasks.Hex.Publish.html"
                ]
              ]
            },
            {
              "id": "service-project",
              "name": "Background service",
              "short": "Workers, integrations and processes that keep running.",
              "start": "Mix + OTP supervision",
              "command": "mix new my_service --sup",
              "explanation": "Use supervision for process lifecycles and recovery. Keep calculations and business operations in ordinary modules; introduce stateful processes where they are needed.",
              "boundary": "Supervision does not persist work. Choose durable storage or a queue when recovery requires it. Add Plug + Bandit for a small HTTP interface if needed; use Mix releases for deployment.",
              "sources": [
                [
                  "Supervision",
                  "https://hexdocs.pm/elixir/Supervisor.html"
                ],
                [
                  "Bandit",
                  "https://hexdocs.pm/bandit/Bandit.html"
                ],
                [
                  "Mix releases",
                  "https://hexdocs.pm/mix/Mix.Tasks.Release.html"
                ]
              ]
            },
            {
              "id": "web-project",
              "name": "Web application or API",
              "short": "Browser products, customer portals and HTTP APIs.",
              "start": "Phoenix",
              "command": "mix phx.new my_web_app",
              "explanation": "Use Phoenix for routing, controllers and web application conventions. Add LiveView for server-driven interactive screens; an API-only product does not need a browser UI.",
              "boundary": "Choose persistence from the product's needs. PostgreSQL + Ecto is our recommendation for shared relational web data, not a prerequisite for every Elixir program. Review generator options for API-only or database-free applications.",
              "sources": [
                [
                  "Phoenix generator options",
                  "https://hexdocs.pm/phoenix/Mix.Tasks.Phx.New.html"
                ],
                [
                  "Phoenix application guide",
                  "https://elixir.menu/#stack"
                ],
                [
                  "Phoenix setup recipe",
                  "https://elixir.menu/setup.md"
                ]
              ],
              "start_note": "LiveView for interactive screens"
            },
            {
              "id": "data-project",
              "name": "Data analysis or machine learning",
              "short": "Notebooks, data transformations and numerical models.",
              "start": "Livebook; Mix for the application",
              "command": null,
              "explanation": "Use Livebook for interactive exploration, Explorer for tabular data, and Nx for numerical computation. Add Axon when defining or training neural networks is the requirement. Move reusable work into a Mix application when it needs a maintained API, tests or a service lifecycle.",
              "boundary": "Hosted model calls, local inference and training are different requirements. Check native backends, memory and hardware before selecting a deployment environment.",
              "sources": [
                [
                  "Livebook",
                  "https://hexdocs.pm/livebook/readme.html"
                ],
                [
                  "Nx",
                  "https://hexdocs.pm/nx/Nx.html"
                ],
                [
                  "Explorer",
                  "https://hexdocs.pm/explorer/Explorer.html"
                ],
                [
                  "Axon",
                  "https://github.com/elixir-nx/axon"
                ]
              ]
            },
            {
              "id": "device-project",
              "name": "Embedded device",
              "short": "Hardware products, sensors and deployed Linux devices.",
              "start": "Nerves",
              "command": null,
              "explanation": "Start from the Nerves installation and project guides for the target hardware. Build firmware with the system and libraries that the device requires.",
              "boundary": "Hardware support, firmware updates and access to the device determine the setup. A web interface can be added when useful; it does not define the device application.",
              "sources": [
                [
                  "Nerves getting started",
                  "https://hexdocs.pm/nerves/getting-started.html"
                ]
              ]
            },
            {
              "id": "media-project",
              "name": "Audio or video system",
              "short": "Streaming, transcoding and realtime media processing.",
              "start": "Membrane + an OTP application",
              "command": null,
              "explanation": "Build media pipelines with the source, processing and output elements needed for the product. Phoenix may provide a separate control interface if there is a web UI.",
              "boundary": "Protocols, codecs and native dependencies determine the pipeline and deployment. Ordinary file uploads do not require a media framework.",
              "sources": [
                [
                  "Membrane",
                  "https://membrane.stream/"
                ]
              ]
            }
          ],
          "decisions": [
            {
              "title": "Choose the interface",
              "body": "A CLI, reusable library, running service and web application have different starting points. Keep reusable business operations independent of the interface."
            },
            {
              "title": "Choose persistence when needed",
              "body": "Files can suit local configuration. SQLite can suit local relational data; PostgreSQL can suit a shared database. Ecto can be used independently of Phoenix. Disposable caches and process state are separate decisions."
            },
            {
              "title": "Choose the deployment target",
              "body": "A developer script, downloadable executable, deployed service and firmware image need different packaging. Decide which runtimes and native libraries can be present on the target."
            }
          ],
          "agent_steps": [
            {
              "title": "Read the existing project",
              "body": "First read https://elixir.menu/agents.md for direct Markdown and JSON retrieval. In the application, start with README.md, mix.exs, mix.lock and runtime pins. Preserve its architecture and follow its maintained workflow. Do not regenerate an existing project."
            },
            {
              "title": "State the application requirements",
              "body": "Identify the interface, whether work must keep running, persistence needs, and deployment target. Choose one of the starting points above; a product may combine more than one. Do not assume Phoenix or PostgreSQL."
            },
            {
              "title": "Check the environment",
              "body": "Check elixir --version and mix --version. Follow the official Elixir installation guide if prerequisites are missing; respect existing version management. Install a web generator, database or specialist toolchain only for the selected path."
            },
            {
              "title": "Generate in an empty destination",
              "body": "Use the selected starter and its current documentation. The commands above are scaffolding examples, not complete applications. For the Phoenix web path, follow setup.md; for Nerves and Membrane, follow their own project guides."
            },
            {
              "title": "Select libraries by requirement",
              "body": "Read runtime.md for built-in state, concurrency and storage choices. Read optional.md and add only tools whose use cases match the product. Check versions, native dependencies and deployment constraints. Record the reasons and setup in the project’s maintained documentation. Preserve its existing agent-guidance conventions."
            },
            {
              "title": "Verify the actual application",
              "body": "Run formatting, compilation and relevant tests. Exercise the real interface: CLI help, output and exit codes; service startup and recovery; HTTP behavior; or the target device. Verify the packaged artifact on the intended target and report what remains untested."
            }
          ],
          "shared_checks": {
            "title": "Checks for every Mix project",
            "body": "Use mix format for formatting, compile with warnings as errors, and test behavior with ExUnit. Add Credo for useful static feedback. Use Boundary when domains or layers need enforced module dependency rules; declare allowed dependencies and exports, enable its Mix compiler, and fail CI on violations. Keep the same checks in local work and CI.",
            "sources": [
              [
                "Mix formatter",
                "https://hexdocs.pm/mix/Mix.Tasks.Format.html"
              ],
              [
                "ExUnit",
                "https://hexdocs.pm/ex_unit/ExUnit.html"
              ],
              [
                "Credo",
                "https://hexdocs.pm/credo/overview.html"
              ],
              [
                "Boundary setup and limits",
                "https://elixir.menu/#boundary-checks"
              ]
            ]
          },
          "agent_guidance": {
            "title": "Dependency guidance for agents",
            "body": "Use usage_rules in any Mix project to collect dependency-authored instructions and find documentation. Follow the project’s existing conventions for where agents read guidance, keep Phoenix’s generated guidance when using its default setup, and refresh dependency rules when versions change.",
            "url": "https://hexdocs.pm/usage_rules/readme.html",
            "label": "usage_rules documentation"
          }
        }
      },
      "extended_reference_owner": "https://elixir.menu/",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": false,
        "static_hosting": false,
        "offline_client_candidate": false
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    },
    {
      "id": "typescript-next-node",
      "name": "TypeScript full-stack web application on Node",
      "use_cases": [
        "Authenticated web products",
        "Server-rendered React interfaces",
        "Browser applications with owned APIs and relational data"
      ],
      "choose_when": [
        "Shared TypeScript contracts and React UI are useful",
        "Server rendering or a web-facing backend is required",
        "Team accepts explicit server/client and cache boundaries"
      ],
      "avoid_when": [
        "Only static editorial content is required",
        "Existing API already owns all backend responsibilities and SSR is unnecessary",
        "Native mobile or desktop UI is the deliverable"
      ],
      "tools": [
        {
          "job": "runtime and dependency management",
          "default": "Node LTS + npm lockfile",
          "alternatives": [
            "Preserve existing pnpm",
            "Bun after compatibility validation"
          ],
          "reason": "LTS production policy and reproducible dependency install",
          "limits": "Pin resolved runtime/dependencies; latest is a scaffold-time lookup, not a CI dependency strategy",
          "source_urls": [
            "https://nodejs.org/en/about/previous-releases",
            "https://nextjs.org/docs/app/getting-started/installation"
          ]
        },
        {
          "job": "application framework",
          "default": "Next.js App Router + React + strict TypeScript",
          "alternatives": [
            "React/Vite for API-backed SPA",
            "TanStack Start for typed route loaders/server functions",
            "Astro for editorial sites"
          ],
          "reason": "Full-stack React with version-matched agent documentation",
          "limits": "TanStack Start official homepage labelled RC at review; web UI is not native UI; framework does not supply business correctness",
          "source_urls": [
            "https://nextjs.org/docs/app/getting-started/installation",
            "https://nextjs.org/docs/app/guides/ai-agents",
            "https://vite.dev/guide/",
            "https://tanstack.com/start/latest",
            "https://docs.astro.build/en/guides/typescript/"
          ]
        },
        {
          "job": "project instructions",
          "default": "README navigation + generated version-matched agent guidance",
          "alternatives": [
            "README-only workflow when the repository explicitly chooses it"
          ],
          "reason": "Keep repository instructions and installed framework documentation discoverable",
          "limits": "Honor existing instruction ownership. Optional README-only policy: scaffold with --no-agents-md and set agentRules:false before next dev; neither is required by this stack.",
          "source_urls": [
            "https://nextjs.org/docs/app/api-reference/cli/create-next-app",
            "https://nextjs.org/docs/app/api-reference/config/next-config-js/agentRules",
            "https://nextjs.org/docs/app/guides/ai-agents"
          ]
        },
        {
          "job": "Agent runtime inspection",
          "default": "Next.js development MCP endpoint with real browser inspection",
          "alternatives": [
            "Existing development logs and browser tooling when MCP is unavailable"
          ],
          "reason": "Combine version-matched framework context, compilation errors, routes and runtime logs with the actual rendered application.",
          "limits": "Development only. Inspect the installed Next.js and next-devtools-mcp versions before configuring tools. Some runtime inspection requires an open browser session; Turbopack compilation tools have their own constraints. Framework tools do not replace authorization tests or real browser verification. Do not install optional skills or enable automatic upgrades merely to read this reference.",
          "setup": "Follow the installed-version MCP guide to connect a selected agent client to the existing dev server; keep the endpoint and development credentials private. Use the project-selected browser verification route.",
          "source_urls": [
            "https://nextjs.org/docs/app/guides/mcp",
            "https://nextjs.org/docs/app/guides/ai-agents"
          ]
        },
        {
          "job": "validation",
          "default": "Zod",
          "alternatives": [
            "Existing compatible runtime schema library"
          ],
          "reason": "Runtime schemas with inferred TypeScript types",
          "limits": "Validate requests/environment/external results; shape checks do not establish permission or truth",
          "source_urls": [
            "https://zod.dev/"
          ]
        },
        {
          "job": "database and migrations",
          "default": "PostgreSQL + Drizzle + reviewed SQL migrations",
          "alternatives": [
            "Existing database/ORM conventions"
          ],
          "reason": "Typed schema with inspectable SQL history",
          "limits": "Configure schema paths and target environment; apply migration once; rehearse fresh DB and forward compatibility",
          "source_urls": [
            "https://orm.drizzle.team/docs/get-started-postgresql",
            "https://orm.drizzle.team/docs/migrations"
          ]
        },
        {
          "job": "identity",
          "default": "Better Auth + Drizzle PostgreSQL adapter",
          "alternatives": [
            "Existing identity provider or auth library matching requirements"
          ],
          "reason": "Integrated session/provider support without designing password/session primitives",
          "limits": "Auth schema generate then Drizzle migrations; direct Better Auth migrate is Kysely-only; configure origin/secrets/recovery; authorize near data",
          "source_urls": [
            "https://better-auth.com/docs/installation",
            "https://better-auth.com/docs/integrations/next",
            "https://nextjs.org/docs/app/guides/authentication"
          ]
        },
        {
          "job": "background work",
          "default": "Inngest durable workflows when required",
          "alternatives": [
            "Omit for request-local work",
            "Existing durable queue/workflow service"
          ],
          "reason": "Checkpointed steps, retries and waits",
          "limits": "Idempotent effects and authorized approvals required; use outbox for DB/event consistency; avoid beta durable endpoints as default",
          "source_urls": [
            "https://www.inngest.com/docs/durable-execution",
            "https://www.inngest.com/docs/durable-execution/quick-start",
            "https://www.inngest.com/docs/durable-execution/concepts"
          ]
        },
        {
          "job": "Static typing",
          "default": "TypeScript strict",
          "alternatives": [
            "Preserve an existing TypeScript configuration after checking its guarantees"
          ],
          "reason": "Independent deterministic checks for generated edits",
          "limits": "Next build does not run lint; never ignore build/type errors to satisfy a check",
          "source_urls": [
            "https://nextjs.org/docs/app/getting-started/installation",
            "https://nextjs.org/docs/app/api-reference/cli/next"
          ]
        },
        {
          "job": "Linting",
          "default": "ESLint",
          "alternatives": [
            "Biome when project has selected it"
          ],
          "reason": "Independent deterministic checks for generated edits",
          "limits": "Next build does not run lint; never ignore build/type errors to satisfy a check",
          "source_urls": [
            "https://nextjs.org/docs/app/getting-started/installation",
            "https://nextjs.org/docs/app/api-reference/cli/next"
          ]
        },
        {
          "job": "Domain tests",
          "default": "Vitest",
          "alternatives": [
            "Existing suitable test suite"
          ],
          "reason": "Run isolated domain behavior checks with a configured test environment",
          "limits": "Install/configure Vitest and DOM environment for UI tests. Next async Server Components require browser/integration coverage instead.",
          "source_urls": [
            "https://vitest.dev/guide/"
          ]
        },
        {
          "job": "Component tests",
          "default": "React Testing Library",
          "alternatives": [
            "Existing suitable test suite"
          ],
          "reason": "Test rendered components through user-visible DOM behavior",
          "limits": "Install @testing-library/react and its @testing-library/dom peer; configure the test runner/DOM environment. This is a component utility library, not a test runner.",
          "source_urls": [
            "https://testing-library.com/docs/react-testing-library/intro/"
          ]
        },
        {
          "job": "Browser tests",
          "default": "Playwright",
          "alternatives": [
            "Existing suitable test suite"
          ],
          "reason": "Exercise critical journeys in actual browser engines",
          "limits": "Install @playwright/test and matching browsers; configure an isolated test server/data and test session expiry, routing and authorization failures.",
          "source_urls": [
            "https://playwright.dev/docs/intro"
          ]
        },
        {
          "job": "deploy",
          "default": "Project-selected Node or Docker host",
          "alternatives": [
            "Verified adapter",
            "Static export for compatible static subset"
          ],
          "reason": "Documented full Next feature support with Node/Docker",
          "limits": "Adapters vary; verify chosen host, secrets, DB connections, sessions, migrations and restore; Cloudflare needs separate compatibility review",
          "source_urls": [
            "https://nextjs.org/docs/app/getting-started/deploying"
          ]
        },
        {
          "job": "Server state cache",
          "default": "TanStack Query for client-owned remote state",
          "alternatives": [
            "Next server loading for server-owned data",
            "Router loaders for simple route data"
          ],
          "reason": "Queries, mutations and invalidation support interactive API screens",
          "limits": "Install @tanstack/react-query and provide QueryClient. Define tenant-aware keys, staleTime/retry policy and clear session data on sign-out; in Next prefer server loading until a client cache has a job.",
          "source_urls": [
            "https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults"
          ]
        },
        {
          "job": "Forms",
          "default": "React Hook Form for complex client forms",
          "alternatives": [
            "Native HTML forms for simple submissions"
          ],
          "reason": "Separates client form state and validation from page components",
          "limits": "Install react-hook-form only where needed; wire existing runtime schemas deliberately. Render accessible labels/errors; validate and authorize submissions on the server.",
          "source_urls": [
            "https://github.com/react-hook-form/react-hook-form"
          ]
        },
        {
          "job": "Styling",
          "default": "Tailwind CSS when utility styling fits the project",
          "alternatives": [
            "CSS Modules or existing CSS design system"
          ],
          "reason": "Reusable styling without a runtime component dependency",
          "limits": "For Vite install tailwindcss and @tailwindcss/vite, add the plugin and CSS import. Use the framework-specific installation path for Next; retain established styles when present.",
          "source_urls": [
            "https://tailwindcss.com/docs/installation/using-vite"
          ]
        },
        {
          "job": "Accessible UI primitives",
          "default": "Radix Primitives for complex controls",
          "alternatives": [
            "Semantic native HTML controls"
          ],
          "reason": "Provides focus and keyboard behavior for common interaction patterns",
          "limits": "Install only used components. Authors still supply names, contrast and meaningful composition; verify keyboard and assistive-technology behavior.",
          "source_urls": [
            "https://www.radix-ui.com/primitives/docs/overview/accessibility"
          ]
        },
        {
          "job": "Accessibility checks",
          "default": "axe-core through Playwright + manual keyboard review",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Automated audits identify common accessibility defects in real pages",
          "limits": "Install @axe-core/playwright; scan representative states and use a screen reader/keyboard. Passing automated rules is not complete accessibility evidence.",
          "source_urls": [
            "https://playwright.dev/docs/accessibility-testing"
          ]
        },
        {
          "job": "Transactional email",
          "default": "Nodemailer with project-selected SMTP provider",
          "alternatives": [
            "Provider-supported SDK when API-specific features are required"
          ],
          "reason": "SMTP transport avoids coupling email templates to a hosting vendor",
          "limits": "Install nodemailer; configure server-only transport, verified sender and TLS. Test locally, queue required delivery, handle ambiguous results and bounces; SMTP acceptance is not inbox delivery. Verify the resolved Nodemailer release supports the pinned Node runtime and preserves TLS certificate validation.",
          "source_urls": [
            "https://github.com/nodemailer/nodemailer"
          ]
        },
        {
          "job": "Uploads and object storage",
          "default": "AWS SDK for JavaScript v3 S3 client",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Object storage separates durable files from ephemeral application disks",
          "limits": "Install @aws-sdk/client-s3; authorize object keys, restrict size/type and configure lifecycle. Keep credentials server-side; add presigner only for direct uploads and validate provider compatibility.",
          "source_urls": [
            "https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/javascript_s3_code_examples.html"
          ]
        },
        {
          "job": "Live server updates",
          "default": "EventSource for one-way server events",
          "alternatives": [
            "WebSocket service for bidirectional collaboration",
            "Polling for infrequent updates"
          ],
          "reason": "Browser-standard streaming suits status/progress feeds",
          "limits": "Backend owns authenticated stream and event IDs. Test reconnect, replay and proxy buffering; EventSource is one-way and its constructor offers no arbitrary authorization-header option. Confirm long-lived connection support on host.",
          "source_urls": [
            "https://html.spec.whatwg.org/multipage/server-sent-events.html"
          ]
        }
      ],
      "setup_steps": [
        "Start in an external source repository parent in a local development workspace with runtime, identity, database and host requirements documented.",
        "Run npx create-next-app@latest my-app --ts --eslint --app --src-dir --use-npm; review prompts; enter my-app; record resolved versions. Add --no-agents-md only for a repository that explicitly opts out of generated agent files.",
        "Preserve generated agent guidance and put purpose, commands, environment names and installed-documentation navigation in README. For an explicit README-only repository policy, set agentRules:false before next dev.",
        "Confirm strict TypeScript. Install npm install zod drizzle-orm pg better-auth server-only and npm install -D drizzle-kit @types/pg dotenv; add inngest only for required durable work.",
        "Configure server-only database/auth modules and Drizzle PostgreSQL schema/config, development DATABASE_URL, auth secret/base URL and Next route/client integration.",
        "Run npx auth@latest generate; include generated schema in Drizzle paths; run npx drizzle-kit generate; review SQL; apply npx drizzle-kit migrate only to verified development DB.",
        "Install npm install -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom vite-tsconfig-paths @playwright/test; configure unit/UI environments and production Playwright webServer; run npx playwright install.",
        "Implement invalid-input, tenant ownership, session and critical browser tests. Register durable workflow endpoint/worker only if used; exercise retries and duplicate events.",
        "Rehearse migrations on fresh test DB, run checks, configure chosen host and single migration job; inspect production session/browser behavior and rollback compatibility."
      ],
      "verification_commands": [
        "npm ci",
        "npx next typegen",
        "npx tsc --noEmit",
        "npx eslint .",
        "npx vitest run",
        "npm run build",
        "npx playwright test"
      ],
      "evidence_status": "documentation-reviewed",
      "sources": [
        {
          "url": "https://nodejs.org/en/about/previous-releases",
          "title": "Node.js release policy",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://nextjs.org/docs/app/getting-started/installation",
          "title": "Next.js installation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://nextjs.org/docs/app/api-reference/cli/create-next-app",
          "title": "create-next-app CLI",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://nextjs.org/docs/app/api-reference/config/next-config-js/agentRules",
          "title": "Next.js agentRules",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://nextjs.org/docs/app/guides/ai-agents",
          "title": "Next.js AI coding agents",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://nextjs.org/docs/app/api-reference/cli/next",
          "title": "Next.js CLI",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://nextjs.org/docs/app/getting-started/deploying",
          "title": "Next.js deployment",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://vite.dev/guide/",
          "title": "Vite getting started",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://tanstack.com/start/latest",
          "title": "TanStack Start",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.astro.build/en/guides/typescript/",
          "title": "Astro TypeScript",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://zod.dev/",
          "title": "Zod",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://orm.drizzle.team/docs/get-started-postgresql",
          "title": "Drizzle PostgreSQL",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://orm.drizzle.team/docs/migrations",
          "title": "Drizzle migrations",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://better-auth.com/docs/installation",
          "title": "Better Auth installation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://better-auth.com/docs/integrations/next",
          "title": "Better Auth Next.js integration",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://nextjs.org/docs/app/guides/authentication",
          "title": "Next.js authentication",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://www.inngest.com/docs/durable-execution",
          "title": "Inngest durable execution",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://www.inngest.com/docs/durable-execution/quick-start",
          "title": "Inngest quickstart",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://www.inngest.com/docs/durable-execution/concepts",
          "title": "Inngest concepts",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://nextjs.org/docs/app/guides/testing/vitest",
          "title": "Next.js Vitest",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://nextjs.org/docs/app/guides/testing/playwright",
          "title": "Next.js Playwright",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults",
          "title": "TanStack Query important defaults",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/react-hook-form/react-hook-form",
          "title": "React Hook Form repository",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://tailwindcss.com/docs/installation/using-vite",
          "title": "Tailwind Vite installation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://www.radix-ui.com/primitives/docs/overview/accessibility",
          "title": "Radix accessibility",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://playwright.dev/docs/accessibility-testing",
          "title": "Playwright accessibility testing",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/nodemailer/nodemailer",
          "title": "Nodemailer maintainer repository",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/javascript_s3_code_examples.html",
          "title": "AWS JavaScript S3 examples",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://html.spec.whatwg.org/multipage/server-sent-events.html",
          "title": "HTML EventSource standard",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://vitest.dev/guide/",
          "title": "Vitest guide",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://playwright.dev/docs/intro",
          "title": "Playwright installation",
          "checked_date": "2026-10-13"
        },
        {
          "url": "https://testing-library.com/docs/react-testing-library/intro/",
          "title": "React Testing Library",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://nextjs.org/docs/app/guides/mcp",
          "title": "Next.js development MCP and runtime tools",
          "checked_date": "2026-10-13"
        }
      ],
      "open_questions": [
        "Does the product require server-rendered routes, client-owned state, or both?",
        "Which identity providers, account recovery and SSO requirements must be supported?",
        "Which host, database connection budget and migration/restore process will own production?",
        "Which workflows need retries, email, object storage or persistent realtime connections?"
      ],
      "title": "Next.js",
      "language": "TypeScript",
      "group": "Web applications",
      "kind": [
        "web"
      ],
      "ui": "full",
      "host": "node",
      "summary": "React interfaces with server rendering, routes and application logic.",
      "shape": "React · Next.js · PostgreSQL · Drizzle",
      "tradeoff": "Server/client boundaries, caching and deployment adapters need deliberate design.",
      "research_file": "typescript.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Keep database imports and secrets in server-only modules. Treat Server Actions and route handlers as authenticated entry points.",
        "Validate external input with schemas and authorize access close to the data. A page redirect is not an access-control boundary.",
        "Commit reviewed SQL migrations. Generate the Better Auth schema into Drizzle's migration path.",
        "Test async Server Components through browser journeys. Exercise logged-out and two-tenant cases, including cached pages."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://nextjs.org/docs/app/getting-started/installation",
          "https://nextjs.org/docs/app/guides/mcp",
          "https://nextjs.org/docs/app/guides/ai-agents"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/typescript-next-node/",
      "markdown_url": "/stacks/typescript-next-node/guide.md",
      "json_url": "/stacks/typescript-next-node/record.json",
      "architecture_and_migration": {
        "id": "typescript-next-node",
        "version_scope": "Documentation reviewed 11 October 2026: current Next.js App Router docs label 16.4.0. Pin the installed Next, React, Node and database packages; distinguish cacheComponents:true from the previous caching model. This profile does not qualify a lockfile or hosting adapter.",
        "operating_model": "A Next application contains server rendering and browser interactivity with an explicit trust boundary. Recommendation: preserve an existing backend's domain ownership during UI adoption; for a new owned backend use server-only data access. Node/Docker and alternative adapters require separate runtime checks.",
        "architecture": [
          "Server Components load server-owned data; Client Components own interaction and browser APIs. Keep the client boundary near interactive leaves and pass minimal serializable DTOs.",
          "Recommendation: one domain writer and migration owner per responsibility. Existing REST/GraphQL services remain authoritative during coexistence; a new server-only DAL can own validation, authorization and transactions after transfer.",
          "Choose server, browser and CDN caches deliberately. Session-dependent output, invalidation and multiple instances require independent policies; adding a framework cache does not migrate a shared session or queue.",
          "Recommendation: durable jobs and realtime run behind explicit service contracts when required. A render, Server Action or browser promise is not an execution backlog."
        ],
        "developer_workflow": [
          "Start in the external source checkout. Read README and inspect package.json, lockfile, next.config, current API ownership, schema and runtime. Record whether Cache Components are enabled before selecting examples.",
          "For an existing npm project run npm ci; use its scripts. With Next installed, npx next typegen then npx tsc --noEmit checks generated route types and TypeScript. Run the configured ESLint/Biome command separately; the build is not a substitute for lint.",
          "Run npm run dev for iteration and npm run build for production compilation; use npm run start only if its script runs the selected production server. Configure Playwright's isolated backend/data first, then npx playwright test for mixed-version journeys.",
          "Recommendation: deploy the same built artifact to all instances, record build/deployment identifiers, cache coordination, migrations, secrets and adapter support. Reproduce cold/warm loads, sign-out, old-tab actions and rollback on a staging topology."
        ],
        "avoid": [
          "Marking the root tree use client brings imported dependencies into the browser bundle and broadens the secret/exposure surface.",
          "Passing whole ORM records to Client Components exposes fields unrelated to presentation; enforce authorization and DTO filtering on the server.",
          "UI-hidden buttons or Proxy redirects cannot replace authorization at the mutation/data boundary.",
          "Copying pre-16 cache defaults into a Cache Components app silently changes freshness behavior; identify the installed model.",
          "Treating an old browser build as gone after deployment ignores existing tabs, prefetched payloads and action identifiers."
        ],
        "transitions": [
          {
            "capability": "data",
            "existing_contract": "Existing REST/GraphQL behavior, DTOs, authorization, transactions and one schema owner.",
            "coexistence": "Recommendation: Adopt server-rendered routes that call the old API; keep its writer and migration authority. Compare read-only fixtures without replaying real side effects.",
            "target": "Recommendation: Retain the API permanently if appropriate, or transfer a bounded domain to a server-only DAL with minimal DTOs after mixed-version checks.",
            "benefits": [
              {
                "benefit": "Server loading can reduce client waterfalls; an owned DAL centralizes authorization.",
                "prerequisites": "Server-reachable API or reviewed database ownership; measurable user journeys.",
                "tradeoffs": "A new domain writer requires schema/transaction review; framework adoption alone changes neither."
              }
            ],
            "checks": [
              "Old and new UI decode identical success/error/empty fixtures.",
              "Forged resource IDs remain denied on both mutation paths.",
              "An acknowledged write is readable through the old interface."
            ],
            "rollback": "Route the cohort back while old-compatible schema remains; reconcile writes before any writer reversal.",
            "sources": [
              "https://nextjs.org/docs/app/guides/data-security",
              "https://nextjs.org/docs/app/getting-started/server-and-client-components"
            ],
            "id": "data-1"
          },
          {
            "capability": "identity",
            "existing_contract": "Existing session issuer, cookie/token format, expiry, revocation, tenant membership and CSRF behavior.",
            "coexistence": "Recommendation: Retain the issuer behind an adapter and authorize data/mutations in both implementations; inventory origin/domain/cookie differences before sharing.",
            "target": "Recommendation: Use an explicitly selected issuer and server-side authorization boundary; transfer session contracts or require a controlled sign-in when compatibility cannot be preserved.",
            "benefits": [
              {
                "benefit": "One identity authority can support gradual UI/backend replacement.",
                "prerequisites": "Validated issuer integration and old/new expiry/revocation fixtures.",
                "tradeoffs": "Session sharing is format/security work; sign-in continuity is not guaranteed by using cookies."
              }
            ],
            "checks": [
              "Revoked and expired sessions fail in old/new paths.",
              "Cross-tenant direct action requests are denied.",
              "Sign-out clears browser remote-state caches and back navigation reveals no protected data."
            ],
            "rollback": "Restore old routes/issuer acceptance only while its keys and session semantics remain supported; do not resurrect revoked sessions.",
            "sources": [
              "https://nextjs.org/docs/app/guides/authentication",
              "https://nextjs.org/docs/app/guides/data-security"
            ],
            "id": "identity-1"
          },
          {
            "capability": "cache",
            "existing_contract": "Actual enabled caching model, personalized response policy, keys, freshness, invalidation and shared-instance behavior.",
            "coexistence": "Recommendation: Keep the prior policy while converting one route/data category; separate old/new cache namespaces and observe stale/account-crossing outcomes.",
            "target": "Recommendation: Choose Cache Components or version-matched previous-model APIs explicitly; keep user-specific data outside shared public entries and coordinate shared invalidation when deployed across instances.",
            "benefits": [
              {
                "benefit": "Repeated eligible work can be reused without refetching each time.",
                "prerequisites": "A documented freshness tolerance, safe keys and working invalidation.",
                "tradeoffs": "Coordination/storage adds operations; freshness and cost gains require measurement."
              }
            ],
            "checks": [
              "A write refreshes affected reads through every serving instance.",
              "Account A cannot read cached output for account B.",
              "Cold, warm and forced-refresh responses agree with the selected policy."
            ],
            "rollback": "Disable the new cache path and purge its namespace; keep source data unchanged and retain old invalidation until transfer completes.",
            "sources": [
              "https://nextjs.org/docs/app/getting-started/caching",
              "https://nextjs.org/docs/app/guides/caching-without-cache-components",
              "https://nextjs.org/docs/app/guides/self-hosting"
            ],
            "id": "cache-1"
          },
          {
            "capability": "jobs",
            "existing_contract": "Existing job producer/consumer payloads, ready/scheduled/retry/failed/in-flight states and external-effect idempotency.",
            "coexistence": "Recommendation: Keep existing workers; move a named job type behind a versioned event contract. Reconcile backlog and retain one consumer owner per item.",
            "target": "Recommendation: Use selected durable execution such as Inngest for required workflows; a transactional outbox is a proposed design when domain commit and event submission are separate systems.",
            "benefits": [
              {
                "benefit": "Checkpointed completed steps allow retry/resume without starting every step again.",
                "prerequisites": "Selected service/SDK integration, stable step IDs, replay-safe external effects and delivery reconciliation.",
                "tradeoffs": "Operating a workflow service adds dependency/cost; checkpoints do not supply business exactly-once effects."
              }
            ],
            "checks": [
              "Crash after an external effect but before step acknowledgement; retry causes one intended business effect.",
              "Domain commit with event-send failure is eventually reconciled.",
              "Old scheduled/retry work is drained or deliberately transformed."
            ],
            "rollback": "Stop new producers for the transferred type, account for active runs and resume old workers with compatible payloads; reconcile irreversible effects first.",
            "sources": [
              "https://www.inngest.com/docs/durable-execution"
            ],
            "id": "jobs-1"
          },
          {
            "capability": "operations",
            "existing_contract": "Current hosting/runtime, static assets, open-tab state, prefetched payloads and Server Function compatibility.",
            "coexistence": "Recommendation: Keep old assets and compatible API routes; promote one built artifact per deployment and rehearse an old tab against the new deployment.",
            "target": "Recommendation: Use version-matched deploymentId support and infrastructure routing as needed; same-build instances share required action keys and cache coordination.",
            "benefits": [
              {
                "benefit": "Explicit rollout handling reduces missing-chunk/navigation mismatches.",
                "prerequisites": "A qualified host, retained assets and tested old-client behavior.",
                "tradeoffs": "Hard navigation can lose component state; same encryption key does not make old action IDs compatible."
              }
            ],
            "checks": [
              "Open an old tab, deploy, navigate and submit an old form; observe success or a controlled update path.",
              "Preserved drafts survive any required full reload.",
              "All instances serve matching build/deployment identifiers."
            ],
            "rollback": "Restore the prior artifact and routing while compatible assets/data remain; do not claim traffic rollback reverses schema or external effects.",
            "sources": [
              "https://nextjs.org/docs/app/guides/self-hosting"
            ],
            "id": "operations-1"
          }
        ],
        "sources": [
          {
            "url": "https://nextjs.org/docs/app/getting-started/server-and-client-components",
            "title": "Next.js Server and Client Components",
            "claim": "Pages/layouts default to server components; browser interaction and APIs require client boundaries."
          },
          {
            "url": "https://nextjs.org/docs/app/guides/data-security",
            "title": "Next.js Data Security",
            "claim": "Existing HTTP APIs or a new server-only DAL provide explicit data ownership; mutations require validation/authorization and minimal DTOs."
          },
          {
            "url": "https://nextjs.org/docs/app/guides/authentication",
            "title": "Next.js Authentication",
            "claim": "Authentication, session management and authorization are separate responsibilities; optimistic redirects do not replace secure checks."
          },
          {
            "url": "https://nextjs.org/docs/app/getting-started/caching",
            "title": "Next.js Caching with Cache Components",
            "claim": "Current caching guide applies when cacheComponents is enabled."
          },
          {
            "url": "https://nextjs.org/docs/app/guides/caching-without-cache-components",
            "title": "Next.js Caching and Revalidating (Previous Model)",
            "claim": "The alternative caching guide applies without Cache Components; defaults and APIs must match that model."
          },
          {
            "url": "https://nextjs.org/docs/app/guides/self-hosting",
            "title": "Next.js Self-Hosting",
            "claim": "Multi-instance cache coordination, action encryption keys, deployment identifiers and old-client version skew need deployment design."
          },
          {
            "url": "https://nextjs.org/docs/app/getting-started/installation",
            "title": "Next.js Installation",
            "claim": "Framework setup and deterministic lint/type/build checks have separate tooling."
          },
          {
            "url": "https://nextjs.org/docs/app/api-reference/cli/next",
            "title": "Next.js CLI",
            "claim": "next typegen, build and production server commands are qualified by installed framework and scripts."
          },
          {
            "url": "https://www.inngest.com/docs/durable-execution",
            "title": "Inngest Durable Execution",
            "claim": "Completed steps are checkpointed and workflows can retry/resume; durable endpoints are separately marked beta."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": false,
        "static_hosting": false,
        "offline_client_candidate": true
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    },
    {
      "id": "typescript-react-vite-browser",
      "name": "TypeScript browser application with an existing API",
      "use_cases": [
        "Interactive dashboards",
        "API-backed browser tools",
        "Client-rendered applications"
      ],
      "choose_when": [
        "Backend/identity already have owners",
        "SSR is not a product requirement",
        "Browser UI and API can be deployed independently"
      ],
      "avoid_when": [
        "Searchable server-rendered content is central",
        "The task requires native device UI",
        "Team expects the frontend scaffold to supply backend auth or persistence"
      ],
      "tools": [
        {
          "job": "browser build and UI",
          "default": "React + Vite + TypeScript",
          "alternatives": [
            "Next.js for full-stack/SSR",
            "TanStack Start when routing/server integration is needed"
          ],
          "reason": "Focused browser development without unnecessary server framework",
          "limits": "TypeScript compiles to JS; Vite is tooling, not a backend; keep HTML/CSS competence",
          "source_urls": [
            "https://vite.dev/guide/",
            "https://tanstack.com/start/latest",
            "https://react.dev/learn/typescript"
          ]
        },
        {
          "job": "validation",
          "default": "Zod at API/client boundaries",
          "alternatives": [
            "Use the existing API's schema/code generation"
          ],
          "reason": "Check external values and share explicit contracts",
          "limits": "Client checks never replace authoritative backend validation or authorization",
          "source_urls": [
            "https://zod.dev/"
          ]
        },
        {
          "job": "Identity ownership",
          "default": "Existing backend owns authentication and authorization",
          "alternatives": [
            "Adopt full-stack Node record when backend is in scope"
          ],
          "reason": "Avoid duplicating external-system ownership in browser code",
          "limits": "No database credentials/server secrets in browser; document API/session/CORS contract",
          "source_urls": [
            "https://nextjs.org/docs/app/guides/authentication"
          ]
        },
        {
          "job": "Database ownership",
          "default": "Existing backend owns persistence and migrations",
          "alternatives": [
            "Adopt full-stack Node record when backend is in scope"
          ],
          "reason": "Avoid duplicating external-system ownership in browser code",
          "limits": "No database credentials/server secrets in browser; document API/session/CORS contract",
          "source_urls": [
            "https://nextjs.org/docs/app/guides/authentication"
          ]
        },
        {
          "job": "Background work ownership",
          "default": "Existing backend owns durable jobs",
          "alternatives": [
            "Adopt full-stack Node record when backend is in scope"
          ],
          "reason": "Avoid duplicating external-system ownership in browser code",
          "limits": "No database credentials/server secrets in browser; document API/session/CORS contract",
          "source_urls": [
            "https://nextjs.org/docs/app/guides/authentication"
          ]
        },
        {
          "job": "Static typing",
          "default": "Strict TypeScript; retain generated project-reference build",
          "alternatives": [
            "Preserve existing compatible tooling"
          ],
          "reason": "Static checks and user-visible browser behavior",
          "limits": "Configure router/API failure/session expiry tests; preserve scaffold-specific build scripts",
          "source_urls": [
            "https://vite.dev/guide/",
            "https://nextjs.org/docs/app/guides/testing/vitest",
            "https://nextjs.org/docs/app/guides/testing/playwright"
          ]
        },
        {
          "job": "Linting",
          "default": "ESLint",
          "alternatives": [
            "Preserve existing compatible tooling"
          ],
          "reason": "Static checks and user-visible browser behavior",
          "limits": "Configure router/API failure/session expiry tests; preserve scaffold-specific build scripts",
          "source_urls": [
            "https://vite.dev/guide/",
            "https://nextjs.org/docs/app/guides/testing/vitest",
            "https://nextjs.org/docs/app/guides/testing/playwright"
          ]
        },
        {
          "job": "Domain and component tests",
          "default": "Vitest",
          "alternatives": [
            "Preserve existing compatible tooling"
          ],
          "reason": "Run isolated domain behavior checks with a configured test environment",
          "limits": "Install Vitest; preserve Vite plugins or add a separate test configuration. Mock only external boundaries and test failure states.",
          "source_urls": [
            "https://vitest.dev/guide/"
          ]
        },
        {
          "job": "Browser tests",
          "default": "Playwright",
          "alternatives": [
            "Preserve existing compatible tooling"
          ],
          "reason": "Exercise critical journeys in actual browser engines",
          "limits": "Install @playwright/test and matching browsers; configure an isolated test server/data and test session expiry, routing and authorization failures.",
          "source_urls": [
            "https://playwright.dev/docs/intro"
          ]
        },
        {
          "job": "deployment",
          "default": "Static asset host chosen by project",
          "alternatives": [
            "Server-rendered framework when justified"
          ],
          "reason": "Browser build can be independently served",
          "limits": "Configure deep-link fallback, API origins, cache invalidation and environment handling; preview is not production",
          "source_urls": [
            "https://vite.dev/guide/"
          ]
        },
        {
          "job": "Server state cache",
          "default": "TanStack Query for client-owned remote state",
          "alternatives": [
            "Next server loading for server-owned data",
            "Router loaders for simple route data"
          ],
          "reason": "Queries, mutations and invalidation support interactive API screens",
          "limits": "Install @tanstack/react-query and provide QueryClient. Define tenant-aware keys, staleTime/retry policy and clear session data on sign-out; in Next prefer server loading until a client cache has a job.",
          "source_urls": [
            "https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults"
          ]
        },
        {
          "job": "Forms",
          "default": "React Hook Form for complex client forms",
          "alternatives": [
            "Native HTML forms for simple submissions"
          ],
          "reason": "Separates client form state and validation from page components",
          "limits": "Install react-hook-form only where needed; wire existing runtime schemas deliberately. Render accessible labels/errors; validate and authorize submissions on the server.",
          "source_urls": [
            "https://github.com/react-hook-form/react-hook-form"
          ]
        },
        {
          "job": "Styling",
          "default": "Tailwind CSS when utility styling fits the project",
          "alternatives": [
            "CSS Modules or existing CSS design system"
          ],
          "reason": "Reusable styling without a runtime component dependency",
          "limits": "For Vite install tailwindcss and @tailwindcss/vite, add the plugin and CSS import. Use the framework-specific installation path for Next; retain established styles when present.",
          "source_urls": [
            "https://tailwindcss.com/docs/installation/using-vite"
          ]
        },
        {
          "job": "Accessible UI primitives",
          "default": "Radix Primitives for complex controls",
          "alternatives": [
            "Semantic native HTML controls"
          ],
          "reason": "Provides focus and keyboard behavior for common interaction patterns",
          "limits": "Install only used components. Authors still supply names, contrast and meaningful composition; verify keyboard and assistive-technology behavior.",
          "source_urls": [
            "https://www.radix-ui.com/primitives/docs/overview/accessibility"
          ]
        },
        {
          "job": "Accessibility checks",
          "default": "axe-core through Playwright + manual keyboard review",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Automated audits identify common accessibility defects in real pages",
          "limits": "Install @axe-core/playwright; scan representative states and use a screen reader/keyboard. Passing automated rules is not complete accessibility evidence.",
          "source_urls": [
            "https://playwright.dev/docs/accessibility-testing"
          ]
        },
        {
          "job": "Routing",
          "default": "TanStack Router",
          "alternatives": [
            "React Router in established projects",
            "No router for a single screen"
          ],
          "reason": "Typed navigation, route loading and search parameters suit application screens",
          "limits": "Install @tanstack/react-router; configure the chosen file-based plugin or code-based routes. Test deep links, not-found routes and browser back; route guards do not replace server authorization.",
          "source_urls": [
            "https://tanstack.com/router/latest/docs/overview"
          ]
        },
        {
          "job": "Live server updates",
          "default": "EventSource for one-way server events",
          "alternatives": [
            "WebSocket service for bidirectional collaboration",
            "Polling for infrequent updates"
          ],
          "reason": "Browser-standard streaming suits status/progress feeds",
          "limits": "Backend owns authenticated stream and event IDs. Test reconnect, replay and proxy buffering; EventSource is one-way and its constructor offers no arbitrary authorization-header option. Confirm long-lived connection support on host.",
          "source_urls": [
            "https://html.spec.whatwg.org/multipage/server-sent-events.html"
          ]
        }
      ],
      "setup_steps": [
        "Start in repository parent in a local development workspace with API/session owners identified.",
        "Run npm create vite@latest my-app -- --template react-ts; enter my-app; npm install; record resolved versions and commit lockfile.",
        "Create README with API contract, run/check instructions and environment variable names. Configure strict TypeScript and router/query tooling only as needed.",
        "Add Zod and test tools; configure request validation, error/loading/session-expiry states and authoritative backend authorization tests.",
        "Build to static assets, configure chosen host deep-link behavior and API origins, then run production browser checks."
      ],
      "verification_commands": [
        "npm ci",
        "npx tsc --noEmit",
        "npx eslint .",
        "npx vitest run",
        "npm run build",
        "npx playwright test"
      ],
      "evidence_status": "documentation-reviewed",
      "sources": [
        {
          "url": "https://vite.dev/guide/",
          "title": "Vite getting started",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://tanstack.com/start/latest",
          "title": "TanStack Start",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://zod.dev/",
          "title": "Zod",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://nextjs.org/docs/app/guides/authentication",
          "title": "Next.js authentication",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://nextjs.org/docs/app/guides/testing/vitest",
          "title": "Next.js Vitest",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://nextjs.org/docs/app/guides/testing/playwright",
          "title": "Next.js Playwright",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://react.dev/learn/typescript",
          "title": "React TypeScript",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults",
          "title": "TanStack Query important defaults",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/react-hook-form/react-hook-form",
          "title": "React Hook Form repository",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://tailwindcss.com/docs/installation/using-vite",
          "title": "Tailwind Vite installation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://www.radix-ui.com/primitives/docs/overview/accessibility",
          "title": "Radix accessibility",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://playwright.dev/docs/accessibility-testing",
          "title": "Playwright accessibility testing",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://tanstack.com/router/latest/docs/overview",
          "title": "TanStack Router overview",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://html.spec.whatwg.org/multipage/server-sent-events.html",
          "title": "HTML EventSource standard",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://vitest.dev/guide/",
          "title": "Vitest guide",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://playwright.dev/docs/intro",
          "title": "Playwright installation",
          "checked_date": "2026-10-13"
        }
      ],
      "open_questions": [
        "Which API and identity owner defines schemas, cookies/tokens and CORS?",
        "Do routes need shareable URLs, offline behavior or server rendering?",
        "Which browser/device matrix and accessibility requirements must be met?",
        "Which static host supports route fallbacks and the selected API origins?"
      ],
      "title": "React + Vite",
      "language": "TypeScript",
      "group": "Web applications",
      "kind": [
        "web"
      ],
      "ui": "client",
      "host": "static",
      "summary": "An interactive browser app connected to an existing or separate API.",
      "shape": "React · Vite · TypeScript · your API",
      "tradeoff": "This is a frontend. Your backend still owns identity, data permissions and durable work.",
      "research_file": "typescript.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Keep credentials, SQL access and authorization behind the API. Browser validation does not establish permission.",
        "Keep strict TypeScript and validate API responses where data crosses trust boundaries.",
        "Choose a router and server-state cache only when navigation and data complexity need them.",
        "Test production asset paths and direct navigation to nested routes. Offline use needs explicit storage, synchronization and conflict rules."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://vite.dev/guide/",
          "https://react.dev/learn/typescript"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/typescript-react-vite-browser/",
      "markdown_url": "/stacks/typescript-react-vite-browser/guide.md",
      "json_url": "/stacks/typescript-react-vite-browser/record.json",
      "architecture_and_migration": {
        "id": "typescript-react-vite-browser",
        "version_scope": "Documentation reviewed 11 October 2026: current React docs label 19.3; current Vite docs include migration from v7 and Rolldown build options. Preserve the project's resolved React/Vite/TypeScript/router versions and API schema. SPA guidance is not a claim that Vite supplies SSR or a backend.",
        "operating_model": "React/Vite builds browser assets. Recommendation: select it when an existing API owns persistence, authorization, email, durable jobs and other privileged effects; choose routing and remote-state tools deliberately. A client-only build has no protected server runtime.",
        "architecture": [
          "Views consume route-loaded or query-cached DTOs; one API client module defines credentials, errors, cancellation and runtime validation. Backend ownership remains independent of UI language.",
          "Recommendation: domain state stays on the server; transient form/navigation state stays in the browser. Use tenant-aware cache keys and an explicit account-switch/reset policy.",
          "Bundled VITE_ values are public configuration. Keep database, provider and signing credentials in the backend; a development proxy is only local routing.",
          "Recommendation: retain content-hashed old chunks during rollout, revalidate HTML and provide a guarded update path for stale tabs. Add service-worker storage/adoption policy only if offline operation is required."
        ],
        "developer_workflow": [
          "Start at the source README, API schema and lockfile. For a new local prototype npm create vite@latest my-app -- --template react-ts creates a starter; record resolved versions before promoting it. Existing applications keep their package manager.",
          "Use npm ci, the configured TypeScript project check (for the standard scaffold npx tsc -b) and npm run build. npm run dev is local development; npm run preview previews a build and is not the production host.",
          "Configure routing, typed API boundaries, TanStack Query only where useful and its QueryClientProvider. Define loading, stale, denied and offline states before using retries.",
          "Recommendation: use browser network/debug tooling and React profiling for the actual slow interaction. Configure Playwright with old/new API fixtures; run npx playwright test only after installing its runner/browsers and setting an isolated webServer."
        ],
        "avoid": [
          "Bundling a secret as VITE_API_KEY publishes it to users; moving its string into a frontend module does not create a trust boundary.",
          "Rebuilding server authorization as React route guards allows direct unauthorized API calls.",
          "Independent fetching in nested effects creates waterfalls and duplicated state ownership; use route loaders or a selected remote-state cache where appropriate.",
          "Treating TanStack Query defaults as an application freshness contract overlooks refetch/retry behavior and account boundaries.",
          "Deleting old chunks on deployment breaks lazy imports in open tabs; repeated automatic reload can also discard unsaved work."
        ],
        "transitions": [
          {
            "capability": "client",
            "existing_contract": "Existing URLs, backend API DTOs, errors, permissions and navigation/deep-link semantics.",
            "coexistence": "Recommendation: Replace one route/screen with React while keeping existing API ownership and deep links; contract fixtures cover old/new UI.",
            "target": "Recommendation: Keep a browser/API split with route loaders or a selected query client; adopt a server framework only when required rendering/backend features justify it.",
            "benefits": [
              {
                "benefit": "An independently delivered browser client can evolve behind a stable API.",
                "prerequisites": "Owned routing/hosting fallback and backward-compatible API.",
                "tradeoffs": "A SPA must own routing/data/loading infrastructure; SSR/RSC are additional architecture choices."
              }
            ],
            "checks": [
              "Direct deep links and refresh work from the production host.",
              "Old/new clients decode success/error/unknown-field fixtures.",
              "Unauthorized direct API requests remain denied."
            ],
            "rollback": "Restore old HTML/assets/routes while API compatibility remains; preserve submitted data and reconcile pending mutations.",
            "sources": [
              "https://react.dev/learn/build-a-react-app-from-scratch",
              "https://vite.dev/guide/static-deploy"
            ],
            "id": "client-1"
          },
          {
            "capability": "identity",
            "existing_contract": "Backend credential transport, allowed origins, cookies/CSRF, token expiry and account boundaries.",
            "coexistence": "Recommendation: Keep the backend issuer; configure same-origin routing or narrowly allowed credentialed CORS and preserve old clients.",
            "target": "Recommendation: Centralize credential/error behavior in the API client; enforce authorization and any cookie CSRF protection in the backend.",
            "benefits": [
              {
                "benefit": "One backend authority reduces duplicated browser identity logic.",
                "prerequisites": "Reviewed origin/credential policy and issuer behavior.",
                "tradeoffs": "CORS controls browser response access, not authorization; frontend guards remain presentation only."
              }
            ],
            "checks": [
              "Credentialed requests succeed only for permitted origins.",
              "Expired credentials transition to sign-in without endless retries.",
              "Cross-tenant and CSRF probes are rejected by the backend."
            ],
            "rollback": "Restore the old browser artifact/origin policy only if existing credential handling remains secure; retain revocation history.",
            "sources": [
              "https://fetch.spec.whatwg.org/",
              "https://vite.dev/guide/env-and-mode"
            ],
            "id": "identity-1"
          },
          {
            "capability": "cache",
            "existing_contract": "Current fetch/cache behavior, stale tolerance, retry limits and account-switch isolation.",
            "coexistence": "Recommendation: Introduce query keys for a bounded remote-state category; keep transient form state separate and compare outcomes with the old fetch path.",
            "target": "Recommendation: Use explicit TanStack Query staleTime, retry, invalidation and account-clear policy where its remote-state cache serves a requirement.",
            "benefits": [
              {
                "benefit": "Shared queries can reuse data and refresh deliberately.",
                "prerequisites": "A QueryClientProvider, stable tenant-aware keys and mutation invalidation.",
                "tradeoffs": "Default stale queries refetch on mount/focus/reconnect; retries can obscure application errors if left unspecified."
              }
            ],
            "checks": [
              "A mutation refreshes affected list/detail views.",
              "Switching accounts cannot reuse the old account's records.",
              "Network restoration produces one coherent refresh; permission errors do not retry indefinitely."
            ],
            "rollback": "Return the category to the old loader and clear the new cache; do not discard durable pending user operations.",
            "sources": [
              "https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults"
            ],
            "id": "cache-1"
          },
          {
            "capability": "realtime",
            "existing_contract": "Existing event envelope, authorization, IDs, reconnect behavior and replay/retention rules.",
            "coexistence": "Recommendation: Keep a backend bridge producing the current event contract; move clients by stable subscription cohort rather than arbitrary per-request routing.",
            "target": "Recommendation: Use EventSource for one-way events when host/credentials fit, WebSocket for bidirectional needs; persist/replay events separately when delivery requires it.",
            "benefits": [
              {
                "benefit": "A standard browser event stream can replace bespoke polling for suitable feeds.",
                "prerequisites": "Authenticated endpoint, event IDs, retention/replay contract and streaming host.",
                "tradeoffs": "EventSource reconnect does not create server event history; its constructor has no arbitrary header option."
              }
            ],
            "checks": [
              "Disconnect after event N and reconnect; no required event is omitted or applied twice.",
              "Revocation terminates access and later reconnect is denied.",
              "Old/new envelopes decode during mixed-version rollout."
            ],
            "rollback": "Restore old polling/transport using the same cursor domain; reconcile delivered events and keep bridge/history through the rollback window.",
            "sources": [
              "https://html.spec.whatwg.org/multipage/server-sent-events.html"
            ],
            "id": "realtime-1"
          },
          {
            "capability": "operations",
            "existing_contract": "Existing HTML/CDN/service-worker policy, lazy chunks and open-tab unsaved state.",
            "coexistence": "Recommendation: Keep prior hashed assets and compatible APIs while serving new HTML to a cohort; include any existing service worker's activation/cache rules.",
            "target": "Recommendation: Revalidate HTML, retain old content-hashed chunks and handle vite:preloadError with a guarded refresh/update flow that preserves drafts.",
            "benefits": [
              {
                "benefit": "Old tabs can continue loading their release's lazy chunks.",
                "prerequisites": "Asset retention, correct base path and tested update UX.",
                "tradeoffs": "Retention costs storage; refresh may lose state, and reload loops do not fix a wrong CDN policy."
              }
            ],
            "checks": [
              "After deployment an old tab lazy-loads its old route successfully.",
              "If a chunk is intentionally unavailable, the update path retains the draft and recovers once.",
              "Production HTML/cache headers and API compatibility match the rollout policy."
            ],
            "rollback": "Restore the prior HTML and retained assets, roll service-worker changes through their actual lifecycle, and keep new-client API support.",
            "sources": [
              "https://vite.dev/guide/build",
              "https://vite.dev/guide/static-deploy"
            ],
            "id": "operations-1"
          }
        ],
        "sources": [
          {
            "url": "https://react.dev/learn/build-a-react-app-from-scratch",
            "title": "React Build an app from Scratch",
            "claim": "A Vite client-only starter requires deliberate routing/data tools; SSR/RSC are additional architecture work."
          },
          {
            "url": "https://vite.dev/guide/",
            "title": "Vite Getting Started",
            "claim": "Scaffold command and runtime requirements must be checked against resolved Vite version."
          },
          {
            "url": "https://vite.dev/guide/env-and-mode",
            "title": "Vite Environment Variables and Modes",
            "claim": "VITE_ values are bundled into client code and must not contain secrets."
          },
          {
            "url": "https://vite.dev/guide/build",
            "title": "Vite Building for Production",
            "claim": "Deleted old chunks can fail dynamic imports; vite:preloadError and HTML cache policy support recovery design."
          },
          {
            "url": "https://vite.dev/guide/static-deploy",
            "title": "Vite Deploying a Static Site",
            "claim": "Build output needs a chosen production host; vite preview is for local preview."
          },
          {
            "url": "https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults",
            "title": "TanStack Query Important Defaults",
            "claim": "Staleness, mount/focus/reconnect refetch, garbage collection and retries require explicit application choices."
          },
          {
            "url": "https://fetch.spec.whatwg.org/",
            "title": "WHATWG Fetch Standard",
            "claim": "Cross-origin response sharing and credential handling are browser protocol rules, separate from application authorization."
          },
          {
            "url": "https://html.spec.whatwg.org/multipage/server-sent-events.html",
            "title": "WHATWG Server-sent Events",
            "claim": "EventSource provides reconnect and event IDs; constructor options include withCredentials, not arbitrary headers."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": false,
        "static_hosting": true,
        "offline_client_candidate": true
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    },
    {
      "id": "rails-hotwire-postgresql",
      "name": "Rails + Hotwire + PostgreSQL",
      "use_cases": [
        "SaaS",
        "Business CRUD",
        "Collaboration and workflow products"
      ],
      "choose_when": [
        "An integrated monolith and server-owned UI fit the product.",
        "A small team benefits from stable conventions and limited integration work."
      ],
      "avoid_when": [
        "The core is an offline-first canvas or requires extensive browser-owned state.",
        "Hard CPU/latency constraints justify a specialist service."
      ],
      "tools": [
        {
          "job": "UI",
          "default": "ERB + Turbo + Stimulus",
          "alternatives": [
            "React client when browser-owned state dominates; retain Rails API"
          ],
          "reason": "Server-rendered HTML and selective JavaScript limit duplicated UI state.",
          "limits": "Do not force Hotwire onto rich offline editors.",
          "source_urls": [
            "https://hotwired.dev/"
          ]
        },
        {
          "job": "Database and migrations",
          "default": "PostgreSQL + Active Record migrations",
          "alternatives": [
            "SQLite for deliberately single-host deployments"
          ],
          "reason": "Relational constraints and conventional migrations fit business data.",
          "limits": "Use unique/foreign-key constraints; assess locks and use expand/contract changes for rolling deploys.",
          "source_urls": [
            "https://guides.rubyonrails.org/active_record_migrations.html"
          ]
        },
        {
          "job": "Authentication",
          "default": "Rails authentication generator",
          "alternatives": [
            "Devise when its additional authentication modules are needed"
          ],
          "reason": "Generated local sessions plus explicit per-resource authorization.",
          "limits": "Generator is a starting point; signup, authorization and account lifecycle require product decisions.",
          "source_urls": [
            "https://guides.rubyonrails.org/getting_started.html",
            "https://github.com/varvet/pundit",
            "https://github.com/heartcombo/devise"
          ]
        },
        {
          "job": "Authorization",
          "default": "Pundit policy classes",
          "alternatives": [
            "Existing resource-level policy implementation; keep authentication separate"
          ],
          "reason": "Generated local sessions plus explicit per-resource authorization.",
          "limits": "Generator is a starting point; signup, authorization and account lifecycle require product decisions.",
          "source_urls": [
            "https://guides.rubyonrails.org/getting_started.html",
            "https://github.com/varvet/pundit",
            "https://github.com/heartcombo/devise"
          ]
        },
        {
          "job": "Jobs",
          "default": "Active Job + Solid Queue",
          "alternatives": [
            "Another Active Job backend only for measured operational needs"
          ],
          "reason": "Database-backed jobs avoid a mandatory separate broker.",
          "limits": "Configure worker capacity, retry limits and idempotency; separate queue DB does not guarantee atomic app-write/enqueue.",
          "source_urls": [
            "https://guides.rubyonrails.org/active_job_basics.html"
          ]
        },
        {
          "job": "Tests",
          "default": "Minitest + Rails integration/system tests",
          "alternatives": [
            "Keep RSpec in an established RSpec repository"
          ],
          "reason": "Exercise authorization, database constraints and essential browser flows.",
          "limits": "Browser tests need their driver/browser; unit tests alone miss UI and transaction races.",
          "source_urls": [
            "https://guides.rubyonrails.org/testing.html"
          ]
        },
        {
          "job": "Lint and security",
          "default": "RuboCop + Brakeman + bundler-audit",
          "alternatives": [
            "Preserve existing compatible project tooling"
          ],
          "reason": "Style, application scanning and dependency advisories cover different risks.",
          "limits": "Scans do not establish security; test tenant isolation and unsafe uploads. bundler-audit has GPL-3.0 licensing.",
          "source_urls": [
            "https://guides.rubyonrails.org/getting_started.html",
            "https://guides.rubyonrails.org/security.html",
            "https://github.com/rubysec/bundler-audit"
          ]
        },
        {
          "job": "Deployment",
          "default": "Kamal + generated Dockerfile + PostgreSQL backups",
          "alternatives": [
            "Managed container hosting when server operations are undesirable"
          ],
          "reason": "Portable container deployment with application-owned configuration.",
          "limits": "Requires registry/server credentials and persistent data strategy; backups and restore drills remain operator work.",
          "source_urls": [
            "https://kamal-deploy.org/docs/installation/",
            "https://guides.rubyonrails.org/getting_started.html"
          ]
        },
        {
          "job": "Agent tooling",
          "default": "Generators + routes/schema/test feedback + version-matched Rails guides",
          "alternatives": [
            "Add only a reviewed MCP integration with a concrete need"
          ],
          "reason": "Conventions make edits easier to locate and verify.",
          "limits": "Agent productivity is an inference; no cross-framework coding-success benchmark established.",
          "source_urls": [
            "https://rubyonrails.org/ai"
          ]
        },
        {
          "job": "Licensing and hosting",
          "default": "Rails MIT; self-hostable",
          "alternatives": [
            "Paid infrastructure/support when operationally useful"
          ],
          "reason": "No mandatory proprietary Rails hosting service.",
          "limits": "Dependency licenses remain separate; do not infer all gems are MIT.",
          "source_urls": [
            "https://github.com/rails/rails/blob/main/MIT-LICENSE"
          ]
        },
        {
          "job": "Transactional email",
          "default": "Action Mailer",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Framework mailers integrate templates and queued delivery",
          "limits": "Configure provider transport and sender; use deliver_later when delivery must be queued; test content and failure behavior. Provider acceptance is not inbox delivery.",
          "source_urls": [
            "https://guides.rubyonrails.org/action_mailer_basics.html"
          ]
        },
        {
          "job": "Uploads and object storage",
          "default": "Active Storage",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Framework attachments support external storage and direct uploads",
          "limits": "Run the installed-version Active Storage generator/migrations; configure private storage, authorization, limits and cleanup. Public blob URLs and user-supplied files need an explicit access policy.",
          "source_urls": [
            "https://guides.rubyonrails.org/active_storage_overview.html"
          ]
        },
        {
          "job": "Realtime transport",
          "default": "Action Cable",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Rails channels integrate WebSocket messages with application code",
          "limits": "Configure chosen cable adapter and connection/channel authorization; test reconnect, revoked membership and host proxy behavior. Broadcast is not durable event history.",
          "source_urls": [
            "https://guides.rubyonrails.org/action_cable_overview.html"
          ]
        }
      ],
      "setup_steps": [
        "Start in a source directory in a local development workspace with supported Ruby/Rails, PostgreSQL and Git installed; choose and record compatible versions before generation.",
        "Run rails new product -d postgresql; enter product; configure development/test database access without committing credentials.",
        "Run bin/rails generate authentication; add Pundit via bundle add pundit and run bin/rails generate pundit:install; implement signup and resource policies deliberately.",
        "Run bin/rails db:prepare; start bin/rails server. Configure Solid Queue from the installed-version guide and run its worker with bin/jobs when enabled.",
        "Add bundler-audit to the development group if absent; preserve Gemfile.lock. Define authorization, duplicate-job and migration tests.",
        "Prepare config/deploy.yml, secrets, database persistence and backup/restore procedure. Only in an authorized deployment run bundle exec kamal setup initially or bundle exec kamal deploy thereafter."
      ],
      "verification_commands": [
        "ruby --version",
        "bundle exec rails --version",
        "bin/rails db:migrate:status",
        "bin/rails zeitwerk:check",
        "bin/rails test",
        "bin/rails test:system",
        "bin/rubocop",
        "bin/brakeman",
        "bundle exec bundler-audit check --update"
      ],
      "evidence_status": "documentation-reviewed",
      "open_questions": [
        "Which signup, SSO/MFA and resource authorization policies are required?",
        "Does the product fit server-owned screens or need substantial offline/client state?",
        "Which host, mail/storage services, worker throughput and restore requirements apply?"
      ],
      "sources": [
        {
          "url": "https://hotwired.dev/",
          "title": "Hotwire: HTML Over The Wire",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://guides.rubyonrails.org/active_record_migrations.html",
          "title": "Active Record Migrations",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://guides.rubyonrails.org/getting_started.html",
          "title": "Getting Started with Rails",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/varvet/pundit",
          "title": "Pundit README",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/heartcombo/devise",
          "title": "Devise README",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://guides.rubyonrails.org/active_job_basics.html",
          "title": "Active Job Basics",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://guides.rubyonrails.org/testing.html",
          "title": "Testing Applications",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://guides.rubyonrails.org/security.html",
          "title": "Securing Rails Applications",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/rubysec/bundler-audit",
          "title": "bundler-audit README and license",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://kamal-deploy.org/docs/installation/",
          "title": "Kamal Installation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://rubyonrails.org/ai",
          "title": "Rails and AI",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/rails/rails/blob/main/MIT-LICENSE",
          "title": "Rails MIT License",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://guides.rubyonrails.org/action_mailer_basics.html",
          "title": "Rails Action Mailer",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://guides.rubyonrails.org/active_storage_overview.html",
          "title": "Rails Active Storage",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://guides.rubyonrails.org/action_cable_overview.html",
          "title": "Rails Action Cable",
          "checked_date": "2026-10-10"
        }
      ],
      "title": "Rails + Hotwire",
      "language": "Ruby",
      "group": "Web applications",
      "kind": [
        "web"
      ],
      "ui": "server",
      "host": "server",
      "summary": "Database-backed products with HTML, accounts and jobs close together.",
      "shape": "Rails · Turbo · Stimulus · PostgreSQL",
      "tradeoff": "Rich offline or canvas-heavy interfaces can need a separate client.",
      "research_file": "rails-laravel.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Keep Turbo and Stimulus focused on interface behavior; put authorization in explicit policies.",
        "Run migrations and exercise the generated authentication flow before building product features around it.",
        "Treat Solid Queue workers as operated processes. Make retries safe and verify recovery after interruption.",
        "Use system tests for the critical browser journey and rehearse backups and restore before shipping."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://guides.rubyonrails.org/getting_started.html",
          "https://guides.rubyonrails.org/active_job_basics.html"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/rails-hotwire-postgresql/",
      "markdown_url": "/stacks/rails-hotwire-postgresql/guide.md",
      "json_url": "/stacks/rails-hotwire-postgresql/record.json",
      "architecture_and_migration": {
        "id": "rails-hotwire-postgresql",
        "version_scope": "Rails guides showing Rails 8.1 examples; current Turbo handbook. These describe target capabilities, not the source application's installed versions. Detect Gemfile.lock, Ruby version and configured adapters before choosing a move.",
        "operating_model": "Rails supplies a conventional MVC application and Active Record persistence. Turbo Drive, Frames and Streams support a server-rendered HTML interface with incremental browser updates. Recommendation: keep domain writes on the server and introduce browser-owned state only for interactions that need it; a framework rewrite is not a prerequisite for fixing an inefficient query or incorrect queue contract.",
        "architecture": [
          "Recommendation: establish one authoritative domain writer and one schema migration runner per shared database during coexistence. Route a stable tenant or feature boundary, and keep the old application able to read new writes until rollback expires.",
          "Active Job is the application interface; Solid Queue is the Rails 8 default backend. Inspect the application's actual adapter before inferring a Redis dependency. Separate workers, recurring task configuration and domain writes are distinct responsibilities.",
          "Recommendation: treat Turbo stream DOM targets, Action Cable channel identifiers, job serialization and session cookies as separate contracts. Sharing a datastore does not prove any of their compatibility."
        ],
        "developer_workflow": [
          "In an existing checkout, read Gemfile.lock and environment configuration before adapting generators. In a disposable feature prototype, bin/rails generate model Product name:string and bin/rails db:migrate demonstrate the conventional model/migration path; review generated schema changes before applying them.",
          "bin/rails generate job guests_cleanup creates an Active Job class; configure its selected backend and worker process separately. Recipe only: use bin/jobs start for a configured Solid Queue application, then exercise enqueue, failure and recovery against its real queue database.",
          "bin/rails console is useful for inspecting application objects. Recommendation: capture authorized and unauthorized request fixtures, mixed-version writes and browser stream behavior as acceptance checks rather than treating successful boot as migration qualification.",
          "For a new local-account prototype, bin/rails generate authentication creates User and Session models plus login surfaces. Review account lifecycle and resource authorization separately; do not run it over an established authentication system without an intentional migration design."
        ],
        "avoid": [
          "Avoid calling a queue-adapter configuration change a backlog migration: the old backend retains work and Active Job can serialize GlobalID and custom types that need the original Ruby classes and database semantics.",
          "Avoid claiming atomic domain-write-and-enqueue from a separate Solid Queue database. After-commit enqueue prevents premature execution but is not a transaction across two stores. Recommendation: use a durable outbox when a crash between commit and delivery must be recoverable.",
          "Avoid the Action Cable async adapter for distributed production delivery; the guide restricts it to development/testing and a single process. Avoid replacing session or lock data with a disposable cache just because both use Redis."
        ],
        "transitions": [
          {
            "capability": "data",
            "existing_contract": "Inventory table names, primary keys, timestamps, enum values, constraints, callbacks and the application that currently owns migrations; Active Record migrations define schema evolution but do not describe all application side effects.",
            "coexistence": "Recommendation: keep the existing writer authoritative while the target reads representative data. Add backward-readable fields first; transfer one domain boundary explicitly. Keep a single migration runner rather than allowing two framework migration histories to modify the same tables independently.",
            "target": "Rails Active Record over the selected PostgreSQL schema, with reviewed database constraints and migrations. Recommendation: remove legacy fields only after old code and rollback readers have retired.",
            "benefits": [
              {
                "benefit": "Recommendation: conventional migrations and model access can concentrate schema work in one maintained application.",
                "prerequisites": "A named schema owner, compatible value semantics and staged writer transfer.",
                "tradeoffs": "Shared tables constrain both deployments; deleting or rewriting data may require reconciliation rather than migration reversal."
              }
            ],
            "checks": [
              "Create in the old application and read in Rails, then reverse the direction after writer transfer; compare IDs, timestamps and nullable values.",
              "Run the proposed migration against a disposable copy; verify both deployed versions can still read and update a fixture, including unique and foreign-key failures."
            ],
            "rollback": "Recommendation: route writes back only while the old reader understands new records. Preserve additive schema changes; rehearse reversible migrations separately and reconcile irreversible data changes.",
            "sources": [
              "https://guides.rubyonrails.org/active_record_migrations.html",
              "https://guides.rubyonrails.org/getting_started.html"
            ],
            "id": "data-1"
          },
          {
            "capability": "jobs",
            "existing_contract": "Record adapter, job class, argument serializers/GlobalIDs, queue names, retries, scheduled work, failed work and running leases. Rails exposes these through Active Job while each backend supplies execution behavior.",
            "coexistence": "Recommendation: retain old consumers for old payloads; route a new job category to a new queue/backend. Transfer its producers and recurring-task owner together. Drain or deliberately transform ready, scheduled, retry, failed and in-flight work; do not run both schedulers for the same business operation.",
            "target": "Active Job with configured Solid Queue or the retained qualified adapter. Same-database enqueue may join a domain transaction; a separate queue database needs an explicit delivery design. Recommendation: require business idempotency even when job uniqueness exists.",
            "benefits": [
              {
                "benefit": "SQL-backed job persistence may allow retirement of a dedicated broker.",
                "prerequisites": "All broker uses inventoried and retired; workers, queue schema, failure monitoring and backlog reconciliation in place.",
                "tradeoffs": "Database work and queue operations remain operational responsibilities; retaining Redis for another capability yields no service-count reduction."
              }
            ],
            "checks": [
              "Replay captured old serializer fixtures using the retained consumer; a deleted GlobalID target must follow the intended failure policy.",
              "Rollback a domain transaction and confirm no executable job escapes it; kill after an external effect before acknowledgement and verify a retry cannot repeat the business effect.",
              "Account for every backlog state and observe only one scheduled enqueue for the transferred category."
            ],
            "rollback": "Recommendation: stop new producers before restoring old routing; retain both consumers through the rollback window and reconcile completed external effects before re-enqueueing.",
            "sources": [
              "https://guides.rubyonrails.org/active_job_basics.html",
              "https://github.com/sidekiq/sidekiq/wiki/Best-Practices"
            ],
            "id": "jobs-1"
          },
          {
            "capability": "identity",
            "existing_contract": "Distinguish the application's generated Session model from Rails session storage. Capture cookie name, serializer, signing/encryption configuration, expiration, account IDs, logout/revocation and per-resource authorization.",
            "coexistence": "Recommendation: keep a shared identity authority or a documented session exchange endpoint. If cookies are shared, qualify the complete cookie format and rotation rules; route stable users and retain the old decoder for the agreed window.",
            "target": "An intentionally selected Rails authentication implementation with application authorization. CookieStore stores session data on the client; account/session lifecycle rules must be designed separately.",
            "benefits": [
              {
                "benefit": "Recommendation: coherent account and session ownership can preserve login continuity during feature migration.",
                "prerequisites": "Verified identity mapping, cookie/exchange fixtures and shared revocation behavior.",
                "tradeoffs": "Compatibility code and key rotation increase maintenance; planned reauthentication is an alternative when continuity is unnecessary."
              }
            ],
            "checks": [
              "Authenticate through the old path and visit the new route; then logout, expire or revoke the session and confirm both paths deny access.",
              "Replay a modified cookie, a stale cookie and a valid session from another tenant against a protected resource; each unauthorized operation must be rejected."
            ],
            "rollback": "Recommendation: preserve old account IDs and accepted session formats until routing stabilizes; coordinate revocation and key rotation so restoring traffic cannot revive invalidated sessions.",
            "sources": [
              "https://guides.rubyonrails.org/security.html",
              "https://guides.rubyonrails.org/getting_started.html"
            ],
            "id": "identity-1"
          },
          {
            "capability": "realtime",
            "existing_contract": "Capture channel names, connection authentication, subscription commands, DOM target IDs, Turbo stream actions and reconnect behavior. Turbo Streams can arrive over WebSockets, SSE or request responses; Action Cable owns its own client/server protocol.",
            "coexistence": "Recommendation: keep the current realtime endpoint for old clients; bridge versioned domain events to the selected target renderer. Assign one event publisher per committed change and route a room/user cohort including reconnects, rather than randomly splitting individual socket requests.",
            "target": "Turbo streams over the selected transport, with Action Cable using a configured shared adapter when multiple server processes must communicate. Solid Cable is database-backed; Redis remains a documented alternative.",
            "benefits": [
              {
                "benefit": "HTML updates can reuse server-rendered partials.",
                "prerequisites": "Stable DOM targets, authorized subscriptions and compatible event-to-view rendering.",
                "tradeoffs": "A new socket protocol still needs client changes or a bridge; reconnection recovery is an application acceptance requirement."
              }
            ],
            "checks": [
              "Place old and new clients on different server processes; commit one change and verify both authorized clients display it once.",
              "Disconnect during a write, reconnect and verify the UI converges to the persisted state; unauthorized origins and subscriptions must fail."
            ],
            "rollback": "Recommendation: preserve the old event renderer/endpoint and backward-readable stream payloads until the cohort can reconnect there; reconcile already-delivered state rather than blindly rebroadcasting.",
            "sources": [
              "https://guides.rubyonrails.org/action_cable_overview.html",
              "https://turbo.hotwired.dev/handbook/streams"
            ],
            "id": "realtime-1"
          },
          {
            "capability": "cache",
            "existing_contract": "List reconstructible values separately from sessions, counters and locks. Capture key namespaces, serialized values, TTLs and invalidation triggers; Rails.cache and request-local SQL query caching have different lifetimes.",
            "coexistence": "Recommendation: use a new cache namespace when representations differ, read through to the authoritative data and maintain invalidation for both deployed readers. Keep shared coordination uses on their qualified store while moving only disposable values.",
            "target": "A deliberately selected Rails cache store; Solid Cache is database-backed and new Rails 8 applications include it. MemoryStore and RedisCacheStore remain choices with different process/service boundaries.",
            "benefits": [
              {
                "benefit": "Database-backed caching can remove a dedicated cache service when it is the last use.",
                "prerequisites": "Reconstructible contents, tested expiration/invalidation, adequate database capacity and retirement of all other service uses.",
                "tradeoffs": "Cache traffic moves to the database; cache durability does not make it the authoritative domain store."
              }
            ],
            "checks": [
              "Warm both versions, update the source record and verify neither version serves the prior value after its specified invalidation boundary.",
              "Restart the application or empty only the dedicated cache namespace; requests must rebuild correctly without losing identity or coordination state."
            ],
            "rollback": "Recommendation: switch to the previous namespace/store and repopulate from domain data; retain the old backend while any coordination capability still depends on it.",
            "sources": [
              "https://guides.rubyonrails.org/caching_with_rails.html"
            ],
            "id": "cache-1"
          },
          {
            "capability": "operations",
            "existing_contract": "Record deployed web and Cable processes, configured workers/dispatchers, recurring.yml tasks and database connections. A web deployment alone does not establish that workers or broadcasts are running.",
            "coexistence": "Recommendation: give each process a named operational owner; keep existing backups and queue monitoring while deploying the new cohort. Transfer recurring schedule ownership once, after checking overlapping old and new schedules.",
            "target": "An explicit Rails process inventory with worker lifecycle, queue failure inspection and the chosen realtime adapter. Recommendation: document separate domain, queue and cache database restore ordering where applicable.",
            "benefits": [
              {
                "benefit": "Recommendation: visible process and schedule ownership makes failures and recovery boundaries reviewable.",
                "prerequisites": "A deployment recipe for the selected adapters and an exercised restore/restart procedure.",
                "tradeoffs": "Coexistence temporarily operates both systems; one healthy HTTP endpoint cannot certify all processes."
              }
            ],
            "checks": [
              "Stop a worker, enqueue a representative task and verify monitoring identifies its growing age; restart and observe the intended completion/failure policy.",
              "Restore a disposable backup and prove domain records, delayed tasks and session behavior are accounted for before promoting traffic."
            ],
            "rollback": "Recommendation: freeze producers and scheduler ownership transfers, restore the previous process configuration, then reconcile work accepted by the new deployment.",
            "sources": [
              "https://guides.rubyonrails.org/active_job_basics.html",
              "https://guides.rubyonrails.org/action_cable_overview.html"
            ],
            "id": "operations-1"
          }
        ],
        "sources": [
          {
            "url": "https://guides.rubyonrails.org/getting_started.html",
            "title": "Getting Started with Rails",
            "claim": "Rails 8.1 examples, MVC/Active Record, model and authentication generators, migration and console commands."
          },
          {
            "url": "https://guides.rubyonrails.org/active_record_migrations.html",
            "title": "Active Record Migrations",
            "claim": "Schema migration files, database constraints, reversal and rollback semantics."
          },
          {
            "url": "https://guides.rubyonrails.org/active_job_basics.html",
            "title": "Active Job Basics",
            "claim": "Active Job serialization, Solid Queue default and process roles, bin/jobs, separate database default, enqueue timing, recurring tasks and retry handling."
          },
          {
            "url": "https://guides.rubyonrails.org/security.html",
            "title": "Securing Rails Applications",
            "claim": "CookieStore, signing/encryption rotation, replay/fixation and session expiration considerations."
          },
          {
            "url": "https://guides.rubyonrails.org/action_cable_overview.html",
            "title": "Action Cable Overview",
            "claim": "Cable connections/channels, adapter configuration, async locality, Solid Cable, origins and server deployment."
          },
          {
            "url": "https://guides.rubyonrails.org/caching_with_rails.html",
            "title": "Caching with Rails",
            "claim": "Rails cache interfaces, SQL cache lifetime, Solid Cache and alternative stores."
          },
          {
            "url": "https://turbo.hotwired.dev/handbook/introduction",
            "title": "Turbo introduction",
            "claim": "Drive, Frames and Streams extend server-rendered HTML navigation and updates."
          },
          {
            "url": "https://turbo.hotwired.dev/handbook/streams",
            "title": "Turbo Streams",
            "claim": "DOM target operations and stream transport options."
          },
          {
            "url": "https://github.com/sidekiq/sidekiq/wiki/Best-Practices",
            "title": "Sidekiq Best Practices",
            "claim": "Jobs must be idempotent; execution is at least once rather than exactly once."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": false,
        "static_hosting": false,
        "offline_client_candidate": false
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    },
    {
      "id": "laravel-livewire-postgresql",
      "name": "Laravel + Livewire + PostgreSQL",
      "use_cases": [
        "SaaS",
        "Administrative and business applications",
        "Server-driven interactive products"
      ],
      "choose_when": [
        "PHP team or Laravel ecosystem fit is strong.",
        "Integrated auth, queues and concrete agent inspection tools reduce assembly work."
      ],
      "avoid_when": [
        "The UI fundamentally requires an offline/client-state architecture; use the Inertia alternative if Laravel still fits.",
        "A hosting plan cannot operate needed queue workers or scheduled jobs."
      ],
      "tools": [
        {
          "job": "UI",
          "default": "Official Livewire starter kit + Blade/Tailwind",
          "alternatives": [
            "Official React/Vue/Svelte Inertia kits for heavier client interactions"
          ],
          "reason": "One supported starter establishes coherent UI/auth integration.",
          "limits": "Starter includes Flux; distinguish its free components from paid Pro assets.",
          "source_urls": [
            "https://laravel.com/framework/docs/13.x/starter-kits",
            "https://fluxui.dev/pricing"
          ]
        },
        {
          "job": "Database and migrations",
          "default": "PostgreSQL + Eloquent + Laravel migrations",
          "alternatives": [
            "SQLite for local/small deployments; existing MySQL where operationally established"
          ],
          "reason": "Conventional ORM and migrations with a production relational store.",
          "limits": "Use constraints; production-engine integration tests; never use migrate:fresh against retained data.",
          "source_urls": [
            "https://laravel.com/framework/docs/13.x/database",
            "https://laravel.com/framework/docs/13.x/migrations"
          ]
        },
        {
          "job": "Authentication",
          "default": "Starter-kit Fortify auth",
          "alternatives": [
            "WorkOS starter variant for managed identity requirements"
          ],
          "reason": "Existing authentication flow plus resource-level authorization.",
          "limits": "Policies remain application work; managed identity adds external terms/cost.",
          "source_urls": [
            "https://laravel.com/framework/docs/13.x/starter-kits",
            "https://laravel.com/framework/docs/13.x/authorization"
          ]
        },
        {
          "job": "Authorization",
          "default": "Laravel policies and gates",
          "alternatives": [
            "Existing explicit resource-level authorization implementation; identity providers still require policies"
          ],
          "reason": "Existing authentication flow plus resource-level authorization.",
          "limits": "Policies remain application work; managed identity adds external terms/cost.",
          "source_urls": [
            "https://laravel.com/framework/docs/13.x/starter-kits",
            "https://laravel.com/framework/docs/13.x/authorization"
          ]
        },
        {
          "job": "Queues",
          "default": "Laravel database queue + supervised workers",
          "alternatives": [
            "Redis + Horizon for queue dashboards/balancing; SQS for an established managed queue"
          ],
          "reason": "Simple starting infrastructure with explicit scale-up options.",
          "limits": "Use after-commit dispatch, idempotent jobs, finite retries and worker restarts. Horizon requires Redis.",
          "source_urls": [
            "https://laravel.com/framework/docs/13.x/queues",
            "https://laravel.com/framework/docs/13.x/horizon"
          ]
        },
        {
          "job": "Tests",
          "default": "Pest or PHPUnit from starter; Dusk for key browser flows",
          "alternatives": [
            "Keep the existing test runner rather than changing syntax for its own sake"
          ],
          "reason": "Application and browser verification complement each other.",
          "limits": "Use a dedicated test database and install Dusk only in development.",
          "source_urls": [
            "https://laravel.com/framework/docs/13.x/testing",
            "https://laravel.com/framework/docs/13.x/dusk"
          ]
        },
        {
          "job": "Lint, static analysis and security",
          "default": "Pint + Larastan/PHPStan + Composer audit",
          "alternatives": [
            "Existing equivalent tooling if already maintained"
          ],
          "reason": "Formatting, static checks and dependency advisory checks expose different failures.",
          "limits": "Install a compatible Larastan version and configure its extension; no audit substitutes for authorization tests.",
          "source_urls": [
            "https://laravel.com/framework/docs/13.x/pint",
            "https://github.com/larastan/larastan",
            "https://getcomposer.org/doc/03-cli.md#audit"
          ]
        },
        {
          "job": "Deployment",
          "default": "PHP-FPM web service + worker supervisor + scheduler on chosen host",
          "alternatives": [
            "Laravel Cloud for managed operation; Forge for server management"
          ],
          "reason": "A conventional process model is a practical default.",
          "limits": "Serve only public/; APP_DEBUG=false; persist uploads; reload workers after releases; paid platforms are optional.",
          "source_urls": [
            "https://laravel.com/framework/docs/13.x/deployment"
          ]
        },
        {
          "job": "Agent tooling",
          "default": "Laravel Boost development dependency",
          "alternatives": [
            "Normal CLI/docs when MCP is unavailable"
          ],
          "reason": "Version-aware documentation and route/schema/log inspection provide concrete context.",
          "limits": "Tools can execute application code; use development credentials and honor maintained repository instructions. A README-only integration is an optional project policy; inspect installed Boost help before opting out of generated instructions.",
          "source_urls": [
            "https://laravel.com/framework/docs/13.x/ai"
          ]
        },
        {
          "job": "Licensing and hosting",
          "default": "Laravel framework MIT; self-hostable",
          "alternatives": [
            "Optional paid Flux Pro and managed services"
          ],
          "reason": "Framework use does not mandate a hosting subscription.",
          "limits": "Check each optional asset/package/service license separately.",
          "source_urls": [
            "https://github.com/laravel/framework/blob/13.x/LICENSE.md",
            "https://fluxui.dev/pricing"
          ]
        },
        {
          "job": "Transactional email",
          "default": "Laravel Mail",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Mailables and queue integration keep delivery in application conventions",
          "limits": "Configure the selected mailer and verified sender; use queued mail where required, after-commit handling and failed-job monitoring. Provider acceptance is not inbox delivery.",
          "source_urls": [
            "https://laravel.com/framework/docs/13.x/mail"
          ]
        },
        {
          "job": "Uploads and object storage",
          "default": "Laravel Storage / Flysystem",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Storage disks support private local or S3-backed files",
          "limits": "Configure filesystems.php; install the selected adapter only, authorize downloads and uploads, define size/type limits and retention. Ephemeral deploy disks are not durable shared storage.",
          "source_urls": [
            "https://laravel.com/framework/docs/13.x/filesystem"
          ]
        },
        {
          "job": "Realtime transport",
          "default": "Laravel broadcasting + Reverb when self-hosted sockets are required",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Private channels integrate realtime application events",
          "limits": "Use the installed broadcasting setup; configure Echo, channel authorization, queued events and a supervised Reverb process. Verify TLS/proxy/scaling and reconnect; broadcast is not durable replay.",
          "source_urls": [
            "https://laravel.com/framework/docs/13.x/broadcasting"
          ]
        }
      ],
      "setup_steps": [
        "Start in a local development workspace with a supported PHP/Composer runtime, PostgreSQL, Node/npm and Git. Resolve actual package compatibility; Boost minimums do not define Laravel minimums.",
        "Install installer if needed with composer global require laravel/installer; run laravel new product and choose Livewire, PostgreSQL and the desired test runner; enter product.",
        "Configure .env database/mail/queue settings and confirm application key generation; do not commit secrets. Run php artisan migrate against the intended development database.",
        "Run npm install then npm run build; run composer run dev. Configure a supervised queue worker and scheduler separately for production.",
        "Add composer require laravel/boost --dev; inspect installed boost:install help and configure the selected integration. Honor generated guidance unless the repository explicitly chooses README-only instructions; inspect available installer options or configure MCP manually for that policy.",
        "Add compatible Larastan as a dev dependency and configure phpstan.neon using its guide. For browser tests add laravel/dusk as a dev dependency then run php artisan dusk:install.",
        "Prepare an authorized release: install locked production dependencies, build assets, review migrations, run php artisan optimize, and reload supervised services. Confirm backup/restore and rollback compatibility before production migration."
      ],
      "verification_commands": [
        "php --version",
        "composer check-platform-reqs",
        "php artisan about",
        "php artisan migrate:status",
        "php artisan test",
        "php artisan dusk",
        "vendor/bin/pint --test",
        "vendor/bin/phpstan analyse",
        "composer audit",
        "npm run build"
      ],
      "evidence_status": "documentation-reviewed",
      "open_questions": [
        "Which starter-kit features and paid UI components are actually required?",
        "Which identity and per-resource authorization policies must be supported?",
        "Which host, mail/storage providers, realtime capacity and worker/scheduler operation will own production?"
      ],
      "sources": [
        {
          "url": "https://laravel.com/framework/docs/13.x/starter-kits",
          "title": "Laravel Starter Kits",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://fluxui.dev/pricing",
          "title": "Flux Pricing and Component Tiers",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://laravel.com/framework/docs/13.x/database",
          "title": "Laravel Database: Getting Started",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://laravel.com/framework/docs/13.x/migrations",
          "title": "Laravel Database Migrations",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://laravel.com/framework/docs/13.x/authorization",
          "title": "Laravel Authorization",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://laravel.com/framework/docs/13.x/queues",
          "title": "Laravel Queues",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://laravel.com/framework/docs/13.x/horizon",
          "title": "Laravel Horizon",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://laravel.com/framework/docs/13.x/testing",
          "title": "Testing Applications",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://laravel.com/framework/docs/13.x/dusk",
          "title": "Laravel Dusk",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://laravel.com/framework/docs/13.x/pint",
          "title": "Laravel Pint",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/larastan/larastan",
          "title": "Larastan README",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://getcomposer.org/doc/03-cli.md#audit",
          "title": "Composer CLI: Audit",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://laravel.com/framework/docs/13.x/deployment",
          "title": "Laravel Deployment",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://laravel.com/framework/docs/13.x/ai",
          "title": "AI Assisted Development",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/laravel/framework/blob/13.x/LICENSE.md",
          "title": "Laravel Framework MIT License",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://laravel.com/framework/docs/13.x/mail",
          "title": "Laravel Mail",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://laravel.com/framework/docs/13.x/filesystem",
          "title": "Laravel file storage",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://laravel.com/framework/docs/13.x/broadcasting",
          "title": "Laravel broadcasting",
          "checked_date": "2026-10-10"
        }
      ],
      "title": "Laravel + Livewire",
      "language": "PHP",
      "group": "Web applications",
      "kind": [
        "web"
      ],
      "ui": "server",
      "host": "server",
      "summary": "PHP product applications with a cohesive UI, auth and queue toolset.",
      "shape": "Laravel · Livewire · Blade · PostgreSQL",
      "tradeoff": "The web process, queue workers and scheduler each need deployment supervision.",
      "research_file": "rails-laravel.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Use policies and gates for permissions; a starter's authentication flow does not supply product authorization.",
        "Preserve the selected starter's test conventions and verify Livewire behavior in a real browser.",
        "Supervise queue workers and schedule execution explicitly. Verify retries and avoid duplicate external effects.",
        "Use Laravel Boost during development with the project's installed documentation; keep production exposure separate."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://laravel.com/framework/docs/13.x/installation",
          "https://laravel.com/framework/docs/13.x/ai"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/laravel-livewire-postgresql/",
      "markdown_url": "/stacks/laravel-livewire-postgresql/guide.md",
      "json_url": "/stacks/laravel-livewire-postgresql/record.json",
      "architecture_and_migration": {
        "id": "laravel-livewire-postgresql",
        "version_scope": "Laravel 13.x and Livewire 4.x documentation fetched 11 October 2026. These are documentation scopes, not proof of installed compatibility; inspect composer.lock, PHP version, queue/session/cache drivers and current Livewire component format before implementation.",
        "operating_model": "Laravel combines conventional routes, middleware, authentication guards/providers and database migrations. Livewire components combine PHP behavior with Blade rendering. Recommendation: use these conventions for connected forms and business screens; keep server authorization and domain writes explicit instead of treating public component properties as trusted state.",
        "architecture": [
          "Recommendation: keep a single domain writer and migration owner during shared-schema coexistence; let controllers, Livewire actions and queued workers call the same application operation with its authorization and transaction rules.",
          "Queue connections select backends while queue names select work categories. The documented choices include relational storage, Redis and SQS. Recommendation: choose a backend from recovery and operation requirements rather than assuming every Laravel application needs Redis.",
          "Recommendation: list HTTP PHP execution, queue workers, the scheduler and a selected broadcast server separately. Livewire component interactivity does not by itself establish multi-client event delivery; broadcasting has its own backend/client and queue configuration."
        ],
        "developer_workflow": [
          "In a configured local Laravel project, php artisan make:livewire post.create creates a Livewire 4 component; --class retains the established class-based style and --mfc creates a multi-file component. Inspect existing conventions before choosing a format.",
          "php artisan make:job ProcessPodcast creates a queued job. Configure the selected connection and run php artisan queue:work --queue=high,default only after those queues and priorities match the application; supervise the production worker separately.",
          "php artisan migrate applies reviewed migrations. For missing database session/queue tables, the selected-version docs provide php artisan make:session-table and php artisan make:queue-table; check existing migrations first to avoid duplicate tables.",
          "Recommendation: verify behavior with real driver instances in a disposable environment, including timeout/retry interaction, denied Livewire actions, concurrent session writes and private broadcast authorization. Faking queue submission alone cannot exercise worker serialization or crash recovery."
        ],
        "avoid": [
          "Avoid switching queue consumers solely because both use Redis: Laravel payloads and Eloquent identifier rehydration are framework execution contracts. Recommendation: preserve old consumers or translate deliberately versioned payloads.",
          "Avoid worker timeout values longer than retry_after; Laravel warns this can allow the job to be processed twice. Avoid assuming unique-job locks make external effects exactly once; recommendation: use business idempotency.",
          "Avoid calling onOneServer a cross-stack scheduler lock. It uses a shared supported Laravel cache store; recommendation: explicitly retire the old scheduler for the transferred business category.",
          "Avoid trusting client-editable Livewire properties or hidden buttons for authorization. Avoid Cache::flush on a backend shared with other applications; the documented flush ignores the configured prefix."
        ],
        "transitions": [
          {
            "capability": "data",
            "existing_contract": "Inventory table identifiers, casts/nullability, timestamps, constraints and side effects currently attached to writes. Migrations evolve the schema; Eloquent models do not automatically reproduce another runtime’s callbacks.",
            "coexistence": "Recommendation: keep the existing writer authoritative, add compatible fields and move one domain operation at a time. Let one named migration runner own shared tables and keep old readers functional during the rollback window.",
            "target": "Laravel database migrations and the selected PostgreSQL schema, with application operations reused by controllers/Livewire/workers. Recommendation: delay destructive schema contraction until all old readers retire.",
            "benefits": [
              {
                "benefit": "Recommendation: conventional schema and application ownership can make changes reviewable in one maintained application.",
                "prerequisites": "Explicit writer transfer, tested value mappings and a single schema owner.",
                "tradeoffs": "Both runtimes remain constrained by the shared schema; reversal does not recreate deleted business data."
              }
            ],
            "checks": [
              "Create and update a representative fixture through both allowed paths; compare IDs, nulls, timezone handling and unique/foreign-key failures.",
              "Apply the reviewed migration to a disposable restored copy and confirm both deployed versions still understand new writes."
            ],
            "rollback": "Recommendation: restore the old writer before contracting fields; preserve additive schema and reconcile writes accepted by Laravel.",
            "sources": [
              "https://laravel.com/docs/13.x/migrations"
            ],
            "id": "data-1"
          },
          {
            "capability": "jobs",
            "existing_contract": "Record connection, queue, PHP job class, serialized model identifiers/relationships, timeout, retry_after, failures and delayed/running work. Model arguments may be re-fetched when the worker executes.",
            "coexistence": "Recommendation: keep old consumers for old payloads; route new categories to isolated Laravel queues. Transfer producers and each schedule owner together. Account for ready, delayed, failed, retry and in-flight work before retiring the old backend.",
            "target": "ShouldQueue jobs on an intentionally selected database/Redis/SQS connection, with supervised workers and explicit attempts/timeouts. after_commit or afterCommit delays dispatch until commit; recommendation: use a durable outbox for a required recoverable commit-to-broker handoff.",
            "benefits": [
              {
                "benefit": "Recommendation: a job category can move without rebuilding the entire backlog.",
                "prerequisites": "Versioned payload fixtures, isolated queues and retained old consumers.",
                "tradeoffs": "Two queue systems may remain temporarily; serialized framework objects are not a portable cross-runtime API."
              }
            ],
            "checks": [
              "Enqueue a model, alter/delete it before execution and verify the intended rehydration/failure behavior.",
              "Roll back the domain transaction and verify after-commit dispatch produces no job; kill after an external effect and prove retry cannot duplicate the business effect.",
              "Set worker timeout below the applicable retry/visibility boundary and verify a long job cannot have two concurrent effects."
            ],
            "rollback": "Recommendation: stop the new producer, keep consumers for accepted payload versions and reconcile external effects before restoring old queue routing.",
            "sources": [
              "https://laravel.com/docs/13.x/queues"
            ],
            "id": "jobs-1"
          },
          {
            "capability": "identity",
            "existing_contract": "Capture guard/provider, account mapping, session driver, cookie/encryption configuration, remember-me behavior, expiry and logout. The current docs default to database sessions; the application may use another driver.",
            "coexistence": "Recommendation: retain a named identity authority or qualified session exchange; share cookies only after full-format fixtures pass. Map old per-resource permissions into every Livewire/server action and keep concurrent session semantics explicit.",
            "target": "Laravel authentication guard/provider plus a selected session store and resource authorization. Session blocking needs a supported atomic-lock cache driver and is unavailable with cookie sessions.",
            "benefits": [
              {
                "benefit": "Recommendation: explicit session/account ownership can preserve user continuity during feature migration.",
                "prerequisites": "Qualified identity/session mapping and common revocation rules.",
                "tradeoffs": "Lock-capable session coordination adds a store dependency; a shared database alone does not prove cookie compatibility."
              }
            ],
            "checks": [
              "Login through the old application, access the Laravel feature and revoke/logout; both paths must deny future operations.",
              "Run concurrent requests that modify one session and verify required data is not lost.",
              "Modify a Livewire public identifier to another tenant’s record and directly invoke the action; the server must reject it."
            ],
            "rollback": "Recommendation: retain old session/exchange support until the cohort can return, while preserving every revocation and account mapping.",
            "sources": [
              "https://laravel.com/docs/13.x/authentication",
              "https://laravel.com/docs/13.x/session",
              "https://livewire.laravel.com/docs/4.x/security"
            ],
            "id": "identity-1"
          },
          {
            "capability": "realtime",
            "existing_contract": "Capture client protocol, event name/payload, private/presence channel identity, authorization endpoint and queue connection. ShouldBroadcast dispatches broadcast work; event production and broadcast execution are separate concerns.",
            "coexistence": "Recommendation: retain the old endpoint for old clients and bridge versioned domain events to the selected Laravel broadcaster. Route a stable room/user cohort including reconnects; designate one publisher per committed domain change.",
            "target": "Laravel broadcasting with an explicitly chosen supported driver and client integration, plus working queue workers when required. Defer transactional events until commit with the documented mechanism; recommendation: persist domain state for reconnect recovery.",
            "benefits": [
              {
                "benefit": "Recommendation: backend events can update multiple authorized clients.",
                "prerequisites": "Configured broadcaster, workers and matching event/client contracts.",
                "tradeoffs": "Livewire alone does not remove those operational pieces; changing the broadcaster protocol may require a bridge or client rollout."
              }
            ],
            "checks": [
              "Put clients on separate server instances and verify one committed event reaches all authorized recipients.",
              "Rollback the domain write and confirm no premature broadcast occurs.",
              "Revoke private-channel access, disconnect/reconnect and verify unauthorized delivery fails and the UI catches up from source state."
            ],
            "rollback": "Recommendation: preserve old event names/endpoints and stop new publication before restoring the old publisher; reconcile already-visible state.",
            "sources": [
              "https://laravel.com/docs/13.x/broadcasting",
              "https://laravel.com/docs/13.x/queues"
            ],
            "id": "realtime-1"
          },
          {
            "capability": "cache",
            "existing_contract": "Inventory cached values, serialization, TTLs and invalidation separately from locks, unique jobs, scheduler coordination and sessions. Laravel supports several cache stores with different capabilities.",
            "coexistence": "Recommendation: version namespaces for changed representations and keep coordination on the same qualified central store. Move reconstructible values separately; never globally flush a shared backend during cutover.",
            "target": "Selected Laravel cache driver for disposable cached data; a supported central store for atomic locks across servers. Recommendation: use explicit dedicated stores/namespaces for distinct ownership boundaries.",
            "benefits": [
              {
                "benefit": "Recommendation: a cache backend can change independently of domain storage when contents are reconstructible.",
                "prerequisites": "Verified invalidation, serialization and coordination inventory.",
                "tradeoffs": "Lock owners and dependent scheduler/session features may still prevent retiring the old backend."
              }
            ],
            "checks": [
              "Warm both application versions, update authoritative data and verify both observe the required invalidation/TTL rule.",
              "Contend for a lock from two servers; only the intended owner may act.",
              "Clear only the migration’s disposable cache and verify other applications and coordination keys survive."
            ],
            "rollback": "Recommendation: restore previous cache routing and rebuild from domain data; preserve lock/session store ownership until a separate qualified transition.",
            "sources": [
              "https://laravel.com/docs/13.x/cache"
            ],
            "id": "cache-1"
          },
          {
            "capability": "operations",
            "existing_contract": "List scheduler definitions, timezones, overlapping task prevention, worker lifecycle and cache-backed coordination. Laravel schedules and old cron/Celery/Rails schedules may describe the same business action.",
            "coexistence": "Recommendation: give each scheduled action one logical owner. Transfer it at an explicit boundary; Laravel onOneServer coordinates Laravel instances using a shared supported store and does not retire an external scheduler.",
            "target": "A documented Laravel scheduler invocation and supervised queue workers. Use withoutOverlapping/onOneServer only with their selected store and intended lock scope; recommendation: document missed-run and business idempotency policies separately.",
            "benefits": [
              {
                "benefit": "Recommendation: explicit schedule and worker ownership can prevent accidental duplicate production during rollout.",
                "prerequisites": "Schedule inventory, shared supported locking when needed and a coordinated old-scheduler retirement.",
                "tradeoffs": "A lock prevents concurrent starts within its scope, not every replayed business effect; coexistence still needs two operational inventories."
              }
            ],
            "checks": [
              "Run the scheduled fixture across two Laravel servers and verify one enqueue, then confirm the old scheduler stays disabled for that category.",
              "Exercise timezone and long-running/overlap cases; restart the worker and scheduler and verify intended missed-run behavior."
            ],
            "rollback": "Recommendation: stop the Laravel schedule before restoring the old owner; reconcile accepted jobs and completed effects before replay.",
            "sources": [
              "https://laravel.com/docs/13.x/scheduling",
              "https://laravel.com/docs/13.x/queues"
            ],
            "id": "operations-1"
          }
        ],
        "sources": [
          {
            "url": "https://laravel.com/docs/13.x/migrations",
            "title": "Laravel 13 Database Migrations",
            "claim": "Schema migration and rollback commands."
          },
          {
            "url": "https://laravel.com/docs/13.x/queues",
            "title": "Laravel 13 Queues",
            "claim": "Connections versus queues, model serialization, after-commit dispatch, workers and timeout/retry_after interaction."
          },
          {
            "url": "https://laravel.com/docs/13.x/session",
            "title": "Laravel 13 HTTP Session",
            "claim": "Database session default, driver/table prerequisites and session-blocking requirements."
          },
          {
            "url": "https://laravel.com/docs/13.x/authentication",
            "title": "Laravel 13 Authentication",
            "claim": "Guard/provider architecture, sessions, logout and authentication configuration."
          },
          {
            "url": "https://laravel.com/docs/13.x/broadcasting",
            "title": "Laravel 13 Broadcasting",
            "claim": "Broadcast drivers, ShouldBroadcast/queue execution, private authorization and after-commit dispatch."
          },
          {
            "url": "https://laravel.com/docs/13.x/cache",
            "title": "Laravel 13 Cache",
            "claim": "Backend capabilities, atomic lock prerequisites and prefix-independent cache flush."
          },
          {
            "url": "https://laravel.com/docs/13.x/scheduling",
            "title": "Laravel 13 Scheduling",
            "claim": "Scheduler operation, timezones, overlap prevention and shared-store onOneServer locking."
          },
          {
            "url": "https://livewire.laravel.com/docs/4.x/components",
            "title": "Livewire 4 Components",
            "claim": "PHP/Blade components and make:livewire format options."
          },
          {
            "url": "https://livewire.laravel.com/docs/4.x/security",
            "title": "Livewire 4 Security",
            "claim": "Client-controlled properties/actions require validation and authorization."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": false,
        "static_hosting": false,
        "offline_client_candidate": false
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    },
    {
      "id": "python-django",
      "name": "Django product applications",
      "use_cases": [
        "CRUD-heavy SaaS",
        "Internal products and admin tools",
        "Server-rendered business applications"
      ],
      "choose_when": [
        "Accounts, forms, admin and database workflows are central",
        "A cohesive conventional monolith reduces integration decisions"
      ],
      "avoid_when": [
        "Only a small stateless endpoint is needed",
        "The core workload needs a different runtime or hard real-time guarantees"
      ],
      "tools": [
        {
          "job": "Packaging and environments",
          "default": "uv + pyproject.toml + committed uv.lock",
          "alternatives": [
            "Preserve an existing maintained packaging workflow"
          ],
          "reason": "One project entry point for dependencies, Python selection, execution and reproducible sync.",
          "limits": "Pin a compatible Python minor and resolve actual package versions at implementation; do not hand-edit uv.lock. Keep environments and caches in a local development workspace.",
          "source_urls": [
            "https://docs.astral.sh/uv/guides/projects/"
          ]
        },
        {
          "job": "Lint and format",
          "default": "Ruff",
          "alternatives": [
            "Preserve existing configured formatter/linter"
          ],
          "reason": "Fast lint and formatting feedback with one configuration.",
          "limits": "Ruff does not replace static typing, tests, authorization checks or runtime validation.",
          "source_urls": [
            "https://docs.astral.sh/ruff/installation/"
          ]
        },
        {
          "job": "Static typing",
          "default": "mypy + django-stubs plugin",
          "alternatives": [
            "ty for isolated plain-Python modules after validation"
          ],
          "reason": "Django-aware stubs and plugin improve checks around ORM and settings.",
          "limits": "Check the django-stubs compatibility table for the selected Django/Python/mypy combination; plugin imports application settings.",
          "source_urls": [
            "https://github.com/typeddjango/django-stubs",
            "https://mypy.readthedocs.io/en/stable/getting_started.html"
          ]
        },
        {
          "job": "Testing",
          "default": "pytest + pytest-django",
          "alternatives": [
            "Django built-in test runner"
          ],
          "reason": "Database fixtures and Django integration while retaining pytest conventions.",
          "limits": "Set DJANGO_SETTINGS_MODULE; use isolated PostgreSQL tests for constraints and transactions. Unit tests alone miss request and migration behavior.",
          "source_urls": [
            "https://docs.pytest.org/en/stable/getting-started.html",
            "https://pytest-django.readthedocs.io/en/latest/"
          ]
        },
        {
          "job": "Database and migrations",
          "default": "PostgreSQL + Django ORM/migrations + Psycopg",
          "alternatives": [
            "SQLite for low-concurrency local products"
          ],
          "reason": "Use the framework's existing data layer and schema history.",
          "limits": "Review schema/data migrations and query counts; run production-relevant DB tests. Do not introduce SQLAlchemy as a second default ORM.",
          "source_urls": [
            "https://docs.djangoproject.com/en/6.0/topics/migrations/"
          ]
        },
        {
          "job": "Validation",
          "default": "Django Forms/ModelForms plus domain checks and DB constraints",
          "alternatives": [
            "Pydantic at external JSON/tool boundaries"
          ],
          "reason": "Form lifecycle handles submitted values and field errors.",
          "limits": "Model saving is not a substitute for form/domain validation; enforce invariants at the appropriate transaction boundary.",
          "source_urls": [
            "https://docs.djangoproject.com/en/6.0/ref/forms/validation/",
            "https://pydantic.dev/docs/validation/latest/concepts/strict_mode/"
          ]
        },
        {
          "job": "Authentication",
          "default": "Django auth, sessions, permissions and CSRF protection",
          "alternatives": [
            "OIDC integration when an existing identity provider owns login"
          ],
          "reason": "Built-in accounts and session conventions fit browser products.",
          "limits": "Object/tenant permissions still need explicit implementation and tests; do not expose the admin as the product UI by default.",
          "source_urls": [
            "https://docs.djangoproject.com/en/6.0/topics/auth/",
            "https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/"
          ]
        },
        {
          "job": "Background jobs",
          "default": "Celery + a configured durable broker",
          "alternatives": [
            "Django Tasks plus a reviewed production backend",
            "Temporal for durable orchestration"
          ],
          "reason": "Documented Django integration for off-request work.",
          "limits": "Broker required; enqueue after commit, retry only safe effects. Django Tasks built-in backends do not supply production workers or durable queues. Celery is a separate integration, not automatically a django.tasks backend.",
          "source_urls": [
            "https://docs.celeryq.dev/en/stable/django/first-steps-with-django.html",
            "https://docs.celeryq.dev/en/stable/userguide/tasks.html",
            "https://docs.djangoproject.com/en/6.0/topics/tasks/"
          ]
        },
        {
          "job": "Long-running durable agents",
          "default": "Temporal Python SDK when recovery across restarts is required",
          "alternatives": [
            "Celery for independent queued jobs; direct function for bounded work"
          ],
          "reason": "Persisted workflow orchestration and separate worker processes suit retries, pauses and human waits.",
          "limits": "Adds a service and operational cost. Keep external I/O in activities, make side effects idempotent, test replay and cancellation; no end-to-end integration was run.",
          "source_urls": [
            "https://docs.temporal.io/develop/python",
            "https://docs.celeryq.dev/en/stable/userguide/tasks.html"
          ]
        },
        {
          "job": "Deployment",
          "default": "Container or managed Python service; WSGI for sync applications, ASGI when justified",
          "alternatives": [
            "Existing organization deployment platform"
          ],
          "reason": "Use the Django production deployment interface and checklist.",
          "limits": "Choose/pin a compatible application server at implementation; never deploy runserver. Configure secrets, HTTPS, static assets, health checks and backups.",
          "source_urls": [
            "https://docs.djangoproject.com/en/6.0/howto/deployment/",
            "https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/",
            "https://docs.astral.sh/uv/guides/integration/docker/"
          ]
        },
        {
          "job": "Application logging",
          "default": "Python logging with configured handlers",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Shared standard logging captures application and dependency diagnostics",
          "limits": "Configure logging at entry point, redact credentials and add request/job IDs, duration and failure context. Persist logs on the execution platform; metrics/tracing backend is a separate operational choice.",
          "source_urls": [
            "https://docs.python.org/3/library/logging.html"
          ]
        },
        {
          "job": "Bounded external-call retries",
          "default": "Tenacity only for retryable transient failures",
          "alternatives": [
            "Provider SDK retry policy when sufficient"
          ],
          "reason": "Explicit stop/wait/filter rules support controlled retries",
          "limits": "Install tenacity; set attempt/deadline limits, jitter and exception filters. The bare decorator retries forever without delay; do not stack retries with SDK/worker retries or repeat non-idempotent effects without keys.",
          "source_urls": [
            "https://tenacity.readthedocs.io/en/latest/"
          ]
        },
        {
          "job": "Transactional email",
          "default": "django.core.mail + selected SMTP backend",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Built-in mail wrappers and test backends fit account/product messages",
          "limits": "Configure TLS, sender and backend; test HTML/text content and enqueue required delivery. Delivery and bounce monitoring remain provider responsibilities.",
          "source_urls": [
            "https://docs.djangoproject.com/en/6.0/topics/email/"
          ]
        },
        {
          "job": "Uploads and file storage",
          "default": "Django FileField + configured storage backend",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Framework file APIs separate model metadata from storage",
          "limits": "Configure storage for the selected host; validate upload size/type and authorize serving. Local MEDIA_ROOT is unsuitable for unshared ephemeral replicas; choose an external backend when required.",
          "source_urls": [
            "https://docs.djangoproject.com/en/6.0/topics/files/"
          ]
        }
      ],
      "setup_steps": [
        "In a new local source directory in a local development workspace: uv init; choose and pin a supported Python minor, then uv add django 'psycopg[binary]'. Resolve compatible versions and commit uv.lock.",
        "uv add --dev ruff mypy django-stubs pytest pytest-django",
        "uv run django-admin startproject config . ; then uv run python manage.py startapp core",
        "Configure installed apps, PostgreSQL credentials from the environment, auth/session settings, pytest DJANGO_SETTINGS_MODULE and the django-stubs mypy plugin/settings module.",
        "Implement one authorized vertical slice; generate migrations with uv run python manage.py makemigrations, review them, then uv run python manage.py migrate against a disposable development DB.",
        "Add Celery only for actual queued work; configure broker, worker and after-commit enqueueing. Add Temporal only when durable multi-step recovery is required.",
        "Document application server, static asset collection, migration release ordering, worker start/restart and rollback. Run verification below before deployment."
      ],
      "verification_commands": [
        "uv sync --locked",
        "uv run ruff check .",
        "uv run ruff format --check .",
        "uv run mypy core config",
        "uv run pytest",
        "uv run python manage.py check",
        "uv run python manage.py makemigrations --check --dry-run",
        "uv run python manage.py migrate --check",
        "uv run python manage.py check --deploy --settings=config.production"
      ],
      "open_questions": [
        "Which supported Python/Django versions and third-party packages are required?",
        "Which host owns HTTPS, static/media serving and deployment settings?",
        "Which identity, email/storage, broker and job-delivery guarantees are required?"
      ],
      "evidence_status": "documentation-reviewed",
      "sources": [
        {
          "url": "https://docs.astral.sh/uv/guides/projects/",
          "title": "uv projects",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.astral.sh/ruff/installation/",
          "title": "Ruff installation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/typeddjango/django-stubs",
          "title": "django-stubs",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://mypy.readthedocs.io/en/stable/getting_started.html",
          "title": "mypy getting started",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.pytest.org/en/stable/getting-started.html",
          "title": "pytest getting started",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pytest-django.readthedocs.io/en/latest/",
          "title": "pytest-django",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.djangoproject.com/en/6.0/topics/migrations/",
          "title": "Django migrations",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.djangoproject.com/en/6.0/ref/forms/validation/",
          "title": "Django form validation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pydantic.dev/docs/validation/latest/concepts/strict_mode/",
          "title": "Pydantic strict mode",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.djangoproject.com/en/6.0/topics/auth/",
          "title": "Django authentication",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/",
          "title": "Django deployment checklist",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.celeryq.dev/en/stable/django/first-steps-with-django.html",
          "title": "Celery Django integration",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.celeryq.dev/en/stable/userguide/tasks.html",
          "title": "Celery tasks",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.djangoproject.com/en/6.0/topics/tasks/",
          "title": "Django Tasks",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.temporal.io/develop/python",
          "title": "Temporal Python SDK",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.djangoproject.com/en/6.0/howto/deployment/",
          "title": "Django deployment",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.astral.sh/uv/guides/integration/docker/",
          "title": "uv Docker",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.python.org/3/library/logging.html",
          "title": "Python logging",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://tenacity.readthedocs.io/en/latest/",
          "title": "Tenacity documentation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.djangoproject.com/en/6.0/topics/email/",
          "title": "Django sending email",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.djangoproject.com/en/6.0/topics/files/",
          "title": "Django files",
          "checked_date": "2026-10-10"
        }
      ],
      "title": "Django",
      "language": "Python",
      "group": "Web applications",
      "kind": [
        "web"
      ],
      "ui": "server",
      "host": "server",
      "summary": "Data-heavy products with an ORM, forms, accounts and admin.",
      "shape": "Django · PostgreSQL · uv · pytest",
      "tradeoff": "Interactive clients and long-running jobs require their own interface and worker choices.",
      "research_file": "python.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Keep Django's auth, session and CSRF protections. Enforce tenant and object permissions in application operations.",
        "Use forms, domain validation and database constraints together; do not rely on one validation layer.",
        "Commit and rehearse migrations against an isolated database; check deployment settings separately from unit tests.",
        "Choose WSGI or ASGI for the actual workload and operate background workers independently."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://docs.djangoproject.com/en/stable/intro/install/"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/python-django/",
      "markdown_url": "/stacks/python-django/guide.md",
      "json_url": "/stacks/python-django/record.json",
      "architecture_and_migration": {
        "id": "python-django",
        "version_scope": "Django 6.0 versioned docs; Celery 5.6.3 and Channels 4.3.2 current docs fetched 11 October 2026. The Django 6 Tasks API is version-specific and does not imply an existing Django 5.2 project should upgrade or abandon Celery. Pin actual Python/package versions before qualifying composition.",
        "operating_model": "Django organizes projects into applications, with conventional URL/view/model boundaries and integrated authentication. Recommendation: keep domain operations and permissions reusable across HTTP views, admin actions and workers. Optional Celery and Channels are separate execution/messaging systems rather than core Django features.",
        "architecture": [
          "Django defaults to database autocommit; transaction.atomic defines an explicit transaction boundary. Recommendation: keep transactions around the domain operation and do external delivery after commit through a recoverable design when required.",
          "Django 6 Tasks defines and enqueues tasks but supplies no worker mechanism. A production backend/worker must be evaluated; Celery remains a separate established candidate. Recommendation: do not equate an API-level task declaration with durable execution.",
          "Channels channel layers exchange high-level application events. channels_redis is the official production-supported layer; the in-memory layer cannot communicate across processes. Recommendation: persist business state separately from transient fanout."
        ],
        "developer_workflow": [
          "In a disposable target, django-admin startproject mysite creates the project and python manage.py startapp polls creates an application. Preserve the existing project/application structure when migrating a feature.",
          "Use python manage.py makemigrations to prepare reviewed migration files, python manage.py migrate to apply them and python manage.py showmigrations to inspect recorded state. Recommendation: nominate one deployment migration runner for shared tables.",
          "For a configured Celery application, adapt celery -A tasks worker --loglevel=INFO from the official first-steps recipe, replacing tasks with the actual application module. Broker and optional result backend are separate configuration choices.",
          "Before a production target, adapt python manage.py check --deploy to its production settings as the checklist instructs. Recommendation: exercise real database, session, task worker and Channels topology; the development runserver is not a production deployment."
        ],
        "avoid": [
          "Avoid deploying Django 6 ImmediateBackend/DummyBackend as a substitute for a durable production queue; the Tasks framework requires an external executing backend and documents built-in development/test backends.",
          "Avoid treating transaction.on_commit as durable cross-store delivery: callbacks run after commit and their failures cannot roll back the transaction. Recommendation: use an outbox when lost dispatch after commit is unacceptable.",
          "Avoid using LocMemCache or Channels in-memory layers as shared multi-process state; both are process-local. Avoid using cache-only session storage when eviction/restart logout violates the product contract.",
          "Avoid running two Celery beat schedulers for the same schedule; Celery documents duplicate task production. Recommendation: transfer ownership across frameworks as well as within Celery."
        ],
        "transitions": [
          {
            "capability": "data",
            "existing_contract": "Capture schema, account IDs, database constraints and model/write side effects. Migration history is framework-owned metadata and must be reconciled deliberately when an existing schema changes owner.",
            "coexistence": "Recommendation: retain one domain writer and schema runner; add compatible fields and move one application/domain boundary while old code still reads new records. Use historical models for Django data migrations as documented.",
            "target": "Django models/migrations with explicit transaction.atomic boundaries for related database writes. Recommendation: delay field deletion until the rollback reader retires.",
            "benefits": [
              {
                "benefit": "Recommendation: coherent model and migration ownership makes a domain boundary reviewable.",
                "prerequisites": "Tested schema mapping and explicit writer transfer.",
                "tradeoffs": "Database reversal may be irreversible for data operations; application objects/cache state also need reconciliation."
              }
            ],
            "checks": [
              "Create in each permitted writer and read in both runtimes; compare identifiers, null values, timestamps and constraint failures.",
              "Fail inside transaction.atomic and verify database writes roll back; inspect whether in-memory/cache state requires explicit restoration."
            ],
            "rollback": "Recommendation: restore the old writer while retaining additive fields; rehearse reverse migrations on a disposable copy and reconcile non-reversible data operations.",
            "sources": [
              "https://docs.djangoproject.com/en/6.0/topics/migrations/",
              "https://docs.djangoproject.com/en/6.0/topics/db/transactions/"
            ],
            "id": "data-1"
          },
          {
            "capability": "jobs",
            "existing_contract": "Inventory task names, argument serializer, broker/result backend, retry/acknowledgement policy, periodic schedule and ready/delayed/failed/running work. Django 6 Tasks and Celery payloads are distinct contracts.",
            "coexistence": "Recommendation: keep old consumers for old tasks; isolate new categories and route producers deliberately. Retain the existing scheduler until an explicit one-owner transfer. Qualify any Django Tasks backend separately from the task API.",
            "target": "Celery with a selected broker/optional result backend, or a qualified Django 6 executing backend. Schedule dispatch after database commit; recommendation: add recoverable outbox delivery when a crash can occur before broker acceptance.",
            "benefits": [
              {
                "benefit": "Recommendation: execution can migrate by task category while the old backlog remains executable.",
                "prerequisites": "Qualified payload fixtures, retained consumers and one schedule owner.",
                "tradeoffs": "Two task systems may be operated; a framework API switch does not translate backlog or broker guarantees."
              }
            ],
            "checks": [
              "Capture a task envelope and run it through its intended consumer, including argument conversion and missing-record behavior.",
              "Rollback the domain transaction and verify no dispatch; kill after an external effect and validate replay-safe completion.",
              "Account for delayed/retry/failed/in-flight tasks and confirm one periodic enqueue for each transferred schedule."
            ],
            "rollback": "Recommendation: pause new producers, retain consumers for accepted payloads and reconcile completed effects before switching categories back.",
            "sources": [
              "https://docs.djangoproject.com/en/6.0/topics/tasks/",
              "https://docs.djangoproject.com/en/6.0/topics/db/transactions/",
              "https://docs.celeryq.dev/en/stable/userguide/tasks.html",
              "https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html"
            ],
            "id": "jobs-1"
          },
          {
            "capability": "identity",
            "existing_contract": "Record authentication backend, user mapping, session engine/cookie name, serializer, expiry and revocation. Django database, cached_db, cache-only and signed-cookie sessions have different persistence/failure behavior.",
            "coexistence": "Recommendation: retain a shared identity authority or qualified exchange; do not treat Redis key sharing as session-format compatibility. Keep every resource permission enforced in the target view/operation.",
            "target": "Django authentication with a selected session backend. cached_db writes through to database/cache and reads the database on cache misses; recommendation: prefer it over cache-only sessions when eviction logout is unacceptable.",
            "benefits": [
              {
                "benefit": "Recommendation: a durable session authority can preserve access through cache eviction.",
                "prerequisites": "Configured database sessions, compatible account mapping and tested revocation.",
                "tradeoffs": "Write-through caching adds operations; cookie continuity across runtimes still requires a decoder/exchange or planned reauthentication."
              }
            ],
            "checks": [
              "Login in the old system, access the Django feature, then logout/expire/revoke and verify both deny unauthorized operations.",
              "Evict the selected session cache and confirm behavior matches the chosen engine; test another tenant’s identifier with a valid login."
            ],
            "rollback": "Recommendation: preserve previous identity/session contracts through the rollback window and retain revocation state during traffic reversal.",
            "sources": [
              "https://docs.djangoproject.com/en/6.0/topics/http/sessions/",
              "https://docs.djangoproject.com/en/6.0/topics/auth/default/"
            ],
            "id": "identity-1"
          },
          {
            "capability": "realtime",
            "existing_contract": "Capture WebSocket protocol, group/event names, authentication and required missed-event behavior. Channels channel layers carry application-level events, not a universal client protocol.",
            "coexistence": "Recommendation: keep old client endpoints, bridge versioned domain events and route room/user cohorts including reconnects. Designate one committed-change publisher; use the configured shared layer for multiple processes.",
            "target": "Channels with channels_redis when using the documented official production channel layer. Recommendation: reconstruct/replay from persistent domain state when missed broadcasts matter.",
            "benefits": [
              {
                "benefit": "Recommendation: a shared channel layer enables cross-process fanout.",
                "prerequisites": "Configured Redis layer, matching consumers/events and authorized subscriptions.",
                "tradeoffs": "Redis remains operated; transient fanout alone does not provide durable business-message recovery."
              }
            ],
            "checks": [
              "Connect subscribers to separate processes and verify one committed change reaches both authorized groups.",
              "Restart/disconnect during an event and verify reconnect obtains missing domain state; revoke access and confirm rejected subscriptions."
            ],
            "rollback": "Recommendation: retain the previous endpoint/event envelope and route cohorts back including their reconnects; avoid replaying already-applied effects.",
            "sources": [
              "https://channels.readthedocs.io/en/stable/topics/channel_layers.html"
            ],
            "id": "realtime-1"
          },
          {
            "capability": "cache",
            "existing_contract": "Inventory key versions/prefixes, serializers, TTLs and invalidation, separating disposable values from session/coordination ownership. Django local-memory cache is per-process even though it is thread-safe.",
            "coexistence": "Recommendation: use separate namespaces for changed representations and invalidate both old/new readers. Retain shared storage for cross-process requirements; move only reconstructible local data to LocMemCache.",
            "target": "A deliberately selected Django cache backend with configured timeout/key version. Recommendation: use local caches only where node/process staleness is accepted and rebuilding is safe.",
            "benefits": [
              {
                "benefit": "Recommendation: reconstructible caching can change independently of domain writes.",
                "prerequisites": "Defined staleness, invalidation and data ownership.",
                "tradeoffs": "Per-process caches duplicate state; sensitive filesystem cache locations/serialization require care as the docs explain."
              }
            ],
            "checks": [
              "Warm two processes, commit a source update and verify both readers meet the stated staleness policy.",
              "Restart or empty only the dedicated cache and verify reconstruction; session/permission correctness must remain intact."
            ],
            "rollback": "Recommendation: restore old namespace/backend routing and repopulate from authoritative data without treating cache contents as business records.",
            "sources": [
              "https://docs.djangoproject.com/en/6.0/topics/cache/",
              "https://docs.djangoproject.com/en/6.0/topics/db/transactions/"
            ],
            "id": "cache-1"
          },
          {
            "capability": "operations",
            "existing_contract": "List production application server, settings/secrets, migrations, static/media handling, Celery worker/beat and Channels processes. Celery requires only one scheduler for a schedule at a time.",
            "coexistence": "Recommendation: keep both process inventories and one named migration/schedule owner during coexistence. Define promotion thresholds for outcomes, queue age and denied access rather than promoting from a clean startup alone.",
            "target": "An explicitly configured deployment following Django’s checklist, plus independently supervised selected workers and scheduler. Recommendation: document restored database/session/queue consistency.",
            "benefits": [
              {
                "benefit": "Recommendation: production checks and role ownership make recovery responsibilities visible.",
                "prerequisites": "Actual production settings and a rehearsed restore/restart.",
                "tradeoffs": "check --deploy detects configuration issues, not end-to-end job, permission or restore correctness."
              }
            ],
            "checks": [
              "Run the deployment checks against intended settings and exercise an authorized/denied request after a disposable restore.",
              "Stop a worker and verify queued work is visible; restart it, then verify one scheduler and intended recovery behavior."
            ],
            "rollback": "Recommendation: restore old routing/settings and schedule ownership explicitly; preserve accepted tasks and reconcile effects before replay.",
            "sources": [
              "https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/",
              "https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html"
            ],
            "id": "operations-1"
          }
        ],
        "sources": [
          {
            "url": "https://docs.djangoproject.com/en/6.0/intro/tutorial01/",
            "title": "Django first application",
            "claim": "Project/application generator commands and development server boundary."
          },
          {
            "url": "https://docs.djangoproject.com/en/6.0/topics/migrations/",
            "title": "Django Migrations",
            "claim": "Migration commands, history, data migrations and reversibility."
          },
          {
            "url": "https://docs.djangoproject.com/en/6.0/topics/db/transactions/",
            "title": "Django Transactions",
            "claim": "Autocommit, atomic, on_commit timing/failure and application-state rollback limitations."
          },
          {
            "url": "https://docs.djangoproject.com/en/6.0/topics/tasks/",
            "title": "Django 6 Tasks",
            "claim": "Task API, no built-in worker, backend requirements, argument conversion and commit timing."
          },
          {
            "url": "https://docs.djangoproject.com/en/6.0/topics/http/sessions/",
            "title": "Django Sessions",
            "claim": "Database/cache/cached_db/cookie choices, persistence, eviction and serialization."
          },
          {
            "url": "https://docs.djangoproject.com/en/6.0/topics/auth/default/",
            "title": "Django Authentication",
            "claim": "Authentication, login/logout and permissions."
          },
          {
            "url": "https://docs.djangoproject.com/en/6.0/topics/cache/",
            "title": "Django Cache",
            "claim": "Backend setup, key versions, per-process local memory and filesystem security concerns."
          },
          {
            "url": "https://channels.readthedocs.io/en/stable/topics/channel_layers.html",
            "title": "Channels Channel Layers",
            "claim": "Official production channels_redis and lack of cross-process delivery in memory."
          },
          {
            "url": "https://docs.celeryq.dev/en/stable/userguide/tasks.html",
            "title": "Celery Tasks",
            "claim": "Task naming/serialization, retries, acknowledgement and idempotency concerns."
          },
          {
            "url": "https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html",
            "title": "Celery Periodic Tasks",
            "claim": "Single scheduler ownership, schedule timezone and overlap concerns."
          },
          {
            "url": "https://docs.celeryq.dev/en/stable/getting-started/first-steps-with-celery.html",
            "title": "Celery First Steps",
            "claim": "Worker command and distinction between broker and result backend."
          },
          {
            "url": "https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/",
            "title": "Django Deployment Checklist",
            "claim": "Production settings, check --deploy and deployment responsibilities."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": false,
        "static_hosting": false,
        "offline_client_candidate": false
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    },
    {
      "id": "go-service",
      "name": "Go service: net/http + PostgreSQL + sqlc + River",
      "use_cases": [
        "APIs",
        "control planes",
        "concurrent network services",
        "background workers"
      ],
      "choose_when": [
        "Prefer explicit service code and standard tooling",
        "Kubernetes or Go infrastructure integration matters",
        "PostgreSQL already owns business state"
      ],
      "avoid_when": [
        "Need a batteries-included product framework",
        "Hard real-time or no-GC constraints",
        "Rich client UI is the primary product"
      ],
      "tools": [
        {
          "job": "HTTP server",
          "default": "net/http",
          "alternatives": [
            "Existing project router when justified"
          ],
          "reason": "Standard handlers and request contexts minimize routing infrastructure.",
          "limits": "Set request/body limits, deadlines and graceful shutdown; middleware and authorization remain application work.",
          "source_urls": [
            "https://pkg.go.dev/net/http"
          ]
        },
        {
          "job": "Optional server-rendered UI",
          "default": "templ + HTMX",
          "alternatives": [
            "No UI for API-only services"
          ],
          "reason": "Compiled components and HTML-fragment updates suit forms and dashboards.",
          "limits": "Generation adds a build step; advanced client state still needs browser-side design and testing.",
          "source_urls": [
            "https://templ.guide/",
            "https://htmx.org/docs/"
          ]
        },
        {
          "job": "Database and migrations",
          "default": "PostgreSQL + pgx + sqlc + goose",
          "alternatives": [
            "pgx without sqlc for small query sets",
            "golang-migrate when already established"
          ],
          "reason": "Visible SQL, generated typed access and one migration owner.",
          "limits": "Generators do not prove query efficiency; review transaction boundaries, pool budgets and online migration behavior. Never mix migration owners.",
          "source_urls": [
            "https://github.com/jackc/pgx",
            "https://docs.sqlc.dev/en/latest/",
            "https://github.com/pressly/goose",
            "https://github.com/golang-migrate/migrate"
          ]
        },
        {
          "job": "Configuration",
          "default": "Typed settings loaded with os.LookupEnv",
          "alternatives": [
            "flag for small command surfaces"
          ],
          "reason": "Explicit startup validation and standard structured logs.",
          "limits": "Define precedence; reject malformed required values; redact secrets. Environment access alone is not validation or secret management.",
          "source_urls": [
            "https://pkg.go.dev/os",
            "https://pkg.go.dev/flag",
            "https://pkg.go.dev/log/slog"
          ]
        },
        {
          "job": "Application logging",
          "default": "log/slog",
          "alternatives": [],
          "reason": "Explicit startup validation and standard structured logs.",
          "limits": "Define precedence; reject malformed required values; redact secrets. Environment access alone is not validation or secret management.",
          "source_urls": [
            "https://pkg.go.dev/os",
            "https://pkg.go.dev/flag",
            "https://pkg.go.dev/log/slog"
          ]
        },
        {
          "job": "Tests and static checks",
          "default": "testing; go vet; race detector; govulncheck",
          "alternatives": [],
          "reason": "Standard toolchain feedback plus exercised concurrency and known-vulnerability checks.",
          "limits": "Race detector requires supported target/toolchain and exercised code; no scanner proves absence of vulnerabilities.",
          "source_urls": [
            "https://pkg.go.dev/testing",
            "https://go.dev/doc/articles/race_detector",
            "https://golangci-lint.run/docs/welcome/quick-start/",
            "https://go.dev/doc/security/vuln/"
          ]
        },
        {
          "job": "HTTP and database integration tests",
          "default": "httptest + real disposable PostgreSQL",
          "alternatives": [
            "In-process handler tests for pure routing"
          ],
          "reason": "Exercise protocols and actual SQL/migrations.",
          "limits": "Database tests need an isolated database; mocks cannot establish PostgreSQL semantics.",
          "source_urls": [
            "https://pkg.go.dev/net/http/httptest",
            "https://github.com/jackc/pgx"
          ]
        },
        {
          "job": "Durable work",
          "default": "River for PostgreSQL-backed jobs",
          "alternatives": [
            "Temporal Go SDK for workflow requirements needing its service"
          ],
          "reason": "Transactional enqueueing ties work to committed business data.",
          "limits": "External effects need idempotency. Default resumable checkpoints may be lost on crash; use transactional checkpoints where required. Inspect Pro feature boundaries.",
          "source_urls": [
            "https://riverqueue.com/docs/transactional-enqueueing",
            "https://riverqueue.com/docs/resumable-jobs",
            "https://docs.temporal.io/develop/go"
          ]
        },
        {
          "job": "Deployment and distribution",
          "default": "Go build binary in a supervised process or container; GoReleaser for releases",
          "alternatives": [],
          "reason": "Small explicit runtime boundary; release automation builds target artifacts.",
          "limits": "Target OS/architecture, libc/cgo, CA certificates, timezone data and signing need explicit verification. Snapshot builds are not publication.",
          "source_urls": [
            "https://goreleaser.com/getting-started/quick-start/"
          ]
        },
        {
          "job": "Browser identity",
          "default": "go-oidc + existing OIDC provider",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Provider discovery and ID-token verification support owned login sessions",
          "limits": "Use v3 module; configure issuer/client, OAuth callback state and session lifecycle. go-oidc verifies ID tokens; API access-token validation follows the provider contract. Authorization stays near data.",
          "source_urls": [
            "https://github.com/coreos/go-oidc"
          ]
        },
        {
          "job": "Transactional email",
          "default": "go-mail + project-selected SMTP provider",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Typed mail construction and SMTP transport support application messages",
          "limits": "Configure TLS, sender credentials and timeouts; send required mail through durable jobs with duplicate protection. Validate chosen async/runtime features in Rust; delivery receipts and bounces need provider handling.",
          "source_urls": [
            "https://pkg.go.dev/github.com/wneessen/go-mail"
          ]
        },
        {
          "job": "Uploads and object storage",
          "default": "AWS SDK for Go S3 client",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Durable object storage avoids dependence on service-local disk",
          "limits": "Configure runtime credentials, region and least-privilege bucket access; authorize object keys and uploads, bound size/concurrency and define retention. Test multipart cleanup and selected provider compatibility.",
          "source_urls": [
            "https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/go_s3_code_examples.html"
          ]
        },
        {
          "job": "Realtime transport",
          "default": "coder/websocket",
          "alternatives": [
            "Server-sent events for one-way feeds",
            "Polling for infrequent updates"
          ],
          "reason": "WebSocket support fits bidirectional connected clients",
          "limits": "Enable the documented module/feature; authorize handshake and every protected message, bound queues/message size and implement heartbeat/shutdown. Socket delivery is not durable history; define reconnect/resync.",
          "source_urls": [
            "https://pkg.go.dev/github.com/coder/websocket"
          ]
        }
      ],
      "setup_steps": [
        "Start in a new source checkout in a local development workspace; run go mod init example.com/project using the real module path.",
        "Resolve and record Go/tool versions and dependencies; go get github.com/jackc/pgx/v5; add River only if jobs are needed.",
        "Create cmd/server plus application packages, typed settings, explicit http.Server limits, health/readiness and shutdown handling.",
        "Install selected sqlc and goose releases; write migrations and sqlc configuration; run sqlc generate. Configure a disposable PostgreSQL database through environment/secrets.",
        "With GOOSE_DRIVER=postgres and GOOSE_DBSTRING targeting only the disposable database, run goose -dir migrations up. Add business transaction and River enqueue tests.",
        "Add the chosen release configuration, pin tools and preserve go.mod/go.sum; document build and rollback. These steps have not been run."
      ],
      "verification_commands": [
        "gofmt -l .",
        "go test ./...",
        "go test -race ./...",
        "go vet ./...",
        "govulncheck ./...",
        "sqlc generate",
        "goose -dir migrations status",
        "go build ./cmd/server"
      ],
      "evidence_status": "documentation-reviewed",
      "sources": [
        {
          "url": "https://pkg.go.dev/net/http",
          "title": "Go net/http",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://templ.guide/",
          "title": "templ",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://htmx.org/docs/",
          "title": "HTMX",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/jackc/pgx",
          "title": "pgx PostgreSQL driver",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.sqlc.dev/en/latest/",
          "title": "sqlc documentation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/pressly/goose",
          "title": "goose migrations",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/golang-migrate/migrate",
          "title": "golang-migrate",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/os",
          "title": "Go os configuration primitives",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/flag",
          "title": "Go flag",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/log/slog",
          "title": "Go structured logging",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/testing",
          "title": "Go testing",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://go.dev/doc/articles/race_detector",
          "title": "Go data race detector",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://golangci-lint.run/docs/welcome/quick-start/",
          "title": "golangci-lint quick start",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://go.dev/doc/security/vuln/",
          "title": "Go vulnerability management",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/net/http/httptest",
          "title": "Go HTTP testing",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://riverqueue.com/docs/transactional-enqueueing",
          "title": "River transactional enqueueing",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://riverqueue.com/docs/resumable-jobs",
          "title": "River resumable jobs",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.temporal.io/develop/go",
          "title": "Temporal Go SDK",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://goreleaser.com/getting-started/quick-start/",
          "title": "GoReleaser quick start",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/coreos/go-oidc",
          "title": "go-oidc repository",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/github.com/wneessen/go-mail",
          "title": "go-mail documentation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/go_s3_code_examples.html",
          "title": "AWS Go S3 examples",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/github.com/coder/websocket",
          "title": "coder/websocket documentation",
          "checked_date": "2026-10-10"
        }
      ],
      "open_questions": [
        "Which API contracts, browser login or service-token requirements apply?",
        "Does realtime need one-way updates or bidirectional sockets?",
        "Which database pool, worker throughput, storage and deployment/restore budgets apply?"
      ],
      "title": "Go service",
      "language": "Go",
      "group": "APIs & services",
      "kind": [
        "api"
      ],
      "ui": "none",
      "host": "binary",
      "summary": "HTTP APIs and backend services with a straightforward binary deployment.",
      "shape": "net/http · pgx · sqlc · PostgreSQL",
      "tradeoff": "Product features such as authorization and administration need explicit assembly.",
      "research_file": "go-rust.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Propagate contexts and set timeouts on external requests. Bound concurrency and handle shutdown.",
        "Keep SQL and migrations reviewed and generated query code synchronized with the schema.",
        "Test handlers with httptest and persistence against a disposable real PostgreSQL instance.",
        "Use River only when durable jobs are required; test retry-safe effects and worker shutdown."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://go.dev/doc/tutorial/create-module",
          "https://pkg.go.dev/net/http"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/go-service/",
      "markdown_url": "/stacks/go-service/guide.md",
      "json_url": "/stacks/go-service/record.json",
      "architecture_and_migration": {
        "id": "go-service",
        "version_scope": "Go 1.27 release documentation and current net/http/context APIs; sqlc latest transaction guide with pgx/v5; River current documentation, PostgreSQL composition. Resolve and record Go toolchain, sqlc, pgx and River versions in go.mod/go.sum and tool configuration before implementation. Official release notes identify Go 1.27 as the August 2026 release; this research does not qualify a lockfile or patch-version/security support.",
        "operating_model": "Recommendation: a Go HTTP process owns request admission and cancellation, domain packages own invariants, and a bounded SQL connection pool provides parallel database access. Durable jobs have their own persisted queue and worker lifecycle. Goroutines and buffered channels are concurrency mechanisms; graceful drain does not turn them into a recoverable queue.",
        "architecture": [
          "Recommendation: compose net/http handlers around small domain packages and explicit interfaces at external boundaries. Pass request contexts into SQL and outbound calls. Use bounded errgroup fan-out or a worker pool, with an overload policy separate from concurrency limits.",
          "Recommendation: maintain reviewed SQL migrations and sqlc-generated queries; share a pool, acquire transactions only around domain writes, and call generated WithTx for the transaction. A single global mutex around all queries recreates avoidable serialization.",
          "Recommendation: PostgreSQL-backed River workers can run with the web binary initially or in an independent process when their scaling or shutdown needs differ. Insert business state and a job in the same database transaction when atomic enqueue is required; cross-database work needs a separately designed outbox.",
          "Recommendation: retain an established identity provider, object store, email sender and broker during a service rewrite. Request/response, cookies, WebSocket application protocol, job payload and retry semantics are separate compatibility contracts."
        ],
        "developer_workflow": [
          "Recommendation: start from the existing repository; inspect go.mod, go.sum, schema migrations and queue configuration. For a new local source project, go mod init example.com/service creates a module; choose the actual module path and supported toolchain deliberately.",
          "Recommendation: pin sqlc using the maintained tool installer, review sqlc.yaml and SQL source, then run sqlc generate after query/schema changes. Regenerate in CI and compare output; generated typing does not validate production schema drift.",
          "Recommendation: run gofmt on changed files, go vet ./..., go test ./... and go test -race ./... on a supported target. Add HTTP contract fixtures and cancellation/queue crash tests against the selected database; these are proposed checks, not executed here.",
          "Recommendation: build the service with go build ./cmd/server when that entry point exists. Set server/header/body deadlines, worker limits, pool capacity and shutdown budget from the deployment shape. Profile a representative workload with Go pprof; performance and cost remain unmeasured."
        ],
        "avoid": [
          "Avoid one fire-and-forget goroutine per email/payment: an acknowledged request can survive while its side effect disappears on process crash.",
          "Avoid spawning unlimited goroutines to hide slow SQL. The downstream pool becomes the queue; cancellation, memory and overload must be bounded explicitly.",
          "Avoid replacing Redis solely because Go has channels. Shared fan-out, sessions, queue persistence and locks have different semantics.",
          "Avoid treating Server.Shutdown as complete WebSocket shutdown; hijacked connections need separate notification and tracking."
        ],
        "transitions": [
          {
            "capability": "data",
            "existing_contract": "Inventory the old schema, isolation, identifiers, null handling, timestamps and transaction invariants before changing language or driver.",
            "coexistence": "Recommendation: let the old application own migrations while Go accesses backward-compatible columns through sqlc; route writes for one domain/cohort to one owner. Expand schema before either runtime needs it.",
            "target": "Recommendation: sqlc plus pgx/v5 or database/sql, a shared bounded pool and explicit transaction-scoped queries. Keep the existing database if its guarantees fit; PostgreSQL replacement is a separate migration.",
            "benefits": [
              {
                "benefit": "Typed query access and concurrent pool usage can improve maintainability and remove an unnecessary application-wide lock.",
                "prerequisites": "Queries generated from the reviewed schema; representative null/time/transaction fixtures; a pool sized across all replicas.",
                "tradeoffs": "Generated types do not prove isolation or business correctness; pool exhaustion and migrations still need operations."
              }
            ],
            "checks": [
              "Verify old-write/new-read and new-write/old-read round trips, including nulls and time zones.",
              "Force a mid-transaction failure; neither half of the domain change may commit.",
              "Saturate the pool and cancel a request; verify bounded waiting and connection release."
            ],
            "rollback": "Recommendation: return domain traffic to the old writer while preserving expanded columns. Contract migrations wait until the rollback window closes; reconcile any new-only writes first.",
            "sources": [
              "https://docs.sqlc.dev/en/latest/howto/transactions.html",
              "https://go.dev/doc/database/manage-connections"
            ],
            "id": "data-1"
          },
          {
            "capability": "jobs",
            "existing_contract": "Capture existing queue kind, JSON arguments, retry/schedule/dead-letter states and external-effect idempotency. Redis/Resque or Sidekiq payloads are not River payloads.",
            "coexistence": "Recommendation: keep old workers consuming old queues. Route selected job kinds into River through versioned producers; transform outstanding states explicitly and retain one scheduler. River Ruby integration is a possible bridge, not automatic Active Job execution.",
            "target": "Recommendation: River PostgreSQL jobs with domain writes plus InsertTx in the same transaction, explicit queue concurrency and bounded retry policy. Keep Redis for any remaining broker/session/cache responsibility.",
            "benefits": [
              {
                "benefit": "Atomic enqueue closes the gap between committing domain state and creating work.",
                "prerequisites": "Domain rows and River insertion use the same transaction/database; validated job-kind/argument mapping; replay-safe external effects.",
                "tradeoffs": "Adds queue schema/maintenance to the database; retries can repeat effects; backlog migration and adapter compatibility are separate work."
              }
            ],
            "checks": [
              "Abort the domain transaction; no job may become available.",
              "Crash after sending an email but before job completion; retry must reconcile or reuse a stable external idempotency key.",
              "Account for ready, scheduled, retry, failed and in-flight jobs before retiring the old consumer."
            ],
            "rollback": "Recommendation: stop new River producers and reroute only unstarted work after reconciliation. Keep a compatible River consumer for already accepted jobs; a broker switch cannot undo sent messages or payments.",
            "sources": [
              "https://riverqueue.com/docs/transactional-enqueueing",
              "https://riverqueue.com/docs/job-retries",
              "https://riverqueue.com/docs/ruby"
            ],
            "id": "jobs-1"
          },
          {
            "capability": "operations",
            "existing_contract": "Preserve response/error behavior, overload rules, deadlines and restart guarantees; establish separate budgets for HTTP and background jobs.",
            "coexistence": "Recommendation: serve a fixed tenant/endpoint cohort from Go behind existing routing, with errgroup/context cancellation inside each operation and deployment-level readiness. Keep the old instance ready for contract-compatible rollback.",
            "target": "Recommendation: signal.NotifyContext, bounded admission/fan-out, Server.Shutdown with a fresh timeout context, tracked worker termination and pool closure after accepted work ends.",
            "benefits": [
              {
                "benefit": "Cooperative cancellation limits work that callers no longer need and makes planned shutdown observable.",
                "prerequisites": "Every called operation honors context; in-flight tasks are tracked; the platform shutdown grace period exceeds the configured drain budget.",
                "tradeoffs": "Cancellation does not reverse a committed write or external effect; forced termination still loses memory-only work."
              }
            ],
            "checks": [
              "Cancel a client while SQL/outbound I/O is blocked; verify resources and goroutines settle.",
              "Send SIGTERM during a write; the server stops admitting traffic and records whether accepted work committed.",
              "Force SIGKILL; verify durable jobs recover independently of graceful drain."
            ],
            "rollback": "Recommendation: return routing to the old process and inspect committed outcomes and queued work before any replay. Preserve identical database/schema contracts for both versions.",
            "sources": [
              "https://pkg.go.dev/net/http#Server.Shutdown",
              "https://pkg.go.dev/golang.org/x/sync/errgroup",
              "https://pkg.go.dev/os/signal#NotifyContext"
            ],
            "id": "operations-1"
          },
          {
            "capability": "realtime",
            "existing_contract": "Preserve authentication, subscription identifiers, frame formats, ordering, reconnect cursors and cross-runtime fan-out. A WebSocket transport does not implement Action Cable automatically.",
            "coexistence": "Recommendation: keep the existing broker and explicit application-protocol adapter while moving complete room/tenant cohorts, including reconnects, to Go. Publish/subscribe in both directions using captured protocol fixtures.",
            "target": "Recommendation: coder/websocket for transport plus bounded per-connection queues, tracked close handshakes and an application resynchronization path. Retain Redis Pub/Sub if ephemeral cross-process fan-out fits; add durable history separately where missed events matter.",
            "benefits": [
              {
                "benefit": "Explicit connection ownership and queue limits bound slow-client resource use.",
                "prerequisites": "Capacity and disconnect policy are defined; clients can reconnect and reconstruct authoritative state; broker/protocol compatibility is tested.",
                "tradeoffs": "Redis Pub/Sub is at-most-once and does not replay disconnected messages; replacing it with process-local channels removes cross-instance delivery."
              }
            ],
            "checks": [
              "Connect an old and new client to the same room; verify broadcasts in both directions and revocation.",
              "Disconnect a subscriber and publish; reconnect must fetch missed authoritative state.",
              "Throttle one client; verify the configured queue overflow policy and independent delivery to others."
            ],
            "rollback": "Recommendation: route the cohort and reconnects back together. Keep the broker and old protocol alive; rebuild client state from durable records rather than pretending ephemeral events can be replayed.",
            "sources": [
              "https://github.com/coder/websocket",
              "https://redis.io/docs/latest/develop/pubsub/",
              "https://pkg.go.dev/net/http#Server.Shutdown"
            ],
            "id": "realtime-1"
          }
        ],
        "sources": [
          {
            "url": "https://go.dev/doc/go1.27",
            "title": "Go 1.27 release notes",
            "claim": "Identifies the August 2026 release; runtime/tool behavior and JSON v2 are documented with compatibility caveats."
          },
          {
            "url": "https://go.dev/doc/modules/managing-dependencies",
            "title": "Managing Go dependencies",
            "claim": "go.mod and go.sum own module dependency versions."
          },
          {
            "url": "https://docs.sqlc.dev/en/latest/howto/transactions.html",
            "title": "sqlc transactions",
            "claim": "Generated WithTx binds queries to a transaction; pgx/v5 example is documented."
          },
          {
            "url": "https://go.dev/doc/database/manage-connections",
            "title": "Go SQL connection management",
            "claim": "sql.DB is a concurrent pool; limits can cause waits and deadlocks."
          },
          {
            "url": "https://riverqueue.com/docs/transactional-enqueueing",
            "title": "River transactional enqueue",
            "claim": "Enqueue with domain changes in one transaction avoids a two-store commit gap."
          },
          {
            "url": "https://riverqueue.com/docs/job-retries",
            "title": "River retries",
            "claim": "Retry attempts and delays are configurable; errors lead to repeated execution."
          },
          {
            "url": "https://riverqueue.com/docs/ruby",
            "title": "River Ruby integration",
            "claim": "Current documentation describes a shared River schema and explicit job kinds/JSON arguments."
          },
          {
            "url": "https://pkg.go.dev/net/http#Server.Shutdown",
            "title": "net/http server shutdown",
            "claim": "HTTP drain does not close or await hijacked WebSocket connections."
          },
          {
            "url": "https://pkg.go.dev/golang.org/x/sync/errgroup",
            "title": "errgroup",
            "claim": "WithContext cancellation and SetLimit support bounded concurrent work."
          },
          {
            "url": "https://pkg.go.dev/os/signal#NotifyContext",
            "title": "os/signal",
            "claim": "NotifyContext connects OS signals to context cancellation."
          },
          {
            "url": "https://github.com/coder/websocket",
            "title": "coder/websocket README",
            "claim": "Go WebSocket transport supports contexts and close handshakes; application protocol is separate."
          },
          {
            "url": "https://redis.io/docs/latest/develop/pubsub/",
            "title": "Redis Pub/Sub",
            "claim": "Pub/Sub delivery is at-most-once; disconnected subscribers miss events."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": false,
        "static_hosting": false,
        "offline_client_candidate": false
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    },
    {
      "id": "rust-service",
      "name": "Rust service: Axum + Tokio + PostgreSQL + SQLx",
      "use_cases": [
        "Native network services",
        "resource-sensitive APIs",
        "services sharing a Rust core"
      ],
      "choose_when": [
        "Memory/resource control or Rust library reuse is important",
        "Team accepts ownership/async complexity for compile-time guarantees"
      ],
      "avoid_when": [
        "Primary goal is conventional CRUD delivery with minimal framework assembly",
        "Team cannot maintain Rust async code",
        "A full product framework is needed immediately"
      ],
      "tools": [
        {
          "job": "HTTP server",
          "default": "Axum + Tokio + tower-http",
          "alternatives": [
            "Direct Hyper only for transport-specific needs"
          ],
          "reason": "Typed extractors/state and Tower middleware compose with Tokio networking.",
          "limits": "Configure limits, timeout/error mapping and graceful shutdown. Blocking work must not monopolize async workers.",
          "source_urls": [
            "https://docs.rs/axum/latest/axum/",
            "https://tokio.rs/"
          ]
        },
        {
          "job": "Database and migrations",
          "default": "PostgreSQL + SQLx; sqlx-cli migrations",
          "alternatives": [],
          "reason": "SQL-oriented async access with optional checked query macros and migration tooling.",
          "limits": "Select runtime/TLS/database features for the resolved release. Checked macros need a database or maintained offline metadata; runtime queries are not compile-time checked.",
          "source_urls": [
            "https://docs.rs/sqlx/latest/sqlx/",
            "https://github.com/transact-rs/sqlx/blob/main/sqlx-cli/README.md"
          ]
        },
        {
          "job": "Configuration",
          "default": "Serde-backed settings + config",
          "alternatives": [
            "std::env for a small fixed settings set"
          ],
          "reason": "Typed settings plus structured events/spans.",
          "limits": "Set precedence explicitly; validate semantics; install a tracing subscriber; never log secrets.",
          "source_urls": [
            "https://docs.rs/config/latest/config/",
            "https://doc.rust-lang.org/std/env/fn.var.html",
            "https://docs.rs/tracing/latest/tracing/"
          ]
        },
        {
          "job": "Application logging",
          "default": "tracing + configured subscriber",
          "alternatives": [],
          "reason": "Typed settings plus structured events/spans.",
          "limits": "Set precedence explicitly; validate semantics; install a tracing subscriber; never log secrets.",
          "source_urls": [
            "https://docs.rs/config/latest/config/",
            "https://doc.rust-lang.org/std/env/fn.var.html",
            "https://docs.rs/tracing/latest/tracing/"
          ]
        },
        {
          "job": "Tests and static checks",
          "default": "cargo test; rustfmt; Clippy; cargo audit",
          "alternatives": [],
          "reason": "Compiler, style, behavior and known-advisory checks complement each other.",
          "limits": "Audit coverage is advisory-driven; compile success does not establish behavior or security. Test supported feature combinations rather than blindly enabling incompatible features.",
          "source_urls": [
            "https://doc.rust-lang.org/cargo/commands/cargo-test.html",
            "https://github.com/rust-lang/rustfmt",
            "https://doc.rust-lang.org/clippy/usage.html",
            "https://rustsec.org/",
            "https://docs.rs/assert_cmd/latest/assert_cmd/"
          ]
        },
        {
          "job": "Durable work",
          "default": "None for request-only service; Restate Rust SDK when durable workflows are required",
          "alternatives": [],
          "reason": "Durable handlers and persisted workflow progress address work outliving a process.",
          "limits": "Requires a Restate service and adoption test. Journal external operations correctly; idempotency and business transactions remain explicit. Tokio tasks alone are not durable.",
          "source_urls": [
            "https://docs.rs/restate-sdk/latest/restate_sdk/"
          ]
        },
        {
          "job": "Deployment",
          "default": "cargo build --release --locked in a target-specific build pipeline",
          "alternatives": [
            "Container with explicit runtime libraries"
          ],
          "reason": "Reproducible dependency resolution from committed lockfile; native executable artifact.",
          "limits": "Not universally static: verify libc, TLS/native libraries, target support, certificates and container runtime needs.",
          "source_urls": [
            "https://doc.rust-lang.org/cargo/commands/cargo-build.html"
          ]
        },
        {
          "job": "API token verification",
          "default": "jsonwebtoken + selected identity provider contract",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Typed claims and signature checks fit JWT-bearing service APIs",
          "limits": "Configure accepted algorithms, issuer/audience, expiry and trusted key rotation; select required crypto features for resolved release. This is a verifier, not an OIDC login/session solution; opaque tokens need provider introspection.",
          "source_urls": [
            "https://docs.rs/jsonwebtoken/latest/jsonwebtoken/"
          ]
        },
        {
          "job": "Transactional email",
          "default": "lettre + project-selected SMTP provider",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Typed mail construction and SMTP transport support application messages",
          "limits": "Configure TLS, sender credentials and timeouts; send required mail through durable jobs with duplicate protection. Validate chosen async/runtime features in Rust; delivery receipts and bounces need provider handling.",
          "source_urls": [
            "https://docs.rs/lettre/latest/lettre/"
          ]
        },
        {
          "job": "Uploads and object storage",
          "default": "AWS SDK for Rust S3 client",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Durable object storage avoids dependence on service-local disk",
          "limits": "Configure runtime credentials, region and least-privilege bucket access; authorize object keys and uploads, bound size/concurrency and define retention. Test multipart cleanup and selected provider compatibility.",
          "source_urls": [
            "https://docs.aws.amazon.com/sdk-for-rust/latest/dg/rust_s3_code_examples.html"
          ]
        },
        {
          "job": "Realtime transport",
          "default": "Axum WebSocket extractor",
          "alternatives": [
            "Server-sent events for one-way feeds",
            "Polling for infrequent updates"
          ],
          "reason": "WebSocket support fits bidirectional connected clients",
          "limits": "Enable the documented module/feature; authorize handshake and every protected message, bound queues/message size and implement heartbeat/shutdown. Socket delivery is not durable history; define reconnect/resync.",
          "source_urls": [
            "https://docs.rs/axum/latest/axum/extract/ws/index.html"
          ]
        }
      ],
      "setup_steps": [
        "Create source in a local development workspace: cargo new service; enter service and commit the generated application Cargo.lock after dependency resolution.",
        "Run cargo add axum; cargo add tokio --features macros,rt-multi-thread; add required tower-http middleware after selecting compatible releases.",
        "Add SQLx selecting PostgreSQL, Tokio and a supported TLS configuration from that release; install matching sqlx-cli. Create config validation and tracing subscriber.",
        "Use a disposable database in DATABASE_URL. Create migrations with sqlx migrate add initial; write SQL and run sqlx migrate run.",
        "For checked query macros, run cargo sqlx prepare after schema/query changes and commit offline metadata. Implement HTTP, real-database and cancellation tests.",
        "Introduce Restate only after a separate restart/retry/idempotency proof. Pin toolchain and release targets. These instructions were not executed."
      ],
      "verification_commands": [
        "cargo fmt --all -- --check",
        "cargo clippy --workspace --all-targets --locked -- -D warnings",
        "cargo test --workspace --locked",
        "cargo audit",
        "sqlx migrate info",
        "cargo sqlx prepare --check",
        "cargo build --release --locked"
      ],
      "evidence_status": "documentation-reviewed",
      "sources": [
        {
          "url": "https://docs.rs/axum/latest/axum/",
          "title": "Axum",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://tokio.rs/",
          "title": "Tokio",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/sqlx/latest/sqlx/",
          "title": "SQLx",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/transact-rs/sqlx/blob/main/sqlx-cli/README.md",
          "title": "SQLx CLI",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/config/latest/config/",
          "title": "Rust config crate",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://doc.rust-lang.org/std/env/fn.var.html",
          "title": "Rust environment variables",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/tracing/latest/tracing/",
          "title": "Rust tracing",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://doc.rust-lang.org/cargo/commands/cargo-test.html",
          "title": "Cargo test",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/rust-lang/rustfmt",
          "title": "rustfmt",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://doc.rust-lang.org/clippy/usage.html",
          "title": "Clippy usage",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://rustsec.org/",
          "title": "RustSec",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/assert_cmd/latest/assert_cmd/",
          "title": "assert_cmd",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/restate-sdk/latest/restate_sdk/",
          "title": "Restate Rust SDK",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://doc.rust-lang.org/cargo/commands/cargo-build.html",
          "title": "Cargo build",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/jsonwebtoken/latest/jsonwebtoken/",
          "title": "jsonwebtoken API",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/lettre/latest/lettre/",
          "title": "lettre documentation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.aws.amazon.com/sdk-for-rust/latest/dg/rust_s3_code_examples.html",
          "title": "AWS Rust S3 examples",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/axum/latest/axum/extract/ws/index.html",
          "title": "Axum WebSocket extractor documentation",
          "checked_date": "2026-10-10"
        }
      ],
      "open_questions": [
        "Which API/token contract and trusted key-rotation mechanism apply?",
        "Which target/runtime/TLS and database configurations must ship?",
        "Does durable work justify a separate Restate service and its operation?",
        "Which workload, realtime capacity and restore objectives must be met?"
      ],
      "title": "Rust service",
      "language": "Rust",
      "group": "APIs & services",
      "kind": [
        "api"
      ],
      "ui": "none",
      "host": "binary",
      "summary": "Services where runtime control and explicit resource handling matter.",
      "shape": "Axum · Tokio · SQLx · PostgreSQL",
      "tradeoff": "Async runtime and type complexity add development work; measure the reason to choose them.",
      "research_file": "go-rust.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Keep blocking work off async executor threads and apply timeouts and concurrency limits.",
        "Use typed configuration and tracing; preserve useful context when returning errors.",
        "Rehearse SQLx migrations and validate prepared query metadata against the intended schema.",
        "Build for the actual deployment target. Type checks do not replace authorization, retry and load tests."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://docs.rs/axum/latest/axum/"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/rust-service/",
      "markdown_url": "/stacks/rust-service/guide.md",
      "json_url": "/stacks/rust-service/record.json",
      "architecture_and_migration": {
        "id": "rust-service",
        "version_scope": "Reviewed docs expose Axum 0.8.9, Tokio 1.53.2 and SQLx 0.9.0 on 11 October 2026; Rust std docs show 1.99.0. These are documentation scopes, not a qualified composition or an automatic upgrade recommendation. Record rust-toolchain.toml, Cargo.lock, enabled features, SQLx CLI compatibility and database version before implementation.",
        "operating_model": "Recommendation: Axum/Tower owns request extraction and middleware; domain functions return explicit errors; Tokio drives async I/O; SQLx pools and transactions own database access. Track child tasks and cancellation separately from persisted jobs. A Tokio channel coordinates tasks inside one live process and cannot recover accepted work after a crash.",
        "architecture": [
          "Recommendation: route through Axum extractors and typed State with cloneable pool/client handles. Keep domain logic independent of HTTP responses, and map business/infrastructure errors deliberately through IntoResponse.",
          "Recommendation: compose Tower limits and timeouts with explicit overload/error mapping. Use bounded channels/semaphores; a concurrency limit without an admission/queue policy does not bound every waiting request.",
          "Recommendation: use SQLx query macros where schema checking fits and dynamic queries where needed. Store reviewed migrations and offline metadata; runtime authorization and isolation remain separate from compile-time type checks.",
          "Recommendation: move sustained CPU work to a bounded blocking executor or dedicated worker process. Track async tasks with cancellation/termination coordination; a started spawn_blocking task cannot be forcibly aborted through Tokio."
        ],
        "developer_workflow": [
          "Recommendation: inspect Cargo.toml/Cargo.lock, rust-toolchain.toml and enabled dependency features. For a new project, cargo new service and cargo add axum can establish the package; select Tokio runtime and SQLx database/TLS features deliberately rather than copying a broad feature list.",
          "Recommendation: run cargo fmt --check, cargo clippy --all-targets -- -D warnings and cargo test --locked with the project-supported feature matrix. Compile and run protocol/cancellation fixtures; no integration was executed in this research.",
          "Recommendation: install a SQLx CLI version compatible with the selected crate; against a disposable database run cargo sqlx migrate run, then cargo sqlx prepare --workspace and commit .sqlx metadata. CI cargo sqlx prepare --check --workspace detects stale metadata; an offline build does not prove the live schema matches.",
          "Recommendation: cargo build --release --locked prepares a release for the selected target. Use tracing/request IDs, pool-wait metrics and representative load profiles before asserting latency, cost or capacity advantages."
        ],
        "avoid": [
          "Avoid Arc<Mutex<Connection>> for all queries; a shared pool permits independent requests without a global database serialization boundary.",
          "Avoid blocking SDK calls or heavy loops on async runtime workers. spawn_blocking needs its own capacity limits and cannot abort a running closure.",
          "Avoid using Tokio mpsc as a drop-in replacement for durable Redis jobs; accepted jobs disappear with memory unless independently persisted.",
          "Avoid confusing Rust memory safety with correct authorization, queue delivery or compatibility guarantees."
        ],
        "transitions": [
          {
            "capability": "data",
            "existing_contract": "Capture the old SQL schema, transactions, tenant filters, nullable values and database engine behavior.",
            "coexistence": "Recommendation: keep existing schema ownership and backward-compatible columns; run SQLx reads for a selected boundary before transferring its writer. Generate metadata against exactly the reviewed migration state.",
            "target": "Recommendation: SQLx pooled access with transaction-scoped domain changes; query! checks literals against a live build schema or checked-in .sqlx metadata. Keep database engine choice independent of the Rust rewrite.",
            "benefits": [
              {
                "benefit": "Compile-time query/type checks can expose SQL/API mismatches before deployment.",
                "prerequisites": "Query macros/features and metadata match the chosen engine and schema; nullable results and dynamic queries receive runtime checks.",
                "tradeoffs": "Dynamic SQL is outside macro checking; stale offline metadata can compile; schema ownership and deployment order still need controls."
              }
            ],
            "checks": [
              "Run an offline locked build with the reviewed metadata and a live prepare --check against the migrated fixture DB.",
              "Verify both runtimes read each other's writes, including null/time/ID mappings.",
              "Cancel during a transaction and confirm the intended committed/rolled-back state plus pool recovery."
            ],
            "rollback": "Recommendation: route writes back while retaining additive schema and a previous compatible binary. Delay destructive migrations; reconcile new-only persisted values before rollback.",
            "sources": [
              "https://docs.rs/sqlx/latest/sqlx/macro.query.html",
              "https://docs.rs/sqlx/latest/sqlx/struct.Pool.html",
              "https://github.com/transact-rs/sqlx/blob/main/sqlx-cli/README.md"
            ],
            "id": "data-1"
          },
          {
            "capability": "jobs",
            "existing_contract": "Preserve old broker serialization, acknowledgement, delayed/retry states, concurrency and effect IDs. Durable Redis workers cannot be replaced transparently by tokio::spawn.",
            "coexistence": "Recommendation: Rust commits an outbox intent in its domain transaction; a replay-safe relay submits to the retained queue/worker interface. Existing workers retain queue ownership while new job kinds are qualified. This outbox design is inferred, not a shipped Axum feature.",
            "target": "Recommendation: keep proven durable workers until a chosen Rust queue implementation is qualified for retries, scheduling, leases and crashes. River current Ruby docs describe a shared schema with Rust; that statement alone does not qualify a Rust worker API or migration.",
            "benefits": [
              {
                "benefit": "A retained worker boundary allows the HTTP layer to change without dropping backlog or broker guarantees.",
                "prerequisites": "Same-transaction outbox intent; stable relay/effect IDs; explicit payload translator; observed delivery and backlog ownership.",
                "tradeoffs": "Two runtimes and a relay add operations; delivery may repeat; a SQLx transaction alone does not atomically submit to Redis."
              }
            ],
            "checks": [
              "Crash after the domain commit but before relay delivery; an intent remains recoverable.",
              "Crash the relay after submission before marking sent; duplicate delivery produces one logical effect.",
              "Reconcile ready, scheduled, retry, failed and in-flight old jobs before any worker replacement."
            ],
            "rollback": "Recommendation: stop the new producer, let accepted outbox entries settle and retain the old worker. Roll back traffic only after ambiguous effects are reconciled; avoid consuming a queue with incompatible handlers.",
            "sources": [
              "https://tokio.rs/tokio/tutorial/channels",
              "https://docs.rs/sqlx/latest/sqlx/macro.query.html",
              "https://riverqueue.com/docs/ruby"
            ],
            "id": "jobs-1"
          },
          {
            "capability": "operations",
            "existing_contract": "Define HTTP admission/error behavior, task ownership, shutdown deadline and behavior for unavoidable CPU/blocking operations.",
            "coexistence": "Recommendation: retain old routing while introducing Tower admission bounds and CancellationToken/TaskTracker-based ownership for a coherent endpoint cohort. Benchmark equivalent resource limits and durability before attributing gains to Rust.",
            "target": "Recommendation: bounded async work, cooperative cancellation, explicit shutdown notification plus tracked task completion, and SQLx pool close. For untrusted/hard-deadline native work, isolate it in a process whose termination contract is tested.",
            "benefits": [
              {
                "benefit": "Tracked tasks and explicit admission limits make resource use and planned termination easier to reason about.",
                "prerequisites": "Every child task is tracked; limits include waiting work; cancellation-safe I/O and shutdown budget are verified.",
                "tradeoffs": "spawn_blocking closures may continue after timeout; killing a process still requires durable recovery and external-effect reconciliation."
              }
            ],
            "checks": [
              "Cancel an overloaded request and verify queue permits/resources are released.",
              "Send termination during async and blocking work; document tasks that drain and work that cannot be aborted.",
              "Force a crash after acceptance; verify recovery of persisted intents and honest failure of memory-only work."
            ],
            "rollback": "Recommendation: return the cohort to the previous service and reconcile persisted outcomes. Do not simply retry every cancelled request; its external effect may already have occurred.",
            "sources": [
              "https://docs.rs/tower/latest/tower/limit/index.html",
              "https://tokio.rs/tokio/topics/shutdown",
              "https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html",
              "https://docs.rs/sqlx/latest/sqlx/struct.Pool.html"
            ],
            "id": "operations-1"
          },
          {
            "capability": "realtime",
            "existing_contract": "Preserve subscriptions, authorization revocation, event versions, reconnect behavior and cross-instance fan-out.",
            "coexistence": "Recommendation: keep the existing shared broker while a Rust gateway serves entire room/tenant cohorts; adapters translate existing messages without dual-emitting user effects. Test cross-runtime publication in both directions.",
            "target": "Recommendation: Axum WebSocket transport and bounded per-client queues. Tokio broadcast is appropriate only for local ephemeral fan-out with explicit Lagged handling; use durable state/event history to resync clients when loss is unacceptable.",
            "benefits": [
              {
                "benefit": "Local bounded fan-out can prevent slow receivers from retaining unbounded memory.",
                "prerequisites": "Overflow/disconnect/resync policy exists; replica routing and shared fan-out remain covered; every broadcast error is handled.",
                "tradeoffs": "Tokio broadcast is process-local; old messages are evicted when capacity is exceeded; it is not a durable cross-node broker."
              }
            ],
            "checks": [
              "Force receiver lag and verify Lagged triggers resync or the documented disconnect policy.",
              "Publish from each runtime and confirm the opposite runtime's subscribers receive the intended event.",
              "Reconnect after deployment/crash and rebuild state without trusting missing ephemeral frames."
            ],
            "rollback": "Recommendation: route the whole cohort back and retain the shared broker/protocol. Resynchronize from authoritative durable records; local channel state cannot be restored from a previous binary.",
            "sources": [
              "https://docs.rs/axum/latest/axum/",
              "https://docs.rs/tokio/latest/tokio/sync/broadcast/index.html",
              "https://redis.io/docs/latest/develop/pubsub/"
            ],
            "id": "realtime-1"
          }
        ],
        "sources": [
          {
            "url": "https://docs.rs/axum/latest/axum/",
            "title": "Axum 0.8.9",
            "claim": "Typed extractors/State and Tower middleware form the HTTP composition."
          },
          {
            "url": "https://docs.rs/tower/latest/tower/limit/index.html",
            "title": "Tower limits",
            "claim": "Concurrency and rate-limit middleware exist; admission/error policy needs application design."
          },
          {
            "url": "https://tokio.rs/tokio/topics/shutdown",
            "title": "Tokio graceful shutdown",
            "claim": "CancellationToken and TaskTracker coordinate shutdown and task completion."
          },
          {
            "url": "https://tokio.rs/tokio/tutorial/channels",
            "title": "Tokio channels",
            "claim": "Bounded mpsc coordinates tasks; capacity/backpressure is explicit, not disk persistence."
          },
          {
            "url": "https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html",
            "title": "Tokio spawn_blocking",
            "claim": "CPU work needs a parallelism limit; started blocking tasks cannot be aborted."
          },
          {
            "url": "https://docs.rs/sqlx/latest/sqlx/macro.query.html",
            "title": "SQLx 0.9.0 query macro",
            "claim": "Literal queries need a matching database schema or offline metadata; engine binding and nullability have limits."
          },
          {
            "url": "https://docs.rs/sqlx/latest/sqlx/struct.Pool.html",
            "title": "SQLx pool",
            "claim": "A shared async pool supports reuse; a mutex around one connection creates serialization; close should be awaited."
          },
          {
            "url": "https://github.com/transact-rs/sqlx/blob/main/sqlx-cli/README.md",
            "title": "SQLx CLI README",
            "claim": "Migrations and prepare/prepare --check maintain offline query metadata."
          },
          {
            "url": "https://docs.rs/tokio/latest/tokio/sync/broadcast/index.html",
            "title": "Tokio broadcast",
            "claim": "A bounded local channel drops older values and reports lagging receivers."
          },
          {
            "url": "https://riverqueue.com/docs/ruby",
            "title": "River cross-language schema statement",
            "claim": "Current Ruby guide explicitly names Go, Rust and TypeScript sharing a schema; Rust API itself is unqualified here."
          },
          {
            "url": "https://redis.io/docs/latest/develop/pubsub/",
            "title": "Redis Pub/Sub",
            "claim": "Ephemeral shared fan-out remains at-most-once and needs a separate recovery path."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": false,
        "static_hosting": false,
        "offline_client_candidate": false
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    },
    {
      "id": "python-fastapi",
      "name": "FastAPI service APIs",
      "use_cases": [
        "Typed JSON APIs",
        "Integration services",
        "HTTP endpoints for model or worker products"
      ],
      "choose_when": [
        "API contracts and Python integrations matter more than built-in product/admin UI",
        "A separate frontend or service boundary already exists"
      ],
      "avoid_when": [
        "The team mostly needs accounts, admin, forms and CRUD that Django supplies",
        "Blocking or CPU-intensive jobs would be run inside request event loops"
      ],
      "tools": [
        {
          "job": "Packaging and environments",
          "default": "uv + pyproject.toml + committed uv.lock",
          "alternatives": [
            "Preserve an existing maintained packaging workflow"
          ],
          "reason": "One project entry point for dependencies, Python selection, execution and reproducible sync.",
          "limits": "Pin a compatible Python minor and resolve actual package versions at implementation; do not hand-edit uv.lock. Keep environments and caches in a local development workspace.",
          "source_urls": [
            "https://docs.astral.sh/uv/guides/projects/"
          ]
        },
        {
          "job": "Lint and format",
          "default": "Ruff",
          "alternatives": [
            "Preserve existing configured formatter/linter"
          ],
          "reason": "Fast lint and formatting feedback with one configuration.",
          "limits": "Ruff does not replace static typing, tests, authorization checks or runtime validation.",
          "source_urls": [
            "https://docs.astral.sh/ruff/installation/"
          ]
        },
        {
          "job": "Static typing",
          "default": "mypy",
          "alternatives": [
            "ty after project-specific compatibility trial"
          ],
          "reason": "Explicit checks on application boundaries with a conservative established checker.",
          "limits": "Configure strictness and third-party stubs; unchecked Any and untyped functions reduce coverage. No checker performance comparison was run.",
          "source_urls": [
            "https://mypy.readthedocs.io/en/stable/getting_started.html",
            "https://docs.astral.sh/ty/type-checking/"
          ]
        },
        {
          "job": "Testing",
          "default": "pytest + HTTPX / FastAPI TestClient",
          "alternatives": [
            "Async client tests for async application lifecycles"
          ],
          "reason": "Test contract failures, auth and integration boundaries.",
          "limits": "Run startup/shutdown lifespan when relevant; include PostgreSQL and external-service fault tests.",
          "source_urls": [
            "https://docs.pytest.org/en/stable/getting-started.html",
            "https://fastapi.tiangolo.com/deployment/docker/"
          ]
        },
        {
          "job": "Database and migrations",
          "default": "PostgreSQL + SQLAlchemy + Psycopg + Alembic",
          "alternatives": [
            "SQLite for local single-user work; no DB for stateless services"
          ],
          "reason": "Explicit transactions and versioned relational changes.",
          "limits": "Session per thread / AsyncSession per task. Review generated migrations, especially renames and data changes; a passing migration check does not prove production lock safety.",
          "source_urls": [
            "https://docs.sqlalchemy.org/en/21/orm/session_basics.html",
            "https://alembic.sqlalchemy.org/en/latest/autogenerate.html"
          ]
        },
        {
          "job": "Validation",
          "default": "Pydantic request/response models; strict validation where coercion is unsafe",
          "alternatives": [
            "Explicit domain validation functions"
          ],
          "reason": "Typed schemas clarify external contracts and generated documentation.",
          "limits": "Coercion is configurable; schema validity is not authorization or business correctness. Avoid returning unrestricted ORM objects.",
          "source_urls": [
            "https://pydantic.dev/docs/validation/latest/concepts/strict_mode/"
          ]
        },
        {
          "job": "Authentication",
          "default": "Existing OIDC provider; validate access tokens and authorization in dependencies",
          "alternatives": [
            "Authlib for browser OIDC client flow",
            "First-party session authentication if architecture requires it"
          ],
          "reason": "Keep identity lifecycle with its owner while enforcing permissions at the API.",
          "limits": "Choose and verify token-validation integration at implementation. FastAPI's JWT tutorial is not a complete identity system; issuer, audience, expiry and permissions need tests.",
          "source_urls": [
            "https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/",
            "https://docs.authlib.org/en/v1.7.0/oauth2/client/web/index.html"
          ]
        },
        {
          "job": "Jobs",
          "default": "Separate Celery workers for queued jobs",
          "alternatives": [
            "Temporal for restart-safe multi-step workflows",
            "BackgroundTasks for small best-effort post-response work"
          ],
          "reason": "Separate request latency from heavy or retried work.",
          "limits": "BackgroundTasks does not establish durable execution. Make job effects idempotent and set retry/deadline limits.",
          "source_urls": [
            "https://fastapi.tiangolo.com/tutorial/background-tasks/",
            "https://docs.celeryq.dev/en/stable/userguide/tasks.html",
            "https://docs.temporal.io/develop/python"
          ]
        },
        {
          "job": "Long-running durable agents",
          "default": "Temporal Python SDK when recovery across restarts is required",
          "alternatives": [
            "Celery for independent queued jobs; direct function for bounded work"
          ],
          "reason": "Persisted workflow orchestration and separate worker processes suit retries, pauses and human waits.",
          "limits": "Adds a service and operational cost. Keep external I/O in activities, make side effects idempotent, test replay and cancellation; no end-to-end integration was run.",
          "source_urls": [
            "https://docs.temporal.io/develop/python",
            "https://docs.celeryq.dev/en/stable/userguide/tasks.html"
          ]
        },
        {
          "job": "Serving and deployment",
          "default": "FastAPI standard CLI / Uvicorn in a container",
          "alternatives": [
            "Managed ASGI platform"
          ],
          "reason": "Official deployment path with explicit process and container choices.",
          "limits": "Build from a supported base rather than deprecated framework images; choose process count to match deployment/memory, and run schema migration once per release.",
          "source_urls": [
            "https://fastapi.tiangolo.com/deployment/docker/",
            "https://docs.astral.sh/uv/guides/integration/docker/",
            "https://fastapi.tiangolo.com/async/"
          ]
        },
        {
          "job": "Application logging",
          "default": "Python logging with configured handlers",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Shared standard logging captures application and dependency diagnostics",
          "limits": "Configure logging at entry point, redact credentials and add request/job IDs, duration and failure context. Persist logs on the execution platform; metrics/tracing backend is a separate operational choice.",
          "source_urls": [
            "https://docs.python.org/3/library/logging.html"
          ]
        },
        {
          "job": "Bounded external-call retries",
          "default": "Tenacity only for retryable transient failures",
          "alternatives": [
            "Provider SDK retry policy when sufficient"
          ],
          "reason": "Explicit stop/wait/filter rules support controlled retries",
          "limits": "Install tenacity; set attempt/deadline limits, jitter and exception filters. The bare decorator retries forever without delay; do not stack retries with SDK/worker retries or repeat non-idempotent effects without keys.",
          "source_urls": [
            "https://tenacity.readthedocs.io/en/latest/"
          ]
        },
        {
          "job": "Uploads",
          "default": "FastAPI UploadFile",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Spooling file interface avoids eagerly materializing all content in application memory",
          "limits": "Install python-multipart; enforce request/file limits and authorization, stream to durable storage and clean partial writes. Multipart parsing does not establish file safety.",
          "source_urls": [
            "https://fastapi.tiangolo.com/tutorial/request-files/"
          ]
        },
        {
          "job": "Realtime transport",
          "default": "FastAPI WebSocket endpoints",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Native ASGI endpoint support fits connected API clients",
          "limits": "Authorize handshake/messages; bound per-client queues, handle disconnect and share state through an external service for replicas. In-memory tutorial connection lists are not multi-process state.",
          "source_urls": [
            "https://fastapi.tiangolo.com/advanced/websockets/"
          ]
        },
        {
          "job": "Object storage",
          "default": "Boto3 S3 client when durable objects are required",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Official SDK supports file transfer to S3",
          "limits": "Install boto3 only for S3-backed work; use platform credentials, private keys and bounded transfers. Boto3 is synchronous: keep blocking transfers out of an async event loop; verify alternative provider compatibility.",
          "source_urls": [
            "https://docs.aws.amazon.com/boto3/latest/guide/s3-uploading-files.html"
          ]
        }
      ],
      "setup_steps": [
        "In a new local source directory: uv init; pin a compatible Python minor; uv add 'fastapi[standard]' sqlalchemy 'psycopg[binary]' alembic pydantic-settings",
        "uv add --dev ruff mypy pytest httpx",
        "Create an importable app package with app/main.py exporting app = FastAPI(), request/response models and a health endpoint.",
        "uv run alembic init migrations; configure environment-based connection URL and target_metadata. Implement per-request/task sessions and domain transaction boundaries.",
        "uv run alembic revision --autogenerate -m 'initial schema'; manually review, then uv run alembic upgrade head against the development DB.",
        "Configure the selected identity provider and token verification; implement tenant/object authorization before adding protected endpoints.",
        "Develop with uv run fastapi dev app/main.py. Package a release with uv sync --locked --no-dev and an explicit production start command; add workers separately when needed."
      ],
      "verification_commands": [
        "uv sync --locked",
        "uv run ruff check .",
        "uv run ruff format --check .",
        "uv run mypy app",
        "uv run pytest",
        "uv run alembic check",
        "uv run alembic current"
      ],
      "open_questions": [
        "Which identity provider, token validation and tenant authorization model apply?",
        "Does workload justify async database access, or is synchronous I/O simpler?",
        "Which host/replica model, upload storage, realtime and worker guarantees apply?"
      ],
      "evidence_status": "documentation-reviewed",
      "sources": [
        {
          "url": "https://docs.astral.sh/uv/guides/projects/",
          "title": "uv projects",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.astral.sh/ruff/installation/",
          "title": "Ruff installation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://mypy.readthedocs.io/en/stable/getting_started.html",
          "title": "mypy getting started",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.astral.sh/ty/type-checking/",
          "title": "ty type checking",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.pytest.org/en/stable/getting-started.html",
          "title": "pytest getting started",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://fastapi.tiangolo.com/deployment/docker/",
          "title": "FastAPI containers",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.sqlalchemy.org/en/21/orm/session_basics.html",
          "title": "SQLAlchemy session basics",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://alembic.sqlalchemy.org/en/latest/autogenerate.html",
          "title": "Alembic autogeneration",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pydantic.dev/docs/validation/latest/concepts/strict_mode/",
          "title": "Pydantic strict mode",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/",
          "title": "FastAPI JWT tutorial",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.authlib.org/en/v1.7.0/oauth2/client/web/index.html",
          "title": "Authlib OAuth web clients",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://fastapi.tiangolo.com/tutorial/background-tasks/",
          "title": "FastAPI background tasks",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.celeryq.dev/en/stable/userguide/tasks.html",
          "title": "Celery tasks",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.temporal.io/develop/python",
          "title": "Temporal Python SDK",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.astral.sh/uv/guides/integration/docker/",
          "title": "uv Docker",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://fastapi.tiangolo.com/async/",
          "title": "FastAPI concurrency",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.python.org/3/library/logging.html",
          "title": "Python logging",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://tenacity.readthedocs.io/en/latest/",
          "title": "Tenacity documentation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://fastapi.tiangolo.com/tutorial/request-files/",
          "title": "FastAPI request files",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://fastapi.tiangolo.com/advanced/websockets/",
          "title": "FastAPI WebSockets",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.aws.amazon.com/boto3/latest/guide/s3-uploading-files.html",
          "title": "Boto3 uploads",
          "checked_date": "2026-10-10"
        }
      ],
      "title": "FastAPI",
      "language": "Python",
      "group": "APIs & services",
      "kind": [
        "api"
      ],
      "ui": "none",
      "host": "server",
      "summary": "Typed Python APIs alongside Python integrations, data or AI libraries.",
      "shape": "FastAPI · Pydantic · SQLAlchemy · Alembic",
      "tradeoff": "Authentication, migrations and durable jobs are separate integration decisions.",
      "research_file": "python.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Validate tokens and permissions in dependencies; Pydantic validation does not establish authorization.",
        "Keep blocking calls out of async request handling and configure database connection lifetimes.",
        "Commit and rehearse Alembic migrations. Use isolated databases for integration tests.",
        "Move durable work to operated workers; an in-process background task cannot guarantee recovery."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://fastapi.tiangolo.com/tutorial/"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/python-fastapi/",
      "markdown_url": "/stacks/python-fastapi/guide.md",
      "json_url": "/stacks/python-fastapi/record.json",
      "architecture_and_migration": {
        "id": "python-fastapi",
        "version_scope": "Current FastAPI online guides fetched 11 October 2026; these pages do not pin an application package release. SQLAlchemy 2.0 documentation, Alembic 1.20.0 documentation and Celery 5.6.3 reviewed. Pin actual Python/FastAPI/Pydantic/Starlette/database-driver versions before implementation.",
        "operating_model": "FastAPI exposes Python type-annotated HTTP operations and dependency boundaries. It supports synchronous and async handlers; the choice depends on whether called libraries support await. Recommendation: keep request models distinct from persistence operations and explicitly select identity, durable jobs, database migrations and distributed messaging instead of assuming the API framework provides an integrated monolith.",
        "architecture": [
          "Use async handlers with awaitable I/O, or normal def handlers for blocking libraries as the guide explains. Recommendation: keep CPU-heavy or durable work behind a deliberate worker boundary; adding async syntax does not change its durability or CPU execution model.",
          "SQLAlchemy Sessions are mutable transaction state and cannot be shared across concurrent tasks/threads. Recommendation: scope a Session to its operation, keep the engine/pool separate and use reviewed Alembic revisions for schema evolution.",
          "FastAPI lifespan manages startup/shutdown resources. Multiple worker processes are a deployment choice; recommendation: treat in-memory connections/caches as worker-local and keep one external scheduler and migration owner."
        ],
        "developer_workflow": [
          "For a configured application, adapt fastapi run --workers 4 main.py or uvicorn main:app --workers 4 from the deployment guide; replace module and worker count for the actual host/container topology. The example is a recipe, not a capacity recommendation.",
          "For a configured SQLAlchemy/Alembic application, use alembic revision -m \"Add a column\", review upgrade/downgrade operations, then alembic upgrade head in a disposable database; alembic current and alembic history show recorded state.",
          "Use FastAPI TestClient and pytest for HTTP contract tests. Recommendation: add real database/worker tests for transaction and retry boundaries, plus WebSocket tests across the intended multi-process topology.",
          "Recommendation: initialize shared process resources through the lifespan context and create independent database sessions for concurrent operations. Validate selected sync/async client usage and cleanup on shutdown before rollout."
        ],
        "avoid": [
          "Avoid using BackgroundTasks as a durable queue replacement: it executes work associated with the application process, while the guide recommends larger worker tools such as Celery for work that belongs in multiple processes/servers. Recommendation: qualify crash/retry behavior explicitly.",
          "Avoid copying the tutorial’s in-memory WebSocket connection list into a multi-worker product; the docs explicitly say it works only in one running process.",
          "Avoid sharing one SQLAlchemy Session among requests/tasks or moving blocking library calls unchanged inside async handlers; the documented concurrency boundaries differ.",
          "Avoid treating a JWT tutorial as a complete identity migration. Recommendation: retain existing identity authority until issuer, account mapping, validation, expiry and revocation are designed. Starlette SessionMiddleware signs readable cookie contents; signing is not confidentiality."
        ],
        "transitions": [
          {
            "capability": "data",
            "existing_contract": "Inventory schema, primary IDs, SQL value/constraint semantics and existing transaction ownership. The old application may use an ORM with callbacks absent from the target service.",
            "coexistence": "Recommendation: keep one writer and migration runner; start with read-only target endpoints or a bounded domain operation. Preserve additive schema and qualify ORM/session behavior before transferring writes.",
            "target": "SQLAlchemy 2.0 Sessions scoped to operations, with reviewed Alembic upgrade/downgrade revisions and the selected PostgreSQL driver. Recommendation: keep transaction and external delivery boundaries explicit.",
            "benefits": [
              {
                "benefit": "Recommendation: explicit sessions and migrations expose the persistence boundary to review.",
                "prerequisites": "Qualified schema mapping, operation-scoped sessions and one writer owner.",
                "tradeoffs": "FastAPI does not remove ORM/migration choices; deleting data cannot be undone by traffic rollback."
              }
            ],
            "checks": [
              "Create through each allowed writer and read through both runtimes; compare IDs, timestamps/null values and constraint failures.",
              "Run concurrent requests with separate sessions and fail one transaction; no other request’s changes or Session state may leak.",
              "Apply a reviewed revision to a disposable restored database and verify both deployed versions still read new writes."
            ],
            "rollback": "Recommendation: restore the old writer while preserving backward-readable schema; use downgrade only for a rehearsed reversible change and reconcile accepted new data.",
            "sources": [
              "https://fastapi.tiangolo.com/tutorial/sql-databases/",
              "https://docs.sqlalchemy.org/en/20/orm/session_basics.html",
              "https://alembic.sqlalchemy.org/en/latest/tutorial.html"
            ],
            "id": "data-1"
          },
          {
            "capability": "jobs",
            "existing_contract": "Record old task name/class, serialized arguments, broker, retries/acknowledgements, schedule ownership and every backlog state. BackgroundTasks and a broker-backed worker are different execution contracts.",
            "coexistence": "Recommendation: retain old consumers and isolate new categories behind a versioned task interface. Use configured Celery or another separately qualified persistent system when restart recovery matters; keep one schedule owner and a recoverable domain-to-broker handoff.",
            "target": "An explicitly selected durable worker/broker composition with business idempotency. Small best-effort same-process tasks may use BackgroundTasks only when their documented process boundary fits the requirement.",
            "benefits": [
              {
                "benefit": "Recommendation: durable work can move independently of the HTTP service.",
                "prerequisites": "Selected broker/worker configuration, tested payloads and explicit idempotency/recovery policy.",
                "tradeoffs": "The broker and worker add operated components; returning HTTP success before enqueue acceptance must have a deliberate contract."
              }
            ],
            "checks": [
              "Enqueue while the worker is stopped, restart it and verify the intended completion/failure result.",
              "Crash after an external effect before acknowledgement and verify retry is safe; test broker outage during a domain write.",
              "Reconcile delayed/retry/failed/running tasks and verify the old and new schedulers never both produce the category."
            ],
            "rollback": "Recommendation: stop new task production, retain consumers for accepted payload versions and reconcile external effects before restoring old routing.",
            "sources": [
              "https://fastapi.tiangolo.com/tutorial/background-tasks/",
              "https://docs.celeryq.dev/en/stable/userguide/tasks.html",
              "https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html",
              "https://docs.celeryq.dev/en/stable/getting-started/first-steps-with-celery.html"
            ],
            "id": "jobs-1"
          },
          {
            "capability": "identity",
            "existing_contract": "Capture the source identity authority, token/cookie format, issuer/audience rules, account IDs, expiration and revocation. The FastAPI OAuth2/JWT guide is a concrete example, not proof of compatibility with existing sessions.",
            "coexistence": "Recommendation: retain the existing identity authority through qualified token verification or session exchange. Move resource authorization with the domain operation, and keep cookie scope/CSRF behavior explicit when using browser cookies.",
            "target": "Selected OAuth2/token or browser-session implementation with deliberate account mapping and authorization. If using Starlette SessionMiddleware, cookie data is signed and readable; use https_only and appropriate scope settings for the selected deployment.",
            "benefits": [
              {
                "benefit": "Recommendation: a shared identity authority can preserve access across service boundaries.",
                "prerequisites": "Qualified token/session validation and common revocation policy.",
                "tradeoffs": "Bearer expiry and server-side revocation are distinct design choices; readable signed cookies must not contain secrets."
              }
            ],
            "checks": [
              "Accept a valid source credential and reject modified/expired credentials and a valid credential for another tenant’s protected record.",
              "Logout/revoke and confirm both old/new paths follow the agreed policy, including an existing WebSocket connection.",
              "Inspect the selected cookie contents and transport flags; no secret should be exposed by a signed-but-readable session."
            ],
            "rollback": "Recommendation: preserve account mapping and old credential/exchange support without reversing revocations; return routing only when validation remains compatible.",
            "sources": [
              "https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/",
              "https://starlette.dev/middleware/",
              "https://fastapi.tiangolo.com/advanced/websockets/"
            ],
            "id": "identity-1"
          },
          {
            "capability": "realtime",
            "existing_contract": "Capture the old client protocol, message envelope, connection authentication, subscription scopes and recovery requirements. FastAPI provides WebSocket handlers; its in-memory chat example is explicitly single-process.",
            "coexistence": "Recommendation: retain the old endpoint for old clients, bridge versioned domain events and route a stable user/room cohort including reconnects. Keep fanout in a separately qualified shared system when multiple worker processes must reach the same recipients.",
            "target": "FastAPI WebSocket handlers with explicit shared fanout and persisted domain-state/cursor recovery when required. No specific broker/client combination is integration-qualified by this research.",
            "benefits": [
              {
                "benefit": "Recommendation: an API service can take ownership of a realtime boundary incrementally.",
                "prerequisites": "Matching message/client protocol, subscription authorization and a tested multi-worker fanout implementation.",
                "tradeoffs": "Connection lists remain worker-local; selecting a shared broker does not itself provide catch-up or protocol compatibility."
              }
            ],
            "checks": [
              "Connect clients to different workers, commit one domain event and verify all authorized recipients converge.",
              "Restart the worker containing a connection, reconnect and recover missed state; test a revoked identity attempting to rejoin."
            ],
            "rollback": "Recommendation: preserve old endpoint/message compatibility through reconnects; return the cohort and reconcile current domain state instead of reissuing effects.",
            "sources": [
              "https://fastapi.tiangolo.com/advanced/websockets/",
              "https://fastapi.tiangolo.com/deployment/server-workers/"
            ],
            "id": "realtime-1"
          },
          {
            "capability": "cache",
            "existing_contract": "List reconstructible values and representation/TTL/invalidation separately from identities, jobs, counters and locks. Multiple application workers have distinct in-memory resource ownership.",
            "coexistence": "Recommendation: keep the existing shared store for coordination; use versioned keys for new representations. Move only disposable values to local caching when per-worker staleness and rebuilding are explicitly accepted.",
            "target": "A selected shared cache accessed with a qualified client such as redis-py, or an explicitly bounded local cache. Recommendation: match sync/async client usage to the handler and manage process resource lifetime deliberately.",
            "benefits": [
              {
                "benefit": "Recommendation: cache choices can evolve without transferring domain ownership.",
                "prerequisites": "Reconstructible values, explicit invalidation and a complete list of shared-store uses.",
                "tradeoffs": "Local values diverge across workers; removing Redis requires separately retiring sessions/queues/coordination, not merely replacing cached reads."
              }
            ],
            "checks": [
              "Warm two workers, update the source and verify required invalidation/staleness across both.",
              "Restart one worker or evict its dedicated cache and verify reconstruction without losing identity or queued work.",
              "Make the shared cache unavailable and verify the agreed failure/fallback behavior rather than silently accepting stale authorization."
            ],
            "rollback": "Recommendation: restore old key/backend routing and repopulate from domain data; preserve shared coordination ownership throughout.",
            "sources": [
              "https://redis.io/docs/latest/develop/clients/redis-py/",
              "https://fastapi.tiangolo.com/deployment/server-workers/",
              "https://fastapi.tiangolo.com/advanced/events/"
            ],
            "id": "cache-1"
          },
          {
            "capability": "operations",
            "existing_contract": "Inventory API workers, startup resources, database migration runner, durable workers, external scheduler and shared fanout/cache. Worker replication and lifespan resources are not a singleton schedule mechanism.",
            "coexistence": "Recommendation: keep one schema runner and logical schedule owner while both services operate. Initialize per-process resources deliberately and transfer traffic by a stable domain/user cohort.",
            "target": "An explicit FastAPI/Uvicorn process/container deployment, lifespan cleanup, separate durable workers and monitored dependency boundaries. Recommendation: record actual worker count and deployment settings instead of inheriting tutorial values.",
            "benefits": [
              {
                "benefit": "Recommendation: process/resource ownership makes multi-worker behavior reviewable.",
                "prerequisites": "Named migration/schedule owners, configured shutdown and tested dependency failure behavior.",
                "tradeoffs": "More workers multiply process-local resources; successful HTTP startup cannot qualify broker, identity or restore behavior."
              }
            ],
            "checks": [
              "Start the intended multi-worker deployment against disposable restored data; exercise authenticated HTTP, one task and cross-worker realtime delivery.",
              "Terminate a worker during active work, verify shutdown/restart behavior and confirm no extra scheduler or migration runner starts."
            ],
            "rollback": "Recommendation: preserve the old release and compatible schema, transfer role ownership before restoring traffic, and reconcile work accepted by the new service.",
            "sources": [
              "https://fastapi.tiangolo.com/advanced/events/",
              "https://fastapi.tiangolo.com/deployment/server-workers/",
              "https://alembic.sqlalchemy.org/en/latest/tutorial.html",
              "https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html"
            ],
            "id": "operations-1"
          }
        ],
        "sources": [
          {
            "url": "https://fastapi.tiangolo.com/async/",
            "title": "FastAPI Concurrency",
            "claim": "Choice of async handlers versus normal def for awaitable/blocking libraries."
          },
          {
            "url": "https://fastapi.tiangolo.com/tutorial/sql-databases/",
            "title": "FastAPI SQL Databases",
            "claim": "Request-scoped database dependency examples and external SQL library choice."
          },
          {
            "url": "https://docs.sqlalchemy.org/en/20/orm/session_basics.html",
            "title": "SQLAlchemy Session Basics",
            "claim": "Mutable transaction/session lifecycle and prohibition on sharing across concurrent threads/tasks."
          },
          {
            "url": "https://alembic.sqlalchemy.org/en/latest/tutorial.html",
            "title": "Alembic Tutorial",
            "claim": "Revision, upgrade/downgrade, current/history commands and schema revision ownership."
          },
          {
            "url": "https://fastapi.tiangolo.com/tutorial/background-tasks/",
            "title": "FastAPI Background Tasks",
            "claim": "Same-process task examples and separate Celery/queue recommendation for larger execution boundaries."
          },
          {
            "url": "https://docs.celeryq.dev/en/stable/userguide/tasks.html",
            "title": "Celery Tasks",
            "claim": "Task serialization, retry/acknowledgement and idempotency concerns."
          },
          {
            "url": "https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html",
            "title": "Celery Periodic Tasks",
            "claim": "Only one scheduler per schedule to prevent duplicate production."
          },
          {
            "url": "https://docs.celeryq.dev/en/stable/getting-started/first-steps-with-celery.html",
            "title": "Celery First Steps",
            "claim": "Broker, worker and optional result backend are separate roles."
          },
          {
            "url": "https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/",
            "title": "FastAPI OAuth2/JWT example",
            "claim": "Token/password validation and expiry example, not cross-framework session interoperability."
          },
          {
            "url": "https://starlette.dev/middleware/",
            "title": "Starlette Middleware",
            "claim": "Signed readable sessions, session cookie configuration and secure transport option."
          },
          {
            "url": "https://fastapi.tiangolo.com/advanced/websockets/",
            "title": "FastAPI WebSockets",
            "claim": "Handler authentication/dependencies and explicit single-process limitation of in-memory connection list."
          },
          {
            "url": "https://fastapi.tiangolo.com/advanced/events/",
            "title": "FastAPI Lifespan",
            "claim": "Startup/shutdown resource ownership through lifespan."
          },
          {
            "url": "https://fastapi.tiangolo.com/deployment/server-workers/",
            "title": "FastAPI Server Workers",
            "claim": "FastAPI/Uvicorn worker commands and deployment process topology choices."
          },
          {
            "url": "https://fastapi.tiangolo.com/tutorial/testing/",
            "title": "FastAPI Testing",
            "claim": "TestClient and pytest request checks."
          },
          {
            "url": "https://redis.io/docs/latest/develop/clients/redis-py/",
            "title": "Redis redis-py guide",
            "claim": "Maintained Python client for Redis with sync/async documentation links."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": false,
        "static_hosting": false,
        "offline_client_candidate": false
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    },
    {
      "id": "go-cli",
      "name": "Go CLI/TUI: Cobra + Bubble Tea + GoReleaser",
      "use_cases": [
        "Shipped command-line products",
        "infrastructure administration tools",
        "terminal dashboards"
      ],
      "choose_when": [
        "Want compiled distribution with Go ecosystem access",
        "Command structure and terminal UX matter more than tight low-level control"
      ],
      "avoid_when": [
        "Primarily a short disposable script",
        "Host SDK or native UI framework mandates another language",
        "Strict no-GC constraints"
      ],
      "tools": [
        {
          "job": "Command parsing",
          "default": "Cobra",
          "alternatives": [
            "flag for a small single command"
          ],
          "reason": "Command/help/completion structure plus event-driven terminal UI.",
          "limits": "Keep noninteractive and machine-readable modes; test TTY absence, cancellation and terminal restoration.",
          "source_urls": [
            "https://github.com/spf13/cobra",
            "https://github.com/charmbracelet/bubbletea",
            "https://pkg.go.dev/flag"
          ]
        },
        {
          "job": "Terminal UI",
          "default": "Bubble Tea only for interactive screens",
          "alternatives": [
            "Line-oriented output when no interactive screen is needed"
          ],
          "reason": "Command/help/completion structure plus event-driven terminal UI.",
          "limits": "Keep noninteractive and machine-readable modes; test TTY absence, cancellation and terminal restoration.",
          "source_urls": [
            "https://github.com/spf13/cobra",
            "https://github.com/charmbracelet/bubbletea",
            "https://pkg.go.dev/flag"
          ]
        },
        {
          "job": "HTTP client",
          "default": "net/http Client",
          "alternatives": [],
          "reason": "Standard client with contexts and transport reuse.",
          "limits": "Set timeouts, bound responses and close bodies; retry only when operation semantics allow.",
          "source_urls": [
            "https://pkg.go.dev/net/http"
          ]
        },
        {
          "job": "Persistence and migrations",
          "default": "None for stateless tools",
          "alternatives": [
            "Use service API for shared state"
          ],
          "reason": "Avoid introducing a database into a command wrapper.",
          "limits": "Local durable state requires a separately selected storage/schema policy; never assume flat-file writes are atomic.",
          "source_urls": [
            "https://pkg.go.dev/os"
          ]
        },
        {
          "job": "Configuration",
          "default": "Typed settings loaded with os.LookupEnv",
          "alternatives": [
            "flag for small command surfaces"
          ],
          "reason": "Explicit startup validation and standard structured logs.",
          "limits": "Define precedence; reject malformed required values; redact secrets. Environment access alone is not validation or secret management.",
          "source_urls": [
            "https://pkg.go.dev/os",
            "https://pkg.go.dev/flag",
            "https://pkg.go.dev/log/slog"
          ]
        },
        {
          "job": "Application logging",
          "default": "log/slog",
          "alternatives": [],
          "reason": "Explicit startup validation and standard structured logs.",
          "limits": "Define precedence; reject malformed required values; redact secrets. Environment access alone is not validation or secret management.",
          "source_urls": [
            "https://pkg.go.dev/os",
            "https://pkg.go.dev/flag",
            "https://pkg.go.dev/log/slog"
          ]
        },
        {
          "job": "Tests and static checks",
          "default": "testing; go vet; race detector; govulncheck",
          "alternatives": [],
          "reason": "Standard toolchain feedback plus exercised concurrency and known-vulnerability checks.",
          "limits": "Race detector requires supported target/toolchain and exercised code; no scanner proves absence of vulnerabilities.",
          "source_urls": [
            "https://pkg.go.dev/testing",
            "https://go.dev/doc/articles/race_detector",
            "https://golangci-lint.run/docs/welcome/quick-start/",
            "https://go.dev/doc/security/vuln/"
          ]
        },
        {
          "job": "Durable work",
          "default": "Delegate long jobs to a service; persist its job ID",
          "alternatives": [
            "River-backed Go service"
          ],
          "reason": "Work survives the terminal process only through an explicit durable owner.",
          "limits": "A goroutine or TUI background command dies with the process; reconnection needs a stable job identity.",
          "source_urls": [
            "https://riverqueue.com/docs/transactional-enqueueing",
            "https://github.com/charmbracelet/bubbletea"
          ]
        },
        {
          "job": "Distribution",
          "default": "GoReleaser",
          "alternatives": [
            "Manual go build for one internal target"
          ],
          "reason": "Target builds and release artifact automation.",
          "limits": "Review generated release actions, supported targets, signing and updater policy. cgo can complicate cross-building.",
          "source_urls": [
            "https://goreleaser.com/getting-started/quick-start/"
          ]
        },
        {
          "job": "Machine-readable output",
          "default": "encoding/json/v2 on a supporting pinned Go toolchain",
          "alternatives": [
            "encoding/json for established output contracts or older supported toolchains"
          ],
          "reason": "Stable JSON output lets scripts consume commands without parsing terminal text",
          "limits": "Add an explicit --json/output mode and document schema/exit codes; reserve stdout for results, stderr for diagnostics, and disable interactive/color output for pipelines. Confirm API availability on the pinned Go version; v2 changes encoding/decoding defaults, so test schema/null/omission compatibility before migrating.",
          "source_urls": [
            "https://pkg.go.dev/encoding/json",
            "https://pkg.go.dev/encoding/json/v2"
          ]
        },
        {
          "job": "Cancellation and shutdown",
          "default": "signal.NotifyContext",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "User interrupts should cancel outbound work and leave terminal/files usable",
          "limits": "Propagate cancellation through work; bound cleanup time and test interrupts during writes. Avoid adding an async runtime to a synchronous Rust CLI solely for signals.",
          "source_urls": [
            "https://pkg.go.dev/os/signal"
          ]
        }
      ],
      "setup_steps": [
        "Start in a source checkout; go mod init example.com/tool using its intended module path.",
        "Run go get github.com/spf13/cobra; resolve a supported Bubble Tea release only if a TUI is required.",
        "Build cmd/tool with injectable I/O, configuration validation, stable exit codes and explicit noninteractive behavior.",
        "Write command tests covering malformed input, stdout/stderr, cancellation and safe retries; use isolated temporary paths.",
        "Run goreleaser init, then review and pin the generated configuration and target matrix. No setup or publishing has been executed."
      ],
      "verification_commands": [
        "gofmt -l .",
        "go test ./...",
        "go test -race ./...",
        "go vet ./...",
        "govulncheck ./...",
        "go build ./cmd/tool",
        "goreleaser check",
        "goreleaser build --snapshot --clean"
      ],
      "evidence_status": "documentation-reviewed",
      "sources": [
        {
          "url": "https://github.com/spf13/cobra",
          "title": "Cobra",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/charmbracelet/bubbletea",
          "title": "Bubble Tea",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/flag",
          "title": "Go flag",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/net/http",
          "title": "Go net/http",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/os",
          "title": "Go os configuration primitives",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/log/slog",
          "title": "Go structured logging",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/testing",
          "title": "Go testing",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://go.dev/doc/articles/race_detector",
          "title": "Go data race detector",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://golangci-lint.run/docs/welcome/quick-start/",
          "title": "golangci-lint quick start",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://go.dev/doc/security/vuln/",
          "title": "Go vulnerability management",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://riverqueue.com/docs/transactional-enqueueing",
          "title": "River transactional enqueueing",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://goreleaser.com/getting-started/quick-start/",
          "title": "GoReleaser quick start",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/encoding/json",
          "title": "Go JSON API",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/os/signal",
          "title": "Go signal API",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pkg.go.dev/encoding/json/v2",
          "title": "Go JSON v2",
          "checked_date": "2026-10-10"
        }
      ],
      "open_questions": [
        "Which OS/architectures and terminals must be supported?",
        "What stable exit codes, JSON schema, configuration precedence and noninteractive behavior are required?",
        "Which signing, package managers and update mechanism will own distribution?"
      ],
      "title": "Go CLI + TUI",
      "language": "Go",
      "group": "Tools & automation",
      "kind": [
        "cli"
      ],
      "ui": "terminal",
      "host": "binary",
      "summary": "Command-line applications and terminal interfaces distributed as binaries.",
      "shape": "Cobra · Bubble Tea when needed · GoReleaser",
      "tradeoff": "Test every target platform; interactive terminals and redirected output have different needs.",
      "research_file": "go-rust.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Keep command parsing separate from domain operations. Test help, exit codes, stdout and stderr.",
        "Respect cancellation, timeouts and non-interactive input; do not require a TUI for scripting.",
        "Skip persistence for stateless tools. Delegate long-lived work to a service with a durable job ID.",
        "Verify release binaries on each supported OS and architecture, including the required runtime dependencies."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://go.dev/doc/tutorial/create-module",
          "https://github.com/spf13/cobra"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/go-cli/",
      "markdown_url": "/stacks/go-cli/guide.md",
      "json_url": "/stacks/go-cli/record.json",
      "architecture_and_migration": {
        "id": "go-cli",
        "version_scope": "Go 1.27 toolchain documentation, Cobra/pflag current guide, Bubble Tea upstream API and GoReleaser v2 documentation. Pin compatible module/tool versions; Bubble Tea major/module-path changes need explicit review. No release matrix was built.",
        "operating_model": "Recommendation: keep the command tree as an adapter over testable application functions. A noninteractive command is a versioned automation interface; a Bubble Tea view is an optional interactive client of the same functions. The executable owns stream, exit-status, cancellation and configuration contracts.",
        "architecture": [
          "Recommendation: Cobra parses and validates arguments, then RunE calls domain operations that return typed results/errors. Formatters own text versus JSON output; diagnostics and progress go to stderr, leaving stdout usable by scripts.",
          "Recommendation: expose a schema/version field in machine-readable output and configuration. Centralize environment/flag/file precedence and secret redaction; preserve old names through an explicit deprecation period.",
          "Recommendation: use Bubble Tea Model/Update/View and commands for terminal interaction. Keep interactive state separate from persisted application configuration, and disable prompts/spinners for pipes or explicit noninteractive mode.",
          "Recommendation: use the established module workflow and GoReleaser target matrix for binary distribution. Native libraries, signing, notarization and OS behavior require per-target checks even when cross-compilation succeeds."
        ],
        "developer_workflow": [
          "Recommendation: inspect existing flags, help output, scripts and configuration before changing the CLI. A new project can start with go mod init and Cobra CLI generation when desired; generation is optional, not an architecture.",
          "Recommendation: run gofmt, go vet ./... and go test ./...; add subprocess-level contract fixtures that capture stdout, stderr and exit status. Domain unit tests alone miss terminal and shell behavior.",
          "Recommendation: exercise --help, invalid flags, piped input, --output json (if implemented), interrupted work and no-TTY execution. Choose and document application exit codes; Cobra does not define every business error code.",
          "Recommendation: after installing a pinned GoReleaser v2, review .goreleaser.yaml, run goreleaser check and goreleaser release --snapshot --clean to prepare local artifacts. These are review commands, not a published release; verify clean-machine install and upgrade on the supported targets. Current GoReleaser OSS installation docs require Go 1.27 when installing the tool from source; a prebuilt tool or a compatible pinned older tool is a separate choice from the application minimum Go version."
        ],
        "avoid": [
          "Avoid logging or progress bars on machine-readable stdout; one extra line can break the calling script.",
          "Avoid os.Exit inside domain functions or cleanup scopes: os.Exit skips deferred calls. Map errors to a code after cleanup in the entry point.",
          "Avoid requiring a TTY for every command; automation needs explicit inputs and a prompt-free path.",
          "Avoid rewriting configuration in place without a version/backup; users may need to downgrade the executable.",
          "Avoid silently switching encoding/json to Go 1.27 encoding/json/v2 during a rewrite; changed serialization defaults require compatibility fixtures and an explicit protocol decision."
        ],
        "transitions": [
          {
            "capability": "cli",
            "existing_contract": "Capture scripts consuming current flags, positional arguments, stdout/stderr, exit codes and completion output.",
            "coexistence": "Recommendation: retain old subcommands/aliases as thin adapters while introducing an explicit JSON mode. Mark renamed flags deprecated through Cobra instead of silently changing their meaning.",
            "target": "Recommendation: Cobra RunE plus centralized result/error mapping; versioned JSON on stdout and diagnostics on stderr. Freeze documented application codes for success, usage and operational failure.",
            "benefits": [
              {
                "benefit": "A stable CLI protocol permits automation and humans to share one executable.",
                "prerequisites": "Consumer fixtures cover streams/status; formatting and error categories are explicit; deprecation schedule preserves callers.",
                "tradeoffs": "Versioned output requires ongoing compatibility ownership; usage errors and remote failures may need different handling."
              }
            ],
            "checks": [
              "Run old calling scripts against the new binary and compare all three output channels.",
              "Verify invalid flags perform no effects and produce the documented exit code.",
              "Pipe JSON to a parser; help/progress/logging must not contaminate its data."
            ],
            "rollback": "Recommendation: install the preceding binary and continue serving the old protocol. Keep newly introduced machine schemas behind explicit versions so callers can choose a compatible response.",
            "sources": [
              "https://cobra.dev/docs/how-to-guides/working-with-flags/",
              "https://pkg.go.dev/encoding/json#Decoder.DisallowUnknownFields",
              "https://pkg.go.dev/os#Exit"
            ],
            "id": "cli-1"
          },
          {
            "capability": "data",
            "existing_contract": "Inventory config paths, default values, flag/environment precedence, secret fields and old readers.",
            "coexistence": "Recommendation: parse both old and versioned schemas through adapters; display migration diagnostics on stderr and offer an explicit migration command with backup. Keep the old file untouched until conversion passes.",
            "target": "Recommendation: a typed versioned config decoded deliberately, with unknown-field policy and semantic validation. Write a same-directory temporary file, validate it and replace only after success; qualify filesystem/OS behavior and cross-process ownership.",
            "benefits": [
              {
                "benefit": "A versioned configuration contract makes upgrades and later rollback predictable.",
                "prerequisites": "Old fixtures exist; migration preserves semantics and backups; one writer and tested replacement behavior are defined.",
                "tradeoffs": "Strict unknown-field rejection can hinder mixed-version use; atomic replacement does not establish crash durability or coordinate concurrent writers."
              }
            ],
            "checks": [
              "Load representative old config, migrate and compare effective settings.",
              "Reject unknown unsupported schema versions before modifying files.",
              "Interrupt conversion and verify either the original or complete new file remains; test permissions on each target OS."
            ],
            "rollback": "Recommendation: restore the backup and preceding executable together. Preserve old readable configuration throughout the downgrade window; do not roll back after newer-only values without an explicit mapping.",
            "sources": [
              "https://pkg.go.dev/encoding/json#Decoder.DisallowUnknownFields",
              "https://cobra.dev/docs/how-to-guides/working-with-flags/"
            ],
            "id": "data-1"
          },
          {
            "capability": "jobs",
            "existing_contract": "Preserve per-item effects, retry decisions, ordering and interrupt behavior for batch commands; a process-local queue has no restart history.",
            "coexistence": "Recommendation: keep the sequential executor available and compare the new bounded executor on fixture inputs. Route one operation class at a time; reuse stable operation IDs across retries.",
            "target": "Recommendation: signal.NotifyContext plus errgroup limit or a fixed worker pool. Pass context through clients, close resources after workers finish, and persist a checkpoint/receipt when interrupted effects need later recovery.",
            "benefits": [
              {
                "benefit": "Bounded fan-out can overlap independent I/O while maintaining a clear cancellation boundary.",
                "prerequisites": "Concurrency quota and total deadline are set; downstream calls honor cancellation; completed and ambiguous effects can be reconciled.",
                "tradeoffs": "No throughput gain is measured; cancellation cannot undo effects; a retry can duplicate a write without provider or business idempotency."
              }
            ],
            "checks": [
              "Interrupt midway through a batch and verify completed, pending and ambiguous items are reported separately.",
              "Simulate one failed item; verify the selected stop/continue policy and bounded parallelism.",
              "Resume using stable IDs and prove acknowledged effects are not repeated."
            ],
            "rollback": "Recommendation: return to sequential execution using the same checkpoint contract. Reconcile ambiguous outcomes first; restarting from item zero is not a safe general rollback.",
            "sources": [
              "https://pkg.go.dev/golang.org/x/sync/errgroup",
              "https://pkg.go.dev/os/signal#NotifyContext",
              "https://pkg.go.dev/os#Exit"
            ],
            "id": "jobs-1"
          },
          {
            "capability": "operations",
            "existing_contract": "Preserve command name, install path, OS/architecture support, update channel and downgrade compatibility.",
            "coexistence": "Recommendation: produce snapshot artifacts beside the old release and smoke-test them without changing the default download. Review generated package-manager changes and publish channels only after target verification.",
            "target": "Recommendation: pinned GoReleaser v2 matrix with metadata/checksums, OS-specific install tests and an explicit signing path. CGO dependencies and macOS signing/notarization need separate toolchain/credential setup; the documented native package notarization flow is Pro; qualify the chosen binary or package flow separately.",
            "benefits": [
              {
                "benefit": "A repeatable artifact matrix reduces manual release assembly.",
                "prerequisites": "Build inputs/tool versions are pinned; each promised target is installed and exercised; signing credentials and package metadata are owned.",
                "tradeoffs": "Cross-compilation is not execution evidence; CGO can require native toolchains; selected signing/notarization automation may require a paid tier."
              }
            ],
            "checks": [
              "Install on clean Linux, macOS and Windows hosts for every advertised architecture.",
              "Verify version metadata, checksums, permissions and executable path.",
              "Upgrade from the old package and downgrade with preserved config; inspect macOS Gatekeeper behavior for the actual downloaded artifact."
            ],
            "rollback": "Recommendation: repoint the owned download/package channel to the previous verified release and keep its artifacts available. Restore compatible configuration with the binary; do not silently overwrite unrelated install locations.",
            "sources": [
              "https://goreleaser.com/getting-started/how-it-works/",
              "https://goreleaser.com/customization/builds/go/",
              "https://goreleaser.com/customization/sign/notarize/",
              "https://goreleaser.com/customization/publish/snapshots/"
            ],
            "id": "operations-1"
          }
        ],
        "sources": [
          {
            "url": "https://cobra.dev/docs/how-to-guides/working-with-flags/",
            "title": "Cobra flag guide",
            "claim": "Flag scoping, validation, deprecation and optional configuration integration are explicit."
          },
          {
            "url": "https://github.com/charmbracelet/bubbletea",
            "title": "Bubble Tea upstream",
            "claim": "The TUI uses Model/Update/View with commands for effects."
          },
          {
            "url": "https://pkg.go.dev/encoding/json#Decoder.DisallowUnknownFields",
            "title": "Go JSON decoder",
            "claim": "Typed decoding and DisallowUnknownFields are available; schema policy is the application responsibility."
          },
          {
            "url": "https://pkg.go.dev/os#Exit",
            "title": "os.Exit",
            "claim": "Process exit skips deferred calls; exit-code meanings need an application contract."
          },
          {
            "url": "https://pkg.go.dev/golang.org/x/sync/errgroup",
            "title": "errgroup",
            "claim": "Group limit and cancellation support bounded batch execution."
          },
          {
            "url": "https://pkg.go.dev/os/signal#NotifyContext",
            "title": "os/signal",
            "claim": "NotifyContext exposes signal cancellation."
          },
          {
            "url": "https://goreleaser.com/getting-started/how-it-works/",
            "title": "GoReleaser workflow",
            "claim": "Release configuration and build/package/publish workflow are described; snapshot behavior has its own source."
          },
          {
            "url": "https://goreleaser.com/customization/builds/go/",
            "title": "GoReleaser Go builds",
            "claim": "GOOS/GOARCH matrix and environment/CGO settings are configurable."
          },
          {
            "url": "https://goreleaser.com/customization/sign/notarize/",
            "title": "GoReleaser notarization",
            "claim": "Signing/notarization requires Apple credentials; the native package flow is Pro and uses Apple tools. Cross-platform binary notarization is a separate documented flow."
          },
          {
            "url": "https://goreleaser.com/customization/publish/snapshots/",
            "title": "GoReleaser snapshots",
            "claim": "Snapshot mode builds review artifacts without publishing to a release channel."
          },
          {
            "url": "https://goreleaser.com/getting-started/quick-start/",
            "title": "GoReleaser quick start",
            "claim": "goreleaser check validates config; release --snapshot --clean builds local review artifacts."
          },
          {
            "url": "https://goreleaser.com/getting-started/install/oss/",
            "title": "GoReleaser OSS installation",
            "claim": "Current source installation requires Go 1.27; verified prebuilt binaries are another documented installation method."
          },
          {
            "url": "https://go.dev/doc/go1.27",
            "title": "Go 1.27 release notes",
            "claim": "Introduces encoding/json/v2 with changed defaults; serializer replacement requires compatibility review."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": false,
        "static_hosting": false,
        "offline_client_candidate": false
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    },
    {
      "id": "rust-cli",
      "name": "Rust CLI/TUI: clap + Ratatui + dist",
      "use_cases": [
        "Fast native developer tools",
        "parsers and analyzers",
        "shipped terminal applications"
      ],
      "choose_when": [
        "Need native performance or reuse of Rust libraries",
        "Want ownership/type checks around complex transformations"
      ],
      "avoid_when": [
        "Disposable automation would be simpler in Python or shell",
        "Build latency and cross-toolchains outweigh runtime needs"
      ],
      "tools": [
        {
          "job": "Command parsing",
          "default": "clap",
          "alternatives": [
            "A simple std::env argument parser for tiny internal tools"
          ],
          "reason": "Typed commands plus a mature terminal widget/rendering ecosystem.",
          "limits": "Keep domain code separate from rendering and support non-TTY output; restore terminal on errors and interruption.",
          "source_urls": [
            "https://docs.rs/clap/latest/clap/",
            "https://ratatui.rs/"
          ]
        },
        {
          "job": "Terminal UI",
          "default": "Ratatui only for interactive screens",
          "alternatives": [
            "Line-oriented output when no interactive screen is needed"
          ],
          "reason": "Typed commands plus a mature terminal widget/rendering ecosystem.",
          "limits": "Keep domain code separate from rendering and support non-TTY output; restore terminal on errors and interruption.",
          "source_urls": [
            "https://docs.rs/clap/latest/clap/",
            "https://ratatui.rs/"
          ]
        },
        {
          "job": "HTTP client",
          "default": "reqwest",
          "alternatives": [
            "No network dependency for offline tools"
          ],
          "reason": "Reusable typed HTTP client APIs.",
          "limits": "Choose blocking or async deliberately; configure timeouts, TLS and response bounds. Never call blocking client inside an async runtime indiscriminately.",
          "source_urls": [
            "https://docs.rs/reqwest/latest/reqwest/"
          ]
        },
        {
          "job": "Persistence and migrations",
          "default": "None for stateless tools",
          "alternatives": [
            "SQLx with SQLite when local relational state is a real requirement"
          ],
          "reason": "Start without a database; add schema ownership only for persistent products.",
          "limits": "SQLite feature/driver and migration setup require target testing; durable local state is not shared distributed workflow state.",
          "source_urls": [
            "https://docs.rs/sqlx/latest/sqlx/",
            "https://github.com/transact-rs/sqlx/blob/main/sqlx-cli/README.md"
          ]
        },
        {
          "job": "Configuration",
          "default": "Serde-backed settings + config",
          "alternatives": [
            "std::env for a small fixed settings set"
          ],
          "reason": "Typed settings plus structured events/spans.",
          "limits": "Set precedence explicitly; validate semantics; install a tracing subscriber; never log secrets.",
          "source_urls": [
            "https://docs.rs/config/latest/config/",
            "https://doc.rust-lang.org/std/env/fn.var.html",
            "https://docs.rs/tracing/latest/tracing/"
          ]
        },
        {
          "job": "Application logging",
          "default": "tracing + configured subscriber",
          "alternatives": [],
          "reason": "Typed settings plus structured events/spans.",
          "limits": "Set precedence explicitly; validate semantics; install a tracing subscriber; never log secrets.",
          "source_urls": [
            "https://docs.rs/config/latest/config/",
            "https://doc.rust-lang.org/std/env/fn.var.html",
            "https://docs.rs/tracing/latest/tracing/"
          ]
        },
        {
          "job": "Tests and static checks",
          "default": "cargo test; rustfmt; Clippy; cargo audit",
          "alternatives": [],
          "reason": "Compiler, style, behavior and known-advisory checks complement each other.",
          "limits": "Audit coverage is advisory-driven; compile success does not establish behavior or security. Test supported feature combinations rather than blindly enabling incompatible features.",
          "source_urls": [
            "https://doc.rust-lang.org/cargo/commands/cargo-test.html",
            "https://github.com/rust-lang/rustfmt",
            "https://doc.rust-lang.org/clippy/usage.html",
            "https://rustsec.org/",
            "https://docs.rs/assert_cmd/latest/assert_cmd/"
          ]
        },
        {
          "job": "Executable behavior tests",
          "default": "assert_cmd",
          "alternatives": [
            "clap-linked snapshot tools for stable help output"
          ],
          "reason": "Tests real exit codes, stdout/stderr and command contracts.",
          "limits": "Snapshot changes need review; also test actual error and side-effect behavior.",
          "source_urls": [
            "https://docs.rs/assert_cmd/latest/assert_cmd/",
            "https://docs.rs/clap/latest/clap/"
          ]
        },
        {
          "job": "Durable work",
          "default": "Delegate to a durable service; retain resumable job identity",
          "alternatives": [
            "Local checkpoints for explicitly local resumable work"
          ],
          "reason": "CLI lifetime does not own remote work lifetime.",
          "limits": "Checkpoint schema, atomic persistence and external idempotency must be designed; async execution alone adds no durability.",
          "source_urls": [
            "https://docs.rs/restate-sdk/latest/restate_sdk/"
          ]
        },
        {
          "job": "Distribution",
          "default": "dist (formerly cargo-dist) + Cargo release builds",
          "alternatives": [
            "Manual artifacts for one internal target"
          ],
          "reason": "Generates multi-platform release pipelines and installers.",
          "limits": "Review generated CI before tags can publish; test installers and target-native dependencies. Signing and notarization are separate platform work.",
          "source_urls": [
            "https://github.com/axodotdev/cargo-dist",
            "https://doc.rust-lang.org/cargo/commands/cargo-build.html"
          ]
        },
        {
          "job": "Machine-readable output",
          "default": "serde_json",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Stable JSON output lets scripts consume commands without parsing terminal text",
          "limits": "Add an explicit --json/output mode and document schema/exit codes; reserve stdout for results, stderr for diagnostics, and disable interactive/color output for pipelines.",
          "source_urls": [
            "https://docs.rs/serde_json/latest/serde_json/"
          ]
        },
        {
          "job": "Cancellation and shutdown",
          "default": "Tokio signal handling for async commands",
          "alternatives": [
            "Existing synchronous shutdown strategy in synchronous Rust tools"
          ],
          "reason": "User interrupts should cancel outbound work and leave terminal/files usable",
          "limits": "Propagate cancellation through work; bound cleanup time and test interrupts during writes. Avoid adding an async runtime to a synchronous Rust CLI solely for signals.",
          "source_urls": [
            "https://docs.rs/tokio/latest/tokio/signal/index.html"
          ]
        }
      ],
      "setup_steps": [
        "Create source in a local development workspace with cargo new tool; enter tool; run cargo add clap --features derive.",
        "Resolve Ratatui and its supported terminal backend only if interactive rendering is required; add reqwest only if network access is needed.",
        "Implement typed commands, injected/configured settings, stable output/exit codes and domain logic independent of terminal rendering.",
        "Add tests with cargo add --dev assert_cmd; cover missing files, invalid input, stdin, cancellation, stdout/stderr and terminal cleanup.",
        "Install a selected dist release and run dist init; review target list and generated CI. Lock dependencies/toolchain; no release tags or publication were executed."
      ],
      "verification_commands": [
        "cargo fmt --all -- --check",
        "cargo clippy --workspace --all-targets --locked -- -D warnings",
        "cargo test --workspace --locked",
        "cargo audit",
        "cargo build --release --locked"
      ],
      "evidence_status": "documentation-reviewed",
      "sources": [
        {
          "url": "https://docs.rs/clap/latest/clap/",
          "title": "clap",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://ratatui.rs/",
          "title": "Ratatui",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/reqwest/latest/reqwest/",
          "title": "reqwest",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/sqlx/latest/sqlx/",
          "title": "SQLx",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/transact-rs/sqlx/blob/main/sqlx-cli/README.md",
          "title": "SQLx CLI",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/config/latest/config/",
          "title": "Rust config crate",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://doc.rust-lang.org/std/env/fn.var.html",
          "title": "Rust environment variables",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/tracing/latest/tracing/",
          "title": "Rust tracing",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://doc.rust-lang.org/cargo/commands/cargo-test.html",
          "title": "Cargo test",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/rust-lang/rustfmt",
          "title": "rustfmt",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://doc.rust-lang.org/clippy/usage.html",
          "title": "Clippy usage",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://rustsec.org/",
          "title": "RustSec",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/assert_cmd/latest/assert_cmd/",
          "title": "assert_cmd",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/restate-sdk/latest/restate_sdk/",
          "title": "Restate Rust SDK",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/axodotdev/cargo-dist",
          "title": "dist binary distribution",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://doc.rust-lang.org/cargo/commands/cargo-build.html",
          "title": "Cargo build",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/serde_json/latest/serde_json/",
          "title": "Rust JSON API",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.rs/tokio/latest/tokio/signal/index.html",
          "title": "Rust signal API",
          "checked_date": "2026-10-10"
        }
      ],
      "open_questions": [
        "Which terminals, non-TTY consumers and OS/architectures must be supported?",
        "What output schema, cancellation and configuration precedence will consumers rely on?",
        "Which native dependencies, signing/notarization and update channels are required?"
      ],
      "title": "Rust CLI + TUI",
      "language": "Rust",
      "group": "Tools & automation",
      "kind": [
        "cli"
      ],
      "ui": "terminal",
      "host": "binary",
      "summary": "Portable command-line tools with explicit memory and resource control.",
      "shape": "Clap · Ratatui when needed · Cargo",
      "tradeoff": "Cross-compilation and native dependencies still need target-specific qualification.",
      "research_file": "go-rust.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Keep parsing separate from domain behavior. Test malformed input, pipes, errors and exit codes.",
        "Use interactive UI only when a terminal is available and the user has requested it.",
        "Bound resource use and retain error context rather than panicking on expected failures.",
        "Build with the committed lockfile and verify each supported release target."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://docs.rs/clap/latest/clap/",
          "https://ratatui.rs/"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/rust-cli/",
      "markdown_url": "/stacks/rust-cli/guide.md",
      "json_url": "/stacks/rust-cli/record.json",
      "architecture_and_migration": {
        "id": "rust-cli",
        "version_scope": "Reviewed clap 4.6.7 and Rust std 1.99.0 documentation; Serde, Ratatui and current axodotdev cargo-dist book. Pin rust-toolchain.toml/Cargo.lock and dist version/config. The older opensource.axo.dev book path failed; no target install or release workflow was executed.",
        "operating_model": "Recommendation: clap derives/parses a stable command interface, domain operations return Result, and the entry point converts errors to streams/status after cleanup. Serde owns a versioned machine format; Ratatui is an optional terminal client. Cargo/dist prepare artifacts for explicitly supported targets and update channels.",
        "architecture": [
          "Recommendation: use a library crate or modules for application operations and a thin binary adapter. Keep clap parsing errors separate from business errors; prefer explicit main ExitCode mapping when the contract requires more than generic failure.",
          "Recommendation: Serde input/output types carry schema versions. Separate strict user configuration from forward-compatible result reading; deny_unknown_fields is an intentional policy, not universal compatibility.",
          "Recommendation: encapsulate raw-mode/alternate-screen lifetime and restore the terminal on errors and panics. Share domain operations between Ratatui and a noninteractive JSON mode; interactive render state is not durable application state.",
          "Recommendation: bounded Rayon/Tokio work is selected by CPU versus I/O needs, with explicit cancellation and effect receipts. A compiled binary reduces interpreter deployment needs but does not remove database, TLS or platform dependencies."
        ],
        "developer_workflow": [
          "Recommendation: start from existing Cargo manifest, consumers and rust-toolchain.toml. For a new local package, cargo new tool and cargo add clap --features derive are optional initial steps; add serde --features derive and serde_json only when a machine/config format is required.",
          "Recommendation: cargo fmt --check, cargo clippy --all-targets -- -D warnings and cargo test --locked verify source checks in the selected feature matrix. Exercise subprocess stdout/stderr/status and panic/interrupt terminal restoration on supported OSs.",
          "Recommendation: cargo build --release --locked builds one selected target. Inspect its native/TLS dependencies and execute on clean target hosts; --target compilation alone does not qualify distribution.",
          "Recommendation: with a pinned dist tool, run dist init and review generated configuration/workflows before committing; init can overwrite manual workflow edits. dist plan --output-format=json previews artifact/announcement intent; actual target builds, installers and upgrade/downgrade checks remain required."
        ],
        "avoid": [
          "Avoid treating debug-formatted Result errors as a stable machine API; define error codes and schema deliberately.",
          "Avoid process::exit in cleanup-sensitive paths; terminal restoration and destructors need normal control flow.",
          "Avoid enabling raw terminal mode for piped/noninteractive invocations; they need predictable streams and no prompts.",
          "Avoid hand-editing generated dist workflows without recording how customization survives regeneration."
        ],
        "transitions": [
          {
            "capability": "cli",
            "existing_contract": "Record current commands, option defaults, exit codes, stdout/stderr, JSON field names and shell completions consumed by callers.",
            "coexistence": "Recommendation: keep an old command adapter and explicit schema version while migrating parsing to clap. Preserve old names/aliases and map new domain errors into the established protocol.",
            "target": "Recommendation: clap plus typed result/error JSON and main ExitCode mapping. clap usage failures use status 2 while help/version uses success; application failures need their own documented policy.",
            "benefits": [
              {
                "benefit": "Typed parsing and a stable output envelope make command automation explicit.",
                "prerequisites": "Contract fixtures cover old callers; result schemas and error/status mapping are versioned; help/completion behavior is checked.",
                "tradeoffs": "Parser defaults can change compatibility; numeric status meanings are not universal across platforms; Rust error types do not define the public protocol."
              }
            ],
            "checks": [
              "Verify help/version succeed and invalid arguments use the intended stream/code without effects.",
              "Execute legacy scripts and compare stdout/stderr/status exactly where promised.",
              "Validate empty, partial and failed JSON results against the advertised schema."
            ],
            "rollback": "Recommendation: return consumers to the previous binary/schema while retaining old option adapters. Keep version selection explicit so a rollback does not silently alter JSON meaning.",
            "sources": [
              "https://docs.rs/clap/latest/clap/",
              "https://docs.rs/clap/latest/clap/error/struct.Error.html",
              "https://doc.rust-lang.org/std/process/struct.ExitCode.html"
            ],
            "id": "cli-1"
          },
          {
            "capability": "data",
            "existing_contract": "Inventory configuration file locations, schema versions, defaults, permissions and old binaries' ability to read newer files.",
            "coexistence": "Recommendation: read old config into a versioned internal model and migrate only through an explicit command with backup. Keep concurrent writer ownership explicit; read-only startup must not silently rewrite files.",
            "target": "Recommendation: Serde-tagged/versioned configuration and documented unknown-field handling. Validate a temporary representation before replacing the live file; platform atomicity, permissions and crash behavior require implementation checks.",
            "benefits": [
              {
                "benefit": "Explicit config migration decouples executable upgrades from accidental data loss.",
                "prerequisites": "Old/new fixtures and semantic transforms exist; backup/restore works; unsupported versions fail before write.",
                "tradeoffs": "Strict Serde unknown-field rejection can prevent mixed-version use; deny_unknown_fields does not compose with flatten; replacing a file is not a complete durability protocol."
              }
            ],
            "checks": [
              "Load old config and compare effective settings after migration.",
              "Verify unsupported versions and malformed values leave the source unchanged.",
              "Downgrade the binary with its preserved config and confirm paths/permissions on each target OS."
            ],
            "rollback": "Recommendation: restore the preserved old config and binary as a pair. Reconcile new-only fields before using an old reader; avoid destructive in-place downgrade guesses.",
            "sources": [
              "https://serde.rs/container-attrs.html"
            ],
            "id": "data-1"
          },
          {
            "capability": "jobs",
            "existing_contract": "Preserve ordering, per-item effects, timeout and interrupt semantics for batch/network subcommands.",
            "coexistence": "Recommendation: retain sequential mode while qualifying bounded parallel work using dry-run/fixtures. Store item operation IDs and completion receipts before enabling resume against live systems.",
            "target": "Recommendation: a bounded executor selected for CPU or async I/O with cooperative stop, tracked joins and cleanup. Started blocking work needs its own stop protocol or process boundary; do not label a task timeout as effect cancellation.",
            "benefits": [
              {
                "benefit": "Bounded parallel execution can overlap independent work without unlimited task creation.",
                "prerequisites": "Independent item semantics; capacity/budget limits; stable effect IDs; tested cancellation and resume contract.",
                "tradeoffs": "Speed is unmeasured; running blocking tasks may continue; a cancelled remote write can have an ambiguous outcome."
              }
            ],
            "checks": [
              "Interrupt a batch and verify no new items start, joins are bounded and terminal state restores.",
              "Simulate a remote success with a lost acknowledgement; resume reconciles rather than duplicating the effect.",
              "Verify CPU tasks cannot starve I/O and the executor respects the declared capacity."
            ],
            "rollback": "Recommendation: use sequential mode with the same receipt format and reconcile unknown outcomes. A previous executable must be able to read checkpoint versions or an explicit converter is required.",
            "sources": [
              "https://tokio.rs/tokio/topics/shutdown",
              "https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html",
              "https://ratatui.rs/recipes/apps/panic-hooks/"
            ],
            "id": "jobs-1"
          },
          {
            "capability": "operations",
            "existing_contract": "Capture existing target triples, libc/native dependencies, install path, package metadata and update/downgrade contracts.",
            "coexistence": "Recommendation: prepare dist artifacts beside the previous release; review generated CI and installers, and use a prerelease or test channel for target qualification. Do not promise all platforms merely because dist generates a matrix.",
            "target": "Recommendation: pinned dist configuration and Cargo.lock with release artifacts/installers for exercised targets. Keep signing/attestation, system dependency baselines and update channel ownership explicit.",
            "benefits": [
              {
                "benefit": "Generated release plans coordinate binary artifacts and installers across targets.",
                "prerequisites": "dist version is pinned; generated workflow is reviewed; native dependencies and every advertised target are exercised.",
                "tradeoffs": "dist init may replace generated workflows; OS signing and Linux libc compatibility remain separate obligations; a plan is not build/publication evidence."
              }
            ],
            "checks": [
              "Inspect dist plan --output-format=json for expected target triples and artifact names.",
              "Install downloaded artifacts on clean target hosts, including the oldest promised Linux baseline.",
              "Exercise upgrade/downgrade, PATH behavior, checksum verification and preserved versioned config."
            ],
            "rollback": "Recommendation: restore the previous verified package/update channel and retain older installers/checksums. Review data/config compatibility before allowing downgrade; never change a public channel based only on a plan.",
            "sources": [
              "https://axodotdev.github.io/cargo-dist/book/workspaces/simple-guide.html",
              "https://axodotdev.github.io/cargo-dist/book/reference/config.html",
              "https://doc.rust-lang.org/cargo/commands/cargo-build.html"
            ],
            "id": "operations-1"
          }
        ],
        "sources": [
          {
            "url": "https://docs.rs/clap/latest/clap/",
            "title": "clap 4.6.7",
            "claim": "Parser/derive command definition supports a typed command boundary."
          },
          {
            "url": "https://docs.rs/clap/latest/clap/error/struct.Error.html",
            "title": "clap errors",
            "claim": "Usage errors generally print to stderr with code 2; help-like output uses stdout and success."
          },
          {
            "url": "https://doc.rust-lang.org/std/process/struct.ExitCode.html",
            "title": "Rust ExitCode",
            "claim": "ExitCode can be returned by main; arbitrary numeric code meanings are platform-specific."
          },
          {
            "url": "https://serde.rs/container-attrs.html",
            "title": "Serde container attributes",
            "claim": "deny_unknown_fields rejects unknown inputs and is incompatible with flatten; version policy is application-owned."
          },
          {
            "url": "https://ratatui.rs/recipes/apps/panic-hooks/",
            "title": "Ratatui panic hooks",
            "claim": "Terminal restoration must be arranged around error/panic paths."
          },
          {
            "url": "https://tokio.rs/tokio/topics/shutdown",
            "title": "Tokio shutdown",
            "claim": "Track/notify/await tasks for planned completion."
          },
          {
            "url": "https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html",
            "title": "Tokio blocking tasks",
            "claim": "Started blocking tasks cannot be aborted; capacity is a separate concern."
          },
          {
            "url": "https://axodotdev.github.io/cargo-dist/book/workspaces/simple-guide.html",
            "title": "dist simple application guide",
            "claim": "init generates config/workflows, can overwrite manual edits, and plan previews artifacts."
          },
          {
            "url": "https://axodotdev.github.io/cargo-dist/book/reference/config.html",
            "title": "dist configuration reference",
            "claim": "Targets, installers and CI/download/update settings are configured explicitly."
          },
          {
            "url": "https://doc.rust-lang.org/cargo/commands/cargo-build.html",
            "title": "Cargo build",
            "claim": "Locked and target-specific builds have defined semantics; build success is not target execution."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": false,
        "static_hosting": false,
        "offline_client_candidate": false
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    },
    {
      "id": "python-scripts-workers",
      "name": "Python scripts and AI workers",
      "use_cases": [
        "Reusable automation scripts",
        "Scheduled imports and transformations",
        "Model/tool orchestration workers"
      ],
      "choose_when": [
        "The deliverable is a bounded task or worker rather than a web product",
        "Python SDKs or data libraries materially simplify integrations"
      ],
      "avoid_when": [
        "A one-off script is being expanded into an undocumented product backend",
        "Hard real-time deadlines or a native deployment requirement dominate"
      ],
      "tools": [
        {
          "job": "Packaging and environments",
          "default": "uv + pyproject.toml + committed uv.lock",
          "alternatives": [
            "Preserve an existing maintained packaging workflow"
          ],
          "reason": "One project entry point for dependencies, Python selection, execution and reproducible sync.",
          "limits": "Pin a compatible Python minor and resolve actual package versions at implementation; do not hand-edit uv.lock. Keep environments and caches in a local development workspace.",
          "source_urls": [
            "https://docs.astral.sh/uv/guides/projects/"
          ]
        },
        {
          "job": "Lint and format",
          "default": "Ruff",
          "alternatives": [
            "Preserve existing configured formatter/linter"
          ],
          "reason": "Fast lint and formatting feedback with one configuration.",
          "limits": "Ruff does not replace static typing, tests, authorization checks or runtime validation.",
          "source_urls": [
            "https://docs.astral.sh/ruff/installation/"
          ]
        },
        {
          "job": "Static typing",
          "default": "mypy",
          "alternatives": [
            "ty after project-specific compatibility trial"
          ],
          "reason": "Explicit checks on application boundaries with a conservative established checker.",
          "limits": "Configure strictness and third-party stubs; unchecked Any and untyped functions reduce coverage. No checker performance comparison was run.",
          "source_urls": [
            "https://mypy.readthedocs.io/en/stable/getting_started.html",
            "https://docs.astral.sh/ty/type-checking/"
          ]
        },
        {
          "job": "Testing",
          "default": "pytest with deterministic fake external services and captured fixtures",
          "alternatives": [
            "Integration suites against sandbox services"
          ],
          "reason": "Fast repeatable tests can verify parsing, permissions and retry decisions.",
          "limits": "Add adversarial outputs and partial-failure cases for agents; do not confuse output snapshots with task success.",
          "source_urls": [
            "https://docs.pytest.org/en/stable/getting-started.html"
          ]
        },
        {
          "job": "Validation",
          "default": "Pydantic at configuration, tool-input and model-output boundaries",
          "alternatives": [
            "Standard-library dataclasses for trusted internal values"
          ],
          "reason": "Reject malformed external structures before effects.",
          "limits": "Define strictness intentionally; a validated plan still needs permission and domain checks.",
          "source_urls": [
            "https://pydantic.dev/docs/validation/latest/concepts/strict_mode/"
          ]
        },
        {
          "job": "External I/O",
          "default": "Provider-supported Python SDK or HTTPX with explicit timeouts and bounded concurrency",
          "alternatives": [
            "Standard-library clients for small dependency-free work"
          ],
          "reason": "Centralize transport settings, credentials and test seams.",
          "limits": "Configure total task deadlines as well as network inactivity timeouts; avoid retry storms and duplicated writes; redact credentials from logs.",
          "source_urls": [
            "https://www.python-httpx.org/advanced/timeouts/"
          ]
        },
        {
          "job": "Persistence and migrations",
          "default": "No database for stateless scripts; PostgreSQL + SQLAlchemy/Alembic for shared durable business state",
          "alternatives": [
            "SQLite for one-machine local state"
          ],
          "reason": "Avoid introducing infrastructure before state ownership requires it.",
          "limits": "Files need atomic writes/checkpoints; database state does not automatically resume execution. Review migrations and use task-local sessions.",
          "source_urls": [
            "https://docs.sqlalchemy.org/en/21/orm/session_basics.html",
            "https://alembic.sqlalchemy.org/en/latest/autogenerate.html"
          ]
        },
        {
          "job": "Auth and credentials",
          "default": "Scoped service credentials injected by the execution platform",
          "alternatives": [
            "Delegated user OAuth when required by the integration"
          ],
          "reason": "Workers generally need service authorization rather than user login UI.",
          "limits": "Credential storage/provider is deployment-specific and unselected; keep secrets out of source, fixtures, task payloads and output.",
          "source_urls": [
            "https://docs.astral.sh/uv/guides/integration/docker/",
            "https://www.python-httpx.org/advanced/timeouts/"
          ]
        },
        {
          "job": "Long-running durable agents",
          "default": "Temporal Python SDK when recovery across restarts is required",
          "alternatives": [
            "Celery for independent queued jobs; direct function for bounded work"
          ],
          "reason": "Persisted workflow orchestration and separate worker processes suit retries, pauses and human waits.",
          "limits": "Adds a service and operational cost. Keep external I/O in activities, make side effects idempotent, test replay and cancellation; no end-to-end integration was run.",
          "source_urls": [
            "https://docs.temporal.io/develop/python",
            "https://docs.celeryq.dev/en/stable/userguide/tasks.html"
          ]
        },
        {
          "job": "Execution and deployment",
          "default": "uv-managed package and explicit CLI entry point; separate managed worker process for persistent workers",
          "alternatives": [
            "uv script metadata for a small standalone file",
            "Scheduled container for bounded jobs"
          ],
          "reason": "Make inputs, exit codes and restart behavior reproducible.",
          "limits": "Scheduler/platform is unselected; document non-overlap and checkpoint semantics. Do not add a web server just to run a job.",
          "source_urls": [
            "https://docs.astral.sh/uv/guides/projects/",
            "https://docs.astral.sh/uv/guides/scripts/",
            "https://docs.astral.sh/uv/guides/integration/docker/"
          ]
        },
        {
          "job": "Application logging",
          "default": "Python logging with configured handlers",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Shared standard logging captures application and dependency diagnostics",
          "limits": "Configure logging at entry point, redact credentials and add request/job IDs, duration and failure context. Persist logs on the execution platform; metrics/tracing backend is a separate operational choice.",
          "source_urls": [
            "https://docs.python.org/3/library/logging.html"
          ]
        },
        {
          "job": "Bounded external-call retries",
          "default": "Tenacity only for retryable transient failures",
          "alternatives": [
            "Provider SDK retry policy when sufficient"
          ],
          "reason": "Explicit stop/wait/filter rules support controlled retries",
          "limits": "Install tenacity; set attempt/deadline limits, jitter and exception filters. The bare decorator retries forever without delay; do not stack retries with SDK/worker retries or repeat non-idempotent effects without keys.",
          "source_urls": [
            "https://tenacity.readthedocs.io/en/latest/"
          ]
        },
        {
          "job": "Object storage",
          "default": "Boto3 S3 client when durable objects are required",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Official SDK supports file transfer to S3",
          "limits": "Install boto3 only for S3-backed work; use platform credentials, private keys and bounded transfers. Boto3 is synchronous: keep blocking transfers out of an async event loop; verify alternative provider compatibility.",
          "source_urls": [
            "https://docs.aws.amazon.com/boto3/latest/guide/s3-uploading-files.html"
          ]
        },
        {
          "job": "HTTP timeouts",
          "default": "HTTPX client timeouts and connection limits",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Connect/read/write/pool deadlines prevent unbounded remote waits",
          "limits": "Configure shared client timeout and limits; retain overall operation deadline separately because read timeout measures inactivity between chunks. Close clients and redact request logs.",
          "source_urls": [
            "https://www.python-httpx.org/advanced/timeouts/"
          ]
        }
      ],
      "setup_steps": [
        "For maintained work, create a local source project: uv init worker-app; cd worker-app; select/pin compatible Python; uv add httpx pydantic pydantic-settings",
        "uv add --dev ruff mypy pytest; define an importable worker_app package and a pyproject.toml CLI entry point.",
        "Implement explicit inputs, a dry-run or fixture mode, bounded external calls, structured result/error output, and credentials injected by the environment.",
        "For a genuinely standalone file, the alternative is uv init --script task.py then uv add --script task.py httpx pydantic; run via uv run task.py. Promote reused logic into a package.",
        "Only when shared persistent state is required: add sqlalchemy, psycopg and alembic, then configure reviewed migrations. For durable orchestration: uv add temporalio and implement workflows/activities plus a worker connected to a separately provisioned Temporal service.",
        "Package the locked environment for the chosen scheduler or worker platform. Record startup, cancellation, retry, checkpoint and failure-resume behavior; verify fixture execution before live access."
      ],
      "verification_commands": [
        "uv sync --locked",
        "uv run ruff check .",
        "uv run ruff format --check .",
        "uv run mypy src",
        "uv run pytest",
        "uv run python -m compileall -q src"
      ],
      "open_questions": [
        "Which provider SDKs and minimum credential scopes are required?",
        "Are runs bounded, scheduled, queued or long-lived with human waits?",
        "Which effects are safe to retry, and what are run deadlines and cost budgets?",
        "Who owns execution history, alerts, secrets and recovery?"
      ],
      "evidence_status": "documentation-reviewed",
      "sources": [
        {
          "url": "https://docs.astral.sh/uv/guides/projects/",
          "title": "uv projects",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.astral.sh/ruff/installation/",
          "title": "Ruff installation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://mypy.readthedocs.io/en/stable/getting_started.html",
          "title": "mypy getting started",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.astral.sh/ty/type-checking/",
          "title": "ty type checking",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.pytest.org/en/stable/getting-started.html",
          "title": "pytest getting started",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://pydantic.dev/docs/validation/latest/concepts/strict_mode/",
          "title": "Pydantic strict mode",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://www.python-httpx.org/advanced/timeouts/",
          "title": "HTTPX timeouts",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.sqlalchemy.org/en/21/orm/session_basics.html",
          "title": "SQLAlchemy session basics",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://alembic.sqlalchemy.org/en/latest/autogenerate.html",
          "title": "Alembic autogeneration",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.astral.sh/uv/guides/integration/docker/",
          "title": "uv Docker",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.temporal.io/develop/python",
          "title": "Temporal Python SDK",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.celeryq.dev/en/stable/userguide/tasks.html",
          "title": "Celery tasks",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.astral.sh/uv/guides/scripts/",
          "title": "uv scripts",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.python.org/3/library/logging.html",
          "title": "Python logging",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://tenacity.readthedocs.io/en/latest/",
          "title": "Tenacity documentation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://docs.aws.amazon.com/boto3/latest/guide/s3-uploading-files.html",
          "title": "Boto3 uploads",
          "checked_date": "2026-10-10"
        }
      ],
      "title": "Python automation + AI",
      "language": "Python",
      "group": "Tools & automation",
      "kind": [
        "automation"
      ],
      "ui": "none",
      "host": "server",
      "summary": "Scripts, integrations and workers close to the Python data and AI ecosystem.",
      "shape": "uv · Pydantic · HTTPX / provider SDK · pytest",
      "tradeoff": "Persistent workers need an execution platform; model outputs and tool calls need validation.",
      "research_file": "python.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Use scoped credentials, explicit timeouts and bounded concurrency for external calls.",
        "Validate model outputs and tool inputs; keep approval boundaries separate from model reasoning.",
        "Test with deterministic fake services and recorded fixtures, including partial failure and replay.",
        "Use a durable workflow engine only when restart recovery is required; make external effects idempotent."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://docs.astral.sh/uv/guides/projects/",
          "https://docs.astral.sh/uv/guides/scripts/"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/python-scripts-workers/",
      "markdown_url": "/stacks/python-scripts-workers/guide.md",
      "json_url": "/stacks/python-scripts-workers/record.json",
      "architecture_and_migration": {
        "id": "python-scripts-workers",
        "version_scope": "Python APIs: TaskGroup/asyncio.timeout require 3.11+; inspected /3 docs currently show 3.15.0. Use a supported minor compatible with selected SDKs and lock it; this does not recommend blindly upgrading to 3.15. Reviewed uv current guides, HTTPX current guides, Celery 5.6.3 task docs and Temporal Python guides. Resolve actual SDK versions in uv.lock before qualification.",
        "operating_model": "Recommendation: a maintained package owns validated inputs, a run/effect ledger, a CLI result contract and a bounded execution loop. A short task may run directly under a scheduler; independent queued jobs fit Celery when broker semantics are qualified; long waits and restart recovery may justify Temporal workflows with external effects in Activities. A prompt, validated model output or log is not proof of a completed effect.",
        "architecture": [
          "Recommendation: separate parsing/validation, pure transformation, provider adapters and effects. Use deterministic fixtures/dry-run for decision logic, scoped injected credentials and stable operation IDs; do not place secrets or raw provider tokens in run payloads.",
          "Recommendation: reuse HTTPX clients with explicit connect/read/write/pool timeouts and connection limits; add a total task deadline and bounded TaskGroup/semaphore or worker-queue execution. Connection limits alone do not bound all queued coroutines.",
          "Recommendation: persist source cursor, input/schema version, effect intent and acknowledged result where restart matters. One-machine SQLite can own local state; shared workers need a chosen shared durable store and lease/ownership model. A checkpoint is not atomically committed with a remote email or payment.",
          "Recommendation: in Temporal, deterministic Workflow code orchestrates Activities, waits and retries; Activities perform provider calls and heartbeat progress. In Celery, configure acknowledgement/redelivery and retry policy to the task's replay semantics. Avoid layering unbounded SDK, decorator and worker retries."
        ],
        "developer_workflow": [
          "Recommendation: inspect existing scheduler, dependencies, input formats and receipts. For maintained local work, uv init --package worker-app creates a package; pin a supported Python minor, add SDK/validation dependencies and commit pyproject.toml plus uv.lock in the maintained source repository.",
          "Recommendation: uv sync --locked, uv run ruff check ., uv run mypy src and uv run pytest require the corresponding dev tools configured/installed. Add fixtures for malformed provider/model output, permission failures, partial effects, ambiguous acknowledgements and resume.",
          "Recommendation: define [project.scripts] for the package CLI and structured JSON results plus explicit success/usage/failure statuses. uv run --locked <entrypoint> uses the locked project; scheduler start, overlap policy, termination and resume command are deployment-owned choices.",
          "Recommendation: for durable orchestration, uv add temporalio and implement Workflow/Activity/Worker components connected to a separately operated Temporal service. Replay representative histories with temporalio.worker.Replayer before workflow changes; test Activity heartbeat/cancellation and time-skipping integration flows.",
          "Recommendation: use uv sync --locked --no-dev inside a reviewed container build, then record the actual entry point, writable state path, credential scopes and dependency/image pins. No scheduler, broker or Temporal integration was executed here."
        ],
        "avoid": [
          "Avoid resuming by rerunning every input: a crash after remote success before checkpoint creates ambiguous effects and needs reconciliation or a provider idempotency key.",
          "Avoid synchronous SDK calls in async execution; use a documented async client or bounded offload, with explicit cancellation limits.",
          "Avoid swallowing CancelledError in TaskGroup work; cooperative cancellation depends on it being propagated after cleanup.",
          "Avoid describing Celery late acknowledgement or a Temporal Workflow as exactly-once external effects. Application/provider idempotency remains necessary.",
          "Avoid importing time/random/network behavior into deterministic Temporal Workflow code; move external I/O into Activities and replay-test changes."
        ],
        "transitions": [
          {
            "capability": "cli",
            "existing_contract": "Capture old script arguments, environment/config precedence, file paths, exit codes and scheduler invocation behavior.",
            "coexistence": "Recommendation: retain the old script as a thin entry point into an importable package while callers transition. Introduce structured output/version fields and an explicit noninteractive/dry-run mode without changing live side effects.",
            "target": "Recommendation: uv package with pyproject.toml entry point, committed uv.lock and supported Python minor; JSON results on stdout, diagnostics on stderr, schema and status policy in the CLI documentation.",
            "benefits": [
              {
                "benefit": "An importable locked package makes repeated automation easier to test and invoke consistently.",
                "prerequisites": "Inputs/entry point/status are defined; compatible Python and SDKs are pinned; scheduler uses the same package build.",
                "tradeoffs": "A lockfile does not fix provider behavior or scheduler overlap; deploy-time environment/credentials remain required."
              }
            ],
            "checks": [
              "Run old scheduler command against the package adapter and compare input/output/status.",
              "Start from a clean locked environment and parse output without progress/log contamination.",
              "Verify dry-run performs zero provider writes and reports the intended actions."
            ],
            "rollback": "Recommendation: restore the previous package/environment and command while preserving versioned run/checkpoint files. Keep the old entry point until every scheduler/caller is migrated.",
            "sources": [
              "https://docs.astral.sh/uv/guides/projects/",
              "https://docs.astral.sh/uv/guides/integration/docker/"
            ],
            "id": "cli-1"
          },
          {
            "capability": "data",
            "existing_contract": "Identify source pagination/cursors, input revisions, item identifiers, partial outputs and acknowledged versus uncertain effects.",
            "coexistence": "Recommendation: introduce a run/effect ledger alongside the old logs and compare reconciliation in fixture mode. Keep one active execution owner; migrate old checkpoints with source-input/version provenance.",
            "target": "Recommendation: transactional SQLite checkpoint/receipt state for one host or an operated shared database for multiple workers. For exported files, validate temporary output then os.replace on the same filesystem; qualify sync/permissions separately.",
            "benefits": [
              {
                "benefit": "Durable progress records allow targeted restart and investigation instead of blind replay.",
                "prerequisites": "Stable item/effect IDs; checkpoint transactions; single writer or tested shared ownership; provider lookup/idempotency for uncertain effects.",
                "tradeoffs": "A file/database commit cannot atomically commit a remote side effect; os.replace atomicity does not establish power-loss durability or cross-filesystem replacement."
              }
            ],
            "checks": [
              "Crash before effect, after remote success and after checkpoint; verify each resume decision.",
              "Resume the same input and prove acknowledged effects are skipped or reconciled.",
              "Interrupt export and verify a complete prior/new artifact; restore ledger from backup and compare cursor ownership."
            ],
            "rollback": "Recommendation: keep the ledger readable by the previous worker or convert it explicitly. Reconcile ambiguous remote outcomes before replay; reverting code cannot unsend a message or reverse a provider write.",
            "sources": [
              "https://docs.python.org/3/library/sqlite3.html",
              "https://docs.python.org/3/library/os.html#os.replace"
            ],
            "id": "data-1"
          },
          {
            "capability": "operations",
            "existing_contract": "Preserve provider rate limits, retry budgets, total run deadline and cleanup/cancellation behavior; SDK inactivity timeout is not a whole-run deadline.",
            "coexistence": "Recommendation: retain sequential mode, add shared HTTPX clients and explicit capacity, and compare fixture results before enabling concurrency. Use a bounded queue for large inputs rather than creating one task for every item.",
            "target": "Recommendation: TaskGroup plus asyncio.timeout for operation lifetime, semaphore/worker limits for admission, HTTPX network timeouts and connection limits. Keep sync SDK work outside the event loop; cancellation of offloaded work needs a separate policy.",
            "benefits": [
              {
                "benefit": "Bounded concurrency and total deadlines prevent unlimited waiting work and reduce abandoned I/O.",
                "prerequisites": "Supported Python 3.11+; every provider adapter honors limits; aggregate retry budget and cancellation cleanup are configured.",
                "tradeoffs": "Read timeout measures inactivity between chunks; cancelling a coroutine does not prove a server write was cancelled; throughput gains are unmeasured."
              }
            ],
            "checks": [
              "Slow streaming chunks beyond the total deadline while below read timeout; the whole operation still stops.",
              "Overload input and verify active plus queued work remain bounded.",
              "Cancel one task during provider I/O; TaskGroup cleanup closes clients and reports any ambiguous write."
            ],
            "rollback": "Recommendation: return to sequential execution with the same receipt IDs and retry budget. Resolve uncertain effects from provider state before retrying; retain operation deadlines.",
            "sources": [
              "https://docs.python.org/3/library/asyncio-task.html",
              "https://docs.python.org/3/library/asyncio-sync.html",
              "https://www.python-httpx.org/advanced/timeouts/",
              "https://www.python-httpx.org/advanced/resource-limits/"
            ],
            "id": "operations-1"
          },
          {
            "capability": "jobs",
            "existing_contract": "Capture independent task payload versions, broker durability, acknowledgement timing, retries, dead-letter handling and scheduler overlap.",
            "coexistence": "Recommendation: keep the old scheduler for unconverted tasks while routing selected task kinds into a qualified Celery queue. One scheduler/consumer owns each kind, and old backlog states remain accounted for.",
            "target": "Recommendation: Celery for independent jobs, with idempotent task bodies, bounded worker concurrency, explicit retry/backoff and intentionally selected acknowledgement/worker-loss settings. Keep existing brokers when their guarantees satisfy the contract.",
            "benefits": [
              {
                "benefit": "A qualified queue permits independent worker restart and retry for bounded jobs.",
                "prerequisites": "Broker persistence/redelivery and payload mapping are tested; task effects are replay-safe; acknowledgement and worker-loss policy are deliberately configured.",
                "tradeoffs": "Late acknowledgement alone does not guarantee redelivery for every child-process termination; Celery worker settings and broker behavior matter; duplicate execution remains possible."
              }
            ],
            "checks": [
              "Terminate the worker during a task and verify actual redelivery for the selected settings.",
              "Lose acknowledgement after an external effect; retries must not duplicate the logical effect.",
              "Drain or transform ready/delayed/retry/failed work before retiring the old scheduler/consumer."
            ],
            "rollback": "Recommendation: stop new producers, retain compatible workers for accepted tasks, and reroute only reconciled unstarted work. A scheduler rollback must not create a second schedule for the same task kind.",
            "sources": [
              "https://docs.celeryq.dev/en/stable/userguide/tasks.html"
            ],
            "id": "jobs-1",
            "option_title": "Independent jobs with Celery"
          },
          {
            "capability": "jobs",
            "existing_contract": "Capture long-lived operation IDs, timer/human-wait behavior, provider effects and history/checkpoint schema before adopting durable orchestration.",
            "coexistence": "Recommendation: keep old workflows running under their existing owner; start only newly routed operation IDs in Temporal. Keep provider calls in Activities and preserve effect IDs across retries. Do not duplicate a live run as a shadow test.",
            "target": "Recommendation: Temporal Python Workflows/Activities with specified timeouts, heartbeats, replay tests and compatible worker deployments. Temporal service/visibility/history retention and operational ownership are prerequisites, not Python package installation side effects.",
            "benefits": [
              {
                "benefit": "Persisted workflow history can resume orchestration across worker restarts and represent long waits.",
                "prerequisites": "Temporal service and workers are operated; Workflow code is deterministic; Activity effects are idempotent/reconcilable; compatible histories pass replay.",
                "tradeoffs": "Adds a service and history/versioning obligations; Activity retries may repeat effects; orchestration recovery is not automatic compensation of external changes."
              }
            ],
            "checks": [
              "Replay representative open and completed histories after code changes; fail promotion on nondeterminism.",
              "Restart workers during timers and Activities; verify orchestration resumes and heartbeat/checkpoint behavior.",
              "Crash after provider success before Activity completion; retry reconciles the stable effect ID."
            ],
            "rollback": "Recommendation: stop routing new IDs to the new workflow version and keep compatible workers servicing existing histories. Replay-test the rollback code; if incompatible, complete/version old executions rather than abandoning their state.",
            "sources": [
              "https://docs.temporal.io/develop/python/workflows/basics",
              "https://docs.temporal.io/develop/python/activities/basics",
              "https://docs.temporal.io/develop/python/activities/timeouts",
              "https://docs.temporal.io/develop/python/best-practices/testing-suite",
              "https://docs.temporal.io/activity-definition"
            ],
            "id": "jobs-2",
            "option_title": "Recoverable multi-step workflows with Temporal"
          }
        ],
        "sources": [
          {
            "url": "https://docs.astral.sh/uv/guides/projects/",
            "title": "uv projects",
            "claim": "Project/package entry points, lockfile-based execution and dependency management are documented."
          },
          {
            "url": "https://docs.astral.sh/uv/guides/integration/docker/",
            "title": "uv Docker",
            "claim": "Locked/no-dev sync and build/runtime environment setup are explicit."
          },
          {
            "url": "https://docs.python.org/3/library/sqlite3.html",
            "title": "Python sqlite3",
            "claim": "Transactions and persisted local state are available; transaction control and concurrency need deliberate configuration."
          },
          {
            "url": "https://docs.python.org/3/library/os.html#os.replace",
            "title": "Python os.replace",
            "claim": "Replacement can be atomic on success and can fail across filesystems; sync/durability is separate."
          },
          {
            "url": "https://docs.python.org/3/library/asyncio-task.html",
            "title": "Python asyncio tasks",
            "claim": "TaskGroup/timeout require 3.11+ and use cancellation; swallowing cancellation breaks structured behavior."
          },
          {
            "url": "https://docs.python.org/3/library/asyncio-sync.html",
            "title": "Python asyncio synchronization",
            "claim": "Semaphore supports bounded task access and is not thread-safe."
          },
          {
            "url": "https://www.python-httpx.org/advanced/timeouts/",
            "title": "HTTPX timeouts",
            "claim": "Connect/read/write/pool timeouts are separate; read timeout concerns waiting for chunks."
          },
          {
            "url": "https://www.python-httpx.org/advanced/resource-limits/",
            "title": "HTTPX resource limits",
            "claim": "Connection and keepalive pool bounds are configurable."
          },
          {
            "url": "https://docs.celeryq.dev/en/stable/userguide/tasks.html",
            "title": "Celery 5.6.3 tasks",
            "claim": "Idempotency, acknowledgements, retries and worker-loss behavior need explicit policy; late ack has exceptions."
          },
          {
            "url": "https://docs.temporal.io/develop/python/workflows/basics",
            "title": "Temporal Python Workflow basics",
            "claim": "Workflow code must respect deterministic/replay constraints."
          },
          {
            "url": "https://docs.temporal.io/develop/python/activities/basics",
            "title": "Temporal Activity basics",
            "claim": "Activity definitions and worker registration place external work outside deterministic Workflow code; idempotency has a separate concept source."
          },
          {
            "url": "https://docs.temporal.io/develop/python/activities/timeouts",
            "title": "Temporal Activity timeouts",
            "claim": "Activity timeouts, retry policies and heartbeats support bounded/recoverable execution."
          },
          {
            "url": "https://docs.temporal.io/develop/python/best-practices/testing-suite",
            "title": "Temporal Python testing",
            "claim": "Replay checks history compatibility; Activity and time-skipping environments support recovery testing."
          },
          {
            "url": "https://docs.temporal.io/activity-definition",
            "title": "Temporal Activity idempotency",
            "claim": "Activities may execute more than once after an unreported completion; completed Activities are not rerun merely by Workflow replay. Provider idempotency keys are enforced by the called service."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": false,
        "static_hosting": false,
        "offline_client_candidate": false
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    },
    {
      "id": "swift-swiftui-ios",
      "name": "Native iOS: Swift + SwiftUI",
      "use_cases": [
        "iPhone and iPad products",
        "Native Apple integrations",
        "Accessible mobile clients for a shared service"
      ],
      "choose_when": [
        "Apple-native UI and platform capabilities are requirements",
        "A Mac/Xcode build environment and Apple distribution ownership are available"
      ],
      "avoid_when": [
        "The requirement is a single shared UI across iOS and Android",
        "There is no supported macOS/Xcode build environment"
      ],
      "tools": [
        {
          "job": "UI and state",
          "default": "SwiftUI + Observation; small @MainActor observable presentation models; explicit services",
          "alternatives": [
            "UIKit for unsupported UI or existing UIKit apps; ObservableObject for older deployment targets"
          ],
          "reason": "Native controls and platform conventions; keep domain and transport logic out of views",
          "limits": "SwiftUI/Observation availability must match the minimum OS; Observation is not persistence or automatic thread safety",
          "source_urls": [
            "https://developer.apple.com/swiftui/",
            "https://developer.apple.com/documentation/swiftui/model-data"
          ]
        },
        {
          "job": "Structured local persistence",
          "default": "SwiftData",
          "alternatives": [
            "Core Data for established stores or older targets; explicit SQLite for requirements SwiftData does not meet"
          ],
          "reason": "Framework-integrated models and persistence with a small dependency footprint",
          "limits": "Validate migrations, relationship behavior and deployment availability; local persistence does not implement cross-platform sync",
          "source_urls": [
            "https://developer.apple.com/documentation/swiftdata/modelcontext"
          ]
        },
        {
          "job": "Nonsecret preferences",
          "default": "UserDefaults",
          "alternatives": [
            "Existing explicit nonsecret preferences storage; structured databases have a separate persistence job"
          ],
          "reason": "Framework-integrated models and persistence with a small dependency footprint",
          "limits": "Validate migrations, relationship behavior and deployment availability; local persistence does not implement cross-platform sync",
          "source_urls": [
            "https://developer.apple.com/documentation/swiftdata/modelcontext"
          ]
        },
        {
          "job": "Networking and API contract",
          "default": "URLSession + Codable behind an injected API client",
          "alternatives": [
            "Generated Swift client from a versioned API contract when its generator is proven"
          ],
          "reason": "Native HTTP client and async APIs; share API schemas and fixtures with Android",
          "limits": "Check status codes, cancellation, timeouts and decoding; do not put provider secrets in the client; server owns authorization",
          "source_urls": [
            "https://developer.apple.com/documentation/foundation/urlsession"
          ]
        },
        {
          "job": "Concurrency and background work",
          "default": "Swift structured concurrency, cancellation and actor isolation; server for durable agent runs",
          "alternatives": [
            "BackgroundTasks or background URLSession for eligible OS-managed local work"
          ],
          "reason": "Keep rendering responsive and avoid tying durable business work to a view lifetime",
          "limits": "async does not mean CPU work runs off the main actor; OS may suspend apps and does not guarantee exact background scheduling",
          "source_urls": [
            "https://developer.apple.com/documentation/foundation/urlsession",
            "https://developer.apple.com/documentation/backgroundtasks"
          ]
        },
        {
          "job": "Credentials",
          "default": "Keychain for app credentials",
          "alternatives": [
            "In-memory credentials when persistence is unnecessary"
          ],
          "reason": "Use platform secret storage rather than preferences or database fields",
          "limits": "Define accessibility and logout/revocation behavior; backend service credentials never belong in app binaries",
          "source_urls": [
            "https://developer.apple.com/documentation/security/keychain-services"
          ]
        },
        {
          "job": "Unit and integration tests",
          "default": "Swift Testing for new domain/API tests; XCTest where needed",
          "alternatives": [
            "Keep established XCTest suites"
          ],
          "reason": "Test deterministic state transitions, fixtures, decoding, persistence and failures",
          "limits": "Do not mix Swift Testing and XCTest assertions inside a single test; simulator tests do not validate all hardware behavior",
          "source_urls": [
            "https://developer.apple.com/documentation/xcode/testing"
          ]
        },
        {
          "job": "UI and accessibility",
          "default": "XCTest/XCUIAutomation; per-screen accessibility audits; VoiceOver and Dynamic Type review",
          "alternatives": [
            "Accessibility Inspector for interactive audit"
          ],
          "reason": "Exercise navigation, permission states, keyboard/focus, screen-reader order and large text",
          "limits": "Automated audits cover the current screen and do not establish usability or complete accessibility; hardware checks remain necessary",
          "source_urls": [
            "https://developer.apple.com/documentation/xcode/testing",
            "https://developer.apple.com/documentation/accessibility/performing-accessibility-audits-for-your-app"
          ]
        },
        {
          "job": "Build, CI and distribution",
          "default": "Xcode + Swift Package Manager; xcodebuild on pinned macOS/Xcode CI; TestFlight before App Store",
          "alternatives": [
            "Xcode Cloud for managed Apple CI"
          ],
          "reason": "One reproducible toolchain, recorded test results, signed archives and beta verification",
          "limits": "Mac and compatible SDK/runtime required; signing team, bundle ID, profiles, capabilities, account access and store submission remain explicit handoffs; archive success is not publication",
          "source_urls": [
            "https://developer.apple.com/xcode-cloud/",
            "https://developer.apple.com/library/archive/technotes/tn2339/_index.html"
          ]
        },
        {
          "job": "Navigation",
          "default": "SwiftUI NavigationStack",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Platform navigation keeps back behavior and destinations in native UI",
          "limits": "Use on supported OS versions; keep route identities separate from loaded objects and test deep-link/session restoration. iOS 16+ availability requires a plan for older targets.",
          "source_urls": [
            "https://developer.apple.com/documentation/swiftui/navigationstack"
          ]
        },
        {
          "job": "Notifications",
          "default": "UserNotifications",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Native notifications support reminders with explicit user permission",
          "limits": "Request authorization in context, handle denied/revoked permission and validate notification routes. Remote delivery adds APNs/server setup; delivery timing is not a durable job guarantee.",
          "source_urls": [
            "https://developer.apple.com/documentation/usernotifications/asking-permission-to-use-notifications"
          ]
        },
        {
          "job": "Media selection",
          "default": "PhotosUI PhotosPicker",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Native picker lets users choose image/video assets",
          "limits": "iOS 16+; load selected representations with cancellation/error handling and bound file size before upload. Selection is not immediate local-file availability.",
          "source_urls": [
            "https://developer.apple.com/documentation/photosui/photospicker"
          ]
        }
      ],
      "setup_steps": [
        "Start in a source checkout in a local development workspace. Record minimum iOS/iPadOS versions, bundle ID, required capabilities, API schema and signing owner.",
        "Install a compatible stable Xcode and required simulator runtimes; finish Apple license/platform setup through the accountable operator. Record xcodebuild -version and selected developer directory.",
        "Create an iOS App in Xcode using Swift and SwiftUI, with unit and UI test targets. Share the scheme. Pin package resolution; use only dependencies justified by a requirement.",
        "Separate views, observable presentation state, repositories and API DTOs. Add migration fixtures and versioned network fixtures; use a fake API for tests.",
        "Run local simulator checks and CI using an actual destination ID. Then verify representative physical devices, offline/reconnect, permissions, VoiceOver and large text.",
        "Have the account owner establish team/bundle ID/capabilities and signing access. Produce a signed archive, verify a TestFlight install, then follow the authorized release workflow. Retain result bundles and release evidence."
      ],
      "verification_commands": [
        "xcodebuild -version",
        "xcode-select -p",
        "xcodebuild -list -project App.xcodeproj",
        "xcodebuild -showdestinations -project App.xcodeproj -scheme App",
        "xcodebuild -resolvePackageDependencies -project App.xcodeproj -scheme App",
        "xcodebuild test -project App.xcodeproj -scheme App -destination \"platform=iOS Simulator,id=<installed-simulator-UUID>\" -resultBundlePath <new-result-path>.xcresult",
        "xcodebuild archive -project App.xcodeproj -scheme App -destination \"generic/platform=iOS\" -archivePath <new-archive-path>.xcarchive",
        "xcodebuild -exportArchive -archivePath <archive-path>.xcarchive -exportPath <export-path> -exportOptionsPlist <reviewed-export-options>.plist"
      ],
      "evidence_status": "documentation-reviewed",
      "sources": [
        {
          "url": "https://developer.apple.com/swiftui/",
          "title": "SwiftUI",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.apple.com/documentation/swiftui/model-data",
          "title": "SwiftUI model data",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.apple.com/documentation/swiftdata/modelcontext",
          "title": "SwiftData ModelContext",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.apple.com/documentation/foundation/urlsession",
          "title": "URLSession",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.apple.com/documentation/xcode/testing",
          "title": "Testing with Xcode",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.apple.com/documentation/accessibility/performing-accessibility-audits-for-your-app",
          "title": "Performing accessibility audits",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.apple.com/xcode-cloud/",
          "title": "Xcode Cloud",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.apple.com/library/archive/technotes/tn2339/_index.html",
          "title": "Xcode command-line FAQ (archived; check local help)",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.apple.com/documentation/security/keychain-services",
          "title": "Keychain services",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.apple.com/documentation/backgroundtasks",
          "title": "Background Tasks",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.apple.com/documentation/swiftui/navigationstack",
          "title": "SwiftUI NavigationStack",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.apple.com/documentation/usernotifications/asking-permission-to-use-notifications",
          "title": "Apple notification permission",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.apple.com/documentation/photosui/photospicker",
          "title": "PhotosPicker",
          "checked_date": "2026-10-10"
        }
      ],
      "open_questions": [
        "What minimum OS versions, device matrix and Apple capabilities must be supported?",
        "Which offline/sync/conflict rules and API contract apply?",
        "Do notifications/media selection require permission-denied and degraded flows?",
        "Who owns bundle identity, signing and beta/release distribution?"
      ],
      "title": "Swift + SwiftUI",
      "language": "Swift",
      "group": "Native mobile",
      "kind": [
        "ios"
      ],
      "ui": "native",
      "host": "native",
      "summary": "Native iPhone and iPad apps using Apple's UI and platform APIs.",
      "shape": "SwiftUI · Swift concurrency · SwiftData · Xcode",
      "tradeoff": "Apple builds and distribution need macOS/Xcode; Android needs its own client.",
      "research_file": "native-mobile.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Keep presentation state small and actor-isolated; inject service and API boundaries for tests.",
        "Use structured concurrency with cancellation and store credentials in Keychain.",
        "Treat offline storage and synchronization as separate decisions, with explicit conflict handling.",
        "Check Dynamic Type, VoiceOver and real-device behavior; a simulator pass does not establish background or distribution behavior."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://developer.apple.com/documentation/swiftui",
          "https://developer.apple.com/tutorials/data/documentation/swiftui.json"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/swift-swiftui-ios/",
      "markdown_url": "/stacks/swift-swiftui-ios/guide.md",
      "json_url": "/stacks/swift-swiftui-ios/record.json",
      "architecture_and_migration": {
        "id": "swift-swiftui-ios",
        "version_scope": "Documentation reviewed 11 October 2026. SwiftUI Observation and SwiftData are iOS/iPadOS 17+; support older OS targets through compatible alternatives. Pin Xcode/SDK/Swift/package resolution and retain the minimum OS/device matrix. No simulator, archive or store-release check was executed.",
        "operating_model": "An installed iOS client persists across backend releases and is suspended or terminated under OS control. Recommendation: SwiftUI views render observable presentation state while repositories own URLSession DTOs and local persistence. Store rollout, API compatibility and local-store migration are separate adoption gates.",
        "architecture": [
          "Use SwiftUI state/Observation according to minimum OS availability; keep view rendering separate from asynchronous repositories and business decisions. Observation is UI dependency tracking, not disk persistence.",
          "Recommendation: version API DTOs separately from SwiftData/Core Data entities; preserve old installed-client contracts and authorize all privileged operations on the backend.",
          "Use a versioned local schema and reviewed migration plan for SwiftData. Recommendation: store unacknowledged user intents durably before claiming an offline write succeeded; reconcile conflicts with an explicit server policy.",
          "Separate foreground structured concurrency, OS-scheduled refresh/processing, background URLSession transfers and server durable jobs. Each has different completion and cancellation semantics.",
          "Recommendation: Keychain stores credential material; isolate account-local data and clear/lock the appropriate state on account switch. Keep backend provider secrets out of the app bundle."
        ],
        "developer_workflow": [
          "Start in the external Xcode source checkout. Read README, minimum OS, shared scheme, signing owner, capabilities, API fixtures and every persisted schema version.",
          "Record xcodebuild -version and xcode-select -p; use xcodebuild -list -project App.xcodeproj and xcodebuild -showdestinations -project App.xcodeproj -scheme App with the actual names. Resolve packages with xcodebuild -resolvePackageDependencies -project App.xcodeproj -scheme App. Check current flags with the pinned xcodebuild -help; the linked command-line FAQ is archived.",
          "After choosing an installed simulator UUID, run xcodebuild test -project App.xcodeproj -scheme App -destination 'platform=iOS Simulator,id=<UUID>' -resultBundlePath <new-path>.xcresult. Placeholders require substitution; simulator results do not establish device background behavior.",
          "Recommendation: use Instruments/network diagnostics, physical-device background checks, upgrade fixtures, VoiceOver and large text. Produce a signed archive/TestFlight update under the established release workflow; record exact old/new client builds and compatible backend revisions."
        ],
        "avoid": [
          "Assuming users update when the backend deploys strands old installed clients and offline requests.",
          "Assuming an older executable can read a migrated store confuses binary rollback with data rollback.",
          "Keeping pending offline writes only in view state loses work after suspension or termination.",
          "Using BGAppRefreshTask as an exact timer or unlimited durable worker ignores OS scheduling and expiration.",
          "Using phased release as install reversal overlooks manual downloads and devices already running the new version."
        ],
        "transitions": [
          {
            "capability": "client",
            "existing_contract": "Installed versions, minimum OS, URLSession DTOs/errors, deep links, auth expiry and old/offline writes.",
            "coexistence": "Recommendation: Ship additive backend responses and versioned fixtures before the new client; retain old contracts until measured adoption and an explicit support policy permit retirement.",
            "target": "Recommendation: Separate API DTOs from local models and use capability negotiation for optional features; authorization remains backend-owned.",
            "benefits": [
              {
                "benefit": "Independent backend/client deployment can preserve supported installations.",
                "prerequisites": "Inventory of real installed versions, API fixtures and release/support owners.",
                "tradeoffs": "Long-lived version support costs maintenance; a new store release cannot force immediate adoption."
              }
            ],
            "checks": [
              "Old and new builds run against the same new backend.",
              "Unknown optional fields and absent new fields do not break supported clients.",
              "A delayed old-client mutation receives the documented success/conflict/upgrade response."
            ],
            "rollback": "Disable the new server feature and retain both API contracts; already-installed clients require a compatible forward fix when needed.",
            "sources": [
              "https://developer.apple.com/documentation/foundation/urlsession",
              "https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases/"
            ],
            "id": "client-1"
          },
          {
            "capability": "data",
            "existing_contract": "Existing on-device store versions, entity meaning, relationships, pending local writes and upgrade paths.",
            "coexistence": "Recommendation: Add compatible fields/stages before removing representations; migration fixtures include every supported historical store and unacknowledged operations.",
            "target": "Recommendation: Use SwiftData VersionedSchema and SchemaMigrationPlan when OS support permits; preserve the established Core Data/store choice if migration value is unproven.",
            "benefits": [
              {
                "benefit": "An explicit schema history makes upgrade behavior inspectable.",
                "prerequisites": "Reviewed stages and fixtures proving values/relationships/pending writes survive.",
                "tradeoffs": "Forward migration does not establish older-binary readability; cross-store conversion is application work."
              }
            ],
            "checks": [
              "Open each supported old store with the new build and compare user data and pending operations.",
              "Interrupt migration and verify recovery behavior.",
              "Attempt the intended rollback build against the migrated fixture; reject release rollback if unreadable."
            ],
            "rollback": "Prefer a compatible forward repair if downgrade is unqualified. Restore a pre-upgrade copy only under a reconciled policy that does not erase later local writes.",
            "sources": [
              "https://developer.apple.com/documentation/swiftdata/schemamigrationplan",
              "https://developer.apple.com/documentation/swiftdata/versionedschema"
            ],
            "id": "data-1"
          },
          {
            "capability": "cache",
            "existing_contract": "Local reads, pending offline changes, tombstones/cursors and server conflict semantics.",
            "coexistence": "Recommendation: Keep the server as shared-domain reconciler; record each local mutation durably with a stable operation ID and schema version while old clients use the same conflict policy.",
            "target": "Recommendation: Use repository-owned local reads and a persistent operation log when offline writes are required; choose revision checks, merge or user resolution per domain instead of accidental timestamp wins.",
            "benefits": [
              {
                "benefit": "Users can retain local work through intermittent connectivity.",
                "prerequisites": "Durable local storage, replay-safe backend, explicit conflict/tombstone protocol.",
                "tradeoffs": "This is a proposed application design; SwiftData does not automatically provide arbitrary backend synchronization."
              }
            ],
            "checks": [
              "Two devices edit the same record offline; the declared policy preserves or exposes both intents.",
              "Disconnect after server commit but before acknowledgement; replay does not duplicate the effect.",
              "Restart/sign-out does not silently replay account A operations as account B."
            ],
            "rollback": "Stop the new synchronizer, retain pending operations and translate/reconcile them before returning to old logic; never clear the log as a rollback shortcut.",
            "sources": [
              "https://developer.apple.com/documentation/swiftdata/schemamigrationplan",
              "https://developer.apple.com/documentation/foundation/urlsession"
            ],
            "id": "cache-1"
          },
          {
            "capability": "jobs",
            "existing_contract": "Foreground task cancellation, pending intents and any existing background task identifiers/handlers.",
            "coexistence": "Recommendation: Retain old handler identifiers and persisted payload readers while new code is installed; use one owner per sync operation.",
            "target": "Recommendation: Choose BGAppRefreshTask/BGProcessingTask for eligible opportunistic device work, foreground tasks for interactive work and backend durable jobs for server completion obligations.",
            "benefits": [
              {
                "benefit": "Eligible refresh/maintenance can execute while the app is backgrounded.",
                "prerequisites": "Capabilities, registered handlers, durable checkpoints and expiration handling.",
                "tradeoffs": "The OS selects launch time; device scheduling does not satisfy a fixed backend completion SLA."
              }
            ],
            "checks": [
              "Expire a task midway; it checkpoints/cancels and marks completion correctly.",
              "Suspend/terminate/relaunch and resume without a duplicated business effect.",
              "Offline, battery and permission constraints show honest pending state."
            ],
            "rollback": "Disable new task submission while preserving payload readers/handlers long enough to reconcile pending work; continue foreground sync or a server job where appropriate.",
            "sources": [
              "https://developer.apple.com/documentation/backgroundtasks",
              "https://developer.apple.com/documentation/backgroundtasks/choosing-background-strategies-for-your-app"
            ],
            "id": "jobs-1"
          },
          {
            "capability": "files",
            "existing_contract": "Existing upload/download IDs, authorized object keys, file hashes, task identifiers and completion acknowledgements.",
            "coexistence": "Recommendation: Keep server upload endpoints/object ownership compatible; persist mapping from background task to logical operation and retain file-backed upload payloads.",
            "target": "Recommendation: Use an identified background URLSession for eligible HTTP(S) transfer; recreate it after system termination and move completed temporary downloads before delegate return.",
            "benefits": [
              {
                "benefit": "Transfers can continue during suspension without holding the app process.",
                "prerequisites": "Delegate lifecycle, stable session identifier, protected files and authorized retry/acknowledgement contract.",
                "tradeoffs": "Background uploads require files; scheduling is not exact and transfer completion differs from domain acceptance."
              }
            ],
            "checks": [
              "Suspend during upload/download and restore the same session after system termination.",
              "Verify file integrity and durable location after completion.",
              "Retry an ambiguous response without producing duplicate owned objects."
            ],
            "rollback": "Stop creating new transfers, inspect/cancel or finish existing tasks and reconcile server objects; keep session callbacks until all retained tasks are accounted for.",
            "sources": [
              "https://developer.apple.com/documentation/foundation/downloading-files-in-the-background"
            ],
            "id": "files-1"
          },
          {
            "capability": "operations",
            "existing_contract": "Store release ownership, supported devices, adoption, crash reports and persisted-data compatibility.",
            "coexistence": "Recommendation: Verify TestFlight install-over-existing fixtures; retain server compatibility through phased adoption and include manual downloads in risk assessment.",
            "target": "Recommendation: Use phased release with explicit crash/data-loss/compatibility stop criteria; assess adoption before retiring old API behavior.",
            "benefits": [
              {
                "benefit": "Gradual automatic-update distribution can limit initial exposure.",
                "prerequisites": "Signed reviewed build, live telemetry and a compatible recovery release.",
                "tradeoffs": "Apple's seven-day phases cover eligible automatic updates; anyone can manually download, and pausing does not reverse installs."
              }
            ],
            "checks": [
              "Verify real install/update preserves store, credentials and deep links.",
              "Track old/new build support and migration failures separately.",
              "Pause/recovery procedure leaves already-updated clients functional."
            ],
            "rollback": "Pause further distribution and disable affected server capabilities if safe; ship a compatible repair rather than assuming an installed-version/store downgrade.",
            "sources": [
              "https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases/"
            ],
            "id": "operations-1"
          }
        ],
        "sources": [
          {
            "url": "https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app",
            "title": "SwiftUI Managing Model Data",
            "claim": "Observation connects model changes to UI and requires iOS/iPadOS 17+; it is not local persistence."
          },
          {
            "url": "https://developer.apple.com/documentation/swiftdata/schemamigrationplan",
            "title": "SwiftData SchemaMigrationPlan",
            "claim": "Versioned schemas and migration stages explicitly model local schema evolution; iOS/iPadOS 17+."
          },
          {
            "url": "https://developer.apple.com/documentation/swiftdata/versionedschema",
            "title": "SwiftData VersionedSchema",
            "claim": "A schema records a particular version and its model set."
          },
          {
            "url": "https://developer.apple.com/documentation/foundation/urlsession",
            "title": "Foundation URLSession",
            "claim": "Configured sessions own data/upload/download/WebSocket tasks, authentication callbacks and asynchronous transfer behavior."
          },
          {
            "url": "https://developer.apple.com/documentation/backgroundtasks",
            "title": "Background Tasks",
            "claim": "Register and schedule task handlers for eligible background processing; the framework has multiple task types."
          },
          {
            "url": "https://developer.apple.com/documentation/backgroundtasks/choosing-background-strategies-for-your-app",
            "title": "Choosing Background Strategies",
            "claim": "Select task strategy by workload, handle expiration and completion; the OS decides refresh/processing launch time."
          },
          {
            "url": "https://developer.apple.com/documentation/foundation/downloading-files-in-the-background",
            "title": "Downloading Files in the Background",
            "claim": "Background sessions require delegates/stable identifiers, support file-backed uploads and need completion-file lifecycle handling."
          },
          {
            "url": "https://developer.apple.com/documentation/security/keychain-services",
            "title": "Keychain Services",
            "claim": "Encrypted Keychain items can store small credential secrets."
          },
          {
            "url": "https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases/",
            "title": "App Store Connect Phased Release",
            "claim": "Automatic updates progress over seven days; manual downloads remain possible and phases can be paused."
          },
          {
            "url": "https://developer.apple.com/documentation/xcode/testing",
            "title": "Xcode Testing",
            "claim": "Swift Testing and XCTest/UI tests have complementary roles; testing is separate from distribution."
          },
          {
            "url": "https://developer.apple.com/library/archive/technotes/tn2339/_index.html",
            "title": "Archived Xcode Command-line FAQ",
            "claim": "Documents command shapes for scheme/project/destination tests and archives; recheck options with the pinned Xcode toolchain."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": true,
        "static_hosting": false,
        "offline_client_candidate": true
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    },
    {
      "id": "kotlin-compose-android",
      "name": "Native Android: Kotlin + Jetpack Compose",
      "use_cases": [
        "Android phones, tablets and foldables",
        "Native Android integrations",
        "Accessible mobile clients for a shared service"
      ],
      "choose_when": [
        "Android-native UI and platform behavior are requirements",
        "The team can own an Android SDK, emulator/device and signed release pipeline"
      ],
      "avoid_when": [
        "The requirement is a single shared UI for Android and iOS",
        "No Android device or emulator verification can be performed"
      ],
      "tools": [
        {
          "job": "UI and state",
          "default": "Jetpack Compose + Material 3; screen ViewModels exposing immutable StateFlow with lifecycle-aware collection",
          "alternatives": [
            "Android Views for existing apps or unsupported controls"
          ],
          "reason": "Unidirectional data flow separates user events and rendered state; repositories own data access",
          "limits": "ViewModels do not survive process death; persist important state and test restoration; add domain layers only for actual complexity",
          "source_urls": [
            "https://developer.android.com/topic/architecture/recommendations"
          ]
        },
        {
          "job": "Structured local persistence",
          "default": "Room",
          "alternatives": [
            "Direct SQLite only when Room cannot satisfy measured requirements"
          ],
          "reason": "Compile-time SQL checking, migrations and observable local data",
          "limits": "Choose compatible Room/KSP/Kotlin versions; test upgrades; neither Room nor DataStore automatically supplies encryption or backend sync",
          "source_urls": [
            "https://developer.android.com/training/data-storage/room",
            "https://developer.android.com/topic/libraries/architecture/datastore"
          ]
        },
        {
          "job": "Preferences",
          "default": "DataStore",
          "alternatives": [
            "Existing supported preferences implementation with an explicit data migration"
          ],
          "reason": "Compile-time SQL checking, migrations and observable local data",
          "limits": "Choose compatible Room/KSP/Kotlin versions; test upgrades; neither Room nor DataStore automatically supplies encryption or backend sync",
          "source_urls": [
            "https://developer.android.com/training/data-storage/room",
            "https://developer.android.com/topic/libraries/architecture/datastore"
          ]
        },
        {
          "job": "Networking and API contract",
          "default": "Retrofit + OkHttp + kotlinx.serialization behind a repository",
          "alternatives": [
            "Ktor Client when deliberate multiplatform business-code sharing justifies it"
          ],
          "reason": "Typed HTTP interfaces with explicit DTOs and a replaceable client",
          "limits": "Pin compatible versions and converter; share schemas/fixtures with iOS rather than UI; test auth refresh, errors and cancellation",
          "source_urls": [
            "https://github.com/lysine-dev/retrofit"
          ]
        },
        {
          "job": "Concurrency and background work",
          "default": "Coroutines/Flow in lifecycle-owned scopes; WorkManager for eligible persistent deferrable work",
          "alternatives": [
            "Server-side durable jobs for long agent runs"
          ],
          "reason": "Cancellation follows lifecycle while scheduled local sync uses a persistent work system",
          "limits": "WorkManager is OS-constrained and not an exact scheduler; coroutine launch alone is not durable across process death",
          "source_urls": [
            "https://developer.android.com/topic/architecture/recommendations",
            "https://developer.android.com/develop/background-work/background-tasks/persistent"
          ]
        },
        {
          "job": "Credentials",
          "default": "Android Keystore-backed cryptographic keys protecting app-private credential material",
          "alternatives": [
            "In-memory sessions when no persisted credentials are needed"
          ],
          "reason": "Use OS key protection and explicitly scoped encrypted storage",
          "limits": "Keystore stores keys, not arbitrary bearer tokens; define encryption, backup exclusions and revocation; no backend provider secrets in APKs",
          "source_urls": [
            "https://developer.android.com/privacy-and-security/keystore"
          ]
        },
        {
          "job": "Unit and integration tests",
          "default": "JUnit + coroutine test utilities; fake repositories/API; Room migration tests",
          "alternatives": [
            "Established project test framework when compatible"
          ],
          "reason": "Deterministically verify state, retries, decoding, migrations and process-restoration assumptions",
          "limits": "Host unit tests cannot prove Android framework/device behavior; emulator tests supplement them",
          "source_urls": [
            "https://developer.android.com/topic/architecture/recommendations",
            "https://developer.android.com/training/data-storage/room"
          ]
        },
        {
          "job": "UI and accessibility",
          "default": "Compose UI tests + AndroidX accessibility checks; TalkBack and large-font/device review",
          "alternatives": [
            "Espresso for mixed Views/Compose apps"
          ],
          "reason": "Verify semantic actions, navigation and permission flows with the actual platform UI",
          "limits": "Automatic checks require supported test dependencies/API environment and do not replace screen-reader usability; test tablets/foldables if supported",
          "source_urls": [
            "https://developer.android.com/develop/ui/compose/testing",
            "https://developer.android.com/develop/ui/compose/accessibility/testing"
          ]
        },
        {
          "job": "Build, CI and distribution",
          "default": "Android Studio + Gradle wrapper/Kotlin DSL; pinned JDK/SDK CI; signed Android App Bundle and Play internal testing",
          "alternatives": [
            "Managed device or device-farm testing where the project needs a broader matrix"
          ],
          "reason": "Reproduce build inputs and separate local tests, device tests and signed release artifacts",
          "limits": "AGP/Gradle/JDK/Kotlin/Compose must be compatible; release requires upload-key custody and Play account access; build success is not store publication",
          "source_urls": [
            "https://developer.android.com/build/building-cmdline",
            "https://developer.android.com/studio/publish/app-signing"
          ]
        },
        {
          "job": "Navigation",
          "default": "Navigation Compose",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Navigation host/controller handle screen back stacks and deep links",
          "limits": "Add compatible navigation-compose dependency; pass minimal route identifiers and test process recreation/back behavior. Preserve Fragment navigation during partial Compose migration.",
          "source_urls": [
            "https://developer.android.com/guide/navigation"
          ]
        },
        {
          "job": "Notifications",
          "default": "Android notification channels + runtime permission",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "Native notifications keep user delivery preferences under system control",
          "limits": "Declare/request POST_NOTIFICATIONS where required; create appropriate channels, handle denial and test release API levels. Remote transport/server enrollment is a separate integration.",
          "source_urls": [
            "https://developer.android.com/develop/ui/compose/notifications/notification-permission"
          ]
        },
        {
          "job": "Media selection",
          "default": "Android Photo Picker",
          "alternatives": [
            "Preserve an existing compatible project choice"
          ],
          "reason": "System picker grants access to selected media",
          "limits": "Use Activity result contracts; handle fallback devices, URI access lifetime and upload size limits. Prefer selected access over requesting broad media-library permissions.",
          "source_urls": [
            "https://developer.android.com/training/data-storage/shared/photo-picker"
          ]
        }
      ],
      "setup_steps": [
        "Start in a source checkout in a local development workspace. Record package ID, minimum/target SDK, supported form factors, API contract, permissions and release owner.",
        "Install Android Studio and compatible SDK/JDK; use the project Gradle wrapper. Create a Kotlin Empty Activity/Compose project. Pin Gradle/AGP/Kotlin/Compose and library versions in a version catalog.",
        "Implement screen state/ViewModels and repositories. Add Room migrations, a typed HTTP client and deterministic fake data. Keep secrets out of version control and app resources.",
        "Run JVM tests, lint and a debug build. Start a documented emulator or attach an authorized device, then run instrumentation/Compose checks.",
        "Exercise process death, offline/reconnect, rotation, permission denial, TalkBack, large fonts and each supported form factor on appropriate devices.",
        "Account owner establishes package ownership, upload key and Play App Signing. Build a signed release bundle, verify internal-track install/update, then use the authorized release workflow; retain reports and distribution receipts."
      ],
      "verification_commands": [
        "./gradlew --version",
        "./gradlew tasks --all",
        "./gradlew :app:lintDebug :app:testDebugUnitTest :app:assembleDebug",
        "adb devices",
        "./gradlew :app:connectedDebugAndroidTest",
        "./gradlew :app:bundleRelease"
      ],
      "evidence_status": "documentation-reviewed",
      "sources": [
        {
          "url": "https://developer.android.com/topic/architecture/recommendations",
          "title": "Android architecture recommendations",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.android.com/training/data-storage/room",
          "title": "Room persistence",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.android.com/topic/libraries/architecture/datastore",
          "title": "DataStore",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://github.com/lysine-dev/retrofit",
          "title": "Retrofit maintained repository; square/retrofit redirects here",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.android.com/develop/background-work/background-tasks/persistent",
          "title": "Persistent background work",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.android.com/develop/ui/compose/testing",
          "title": "Compose testing",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.android.com/develop/ui/compose/accessibility/testing",
          "title": "Compose accessibility testing",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.android.com/build/building-cmdline",
          "title": "Android command-line build",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.android.com/studio/publish/app-signing",
          "title": "Android app signing",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.android.com/privacy-and-security/keystore",
          "title": "Android Keystore system",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.android.com/guide/navigation",
          "title": "Android Navigation",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.android.com/develop/ui/compose/notifications/notification-permission",
          "title": "Android notification permission",
          "checked_date": "2026-10-10"
        },
        {
          "url": "https://developer.android.com/training/data-storage/shared/photo-picker",
          "title": "Android Photo Picker",
          "checked_date": "2026-10-10"
        }
      ],
      "open_questions": [
        "What minimum/target API and phone/tablet/foldable matrix must be supported?",
        "Which offline/sync/conflict rules and API authentication contract apply?",
        "Which notification/media features and denied-permission flows are required?",
        "Who owns package identity, upload key and Play internal/release tracks?"
      ],
      "title": "Kotlin + Compose",
      "language": "Kotlin",
      "group": "Native mobile",
      "kind": [
        "android"
      ],
      "ui": "native",
      "host": "native",
      "summary": "Native Android apps with platform UI, lifecycle and storage integration.",
      "shape": "Compose · ViewModel · Room · Coroutines",
      "tradeoff": "Device diversity and background restrictions need Android-specific checks; iOS is a separate client.",
      "research_file": "native-mobile.json",
      "reviewed": "2026-10-10",
      "best_practices": [
        "Expose immutable screen state from ViewModels and collect it with lifecycle awareness.",
        "Use lifecycle-owned coroutine scopes. Use WorkManager for eligible persistent, deferrable work.",
        "Test Room migrations and keep credential material protected by platform-backed keys.",
        "Check TalkBack, large text and real devices, then qualify the signed bundle through internal testing."
      ],
      "research_freshness": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://developer.android.com/compose",
          "https://developer.android.com/topic/architecture"
        ],
        "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
      },
      "guide_url": "/stacks/kotlin-compose-android/",
      "markdown_url": "/stacks/kotlin-compose-android/guide.md",
      "json_url": "/stacks/kotlin-compose-android/record.json",
      "architecture_and_migration": {
        "id": "kotlin-compose-android",
        "version_scope": "Documentation reviewed 11 October 2026. Use the project's minimum/target SDK, compatible Kotlin/Compose/AGP/Gradle/JDK/Room/WorkManager versions and version catalog. Current guidance is conditional on supported platform behavior; no APK, App Bundle, emulator or store release was tested.",
        "operating_model": "An installed Android client renders immutable screen state with lifecycle-aware collection and persists important data separately. Recommendation: repositories mediate Room/API data and WorkManager handles selected persistent work; backend services own privileged domain effects. Installed versions coexist through staged distribution.",
        "architecture": [
          "Android guidance recommends separate UI and data layers, repositories, unidirectional data flow and lifecycle-aware Flow collection. Add a domain layer only when complexity/reuse warrants it.",
          "Recommendation: keep API DTOs distinct from Room entities, and local observable data authoritative for offline screen reads while the backend owns shared-domain reconciliation.",
          "Room owns schema versions and migrations; DataStore serves preferences rather than a general relational substitute. Record durable user operations and acknowledgement state when offline writes are required.",
          "Coroutines serve lifecycle/in-process async work; WorkManager persists scheduled work across restart/reboot and remains subject to constraints and power policy.",
          "Recommendation: use Keystore-backed keys to protect separately stored app-private credentials. A Keystore key is not arbitrary token storage, nor a guarantee that a revoked backend session remains usable."
        ],
        "developer_workflow": [
          "Start at the external source README, API and database fixtures, version catalog and Gradle wrapper. Record package identity, SDK/device matrix, signing owner and release track.",
          "Use ./gradlew --version and ./gradlew tasks --all; with an actual app module run ./gradlew :app:lintDebug :app:testDebugUnitTest :app:assembleDebug. Keep wrapper/JDK/SDK inputs reproducible.",
          "After adb devices identifies an authorized emulator/device, run ./gradlew :app:connectedDebugAndroidTest. Configure Room's migration testing/exported schemas; assertions must check preserved data as well as schema shape.",
          "Recommendation: use Android Studio profilers/inspection, coroutine fakes, Compose navigation/accessibility tests and physical-device reboot/offline checks. Build ./gradlew :app:bundleRelease only with reviewed signing, then verify an internal-track install/update before staged promotion."
        ],
        "avoid": [
          "Collecting Flow without lifecycle ownership can keep work running when a screen is stopped; repeating effects inside recomposition can duplicate requests.",
          "Treating a ViewModel or coroutine as disk persistence loses work on process death.",
          "Using destructive migration for user-created offline data deletes the only copy.",
          "Expecting WorkManager to execute at an exact wall-clock deadline ignores scheduling windows and power constraints.",
          "Halt rollout is not uninstall or downgrade; already-updated users stay on the new build."
        ],
        "transitions": [
          {
            "capability": "client",
            "existing_contract": "Supported installed APK versions/OS levels, DTOs/errors, auth, deep links and delayed old-client operations.",
            "coexistence": "Recommendation: Deploy backward-compatible server behavior first; run old/new clients against it and retain contracts through explicit adoption/support gates.",
            "target": "Recommendation: Version API DTOs independently of Room entities and gate optional features by negotiated capability; keep backend authorization authoritative.",
            "benefits": [
              {
                "benefit": "Client releases and backend changes can progress independently.",
                "prerequisites": "Installed-version inventory, shared API fixtures and support ownership.",
                "tradeoffs": "Maintaining old contracts costs work; Compose adoption does not upgrade installed clients."
              }
            ],
            "checks": [
              "Old/new builds decode missing/unknown fields and documented errors.",
              "A delayed old offline operation succeeds or returns the declared conflict.",
              "Deep links, session expiry and denied resources work across supported releases."
            ],
            "rollback": "Disable the new capability and preserve old/new APIs; repair already-installed clients with a compatible higher-version release when needed.",
            "sources": [
              "https://developer.android.com/topic/architecture/recommendations",
              "https://support.google.com/googleplay/android-developer/answer/6346149"
            ],
            "id": "client-1"
          },
          {
            "capability": "data",
            "existing_contract": "Room schema versions, exported schemas, all upgrade paths and user-owned unsynced records.",
            "coexistence": "Recommendation: Add migrations without discarding old fields until adoption permits; include direct upgrades from every supported starting version.",
            "target": "Recommendation: Keep exported Room schemas and explicit migration tests; use automatic or manual migrations according to the actual change.",
            "benefits": [
              {
                "benefit": "Reviewed migrations preserve local user data across updates.",
                "prerequisites": "Complete paths plus assertions on data/relationships/pending work.",
                "tradeoffs": "Schema validation alone does not establish value preservation; destructive fallback permanently deletes table data."
              }
            ],
            "checks": [
              "MigrationTestHelper exercises each path and earliest-to-current upgrade.",
              "Assert unsynced rows, IDs and relationships remain meaningful.",
              "Verify intended downgrade behavior; prohibit destructive fallback for the only copy of user work."
            ],
            "rollback": "Ship a forward repair when older code cannot read the new store; any restore requires reconciling writes made after upgrade.",
            "sources": [
              "https://developer.android.com/training/data-storage/room/migrating-db-versions"
            ],
            "id": "data-1"
          },
          {
            "capability": "cache",
            "existing_contract": "Local source-of-truth reads, pending offline operations, revision/cursor/tombstone and conflict rules.",
            "coexistence": "Recommendation: Use one repository and one reconciler for each data category; persist queued mutations with operation IDs before reporting success.",
            "target": "Recommendation: Use Room-backed local reads and a durable operation queue when offline writes are needed; select push/pull/hybrid sync and a domain-specific conflict policy.",
            "benefits": [
              {
                "benefit": "Cached local data can keep required reads available and preserve offline intent.",
                "prerequisites": "Server sync support, retry-safe writes and an explicit conflict policy.",
                "tradeoffs": "Offline-first reads do not imply offline writes; last-write-wins can discard intent and depends on metadata semantics."
              }
            ],
            "checks": [
              "Two offline devices make conflicting changes and obtain the documented resolution.",
              "Kill process after local commit and before network send; operation survives.",
              "Repeat server-committed/unacknowledged mutation without duplication; honor deletes/tombstones."
            ],
            "rollback": "Stop the new synchronizer and retain its queue; map remaining operations/cursors to old semantics before resume.",
            "sources": [
              "https://developer.android.com/topic/architecture/data-layer/offline-first"
            ],
            "id": "cache-1"
          },
          {
            "capability": "jobs",
            "existing_contract": "Existing queued Worker class names, input Data versions, unique-work identities and external effects.",
            "coexistence": "Recommendation: Retain readers/worker entry points for already-enqueued payloads; transfer one job category and prevent duplicate schedulers.",
            "target": "Recommendation: Use WorkManager for eligible persistent device work with constraints/backoff; keep server completion obligations in a backend durable job.",
            "benefits": [
              {
                "benefit": "Scheduled work persists across restart and device reboot.",
                "prerequisites": "Compatible worker payloads, stable unique names, replay-safe effects and documented constraints.",
                "tradeoffs": "Scheduling windows/power policy affect timing; unique work does not provide exactly-once remote effects."
              }
            ],
            "checks": [
              "Reboot with queued work and verify it resumes when constraints permit.",
              "Update app with old queued input; the new worker decodes it.",
              "Crash after remote effect/before acknowledgement and confirm retry is safe."
            ],
            "rollback": "Cancel new scheduling and account for pending/running work; keep compatibility workers until drained or safely transformed.",
            "sources": [
              "https://developer.android.com/develop/background-work/background-tasks/persistent",
              "https://developer.android.com/topic/architecture/data-layer/offline-first"
            ],
            "id": "jobs-1"
          },
          {
            "capability": "identity",
            "existing_contract": "Existing stored credential encryption, key alias/access constraints, backup exclusions, issuer expiry/revocation.",
            "coexistence": "Recommendation: Retain the backend issuer and read old encrypted credential formats during a bounded transition; isolate account-local data.",
            "target": "Recommendation: Use Keystore-backed cryptographic keys with reviewed encrypted app-private credential storage and backend revocation.",
            "benefits": [
              {
                "benefit": "OS key protection can reduce key extraction exposure.",
                "prerequisites": "Qualified device/API support, key invalidation handling and a reviewed storage/backup policy.",
                "tradeoffs": "Keystore stores keys rather than arbitrary tokens; device protection does not replace backend authorization."
              }
            ],
            "checks": [
              "Key invalidation produces a controlled sign-in path.",
              "Backup/restore cannot silently expose unusable/plain credentials.",
              "Sign-out/account switch stops old-account queued work and backend revocation is enforced."
            ],
            "rollback": "Retain compatibility decryption only while secure; require sign-in if the old format/key cannot be restored safely.",
            "sources": [
              "https://developer.android.com/privacy-and-security/keystore"
            ],
            "id": "identity-1"
          },
          {
            "capability": "operations",
            "existing_contract": "Play tracks, signing/version codes, adoption, crash metrics and schema/API compatibility.",
            "coexistence": "Recommendation: Verify an internal/closed-track update over supported old builds and preserve compatible backend behavior for the whole mixed-version population.",
            "target": "Recommendation: Use a staged rollout with explicit crash/data-loss thresholds and a higher-version compatible repair path.",
            "benefits": [
              {
                "benefit": "Percentage-based adoption can limit initial exposure.",
                "prerequisites": "Signed build, account/track owner, telemetry and recovery artifact.",
                "tradeoffs": "Halting only prevents further rollout; users who already updated remain on that version."
              }
            ],
            "checks": [
              "Install-over-old-build retains unsynced data and auth.",
              "Track failures by app/OS/schema version.",
              "Halt/recovery rehearsal keeps already-updated users functional."
            ],
            "rollback": "Halt additional rollout and disable the affected capability if safe; publish a compatible fixed build without assuming a downgrade of installed clients.",
            "sources": [
              "https://support.google.com/googleplay/android-developer/answer/6346149"
            ],
            "id": "operations-1"
          }
        ],
        "sources": [
          {
            "url": "https://developer.android.com/topic/architecture/recommendations",
            "title": "Android Architecture Recommendations",
            "claim": "Separate UI/data layers, repositories, immutable state and lifecycle-aware collection are documented recommendations."
          },
          {
            "url": "https://developer.android.com/topic/architecture/data-layer/offline-first",
            "title": "Android Offline-first Architecture",
            "claim": "Local sources, queues, sync and conflict resolution need explicit policies; offline reads need not imply offline writes."
          },
          {
            "url": "https://developer.android.com/training/data-storage/room/migrating-db-versions",
            "title": "Migrate Your Room Database",
            "claim": "Migration testing should cover all paths; destructive fallback can permanently delete local table data."
          },
          {
            "url": "https://developer.android.com/develop/background-work/background-tasks/persistent",
            "title": "Android WorkManager Task Scheduling",
            "claim": "Work is persisted and rescheduled across reboots with constraints/retries; it is not an exact timer or all immediate work."
          },
          {
            "url": "https://developer.android.com/privacy-and-security/keystore",
            "title": "Android Keystore System",
            "claim": "Keystore protects cryptographic key material and usage constraints; arbitrary credentials need their own protected storage design."
          },
          {
            "url": "https://developer.android.com/build/building-cmdline",
            "title": "Build Android Apps from the Command Line",
            "claim": "Gradle wrapper build/test tasks and signed release artifacts require configured inputs."
          },
          {
            "url": "https://support.google.com/googleplay/android-developer/answer/6346149",
            "title": "Play Console Staged Rollouts",
            "claim": "Halting stops additional staged installs; already-updated users remain on that version."
          }
        ],
        "reviewed_at": "2026-10-11",
        "evidence": "documentation-reviewed"
      },
      "rewrite_url": "/rewrite/guide.md",
      "migration_contracts_url": "/rewrite/contracts.json",
      "agent_workflow": [
        "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
        "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
        "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
        "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
        "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
      ],
      "selection": {
        "native_ui": true,
        "static_hosting": false,
        "offline_client_candidate": true
      },
      "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
    }
  ],
  "research_freshness": {
    "schema_version": "1.0",
    "checked_on": "2026-10-13",
    "original_tool_research_date": "2026-10-10",
    "original_architecture_research_date": "2026-10-11",
    "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency.",
    "source_link_check": {
      "referenced_urls": 394,
      "successful_after_retry": 394,
      "corrected_broken_url": {
        "from": "https://playwright.dev/docs/intro/",
        "to": "https://playwright.dev/docs/intro"
      },
      "interrupted_fetches_recovered": 13
    },
    "changes": [
      "Corrected Playwright installation source URL.",
      "Added explicit Next.js development MCP/browser inspection guidance.",
      "Added current Ecto transact/2 version/semantics note."
    ],
    "integration_status": "not-qualified; setup, capacity and migration checks remain unexecuted",
    "profiles": {
      "elixir-phoenix-liveview": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://phoenix.hexdocs.pm/overview.html",
          "https://phoenix.hexdocs.pm/installation.html",
          "https://hexdocs.pm/ecto/Ecto.Repo.html#c:transact/2"
        ]
      },
      "typescript-next-node": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://nextjs.org/docs/app/getting-started/installation",
          "https://nextjs.org/docs/app/guides/mcp",
          "https://nextjs.org/docs/app/guides/ai-agents"
        ]
      },
      "typescript-react-vite-browser": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://vite.dev/guide/",
          "https://react.dev/learn/typescript"
        ]
      },
      "rails-hotwire-postgresql": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://guides.rubyonrails.org/getting_started.html",
          "https://guides.rubyonrails.org/active_job_basics.html"
        ]
      },
      "laravel-livewire-postgresql": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://laravel.com/framework/docs/13.x/installation",
          "https://laravel.com/framework/docs/13.x/ai"
        ]
      },
      "python-django": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://docs.djangoproject.com/en/stable/intro/install/"
        ]
      },
      "python-fastapi": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://fastapi.tiangolo.com/tutorial/"
        ]
      },
      "python-scripts-workers": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://docs.astral.sh/uv/guides/projects/",
          "https://docs.astral.sh/uv/guides/scripts/"
        ]
      },
      "go-service": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://go.dev/doc/tutorial/create-module",
          "https://pkg.go.dev/net/http"
        ]
      },
      "go-cli": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://go.dev/doc/tutorial/create-module",
          "https://github.com/spf13/cobra"
        ]
      },
      "rust-service": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://docs.rs/axum/latest/axum/"
        ]
      },
      "rust-cli": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://docs.rs/clap/latest/clap/",
          "https://ratatui.rs/"
        ]
      },
      "swift-swiftui-ios": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://developer.apple.com/documentation/swiftui",
          "https://developer.apple.com/tutorials/data/documentation/swiftui.json"
        ]
      },
      "kotlin-compose-android": {
        "core_guidance_checked_on": "2026-10-13",
        "sources": [
          "https://developer.android.com/compose",
          "https://developer.android.com/topic/architecture"
        ]
      }
    },
    "source_access_notes": [
      "Apple documentation HTML is a JavaScript shell; official DocC JSON was read for SwiftUI.",
      "The optional Laravel /for/agents route was advertised in official installation docs but direct retrieval returned 403; the existing installation and AI/Boost sources were available."
    ]
  },
  "migration_reviewed_at": "2026-10-11",
  "rewrite_guide": "/rewrite/guide.md",
  "migration_contracts": "/rewrite/contracts.json",
  "migration_evidence_status": "documentation-reviewed; application compatibility untested"
}
