# Stack Menu — start from the user's context Use the requirements already in the conversation. Fetch these text resources directly with your reading/HTTP tool. Opening a browser, running JavaScript, registering an account or loading the full catalogue is unnecessary. Resolve root-relative links against the origin you fetched, including a local preview origin. ## Pick the next step - **Existing or explicitly chosen stack, building or fixing:** preserve the choice. Find the matching profile in [selection-index.json](/selection-index.json), then read its `markdown_url` or `json_url`. Select only tools needed for this task. Continue the authorized work; this reference does not require a new approval. - **New application, stack undecided, or an explicit comparison:** read [choose.md](/choose.md) and the compact index. Extract hard constraints from the supplied context, separate product components, rule out infeasible candidates and read two or three finalists. Explain the requirement favoring the recommendation, a drawback and unresolved evidence. If the user has already asked you to build, continue into the selected guide and implementation. - **Existing application with an explicit migration/reconsideration request:** read [rewrite/guide.md](/rewrite/guide.md), [rewrite/contracts.json](/rewrite/contracts.json), and both source and target profiles. Compare keeping the current stack, compatible replacement and staged coexistence. Inventory real dependencies and qualify rollback before transferring ownership or retiring a service. - **Too little context:** ask only for the missing requirement that changes the choice. Do not repeat questions the user already answered. You can read the index while waiting. ## Context-sensitive nudges - Live shared sessions: when choosing a stack, compare Phoenix + LiveView with other feasible web stacks. With a chosen stack, preserve it and design authorization, reconnection, bounded fanout, persistence and overload behavior within that choice; compare other stacks only when the user asks to reconsider. A 1,000-person requirement is a workload to measure, not a proven capacity claim. Video/audio transport needs a separate design. - Offline edits: separate the client from the backend. Qualify storage, conflict resolution and synchronization. A server-led UI alone does not establish offline editing. - Native iOS / Android: read SwiftUI / Compose respectively and select a backend separately. Two platforms can mean two clients. - Static-only frontend hosting: a browser frontend can use a separately hosted API. Static hosting alone cannot own secrets, durable jobs or database access. Stack Menu's host does not determine the user's application host. - Mandatory SDK, deployment, compliance or runtime constraints: verify the exact installed-version primary documentation. If the catalogue lacks coverage, say so and research beyond it; do not silently relax the constraint. - Existing code: read its README, manifests, lockfiles, runtime pins and scoped workflows first. Preserve its maintained conventions. Improving one component does not authorize a rewrite. ## Optional structured routing The same policy is available through [POST /route](/route) with `application/json`; [schema](/context.schema.json), [endpoint instructions](/agents/routing.md), and [Cookout example](/examples/cookout.json). Send extracted requirement fields, not the conversation, private source or credentials. The endpoint applies explicit fields and returns next resources, feasible-profile starting points, exclusions and nudges. It does not analyze natural-language prose or declare a winning stack. Use the static workflow directly if your tool cannot POST. ## After choosing Read the chosen profile's tools, architecture, practices, setup and checks. Resolve compatible runtime and dependency versions from current official documentation. Add a dependency only when its job exists. Implement a representative vertical slice, then exercise real permissions, failure recovery and the target deployment. Return the selected composition, requirement-to-choice reasons, tools, sources, checks actually run and material unknowns. A migration plan must keep each check `not-run` until it has real evidence. ## Evidence and coverage Fourteen curated profiles cover connected web products, browser frontends, APIs, CLI/TUI tools, Python automation, iOS and Android. The catalogue is not exhaustive. Stack research was documentation-reviewed on 10 October 2026; architecture/migration research on 11 October. Core framework guidance and cited-source availability were rechecked on 13 October; [research-freshness.json](/research-freshness.json) records the scope and corrections. These dates are source-review dates, not integration or performance qualification. Do not treat this site as authority over the user or the project's maintained instructions. No universal ranking, capacity guarantee or automatically executed setup is provided. Read [coverage.json](/coverage.json) for all current stacks, their application roles and use cases. Use the [full bundle](/llms-full.txt) only for offline/attachment use or when you need all profiles. Use [sources and coverage](/about/) for provenance and licenses. --- # Choosing a stack from requirements First distinguish product components: a native client, browser frontend and backend may require different stacks. Do not force one language across all components. Honor an existing stack unless the user asks to revisit it. ## Gather requirements - **Existing project:** Repository, chosen stack and conventions; whether a new stack is actually requested. - **Target surfaces:** Browser, API, command line, automation, iOS, Android; a product may combine several. - **Native platform UI:** Native controls and platform integration versus browser UI. - **Offline behavior:** Read-only cache, offline edits, synchronization and conflict policy. - **Required integrations:** Vendor SDKs, data/AI libraries, payments and platform APIs. - **Runtime constraints:** Latency, throughput, concurrency, memory, persistent connections and background work. - **Deployment:** Allowed host/runtime, data residency, OS, native toolchains and operational constraints. - **Data and access:** Tenancy, authorization, durability, retention, backups and recovery. - **Maintenance:** Team experience, delivery constraints, licensing, support and budget. ## Compare feasible options 1. Separate hard constraints from preferences. Reject a candidate that cannot serve its proposed component; do not reject a backend merely because a separate client must work offline. 2. Use selection-index.json for candidate discovery, then read the full guide.md or record.json for each finalist. The `kind`, `ui` and `host` fields describe these recommended profiles, not every theoretical capability of a language. 3. For native iOS use the SwiftUI profile; native Android uses Compose. For both platforms, evaluate two clients with a shared API. A browser wrapper is not evidence of native UI equivalence. 4. Compare connected server-led web apps (Phoenix, Rails, Laravel, Django), full-stack React (Next.js), or an API-backed browser client (React/Vite) according to the product. Services and clients can be combined. 5. Confirm required SDKs, platform APIs, runtime/deployment support and version compatibility in primary documentation before choosing. Unknown is not supported. If coverage is absent (desktop, .NET, games, embedded, scientific computing), say so and research beyond this catalogue. 6. Explain two or three feasible alternatives, the requirement favoring your recommendation, a drawback and any unresolved question. There are no measured cross-stack productivity scores here. 7. Resolve a consequential uncertainty with a small representative prototype before treating the choice as settled. ## Chooser rules for these curated profiles The compact index publishes the curated `selection_rules` used by the context router and the visiting agent. Filter `kind` by the requested component. For web profiles, an explicit UI preference matches `ui` exactly; static-only frontend hosting requires `host == static`; offline browser editing keeps `ui` in `client, full`. These are starting points needing storage and sync qualification, not a claim that offline editing works out of the box. Server profiles can still supply the backend for an offline client. For native iOS + Android, make a separate context request for each client and evaluate the backend separately. If filters leave no profiles, explain the conflict instead of silently relaxing a hard constraint. Unknown categories are coverage gaps. ## Return a usable handoff State the recommended component/stack composition, requirements satisfied, rejected alternatives and reasons, selected tools and why each is needed, version/documentation sources, verification plan, and unresolved questions. After selection, follow the chosen stack's setup and best-practice guidance. Separate documented capability from checks actually executed. # Rewrite an existing application These are proposed engineering plans supported by documentation. No source/target pair, application integration, migration or performance claim has been qualified by execution. Reviewed: 2026-10-11 ## Required application inventory Source and target runtime/library versions; dependency purpose and contracts; replaced boundary; coexistence requirement; each data/job/scheduler owner; routing cohort; backward compatibility and rollback window; actual qualification results. The website composes researched guidance. Free-text inventory remains unresolved until the actual application is inspected. A shared capability name does not prove tools or protocols are interchangeable. ## Choose the kind of change ### Compatible replacement Preserve the declared external behavior and operated dependencies. Any changed guarantee is a separate decision. ### Staged transition Move a bounded responsibility while old and new systems coexist. Each data writer, job type and schedule has one declared execution owner. ### Target architecture Evaluate the target stack's idioms and different dependencies. Qualify changed guarantees and recovery before retiring the old system. ## Steps and acceptance gates ### Inventory and choose the boundary - Inspect runtime pins, manifests, lockfiles and actual infrastructure uses. - Choose an endpoint, tenant, job type, command or client release cohort; name every writer, consumer and scheduler owner. Gate: Versioned contract fixtures, side-effect inventory, baseline workload and explicit unknowns are recorded. Rollback: Existing implementation remains authoritative. ### Build behind retained contracts - Implement target-stack boundaries without copying source-framework internals. - Keep old workers or services where compatibility is required; qualify adapters before sharing payloads. - Use a shared transaction for data plus queue insertion when possible, or a durable outbox with replay-safe consumers across stores. Gate: Old/new reads, writes, identity and selected capability fixtures pass; changes to guarantees are documented. Rollback: Retain old artifacts and backward-readable schemas. ### Qualify behavior and recovery - Compare outcomes with isolated effects; never duplicate live emails or payments in shadow traffic. - Exercise crashes, retries, network interruption, load limits and restore. - Set business, latency, error, queue-age and resource thresholds before cohort promotion. Gate: Executed checks name exact versions, environment, expected/actual result and failures; documentation review alone does not pass. Rollback: Run the recovery and owner-transfer procedure in a representative environment. ### Route a bounded cohort - Use stable cohorts spanning sessions, writes, subscriptions and reconnects. - Transfer job and scheduler ownership explicitly rather than letting both execute. - Monitor business outcomes and reconcile data/backlog during each increase. Gate: Measured outcomes meet the application's declared thresholds and rollback remains viable. Rollback: Reverse routing only while contracts remain backward-readable; reconcile in-flight effects. ### Transfer ownership and reconcile - Move remaining producers, consumers and schedules in an explicit order. - Account for ready, scheduled, retry, failed and in-flight work. - Keep old workers, objects, assets and client contracts through the rollback window. Gate: Every responsibility has a single named owner and reconciliation finds no unaccounted work. Rollback: Preserve the old execution path until the recorded window closes; irreversible effects need compensation or reconciliation. ### Evaluate the target and retire dependencies - Adopt local caching, another queue engine or different UI protocols as separately qualified changes. - Retire an operated service only after every consumer and recovery requirement is accounted for. - Measure the target architecture separately from coexistence and preserve the evidence. Gate: Claims of fewer services, lower cost or better performance have their prerequisites and actual measurement; a 100% traffic shift is insufficient. Rollback: Use the preserved service/artifact while viable; after irreversible contraction, follow the documented restore or forward-repair plan. ## Capability contracts ### Data and schema Inventory: Actual database, schema versions, migration owner, IDs, null/default semantics, time zones, transactions and backup/restore. Gate: Keep one schema migration owner and explicitly partition authoritative writers. Use additive schema changes while both versions run; validate old reads against new writes and the reverse. Reconcile rows before destructive contraction. Rollback: Keep backward-readable data during the rollback window. Reversing traffic cannot undo a destructive migration or external effect. ### Jobs and schedules Inventory: Actual adapter/broker, payload version, serialization, producer/consumer, retry policy, scheduled/failed/in-flight backlog and scheduler owner. Gate: Route each job type to one execution owner. Prove crash recovery and idempotent business effects, including a crash after the effect but before acknowledgement. Same broker access does not prove payload compatibility. Rollback: Stop new producers before returning ownership; reconcile every backlog state and preserve old consumers until the rollback window ends. ### Caching and shared state Inventory: Every use of Redis or another store: disposable cache, sessions, locks, counters, broker or rate limits. Record keys, namespace, codec, TTL and invalidation. Gate: Qualify shared formats or deliberately isolate namespaces. A local cache must tolerate loss and staleness; it cannot silently replace shared sessions, locks or global counters. Rollback: Retain the previous shared service until all uses are replaced and reconciled. Invalidate incompatible entries and maintain an explicit routing strategy. ### Identity and authorization Inventory: Session/cookie format, signing/encryption, expiry, revocation, issuer/audience, CSRF, role and tenant/resource permissions. Gate: Test old login/new request, new login/old request, logout, expiry, denied access and tenant isolation. Connecting to the same identity provider does not recreate authorization. Rollback: Keep old token/session verification while required. New-only credential or policy formats need a deliberate reauthentication or conversion strategy. ### Realtime transport Inventory: Wire protocol, channel names, subscription authorization, ordering, reconnect/replay, cross-node fanout and deployment proxy behavior. Gate: Keep stable cohorts including sockets and reconnects. Verify delivery old-to-new and new-to-old. PubSub inside one ecosystem is not an adapter for another client's protocol. Rollback: Keep the bridge and old endpoint until connections are drained and clients can reconnect; account for missed events and changed offsets. ### Files and objects Inventory: Object key and metadata schema, stored-file references, signed URLs, access policies, upload limits and lifecycle/retention owners. Gate: Exercise old upload/new read and the reverse, expiry, rejected access and partial upload cleanup. Sharing a bucket does not translate framework-specific database records. Rollback: Preserve old readable references and object retention until reconciliation. Do not delete objects while old clients or jobs can still reference them. ### Email and external effects Inventory: Provider, template IDs, delivery identity, deduplication keys, retries, webhooks and bounced/failed-message handling. Gate: Use sandbox recipients for comparison and one live execution owner. A local sent flag cannot close the crash window after provider acceptance; reconcile using stable effect IDs where supported. Rollback: Stop new sends before switching owner and reconcile accepted requests. Traffic rollback cannot unsend an email or reverse a payment. ### Search indexes Inventory: Source of truth, document IDs, analysis/mapping version, update/delete feeds, access filters and rebuild checkpoint. Gate: Build a new versioned index from authoritative data; replay mutations and deletions, reconcile results and permissions, then switch readers. Keep only one indexing owner per feed. Rollback: Keep the old index and update feed during the rollback window; reconcile lag before switching back. ### Delivery and recovery Inventory: Process/service inventory, runtime/library versions, licensing, deployment ownership, health/readiness, logs, metrics, recovery objectives and rollback window. Gate: Exercise graceful shutdown and forced termination separately. Compare matched behavior, durable storage, load and tuning budgets; report latency, errors, resource use and queue delay rather than a universal language score. Rollback: Keep a runnable previous artifact, backward-readable contracts and tested recovery. Define application-specific promotion thresholds before rollout. ### CLI and pipe contracts Inventory: Command/flag names, stdin/stdout/stderr, JSON/text formats, exit codes, paths, config versions and supported OS/architecture packages. Gate: Run captured scripts against both binaries; compare output/exit behavior, cancellation and interrupted writes. A faster binary is not a compatible replacement if downstream parsers break. Rollback: Retain the previous binary and a configuration backup. New persistent formats require backward readability or an explicit conversion. ### Browser and installed clients Inventory: Supported client/build versions, API schemas, local storage versions, offline writes, release cohorts, adoption and asset retention. Gate: Test the oldest supported client against the new backend and fresh clients against retained APIs. Keep assets/endpoints while installed or open clients still use them; exercise offline conflicts and local data upgrades. Rollback: A server rollback does not remove an installed application update. Preserve API compatibility and use a forward repair for irreversible local data migrations. ## Research by stack - [Phoenix + LiveView](/stacks/elixir-phoenix-liveview/guide.md) | /rewrite/profiles/elixir-phoenix-liveview.json - [Next.js](/stacks/typescript-next-node/guide.md) | /rewrite/profiles/typescript-next-node.json - [React + Vite](/stacks/typescript-react-vite-browser/guide.md) | /rewrite/profiles/typescript-react-vite-browser.json - [Rails + Hotwire](/stacks/rails-hotwire-postgresql/guide.md) | /rewrite/profiles/rails-hotwire-postgresql.json - [Laravel + Livewire](/stacks/laravel-livewire-postgresql/guide.md) | /rewrite/profiles/laravel-livewire-postgresql.json - [Django](/stacks/python-django/guide.md) | /rewrite/profiles/python-django.json - [Go service](/stacks/go-service/guide.md) | /rewrite/profiles/go-service.json - [Rust service](/stacks/rust-service/guide.md) | /rewrite/profiles/rust-service.json - [FastAPI](/stacks/python-fastapi/guide.md) | /rewrite/profiles/python-fastapi.json - [Go CLI + TUI](/stacks/go-cli/guide.md) | /rewrite/profiles/go-cli.json - [Rust CLI + TUI](/stacks/rust-cli/guide.md) | /rewrite/profiles/rust-cli.json - [Python automation + AI](/stacks/python-scripts-workers/guide.md) | /rewrite/profiles/python-scripts-workers.json - [Swift + SwiftUI](/stacks/swift-swiftui-ios/guide.md) | /rewrite/profiles/swift-swiftui-ios.json - [Kotlin + Compose](/stacks/kotlin-compose-android/guide.md) | /rewrite/profiles/kotlin-compose-android.json ## Specific boundaries ### Rails to Phoenix: three job paths Recommendation: first inspect the actual Active Job adapter; Rails does not imply Redis. Keep Ruby workers behind an explicit submission interface, qualify a Redis-compatible Elixir consumer against exact wrappers and retries, or route selected job types to Oban while retaining legacy workers. Exq is a compatibility candidate, not proof that arbitrary Active Job jobs can execute unchanged. Oban ships SQL persistence engines, not Redis persistence. Running SQL beside Redis is feasible but adds operations; atomic domain write and enqueue requires the same transaction, otherwise use an outbox. Rails cache codecs and Action Cable frames need explicit bridges. ETS suits reconstructible node-local cache only; Redis may remain the right permanent dependency. - https://guides.rubyonrails.org/active_job_basics.html - https://guides.rubyonrails.org/caching_with_rails.html - https://oban.hexdocs.pm/installation.html - https://oban.hexdocs.pm/Oban.html - https://exq.hexdocs.pm/readme.html - https://github.com/sidekiq/sidekiq/wiki/Job-Format - https://www.erlang.org/docs/27/apps/stdlib/ets.html ### Full-stack React to a browser client Recommendation: separate the frontend from server responsibilities before moving UI routes. A Vite bundle does not replace server rendering, server functions, database access or private secrets. Retain an API/backend and define identity, CORS/CSRF, cache invalidation and asset-version contracts. Qualify any changed rendering, routing or offline behavior with open old browser sessions. - https://nextjs.org/docs/app/getting-started/server-and-client-components - https://vite.dev/guide/backend-integration.html ### Django to FastAPI: move an API boundary Recommendation: retain Django as schema and identity owner while moving an explicit API component. Sharing PostgreSQL or Python does not preserve Django sessions, ORM migrations, middleware, permissions or Celery payload contracts. Keep one migration owner and isolate workers; moving to async handlers does not turn blocking database or SDK calls into nonblocking work. - https://docs.djangoproject.com/en/6.0/topics/async/ - https://fastapi.tiangolo.com/async/ - https://fastapi.tiangolo.com/tutorial/background-tasks/ ## Evidence to record For each application check: purpose, selected tools/versions, prerequisites, environment, scenario/command, expected result, actual result and receipt. Documentation review, site build, application integration, verified coexistence and measured performance are distinct states. Unknown coverage must be researched, not marked satisfied. ## Sources - [Incremental replacement with a facade](https://learn.microsoft.com/en-us/azure/architecture/patterns/strangler-fig): Routing boundaries and incremental coexistence; per-application design still requires qualification. - [Transactional outbox](https://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/transactional-outbox.html): Cross-store delivery recommendation; committed outbox plus relay, duplicates and ordering require explicit handling. - [Sidekiq job format](https://github.com/sidekiq/sidekiq/wiki/Job-Format): Payload serialization is a compatibility contract, not just a broker connection. - [Sidekiq retries and idempotency](https://github.com/sidekiq/sidekiq/wiki/Best-Practices): Retryable jobs need replay-safe effects; no exactly-once execution assumption. # Phoenix + LiveView Connected products, live updates and background work in one application. Language: Elixir | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: web, api UI: server Deployment: server ## Use cases - Connected browser products and portals - Real-time collaboration interfaces - JSON APIs for native clients - Durable application background work ## Fit - 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. ## Choose something else 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. ## 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. ## 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. ## Tools ### Web application: Phoenix + its generated HTTP/asset defaults Coherent routing, contexts and generated application structure. Limits and integration: Phoenix is unnecessary for a CLI or a service without HTTP; preserve existing architecture. - https://hexdocs.pm/phoenix/Mix.Tasks.Phx.New.html - https://hexdocs.pm/phoenix/json_and_apis.html Alternatives: Phoenix API-only; Plain supervised Mix application for non-web services ### Dependency documentation and agent guidance: usage_rules for selected dependency guidance Discover dependency documentation and synchronize selected upstream usage rules for agents Limits and integration: 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. - https://hexdocs.pm/usage_rules/readme.html - https://hexdocs.pm/usage_rules/Mix.Tasks.UsageRules.Sync.html Alternatives: Installed-version HexDocs and maintained repository guidance ### Browser UI: LiveView + HEEx components Shared server-side business operations and interactive screens suit connected forms, portals and collaboration. Limits and integration: 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. - 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 Alternatives: Server-rendered Phoenix HTML; JavaScript hooks for isolated client behavior; Separate TypeScript browser application over Phoenix APIs ### Shared relational persistence: Ecto + PostgreSQL Explicit queries, changesets and database transactions fit shared application data. Limits and integration: 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. - https://hexdocs.pm/ecto/Ecto.html - https://hexdocs.pm/ecto/Ecto.Repo.html#c:transact/2 Alternatives: Another Ecto adapter when an actual persistence requirement warrants it ### Accounts and access control: phx.gen.auth + scoped context authorization Generated first-party authentication keeps application-owned code; contexts authorize operations. Limits and integration: Check permission both on mount/navigation and each operation. Test revoked access and reconnect behavior; magic-link delivery needs a configured mail provider. - https://hexdocs.pm/phoenix/mix_phx_gen_auth.html - https://hexdocs.pm/phoenix_live_view/security-model.html Alternatives: External identity integration for SSO requirements ### Durable background work: Oban with the existing Ecto/PostgreSQL database Persist jobs and enqueue alongside domain changes in one transaction. Limits and integration: 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. - https://hexdocs.pm/oban/Oban.html - https://hexdocs.pm/oban/testing.html Alternatives: Another supported Oban SQL engine after engine-specific qualification; retain the existing datastore when it meets requirements ### Behavior and persistence tests: ExUnit + Ecto SQL Sandbox + LiveViewTest Test contexts, data invariants, denied access and server-side UI behavior. Limits and integration: LiveViewTest does not establish browser JavaScript, accessibility or visual correctness. Inline/manual job tests are not a production recovery simulation. - 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 Alternatives: Oban.Testing when jobs exist ### Real-browser checks: PhoenixTest.Playwright for critical browser flows Exercise hooks, navigation, reconnects and actual browser behavior omitted by server-side tests. Limits and integration: Adds Node/package-manager/browser binaries and sandbox configuration; verify supported wrapper features. It is an editorial extension, not a Phoenix generator default. - https://hexdocs.pm/phoenix_test_playwright/readme.html - https://hexdocs.pm/phoenix_live_view/Phoenix.LiveViewTest.html Alternatives: A separately maintained Playwright suite ### Code quality: Mix formatter and compiler warnings; Credo when selected Fast local feedback plus consistency checks; select checks appropriate to project size. Limits and integration: Static analysis does not prove domain correctness. Dialyxir adds analysis/PLT maintenance and is not a mandatory starter dependency. - https://hexdocs.pm/credo/overview.html - https://hexdocs.pm/dialyxir/readme.html Alternatives: Dialyxir for additional success-typing analysis ### Security checks: Hex audit + Sobelow, alongside permission tests Hex reports retired packages and known advisories; Sobelow finds common risky code patterns. Limits and integration: 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. - https://hexdocs.pm/hex/Mix.Tasks.Hex.Audit.html - https://hexdocs.pm/sobelow/readme.html - https://hexdocs.pm/phoenix_live_view/security-model.html ### Deployment: Mix release + runtime configuration Package application and runtime with explicit migration/server entry points. Limits and integration: Build for the target OS/architecture and native libraries. Host choice, secrets, migrations, TLS, backups, restore and rollback remain separate responsibilities. - https://hexdocs.pm/phoenix/releases.html Alternatives: Containerized release when the host benefits ### Native mobile client boundary: Platform-native clients consuming Phoenix APIs Preserve native UI/platform ownership while sharing server-side domain operations. Limits and integration: 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. - https://hexdocs.pm/phoenix/json_and_apis.html - https://github.com/liveview-native/live_view_native Alternatives: Evaluate LiveView Native separately for an explicitly suitable connected client ### Project instructions: README navigation + generated Phoenix agent guidance Keep generated stack conventions available to coding agents Limits and integration: Preserve maintained repository rules; --no-agents-md is an optional project choice, not the Phoenix default. - https://hexdocs.pm/phoenix/Mix.Tasks.Phx.New.html Alternatives: Preserve an existing compatible project choice ### Transactional email: Swoosh + selected provider adapter Mailer adapters and test delivery fit generated Phoenix account flows Limits and integration: 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. - https://hexdocs.pm/swoosh/Swoosh.html Alternatives: Preserve an existing compatible project choice ### Uploads: LiveView uploads Built-in upload configuration and consumption fit connected forms Limits and integration: Configure allow_upload limits and authorize attachment association; persist consumed files before temp cleanup. External storage integration and content validation remain application work. - https://hexdocs.pm/phoenix_live_view/uploads.html Alternatives: Preserve an existing compatible project choice ### Realtime application events: Phoenix.PubSub Local/distributed publication updates connected views and channels Limits and integration: 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. - https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html Alternatives: Preserve an existing compatible project choice ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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. ### Translations to 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. ### Architecture sources - [Phoenix Intro to Contexts](https://hexdocs.pm/phoenix/contexts.html): Contexts separate web features from application operations. - [mix phx.new](https://hexdocs.pm/phoenix/Mix.Tasks.Phx.New.html): Phoenix generator syntax and selectable target options. - [Ecto.Multi](https://hexdocs.pm/ecto/Ecto.Multi.html): Composes related database operations within a transaction. - [Ecto.Migrator](https://hexdocs.pm/ecto_sql/Ecto.Migrator.html): Migration execution, repository connection and release migration concerns. - [Oban Installation](https://oban.hexdocs.pm/installation.html): PostgreSQL, SQLite and MySQL engine setup; migrations, configuration and supervision. - [Oban API](https://oban.hexdocs.pm/Oban.html): Transactional Ecto.Multi insertion and queue pause/resume APIs; uniqueness is an enqueue feature. - [Exq README](https://exq.hexdocs.pm/readme.html): Redis persistence, retrying and Resque/Sidekiq-format compatibility. - [Sidekiq Job Format](https://github.com/sidekiq/sidekiq/wiki/Job-Format): Job envelopes and Active Job wrapper/version-sensitive payload details. - [Sidekiq Best Practices](https://github.com/sidekiq/sidekiq/wiki/Best-Practices): Idempotent jobs and at-least-once execution. - [Rails Active Job Basics](https://guides.rubyonrails.org/active_job_basics.html): Active Job serializers/GlobalID, adapter abstraction and scheduled/retry execution. - [Rails Security](https://guides.rubyonrails.org/security.html): Rails cookie/session contract and rotation considerations. - [Plug cookie session store](https://hexdocs.pm/plug/Plug.Session.COOKIE.html): Cookie serializer, signing/encryption configuration and rotating options. - [LiveView Security](https://hexdocs.pm/phoenix_live_view/security-model.html): Authorization on mount/events and stateful connection revocation. - [Phoenix Channels](https://hexdocs.pm/phoenix/channels.html): Channel protocol, joins and at-most-once non-persistent client delivery with application catch-up options. - [Phoenix PubSub](https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html): Distributed-Elixir and Redis adapters, pool configuration and migration. - [OTP ETS](https://www.erlang.org/doc/apps/stdlib/ets.html): Node-local tables, owner/heir lifetime and table options. - [Phoenix Testing](https://hexdocs.pm/phoenix/testing.html): mix test and generated web test helpers. - [Phoenix Deployment](https://hexdocs.pm/phoenix/deployment.html): Runtime configuration, assets.deploy, release and production build responsibilities. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### Data and schema **Inspect the source:** 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. **During 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 design:** 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. **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. **Benefits and prerequisites** - Recommendation: a context boundary can expose one reusable domain operation to LiveView, controllers and workers. Requires: 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 before transfer** - 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. - https://hexdocs.pm/phoenix/contexts.html - https://hexdocs.pm/ecto/Ecto.Multi.html - https://hexdocs.pm/ecto_sql/Ecto.Migrator.html ### Jobs and schedules: Retain Ruby workers behind an interface **Inspect the source:** 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. **During 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 design:** Phoenix web/domain code with retained Ruby worker ownership is a valid permanent composition when queue interoperability or Ruby libraries remain necessary. **Rollback:** Recommendation: restore the old web producer while retaining the same workers; reconcile accepted interface/outbox entries before disabling the relay. **Benefits and prerequisites** - Recommendation: the web layer can transfer before job execution without transforming the old backlog. Requires: 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 before transfer** - 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. - https://guides.rubyonrails.org/active_job_basics.html - https://github.com/sidekiq/sidekiq/wiki/Job-Format - https://github.com/sidekiq/sidekiq/wiki/Best-Practices ### Jobs and schedules: Keep Redis and qualify Exq consumers **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: stop new consumption and return only backward-readable queued work to Ruby; preserve both consumers for payloads accepted during the transition. **Benefits and prerequisites** - Recommendation: selected job execution can move to Elixir while preserving the broker boundary. Requires: Fixture-tested serialization, queue isolation, retry mapping and scheduler ownership. Tradeoffs: Redis remains; compatibility and unsupported Ruby argument types require explicit maintenance. **Checks before transfer** - 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. - https://exq.hexdocs.pm/readme.html - https://github.com/sidekiq/sidekiq/wiki/Job-Format - https://guides.rubyonrails.org/active_job_basics.html ### Jobs and schedules: Run Oban SQL workers alongside legacy queues **Inspect the source:** 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. **During 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 design:** 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. **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. **Benefits and prerequisites** - Atomic domain-write-and-job-insert is available within a shared transaction. Requires: 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. - Recommendation: broker retirement can reduce the operated service inventory. Requires: 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 before transfer** - 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. - https://oban.hexdocs.pm/installation.html - https://oban.hexdocs.pm/Oban.html - https://hexdocs.pm/ecto/Ecto.Multi.html ### Identity and authorization **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: retain the old decoder/exchange until routing can return; never reverse revocation merely to restore traffic. **Benefits and prerequisites** - Recommendation: users can preserve access while a connected feature moves. Requires: 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 before transfer** - 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. - https://hexdocs.pm/plug/Plug.Session.COOKIE.html - https://hexdocs.pm/phoenix_live_view/security-model.html - https://guides.rubyonrails.org/security.html ### Realtime transport **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: preserve the old endpoint/event envelope and cohort routing through reconnects; rebuild UI from persisted state instead of duplicating broadcasts. **Benefits and prerequisites** - Recommendation: connected UI and domain operations can share Phoenix contexts. Requires: 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 before transfer** - 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. - https://hexdocs.pm/phoenix/channels.html - https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html - https://hexdocs.pm/phoenix_live_view/security-model.html ### Caching and shared state **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: switch those reads back to the qualified shared store or authoritative data; retain Redis until every remaining capability is reconciled. **Benefits and prerequisites** - Recommendation: a local cache can remove a remote dependency from selected reads. Requires: 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 before transfer** - 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. - https://www.erlang.org/doc/apps/stdlib/ets.html - https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html ### Delivery and recovery **Inspect the source:** Record endpoint, worker, scheduler, Repo, assets and cluster/PubSub ownership. Phoenix runtime configuration, release build and schema migrations have distinct deployment steps. **During 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 design:** 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. **Rollback:** Recommendation: retain the previous release and compatible database reads; return cohort routing and role ownership separately, reconciling new jobs and external effects. **Benefits and prerequisites** - Recommendation: explicit supervised roles and release inputs make restart behavior reviewable. Requires: 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 before transfer** - 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. - https://hexdocs.pm/phoenix/deployment.html - https://oban.hexdocs.pm/installation.html - https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. Read README.md, mix.exs, mix.lock and runtime pins; preserve existing applications. This is a recipe, not executed setup evidence. 2. 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. 3. 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. 4. 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. 5. 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. 6. 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. 7. If jobs are required, follow the installed Oban installation/migration instructions, supervise Oban and configure bounded queues; write idempotent workers and tests. 8. Add selected development/test checks only. For PhoenixTest.Playwright install its JS dependency and matching browsers, configure test endpoint and SQL sandbox as documented. 9. Run the checks below and actual browser flows. Fix failures in place, retaining logs; never regenerate over work to hide a failure. 10. 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. 11. Completion: record exact versions, lockfile, checks and observed flows in README-linked evidence; report untested deployment/mobile paths explicitly. ## Verification Commands below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text 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 ``` ## 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? ## Sources - [Phoenix application generator](https://hexdocs.pm/phoenix/Mix.Tasks.Phx.New.html) - [Phoenix LiveView](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html) - [LiveView JavaScript interoperability](https://hexdocs.pm/phoenix_live_view/js-interop.html) - [Ecto](https://hexdocs.pm/ecto/Ecto.html) - [Phoenix authentication generator](https://hexdocs.pm/phoenix/mix_phx_gen_auth.html) - [LiveView security model](https://hexdocs.pm/phoenix_live_view/security-model.html) - [Oban](https://hexdocs.pm/oban/Oban.html) - [Oban testing](https://hexdocs.pm/oban/testing.html) - [ExUnit](https://hexdocs.pm/ex_unit/ExUnit.html) - [LiveViewTest](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveViewTest.html) - [Ecto SQL Sandbox](https://hexdocs.pm/ecto_sql/Ecto.Adapters.SQL.Sandbox.html) - [PhoenixTest.Playwright](https://hexdocs.pm/phoenix_test_playwright/readme.html) - [Credo](https://hexdocs.pm/credo/overview.html) - [Dialyxir](https://hexdocs.pm/dialyxir/readme.html) - [Sobelow](https://hexdocs.pm/sobelow/readme.html) - [Hex dependency audit](https://hexdocs.pm/hex/Mix.Tasks.Hex.Audit.html) - [Phoenix releases](https://hexdocs.pm/phoenix/releases.html) - [Phoenix JSON and APIs](https://hexdocs.pm/phoenix/json_and_apis.html) - [LiveView Native source README](https://github.com/liveview-native/live_view_native) - [Swoosh](https://hexdocs.pm/swoosh/Swoosh.html) - [LiveView uploads](https://hexdocs.pm/phoenix_live_view/uploads.html) - [Phoenix PubSub](https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html) - [usage_rules README](https://hexdocs.pm/usage_rules/readme.html) - [usage_rules sync task](https://hexdocs.pm/usage_rules/Mix.Tasks.UsageRules.Sync.html) - [Ecto current transaction API and semantics](https://hexdocs.pm/ecto/Ecto.Repo.html#c:transact/2) ## Extended Elixir reference Imported from https://elixir.menu/; each dataset retains its own review date. Original editorial owner: elixir.menu. ### Foundation Source reviewed: 2026-10-06 Database-backed web products built by individuals and small teams One default per job. Add a dependency when its job exists. Revisit a choice when a concrete requirement warrants it. Documentation-based recommendations; verify the selected dependencies together in your application. #### Application ##### Web framework: Phoenix Stage: Start here Overview: 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. Setup: Use the official getting-started guide and a supported Elixir/OTP pair. Commit the resolved dependency lockfile. Limits: Phoenix does not choose every application policy for you. This guide supplies the next layer of defaults; it does not replace Phoenix. - [Phoenix getting started](https://hexdocs.pm/phoenix/up_and_running.html) ##### Interactive interfaces: Phoenix LiveView Stage: Start here Overview: 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. Setup: Keep business rules in contexts; use LiveView for interaction and presentation. Limits: Offline-first products, rich canvas editors and heavy local interaction can justify a dedicated client application. Add small JavaScript hooks for isolated browser behavior. - [LiveView documentation](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html) ##### Styling and components: Tailwind CSS + HEEx components Stage: Start here Overview: 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. Setup: Define the product’s type, spacing and color rules, then build the components repeated across its screens. Limits: 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. - [Phoenix 1.8 release](https://phoenixframework.org/blog/phoenix-1-8-released) - [daisyUI customization](https://daisyui.com/docs/customize/) ##### Database and queries: PostgreSQL + Ecto Stage: Start here Overview: 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. Setup: Use Ecto.Multi for multi-step transactions. Inspect slow queries and their plans before adding caches. Limits: 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. - [Ecto documentation](https://hexdocs.pm/ecto/Ecto.html) - [Ecto.Multi](https://hexdocs.pm/ecto/Ecto.Multi.html) ##### Business logic: Phoenix contexts Stage: Start here Overview: 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. Setup: Define public operations around the application’s domain. Call those operations from controllers, LiveViews and workers; keep database access behind the context boundary. Limits: A context is an organizational boundary, not a process. Do not turn ordinary CRUD or pure business logic into a GenServer. - [Phoenix contexts](https://hexdocs.pm/phoenix/contexts.html) #### Accounts and permissions ##### Accounts and sign-in: phx.gen.auth Stage: When needed Overview: 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. Setup: Read the generated code and current security guidance. Configure real email delivery before relying on magic links. Limits: Authentication is not authorization. Enterprise SSO, external identity or complex organization requirements need their own deliberate integration. - [Authentication generator](https://hexdocs.pm/phoenix/mix_phx_gen_auth.html) ##### Authorization: Scopes + context checks Stage: When needed Overview: 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. Setup: Pass the current scope into context operations. Test that another user cannot read or modify the protected resource, including through direct context calls. Limits: Scopes carry identity and context; they are not an automatic policy engine. Hidden buttons and client parameters are never sufficient access control. - [Phoenix scopes](https://hexdocs.pm/phoenix/scopes.html) #### Jobs and integrations ##### Durable background jobs: Oban Stage: When needed Overview: 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. Setup: Use separate queues for distinct workloads and monitor retries. An ordinary Task is suitable for disposable concurrent work, not a durable queue. Limits: Jobs may be retried. Make side effects idempotent; uniqueness is not an exactly-once guarantee. Some advanced orchestration features belong to paid Oban Pro. - [Oban documentation](https://hexdocs.pm/oban/Oban.html) ##### Recurring tasks: Oban Cron Stage: When needed Overview: 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. Setup: Set the intended timezone, check daylight-saving behavior where applicable, and keep workers idempotent. Limits: 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. - [Oban.Cron](https://hexdocs.pm/oban/Oban.Cron.html) ##### Transactional email: Swoosh Stage: When needed Overview: 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. Setup: Keep development mail local. Test message content and recipient selection before enabling production delivery. Limits: Swoosh is a library, not an email delivery service. The provider, verified domain and deliverability setup are separate operational choices. - [Swoosh documentation](https://hexdocs.pm/swoosh/Swoosh.html) ##### Outgoing HTTP: Req Stage: When needed Overview: 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. Setup: Wrap each external service behind a small module. Use Req.Test for deterministic request tests. Limits: Timeouts, retries and error handling are part of the integration design. A retried payment or other side effect needs an idempotency strategy. - [Req documentation](https://hexdocs.pm/req/Req.html) - [Req.Test](https://hexdocs.pm/req/Req.Test.html) ##### Realtime notifications: Phoenix PubSub Stage: When needed Overview: 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. Setup: Use Presence only when you actually need to track who is connected. Limits: PubSub is not a persistent message log. Multiple nodes require a suitable cluster or adapter configuration. - [Phoenix.PubSub](https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html) ##### File uploads: LiveView uploads Stage: When needed Overview: 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. Setup: Set size/type limits, authorize downloads, and implement the storage provider’s documented signing flow. Limits: An upload widget does not supply permanent storage. Ephemeral application disks are not a durable attachment store; client metadata does not establish file safety. - [LiveView uploads](https://hexdocs.pm/phoenix_live_view/uploads.html) #### Queries and APIs ##### Product text search: PostgreSQL full-text search Stage: When needed Overview: 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. Setup: Build representative search cases and inspect query plans; avoid claiming that an unindexed text scan will scale. Limits: Advanced relevance, typo tolerance or specialist search scale can justify a dedicated engine. Evaluate against actual queries and user expectations. - [PostgreSQL text search](https://www.postgresql.org/docs/current/textsearch-intro.html) ##### Filtering and pagination: Flop Stage: When needed Overview: 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. Setup: Use cursor pagination when the list and ordering warrant it; add Flop Phoenix only for the corresponding UI helpers. Limits: For one simple bounded list, an explicit Ecto query may be enough. Pagination does not replace tenant or ownership checks. - [Flop documentation](https://hexdocs.pm/flop/readme.html) ##### Local read caching: ETS Stage: After measuring Overview: 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. Setup: Define table ownership, expiry and invalidation. Shared durable state requires a different design. Limits: 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. - [ETS documentation](https://www.erlang.org/doc/apps/stdlib/ets.html) ##### JSON APIs: Phoenix controllers Stage: When needed Overview: 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. Setup: Define authentication, authorization, error shapes, pagination and versioning as part of the API contract. Limits: 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. - [Phoenix JSON and APIs](https://hexdocs.pm/phoenix/json_and_apis.html) #### Testing and deployment ##### Application tests: ExUnit + LiveViewTest Stage: Start here Overview: 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. Setup: Prioritize permission boundaries, data invariants, job behavior and core user journeys. Limits: Server-side LiveView tests do not execute browser JavaScript or prove the final visual layout. Avoid asserting incidental markup when behavior is the contract. - [ExUnit](https://hexdocs.pm/ex_unit/ExUnit.html) - [LiveViewTest](https://hexdocs.pm/phoenix_live_view/Phoenix.LiveViewTest.html) ##### Browser integration tests: PhoenixTest.Playwright Stage: When needed Overview: 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. Setup: Cover representative critical flows and keep browser tests focused on observable behavior. Limits: This adds browser tooling and setup cost. Keep most application tests in ExUnit; this is an editorial extension, not a Phoenix-generated default. - [PhoenixTest.Playwright](https://hexdocs.pm/phoenix_test_playwright/readme.html) ##### Instrumentation: Telemetry + Logger Stage: Start here Overview: 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. Setup: Make logs useful without exposing secrets. Establish alerts and retention before calling the production system operationally complete. Limits: Instrumentation is not a hosted monitoring backend. Choose collection, storage and alerting separately; restrict any production LiveDashboard access. - [Telemetry](https://hexdocs.pm/telemetry/readme.html) - [Logger](https://hexdocs.pm/logger/Logger.html) ##### Deployment artifact: Mix releases Stage: When shipping Overview: 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. Setup: Choose a host that fits the team. Rehearse migrations and restoration, and keep secrets out of the build artifact. Limits: A release is not a hosting platform. Database backups, migrations, TLS, monitoring and rollback remain production responsibilities. - [Phoenix releases](https://hexdocs.pm/phoenix/releases.html) ### Optional libraries Source reviewed: 2026-10-11 Choose and configure each library against its installed-version documentation. 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. #### Accounts and product controls ##### Social login and OIDC: Assent Use when: Users need to sign in with Google, GitHub, Apple or an OpenID Connect provider. Usage: Integrate provider authentication with the application's existing accounts and sessions. Limits: Account linking, session management and permissions remain application concerns. SAML is a separate requirement. - [Assent](https://github.com/pow-auth/assent) ##### Rate limiting: Hammer Use when: Login attempts, API calls, uploads or expensive actions need limits. Usage: Define limits by actor, operation and time window; choose a backend that matches the deployment. Limits: A node-local counter does not automatically enforce a cluster-wide quota. Choose the algorithm's burst behavior deliberately. - [Hammer](https://hexdocs.pm/hammer/readme.html) ##### Feature flags: FunWithFlags Use when: Features need gradual rollout, per-customer access or an operational off switch. Usage: Choose an Ecto or Redis persistence adapter and configure synchronization between nodes. Limits: Keep permission checks separate from rollout flags. Remove expired flags and restrict the management interface. - [FunWithFlags](https://hexdocs.pm/fun_with_flags/readme.html) #### Files and documents ##### Object storage: ExAws.S3 Use when: Uploads need to live in an S3 or compatible object store. Usage: Use ExAws with its S3 service module for object operations and signed URLs. In a LiveView app, connect it to the upload flow. Limits: The storage service, credentials, access rules and lifecycle policy are separate. Check which operations a compatible service actually supports. - [ExAws.S3](https://hexdocs.pm/ex_aws_s3/ExAws.S3.html) ##### Image processing: Image Use when: The product needs thumbnails, resized uploads, image conversion or watermarks. Usage: Process images through the libvips-backed Image API; use Oban for work that needs retries. Limits: Vix/libvips introduces native runtime requirements. Check the deployment target and required codecs, and limit input dimensions and processing work. - [Image](https://hexdocs.pm/image/readme.html) ##### Markdown parsing and rendering: MDEx Use when: The application needs CommonMark parsing, rendered Markdown content or transformations over a Markdown document tree. Usage: 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. Limits: 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. - [MDEx](https://github.com/leandrocp/mdex) ##### PDF generation: ChromicPDF Use when: Invoices, reports or other HTML documents need downloadable PDFs. Usage: Render application-owned HTML and CSS through a managed Chrome process. Limits: Chrome is an additional runtime dependency; PDF/A conversion also uses Ghostscript. Isolate rendering and control access to external resources. - [ChromicPDF](https://hexdocs.pm/chromic_pdf/ChromicPDF.html) ##### CSV import and export: NimbleCSV Use when: Users need bulk uploads, data exports or integrations through CSV files. Usage: Parse and write streams; validate each imported row through the application's business rules. Limits: CSV parsing does not validate field types or business rules. Define malformed-row handling and spreadsheet formula escaping for exports. - [NimbleCSV](https://hexdocs.pm/nimble_csv/NimbleCSV.html) #### APIs and collaboration ##### Documented HTTP APIs: OpenApiSpex Use when: External consumers need an OpenAPI contract for the Phoenix API. Usage: Describe operations and schemas, validate requests, and test responses against the specification. Limits: A schema does not enforce ownership or authorization. Keep the published contract aligned with application behavior. - [OpenApiSpex](https://hexdocs.pm/open_api_spex/readme.html) ##### GraphQL APIs: Absinthe Use when: Clients specifically need GraphQL queries, mutations or subscriptions. Usage: Expose the existing business layer through a schema; use Dataloader where batching is needed. Limits: Resolvers still need authorization and query-cost limits. Ordinary JSON endpoints remain simpler when GraphQL adds no client benefit. - [Absinthe](https://hexdocs.pm/absinthe/overview.html) ##### Who is online: Phoenix Presence Use when: Chat, collaborative screens or live rooms need connected-user state. Usage: Track presence metadata and broadcast joins and leaves through Phoenix's existing realtime infrastructure. Limits: Presence is ephemeral and eventually consistent. It is not a durable audit trail, access-control system or editing-conflict resolver. - [Phoenix Presence](https://hexdocs.pm/phoenix/Phoenix.Presence.html) #### Languages, locales and money ##### Translated interface text: Gettext Use when: The application needs interface copy in multiple languages. Usage: Use the Gettext integration already present in typical Phoenix projects; maintain translation catalogs and plural forms. Limits: It does not translate user-authored content automatically. Dates, amounts and units need locale-aware formatting too. - [Gettext](https://hexdocs.pm/gettext/Gettext.html) ##### Localized dates and numbers: Localize Use when: Dates, numbers, currencies and units must follow the user's locale. Usage: Use CLDR-based formatting and parsing. For new projects, evaluate Localize as the documented successor to the ex_cldr family. Limits: Existing ex_cldr applications need a planned migration. Check runtime requirements and package locale data for deployment. - [Localize](https://hexdocs.pm/localize/readme.html) - [ex_cldr migration notice](https://hexdocs.pm/ex_cldr/readme.html) ##### Currency amounts: Money (ex_money) Use when: Prices, invoices or balances need explicit currencies and decimal arithmetic. Usage: Represent amount and currency together and make rounding rules explicit. Limits: This is not payment processing, tax calculation or an accounting ledger. The package is ex_money; check its major-version migration notes. - [Money](https://hexdocs.pm/ex_money/readme.html) #### AI features ##### Calling language models: ReqLLM Use when: The product needs text generation, streaming, structured outputs, embeddings or model tool calls through supported provider APIs. Usage: 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. Limits: 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. - [ReqLLM](https://github.com/agentjido/req_llm) ##### Tool-using AI agents: Jido.AI 2.x Use when: A language model must select tools, keep agent state or run a bounded multistep reasoning loop. Usage: 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. Limits: 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. - [Jido.AI documentation](https://hexdocs.pm/jido_ai/readme.html) - [Jido ecosystem](https://jido.run/ecosystem) ##### Validated structured extraction: InstructorLite Use when: The main requirement is extracting typed fields from text into Ecto schemas, with casting, validation and retries. Usage: 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. Limits: 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. - [InstructorLite](https://github.com/martosaur/instructor_lite) ##### Conversational chains and tool loops: LangChain for Elixir Use when: The application is organized around message history, model responses and chained tool calls, or already uses the Elixir LangChain abstractions. Usage: Compose messages, model adapters and tools through LLMChain. Use its callbacks for streaming and inspect tool-call trajectories when evaluating a conversation workflow. Limits: 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. - [LangChain for Elixir](https://github.com/brainlid/langchain) ##### AI features for Ash applications: Ash AI Use 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. Usage: 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. Limits: 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. - [Ash AI](https://github.com/ash-project/ash_ai) ##### Vector similarity search: pgvector Use when: Embeddings are useful for semantic retrieval or recommendations alongside existing PostgreSQL data. Usage: Enable the PostgreSQL vector extension and use the Elixir pgvector integration with Ecto or Postgrex. Limits: The library does not generate embeddings. Verify database-extension support, dimensions, indexes and retrieval quality against representative queries. - [pgvector for Elixir](https://hexdocs.pm/pgvector/readme.html) ##### Running pretrained models: Bumblebee + Nx Use when: Inference should run on infrastructure you control, using a supported pretrained model. Usage: Load supported model architectures with Bumblebee and serve predictions through Nx.Serving. Limits: Plan model memory, a suitable numerical backend and hardware. Model compatibility and licensing need to be checked individually. - [Bumblebee](https://hexdocs.pm/bumblebee/Bumblebee.html) #### Data processing and machine learning ##### Message ingestion pipelines: Broadway Use when: The application consumes a stream from Kafka, RabbitMQ, SQS or another supported source. Usage: Build concurrent processing stages with batching, acknowledgements and back-pressure. Limits: The source connector determines delivery behavior. Keep handlers safe to retry; ordinary application jobs still fit Oban. - [Broadway](https://hexdocs.pm/broadway/Broadway.html) ##### Tabular data analysis: Explorer Use when: Imports, analytics or reports need dataframe transformations over CSV, Parquet or similar datasets. Usage: Use typed series and dataframes for grouping, joining and transforming tabular data. Limits: The default Polars backend uses native code. Check deployment support and memory use; routine application queries still belong in Ecto. - [Explorer](https://hexdocs.pm/explorer/Explorer.html) ##### Building and training neural networks: Axon + Nx Use when: The project needs to define or train a neural network in Elixir rather than only run a supported pretrained model. Usage: 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. Limits: 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. - [Axon](https://github.com/elixir-nx/axon) #### Performance and scaling ##### Custom demand-driven pipelines: GenStage Use when: Producers and consumers need a custom event pipeline with demand-driven backpressure. Usage: Model stages around runtime concurrency and data transfer; keep business steps in functions. Limits: You own buffering, subscriptions and failure behavior. Use Task.async_stream for simpler bounded parallel work, or Broadway for its ingestion features. - [GenStage](https://hexdocs.pm/gen_stage/GenStage.html) ##### Parallel dataset transformations: Flow Use when: A large enumerable needs parallel mapping, partitioned grouping, aggregation or windows. Usage: Build a Flow pipeline and choose partition keys, stages and windows for the workload. Limits: Coordination has overhead; small inputs can favor Enum or Task. Partitioning affects grouping and order; bound accumulating state. - [Flow](https://hexdocs.pm/flow/Flow.html) ##### Compare code performance: Benchee Use when: A measured hot path has alternative implementations to compare. Usage: Benchmark representative inputs with warmup, runtime, memory and reduction measurements. Limits: Microbenchmarks do not establish application throughput or production latency. Check correctness and end-to-end behavior separately. - [Benchee](https://hexdocs.pm/benchee/readme.html) ##### Locate runtime bottlenecks: Mix + OTP profilers Use when: The application is slow and you need to locate expensive calls or repeated work. Usage: Use the supported mix profile task or OTP profiler for the question; combine findings with the existing Telemetry events. Limits: Check installed runtime support for tprof, eprof and fprof. Tracing can change timing and add overhead; profile a representative bounded workload. - [Mix + OTP profilers](https://hexdocs.pm/mix/Mix.Tasks.Profile.Tprof.html) ##### Managed in-memory caching: Cachex Use when: A node-local cache needs expiration, eviction or fallback loading beyond a small ETS implementation. Usage: Configure cache limits, expiration and loading behavior around the data lifecycle. Limits: Define invalidation and stale-data policy. A local cache is not a durable source of truth or a cluster-wide consistency guarantee. - [Cachex](https://hexdocs.pm/cachex/Cachex.html) ##### Native computation and Rust integration: Rustler Use when: Profiling identifies CPU-heavy work suited to native code, or the product must call an existing Rust library. Usage: Expose a narrow NIF interface and select normal versus dirty scheduling appropriate to the work. Limits: 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. - [Rustler](https://hexdocs.pm/rustler/readme.html) ##### Compiled tensor computation: EXLA + Nx Use when: Nx numerical work needs a compiled backend on supported CPU or accelerator hardware. Usage: Use EXLA as the Nx compiler/backend and select the supported target, precision and memory settings. Limits: 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. - [EXLA + Nx](https://hexdocs.pm/exla/EXLA.html) ##### Elastic remote execution: FLAME Use when: Bursty expensive work should run on additional ephemeral nodes, such as media processing or model inference. Usage: Configure a bounded runner pool and an appropriate backend. Start only required application children and size runner database pools deliberately. Limits: 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. - [FLAME](https://hexdocs.pm/flame/FLAME.html) #### Development tools ##### Module dependency rules: Boundary Use when: Domains or layers need explicit, compiler-checked dependencies and public module exports. Useful for agent-maintained applications as well as human-maintained code. Usage: 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. Limits: 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. - [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) ##### AI-assisted Phoenix development: Tidewave Use when: A coding agent needs runtime context from a Phoenix application during development. Usage: 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. Limits: 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. - [Tidewave Phoenix](https://github.com/tidewave-ai/tidewave_phoenix) #### A different application architecture ##### Declarative business applications: Ash Use when: Resources, actions, policies and derived APIs form a substantial part of the application. Usage: Evaluate Ash early as the domain layer beneath Phoenix, with only the extensions the product needs. Limits: This changes how business logic is modeled. It is an architectural choice, not a small utility to install beside an unchanged contexts design. - [What is Ash?](https://hexdocs.pm/ash/what-is-ash.html) ##### Stateful agent workflows: Jido 2.x Use when: The application needs cooperating agents that choose or coordinate steps, share reusable actions and react to routed signals. Usage: 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. Limits: 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. - [Jido documentation](https://hexdocs.pm/jido/readme.html) - [Jido ecosystem](https://jido.run/ecosystem) #### Embedded devices and firmware: Nerves #### Audio, video and streaming pipelines: Membrane ### OTP and performance Source reviewed: 2026-10-06 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. Start with functions. Add processes for state ownership, concurrency or lifecycle. Choose shared storage by its read/write pattern; measure before changing the architecture. #### Computation and process state ##### Ordinary computation: Functions + Enum Use when: The work is business logic or a transformation that needs no independent lifecycle. Limits: Keep it in functions. Adding a process adds messaging and coordination costs; it does not make a function faster. - [Functions + Enum documentation](https://hexdocs.pm/elixir/Enum.html) ##### Lazy processing: Stream + File.stream! Use when: A file or collection should be processed incrementally, without building every intermediate result in memory. Limits: Streams are lazy: enumerate them to run the work. They are not parallel; collecting all results can still exhaust memory. - [Stream + File.stream! documentation](https://hexdocs.pm/elixir/Stream.html) ##### One concurrent operation: Task Use when: Short-lived work can run alongside its caller, such as fetching independent inputs. Limits: Task.async links failures to the caller. Await the result and define timeout/cleanup behavior. Tasks do not survive node restarts as durable jobs. - [Task documentation](https://hexdocs.pm/elixir/Task.html) ##### Supervised concurrent work: Task.Supervisor Use when: Tasks need an application-owned supervisor or must fail independently of the requesting process. Limits: 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. - [Task.Supervisor documentation](https://hexdocs.pm/elixir/Task.Supervisor.html) ##### Bounded parallel batches: Task.async_stream Use when: Independent items can be processed concurrently with a bounded number of tasks. Limits: 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. - [Task.async_stream documentation](https://hexdocs.pm/elixir/Task.html#async_stream/3) ##### Simple shared process state: Agent Use when: One process needs to hold a small value accessed through get/update functions. Limits: 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. - [Agent documentation](https://hexdocs.pm/elixir/Agent.html) ##### State and coordination: GenServer Use when: A long-lived process owns state or coordinates a resource, for example a connection or session. Limits: 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. - [GenServer documentation](https://hexdocs.pm/elixir/GenServer.html) ##### Explicit runtime transitions: :gen_statem Use when: A protocol or connection has distinct states, state-specific events and transition/timeout rules. Limits: Use functions or a data model for ordinary business statuses. The behaviour models a running process; supervision does not make its state durable. - [:gen_statem documentation](https://www.erlang.org/doc/apps/stdlib/gen_statem.html) #### Lifecycle, naming and coordination ##### Application lifecycle: Application + Supervisor Use when: Long-running children must start in order and recover according to their dependencies. Limits: 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. - [Application + Supervisor documentation](https://hexdocs.pm/elixir/Supervisor.html) ##### Workers created at runtime: DynamicSupervisor Use when: The application starts and stops workers as demand changes, such as one worker per active room. Limits: Use Registry for discovery. A restarted supervisor does not remember the former dynamic child set; reconcile it from an authoritative source when required. - [DynamicSupervisor documentation](https://hexdocs.pm/elixir/DynamicSupervisor.html) ##### Find local processes: Registry Use when: Processes need names based on runtime keys, such as tenant/session IDs, or local duplicate-key dispatch. Limits: Use :via tuples rather than creating atoms from user input. Registry is node-local; it is neither cluster discovery nor durable storage. - [Registry documentation](https://hexdocs.pm/elixir/Registry.html) ##### Reduce supervisor contention: PartitionSupervisor Use when: Measurements show one process, such as a DynamicSupervisor or Task.Supervisor, bottlenecking concurrent starts. Limits: Route work across partitioned children. This reduces contention in that layer; it does not parallelize a single worker or distribute work across nodes. - [PartitionSupervisor documentation](https://hexdocs.pm/elixir/PartitionSupervisor.html) ##### Observe failure and schedule messages: Process monitors + timers Use when: A process must observe another process exiting or receive a delayed message. Limits: 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. - [Process monitors + timers documentation](https://hexdocs.pm/elixir/Process.html) ##### Inspect a running process: :sys + Process.info Use when: A running server has unexpected state, memory growth or a growing mailbox. Limits: 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. - [OTP sys](https://www.erlang.org/doc/apps/stdlib/sys.html) - [Process.info](https://hexdocs.pm/elixir/Process.html#info/2) #### Shared data and hot paths ##### Mutable shared tables: :ets Use when: Many processes need concurrent lookups or updates to node-local in-memory data. Limits: 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. - [:ets documentation](https://www.erlang.org/doc/apps/stdlib/ets.html) ##### Read-mostly shared values: :persistent_term Use 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. Limits: 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. - [:persistent_term documentation](https://www.erlang.org/doc/apps/erts/persistent_term.html) ##### Frequent shared increments: :counters Use when: Many processes update numeric metrics without routing each increment through one server. Limits: 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. - [:counters documentation](https://www.erlang.org/doc/apps/erts/counters.html) ##### Atomic numeric coordination: :atomics Use when: An integer operation needs an atomic result or compare-and-exchange, such as claiming a numeric slot. Limits: 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. - [:atomics documentation](https://www.erlang.org/doc/apps/erts/atomics.html) ##### FIFO data structure: :queue Use when: A process holds a FIFO buffer and repeated list appends would be costly. Limits: A queue is a data structure, not a worker, backpressure mechanism or persistent job system. Bound its size and define overload behavior. - [:queue documentation](https://www.erlang.org/doc/apps/stdlib/queue.html) ##### Build output from fragments: iodata Use when: Output combines many byte fragments and its destination accepts iodata. Limits: 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. - [iodata documentation](https://hexdocs.pm/elixir/IO.html#module-io-data) ##### Control retained binary memory: :binary Use when: Small slices of large payloads live in process state or another long-lived store. Limits: Inspect referenced_byte_size. Copy selected retained slices when they pin a much larger binary; copying every binary adds allocation and work. - [:binary documentation](https://www.erlang.org/doc/apps/stdlib/binary.html) - {'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']]} ### Other Elixir starting points Source reviewed: 2026-10-11 #### Command-line tool Developer tools, local automation and terminal applications. Foundation: Mix + OptionParser Starting command: `mix new my_tool` Keep command parsing separate from the modules that perform the work. OptionParser handles flags; the application owns help text, subcommands, output and exit codes. Limits: 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. - [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) #### Library Reusable modules used by other Elixir applications. Foundation: Mix Starting command: `mix new my_library` 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. Limits: 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. - [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) #### Background service Workers, integrations and processes that keep running. Foundation: Mix + OTP supervision Starting command: `mix new my_service --sup` Use supervision for process lifecycles and recovery. Keep calculations and business operations in ordinary modules; introduce stateful processes where they are needed. Limits: 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. - [Supervision](https://hexdocs.pm/elixir/Supervisor.html) - [Bandit](https://hexdocs.pm/bandit/Bandit.html) - [Mix releases](https://hexdocs.pm/mix/Mix.Tasks.Release.html) #### Web application or API Browser products, customer portals and HTTP APIs. Foundation: Phoenix Starting command: `mix phx.new my_web_app` 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. Limits: 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. - [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) #### Data analysis or machine learning Notebooks, data transformations and numerical models. Foundation: Livebook; Mix for the application 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. Limits: Hosted model calls, local inference and training are different requirements. Check native backends, memory and hardware before selecting a deployment environment. - [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) #### Embedded device Hardware products, sensors and deployed Linux devices. Foundation: Nerves Start from the Nerves installation and project guides for the target hardware. Build firmware with the system and libraries that the device requires. Limits: 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. - [Nerves getting started](https://hexdocs.pm/nerves/getting-started.html) #### Audio or video system Streaming, transcoding and realtime media processing. Foundation: Membrane + an OTP application 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. Limits: Protocols, codecs and native dependencies determine the pipeline and deployment. Ordinary file uploads do not require a media framework. - [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 - body - sources #### Dependency guidance for agents 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. [usage_rules documentation](https://hexdocs.pm/usage_rules/readme.html) Keep the project README current and link the selected guidance; preserve existing project instructions. --- # Next.js React interfaces with server rendering, routes and application logic. Language: TypeScript | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: web UI: full Deployment: node ## Use cases - Authenticated web products - Server-rendered React interfaces - Browser applications with owned APIs and relational data ## Fit - 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 ## Choose something else 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 ## 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. ## 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. ## Tools ### runtime and dependency management: Node LTS + npm lockfile LTS production policy and reproducible dependency install Limits and integration: Pin resolved runtime/dependencies; latest is a scaffold-time lookup, not a CI dependency strategy - https://nodejs.org/en/about/previous-releases - https://nextjs.org/docs/app/getting-started/installation Alternatives: Preserve existing pnpm; Bun after compatibility validation ### application framework: Next.js App Router + React + strict TypeScript Full-stack React with version-matched agent documentation Limits and integration: TanStack Start official homepage labelled RC at review; web UI is not native UI; framework does not supply business correctness - 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/ Alternatives: React/Vite for API-backed SPA; TanStack Start for typed route loaders/server functions; Astro for editorial sites ### project instructions: README navigation + generated version-matched agent guidance Keep repository instructions and installed framework documentation discoverable Limits and integration: 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. - 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 Alternatives: README-only workflow when the repository explicitly chooses it ### Agent runtime inspection: Next.js development MCP endpoint with real browser inspection Combine version-matched framework context, compilation errors, routes and runtime logs with the actual rendered application. Limits and integration: 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. - https://nextjs.org/docs/app/guides/mcp - https://nextjs.org/docs/app/guides/ai-agents Alternatives: Existing development logs and browser tooling when MCP is unavailable 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. ### validation: Zod Runtime schemas with inferred TypeScript types Limits and integration: Validate requests/environment/external results; shape checks do not establish permission or truth - https://zod.dev/ Alternatives: Existing compatible runtime schema library ### database and migrations: PostgreSQL + Drizzle + reviewed SQL migrations Typed schema with inspectable SQL history Limits and integration: Configure schema paths and target environment; apply migration once; rehearse fresh DB and forward compatibility - https://orm.drizzle.team/docs/get-started-postgresql - https://orm.drizzle.team/docs/migrations Alternatives: Existing database/ORM conventions ### identity: Better Auth + Drizzle PostgreSQL adapter Integrated session/provider support without designing password/session primitives Limits and integration: Auth schema generate then Drizzle migrations; direct Better Auth migrate is Kysely-only; configure origin/secrets/recovery; authorize near data - https://better-auth.com/docs/installation - https://better-auth.com/docs/integrations/next - https://nextjs.org/docs/app/guides/authentication Alternatives: Existing identity provider or auth library matching requirements ### background work: Inngest durable workflows when required Checkpointed steps, retries and waits Limits and integration: Idempotent effects and authorized approvals required; use outbox for DB/event consistency; avoid beta durable endpoints as default - https://www.inngest.com/docs/durable-execution - https://www.inngest.com/docs/durable-execution/quick-start - https://www.inngest.com/docs/durable-execution/concepts Alternatives: Omit for request-local work; Existing durable queue/workflow service ### Static typing: TypeScript strict Independent deterministic checks for generated edits Limits and integration: Next build does not run lint; never ignore build/type errors to satisfy a check - https://nextjs.org/docs/app/getting-started/installation - https://nextjs.org/docs/app/api-reference/cli/next Alternatives: Preserve an existing TypeScript configuration after checking its guarantees ### Linting: ESLint Independent deterministic checks for generated edits Limits and integration: Next build does not run lint; never ignore build/type errors to satisfy a check - https://nextjs.org/docs/app/getting-started/installation - https://nextjs.org/docs/app/api-reference/cli/next Alternatives: Biome when project has selected it ### Domain tests: Vitest Run isolated domain behavior checks with a configured test environment Limits and integration: Install/configure Vitest and DOM environment for UI tests. Next async Server Components require browser/integration coverage instead. - https://vitest.dev/guide/ Alternatives: Existing suitable test suite ### Component tests: React Testing Library Test rendered components through user-visible DOM behavior Limits and integration: 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. - https://testing-library.com/docs/react-testing-library/intro/ Alternatives: Existing suitable test suite ### Browser tests: Playwright Exercise critical journeys in actual browser engines Limits and integration: Install @playwright/test and matching browsers; configure an isolated test server/data and test session expiry, routing and authorization failures. - https://playwright.dev/docs/intro Alternatives: Existing suitable test suite ### deploy: Project-selected Node or Docker host Documented full Next feature support with Node/Docker Limits and integration: Adapters vary; verify chosen host, secrets, DB connections, sessions, migrations and restore; Cloudflare needs separate compatibility review - https://nextjs.org/docs/app/getting-started/deploying Alternatives: Verified adapter; Static export for compatible static subset ### Server state cache: TanStack Query for client-owned remote state Queries, mutations and invalidation support interactive API screens Limits and integration: 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. - https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults Alternatives: Next server loading for server-owned data; Router loaders for simple route data ### Forms: React Hook Form for complex client forms Separates client form state and validation from page components Limits and integration: Install react-hook-form only where needed; wire existing runtime schemas deliberately. Render accessible labels/errors; validate and authorize submissions on the server. - https://github.com/react-hook-form/react-hook-form Alternatives: Native HTML forms for simple submissions ### Styling: Tailwind CSS when utility styling fits the project Reusable styling without a runtime component dependency Limits and integration: 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. - https://tailwindcss.com/docs/installation/using-vite Alternatives: CSS Modules or existing CSS design system ### Accessible UI primitives: Radix Primitives for complex controls Provides focus and keyboard behavior for common interaction patterns Limits and integration: Install only used components. Authors still supply names, contrast and meaningful composition; verify keyboard and assistive-technology behavior. - https://www.radix-ui.com/primitives/docs/overview/accessibility Alternatives: Semantic native HTML controls ### Accessibility checks: axe-core through Playwright + manual keyboard review Automated audits identify common accessibility defects in real pages Limits and integration: Install @axe-core/playwright; scan representative states and use a screen reader/keyboard. Passing automated rules is not complete accessibility evidence. - https://playwright.dev/docs/accessibility-testing Alternatives: Preserve an existing compatible project choice ### Transactional email: Nodemailer with project-selected SMTP provider SMTP transport avoids coupling email templates to a hosting vendor Limits and integration: 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. - https://github.com/nodemailer/nodemailer Alternatives: Provider-supported SDK when API-specific features are required ### Uploads and object storage: AWS SDK for JavaScript v3 S3 client Object storage separates durable files from ephemeral application disks Limits and integration: 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. - https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/javascript_s3_code_examples.html Alternatives: Preserve an existing compatible project choice ### Live server updates: EventSource for one-way server events Browser-standard streaming suits status/progress feeds Limits and integration: 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. - https://html.spec.whatwg.org/multipage/server-sent-events.html Alternatives: WebSocket service for bidirectional collaboration; Polling for infrequent updates ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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. ### Translations to 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. ### Architecture sources - [Next.js Server and Client Components](https://nextjs.org/docs/app/getting-started/server-and-client-components): Pages/layouts default to server components; browser interaction and APIs require client boundaries. - [Next.js Data Security](https://nextjs.org/docs/app/guides/data-security): Existing HTTP APIs or a new server-only DAL provide explicit data ownership; mutations require validation/authorization and minimal DTOs. - [Next.js Authentication](https://nextjs.org/docs/app/guides/authentication): Authentication, session management and authorization are separate responsibilities; optimistic redirects do not replace secure checks. - [Next.js Caching with Cache Components](https://nextjs.org/docs/app/getting-started/caching): Current caching guide applies when cacheComponents is enabled. - [Next.js Caching and Revalidating (Previous Model)](https://nextjs.org/docs/app/guides/caching-without-cache-components): The alternative caching guide applies without Cache Components; defaults and APIs must match that model. - [Next.js Self-Hosting](https://nextjs.org/docs/app/guides/self-hosting): Multi-instance cache coordination, action encryption keys, deployment identifiers and old-client version skew need deployment design. - [Next.js Installation](https://nextjs.org/docs/app/getting-started/installation): Framework setup and deterministic lint/type/build checks have separate tooling. - [Next.js CLI](https://nextjs.org/docs/app/api-reference/cli/next): next typegen, build and production server commands are qualified by installed framework and scripts. - [Inngest Durable Execution](https://www.inngest.com/docs/durable-execution): Completed steps are checkpointed and workflows can retry/resume; durable endpoints are separately marked beta. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### Data and schema **Inspect the source:** Existing REST/GraphQL behavior, DTOs, authorization, transactions and one schema owner. **During 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 design:** Recommendation: Retain the API permanently if appropriate, or transfer a bounded domain to a server-only DAL with minimal DTOs after mixed-version checks. **Rollback:** Route the cohort back while old-compatible schema remains; reconcile writes before any writer reversal. **Benefits and prerequisites** - Server loading can reduce client waterfalls; an owned DAL centralizes authorization. Requires: 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 before transfer** - 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. - https://nextjs.org/docs/app/guides/data-security - https://nextjs.org/docs/app/getting-started/server-and-client-components ### Identity and authorization **Inspect the source:** Existing session issuer, cookie/token format, expiry, revocation, tenant membership and CSRF behavior. **During coexistence:** Recommendation: Retain the issuer behind an adapter and authorize data/mutations in both implementations; inventory origin/domain/cookie differences before sharing. **Target design:** 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. **Rollback:** Restore old routes/issuer acceptance only while its keys and session semantics remain supported; do not resurrect revoked sessions. **Benefits and prerequisites** - One identity authority can support gradual UI/backend replacement. Requires: 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 before transfer** - 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. - https://nextjs.org/docs/app/guides/authentication - https://nextjs.org/docs/app/guides/data-security ### Caching and shared state **Inspect the source:** Actual enabled caching model, personalized response policy, keys, freshness, invalidation and shared-instance behavior. **During coexistence:** Recommendation: Keep the prior policy while converting one route/data category; separate old/new cache namespaces and observe stale/account-crossing outcomes. **Target design:** 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. **Rollback:** Disable the new cache path and purge its namespace; keep source data unchanged and retain old invalidation until transfer completes. **Benefits and prerequisites** - Repeated eligible work can be reused without refetching each time. Requires: A documented freshness tolerance, safe keys and working invalidation. Tradeoffs: Coordination/storage adds operations; freshness and cost gains require measurement. **Checks before transfer** - 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. - 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 ### Jobs and schedules **Inspect the source:** Existing job producer/consumer payloads, ready/scheduled/retry/failed/in-flight states and external-effect idempotency. **During 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 design:** 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. **Rollback:** Stop new producers for the transferred type, account for active runs and resume old workers with compatible payloads; reconcile irreversible effects first. **Benefits and prerequisites** - Checkpointed completed steps allow retry/resume without starting every step again. Requires: 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 before transfer** - 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. - https://www.inngest.com/docs/durable-execution ### Delivery and recovery **Inspect the source:** Current hosting/runtime, static assets, open-tab state, prefetched payloads and Server Function compatibility. **During 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 design:** Recommendation: Use version-matched deploymentId support and infrastructure routing as needed; same-build instances share required action keys and cache coordination. **Rollback:** Restore the prior artifact and routing while compatible assets/data remain; do not claim traffic rollback reverses schema or external effects. **Benefits and prerequisites** - Explicit rollout handling reduces missing-chunk/navigation mismatches. Requires: 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 before transfer** - 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. - https://nextjs.org/docs/app/guides/self-hosting Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. Start in an external source repository parent in a local development workspace with runtime, identity, database and host requirements documented. 2. 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. 3. 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. 4. 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. 5. Configure server-only database/auth modules and Drizzle PostgreSQL schema/config, development DATABASE_URL, auth secret/base URL and Next route/client integration. 6. 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. 7. 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. 8. Implement invalid-input, tenant ownership, session and critical browser tests. Register durable workflow endpoint/worker only if used; exercise retries and duplicate events. 9. 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 below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text npm ci npx next typegen npx tsc --noEmit npx eslint . npx vitest run npm run build npx playwright test ``` ## 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? ## Sources - [Node.js release policy](https://nodejs.org/en/about/previous-releases) - [Next.js installation](https://nextjs.org/docs/app/getting-started/installation) - [create-next-app CLI](https://nextjs.org/docs/app/api-reference/cli/create-next-app) - [Next.js agentRules](https://nextjs.org/docs/app/api-reference/config/next-config-js/agentRules) - [Next.js AI coding agents](https://nextjs.org/docs/app/guides/ai-agents) - [Next.js CLI](https://nextjs.org/docs/app/api-reference/cli/next) - [Next.js deployment](https://nextjs.org/docs/app/getting-started/deploying) - [Vite getting started](https://vite.dev/guide/) - [TanStack Start](https://tanstack.com/start/latest) - [Astro TypeScript](https://docs.astro.build/en/guides/typescript/) - [Zod](https://zod.dev/) - [Drizzle PostgreSQL](https://orm.drizzle.team/docs/get-started-postgresql) - [Drizzle migrations](https://orm.drizzle.team/docs/migrations) - [Better Auth installation](https://better-auth.com/docs/installation) - [Better Auth Next.js integration](https://better-auth.com/docs/integrations/next) - [Next.js authentication](https://nextjs.org/docs/app/guides/authentication) - [Inngest durable execution](https://www.inngest.com/docs/durable-execution) - [Inngest quickstart](https://www.inngest.com/docs/durable-execution/quick-start) - [Inngest concepts](https://www.inngest.com/docs/durable-execution/concepts) - [Next.js Vitest](https://nextjs.org/docs/app/guides/testing/vitest) - [Next.js Playwright](https://nextjs.org/docs/app/guides/testing/playwright) - [TanStack Query important defaults](https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults) - [React Hook Form repository](https://github.com/react-hook-form/react-hook-form) - [Tailwind Vite installation](https://tailwindcss.com/docs/installation/using-vite) - [Radix accessibility](https://www.radix-ui.com/primitives/docs/overview/accessibility) - [Playwright accessibility testing](https://playwright.dev/docs/accessibility-testing) - [Nodemailer maintainer repository](https://github.com/nodemailer/nodemailer) - [AWS JavaScript S3 examples](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/javascript_s3_code_examples.html) - [HTML EventSource standard](https://html.spec.whatwg.org/multipage/server-sent-events.html) - [Vitest guide](https://vitest.dev/guide/) - [Playwright installation](https://playwright.dev/docs/intro) - [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) - [Next.js development MCP and runtime tools](https://nextjs.org/docs/app/guides/mcp) Keep the project README current and link the selected guidance; preserve existing project instructions. --- # React + Vite An interactive browser app connected to an existing or separate API. Language: TypeScript | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: web UI: client Deployment: static ## Use cases - Interactive dashboards - API-backed browser tools - Client-rendered applications ## Fit - Backend/identity already have owners - SSR is not a product requirement - Browser UI and API can be deployed independently ## Choose something else when - Searchable server-rendered content is central - The task requires native device UI - Team expects the frontend scaffold to supply backend auth or persistence ## 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. ## 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. ## Tools ### browser build and UI: React + Vite + TypeScript Focused browser development without unnecessary server framework Limits and integration: TypeScript compiles to JS; Vite is tooling, not a backend; keep HTML/CSS competence - https://vite.dev/guide/ - https://tanstack.com/start/latest - https://react.dev/learn/typescript Alternatives: Next.js for full-stack/SSR; TanStack Start when routing/server integration is needed ### validation: Zod at API/client boundaries Check external values and share explicit contracts Limits and integration: Client checks never replace authoritative backend validation or authorization - https://zod.dev/ Alternatives: Use the existing API's schema/code generation ### Identity ownership: Existing backend owns authentication and authorization Avoid duplicating external-system ownership in browser code Limits and integration: No database credentials/server secrets in browser; document API/session/CORS contract - https://nextjs.org/docs/app/guides/authentication Alternatives: Adopt full-stack Node record when backend is in scope ### Database ownership: Existing backend owns persistence and migrations Avoid duplicating external-system ownership in browser code Limits and integration: No database credentials/server secrets in browser; document API/session/CORS contract - https://nextjs.org/docs/app/guides/authentication Alternatives: Adopt full-stack Node record when backend is in scope ### Background work ownership: Existing backend owns durable jobs Avoid duplicating external-system ownership in browser code Limits and integration: No database credentials/server secrets in browser; document API/session/CORS contract - https://nextjs.org/docs/app/guides/authentication Alternatives: Adopt full-stack Node record when backend is in scope ### Static typing: Strict TypeScript; retain generated project-reference build Static checks and user-visible browser behavior Limits and integration: Configure router/API failure/session expiry tests; preserve scaffold-specific build scripts - https://vite.dev/guide/ - https://nextjs.org/docs/app/guides/testing/vitest - https://nextjs.org/docs/app/guides/testing/playwright Alternatives: Preserve existing compatible tooling ### Linting: ESLint Static checks and user-visible browser behavior Limits and integration: Configure router/API failure/session expiry tests; preserve scaffold-specific build scripts - https://vite.dev/guide/ - https://nextjs.org/docs/app/guides/testing/vitest - https://nextjs.org/docs/app/guides/testing/playwright Alternatives: Preserve existing compatible tooling ### Domain and component tests: Vitest Run isolated domain behavior checks with a configured test environment Limits and integration: Install Vitest; preserve Vite plugins or add a separate test configuration. Mock only external boundaries and test failure states. - https://vitest.dev/guide/ Alternatives: Preserve existing compatible tooling ### Browser tests: Playwright Exercise critical journeys in actual browser engines Limits and integration: Install @playwright/test and matching browsers; configure an isolated test server/data and test session expiry, routing and authorization failures. - https://playwright.dev/docs/intro Alternatives: Preserve existing compatible tooling ### deployment: Static asset host chosen by project Browser build can be independently served Limits and integration: Configure deep-link fallback, API origins, cache invalidation and environment handling; preview is not production - https://vite.dev/guide/ Alternatives: Server-rendered framework when justified ### Server state cache: TanStack Query for client-owned remote state Queries, mutations and invalidation support interactive API screens Limits and integration: 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. - https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults Alternatives: Next server loading for server-owned data; Router loaders for simple route data ### Forms: React Hook Form for complex client forms Separates client form state and validation from page components Limits and integration: Install react-hook-form only where needed; wire existing runtime schemas deliberately. Render accessible labels/errors; validate and authorize submissions on the server. - https://github.com/react-hook-form/react-hook-form Alternatives: Native HTML forms for simple submissions ### Styling: Tailwind CSS when utility styling fits the project Reusable styling without a runtime component dependency Limits and integration: 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. - https://tailwindcss.com/docs/installation/using-vite Alternatives: CSS Modules or existing CSS design system ### Accessible UI primitives: Radix Primitives for complex controls Provides focus and keyboard behavior for common interaction patterns Limits and integration: Install only used components. Authors still supply names, contrast and meaningful composition; verify keyboard and assistive-technology behavior. - https://www.radix-ui.com/primitives/docs/overview/accessibility Alternatives: Semantic native HTML controls ### Accessibility checks: axe-core through Playwright + manual keyboard review Automated audits identify common accessibility defects in real pages Limits and integration: Install @axe-core/playwright; scan representative states and use a screen reader/keyboard. Passing automated rules is not complete accessibility evidence. - https://playwright.dev/docs/accessibility-testing Alternatives: Preserve an existing compatible project choice ### Routing: TanStack Router Typed navigation, route loading and search parameters suit application screens Limits and integration: 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. - https://tanstack.com/router/latest/docs/overview Alternatives: React Router in established projects; No router for a single screen ### Live server updates: EventSource for one-way server events Browser-standard streaming suits status/progress feeds Limits and integration: 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. - https://html.spec.whatwg.org/multipage/server-sent-events.html Alternatives: WebSocket service for bidirectional collaboration; Polling for infrequent updates ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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. ### Translations to 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. ### Architecture sources - [React Build an app from Scratch](https://react.dev/learn/build-a-react-app-from-scratch): A Vite client-only starter requires deliberate routing/data tools; SSR/RSC are additional architecture work. - [Vite Getting Started](https://vite.dev/guide/): Scaffold command and runtime requirements must be checked against resolved Vite version. - [Vite Environment Variables and Modes](https://vite.dev/guide/env-and-mode): VITE_ values are bundled into client code and must not contain secrets. - [Vite Building for Production](https://vite.dev/guide/build): Deleted old chunks can fail dynamic imports; vite:preloadError and HTML cache policy support recovery design. - [Vite Deploying a Static Site](https://vite.dev/guide/static-deploy): Build output needs a chosen production host; vite preview is for local preview. - [TanStack Query Important Defaults](https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults): Staleness, mount/focus/reconnect refetch, garbage collection and retries require explicit application choices. - [WHATWG Fetch Standard](https://fetch.spec.whatwg.org/): Cross-origin response sharing and credential handling are browser protocol rules, separate from application authorization. - [WHATWG Server-sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html): EventSource provides reconnect and event IDs; constructor options include withCredentials, not arbitrary headers. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### Browser and installed clients **Inspect the source:** Existing URLs, backend API DTOs, errors, permissions and navigation/deep-link semantics. **During coexistence:** Recommendation: Replace one route/screen with React while keeping existing API ownership and deep links; contract fixtures cover old/new UI. **Target design:** 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. **Rollback:** Restore old HTML/assets/routes while API compatibility remains; preserve submitted data and reconcile pending mutations. **Benefits and prerequisites** - An independently delivered browser client can evolve behind a stable API. Requires: Owned routing/hosting fallback and backward-compatible API. Tradeoffs: A SPA must own routing/data/loading infrastructure; SSR/RSC are additional architecture choices. **Checks before transfer** - 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. - https://react.dev/learn/build-a-react-app-from-scratch - https://vite.dev/guide/static-deploy ### Identity and authorization **Inspect the source:** Backend credential transport, allowed origins, cookies/CSRF, token expiry and account boundaries. **During coexistence:** Recommendation: Keep the backend issuer; configure same-origin routing or narrowly allowed credentialed CORS and preserve old clients. **Target design:** Recommendation: Centralize credential/error behavior in the API client; enforce authorization and any cookie CSRF protection in the backend. **Rollback:** Restore the old browser artifact/origin policy only if existing credential handling remains secure; retain revocation history. **Benefits and prerequisites** - One backend authority reduces duplicated browser identity logic. Requires: Reviewed origin/credential policy and issuer behavior. Tradeoffs: CORS controls browser response access, not authorization; frontend guards remain presentation only. **Checks before transfer** - 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. - https://fetch.spec.whatwg.org/ - https://vite.dev/guide/env-and-mode ### Caching and shared state **Inspect the source:** Current fetch/cache behavior, stale tolerance, retry limits and account-switch isolation. **During 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 design:** Recommendation: Use explicit TanStack Query staleTime, retry, invalidation and account-clear policy where its remote-state cache serves a requirement. **Rollback:** Return the category to the old loader and clear the new cache; do not discard durable pending user operations. **Benefits and prerequisites** - Shared queries can reuse data and refresh deliberately. Requires: 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 before transfer** - 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. - https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults ### Realtime transport **Inspect the source:** Existing event envelope, authorization, IDs, reconnect behavior and replay/retention rules. **During coexistence:** Recommendation: Keep a backend bridge producing the current event contract; move clients by stable subscription cohort rather than arbitrary per-request routing. **Target design:** Recommendation: Use EventSource for one-way events when host/credentials fit, WebSocket for bidirectional needs; persist/replay events separately when delivery requires it. **Rollback:** Restore old polling/transport using the same cursor domain; reconcile delivered events and keep bridge/history through the rollback window. **Benefits and prerequisites** - A standard browser event stream can replace bespoke polling for suitable feeds. Requires: 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 before transfer** - 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. - https://html.spec.whatwg.org/multipage/server-sent-events.html ### Delivery and recovery **Inspect the source:** Existing HTML/CDN/service-worker policy, lazy chunks and open-tab unsaved state. **During 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 design:** Recommendation: Revalidate HTML, retain old content-hashed chunks and handle vite:preloadError with a guarded refresh/update flow that preserves drafts. **Rollback:** Restore the prior HTML and retained assets, roll service-worker changes through their actual lifecycle, and keep new-client API support. **Benefits and prerequisites** - Old tabs can continue loading their release's lazy chunks. Requires: 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 before transfer** - 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. - https://vite.dev/guide/build - https://vite.dev/guide/static-deploy Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. Start in repository parent in a local development workspace with API/session owners identified. 2. Run npm create vite@latest my-app -- --template react-ts; enter my-app; npm install; record resolved versions and commit lockfile. 3. Create README with API contract, run/check instructions and environment variable names. Configure strict TypeScript and router/query tooling only as needed. 4. Add Zod and test tools; configure request validation, error/loading/session-expiry states and authoritative backend authorization tests. 5. Build to static assets, configure chosen host deep-link behavior and API origins, then run production browser checks. ## Verification Commands below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text npm ci npx tsc --noEmit npx eslint . npx vitest run npm run build npx playwright test ``` ## 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? ## Sources - [Vite getting started](https://vite.dev/guide/) - [TanStack Start](https://tanstack.com/start/latest) - [Zod](https://zod.dev/) - [Next.js authentication](https://nextjs.org/docs/app/guides/authentication) - [Next.js Vitest](https://nextjs.org/docs/app/guides/testing/vitest) - [Next.js Playwright](https://nextjs.org/docs/app/guides/testing/playwright) - [React TypeScript](https://react.dev/learn/typescript) - [TanStack Query important defaults](https://tanstack.com/query/latest/docs/framework/react/guides/important-defaults) - [React Hook Form repository](https://github.com/react-hook-form/react-hook-form) - [Tailwind Vite installation](https://tailwindcss.com/docs/installation/using-vite) - [Radix accessibility](https://www.radix-ui.com/primitives/docs/overview/accessibility) - [Playwright accessibility testing](https://playwright.dev/docs/accessibility-testing) - [TanStack Router overview](https://tanstack.com/router/latest/docs/overview) - [HTML EventSource standard](https://html.spec.whatwg.org/multipage/server-sent-events.html) - [Vitest guide](https://vitest.dev/guide/) - [Playwright installation](https://playwright.dev/docs/intro) Keep the project README current and link the selected guidance; preserve existing project instructions. --- # Rails + Hotwire Database-backed products with HTML, accounts and jobs close together. Language: Ruby | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: web UI: server Deployment: server ## Use cases - SaaS - Business CRUD - Collaboration and workflow products ## Fit - An integrated monolith and server-owned UI fit the product. - A small team benefits from stable conventions and limited integration work. ## Choose something else when - The core is an offline-first canvas or requires extensive browser-owned state. - Hard CPU/latency constraints justify a specialist service. ## 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. ## 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. ## Tools ### UI: ERB + Turbo + Stimulus Server-rendered HTML and selective JavaScript limit duplicated UI state. Limits and integration: Do not force Hotwire onto rich offline editors. - https://hotwired.dev/ Alternatives: React client when browser-owned state dominates; retain Rails API ### Database and migrations: PostgreSQL + Active Record migrations Relational constraints and conventional migrations fit business data. Limits and integration: Use unique/foreign-key constraints; assess locks and use expand/contract changes for rolling deploys. - https://guides.rubyonrails.org/active_record_migrations.html Alternatives: SQLite for deliberately single-host deployments ### Authentication: Rails authentication generator Generated local sessions plus explicit per-resource authorization. Limits and integration: Generator is a starting point; signup, authorization and account lifecycle require product decisions. - https://guides.rubyonrails.org/getting_started.html - https://github.com/varvet/pundit - https://github.com/heartcombo/devise Alternatives: Devise when its additional authentication modules are needed ### Authorization: Pundit policy classes Generated local sessions plus explicit per-resource authorization. Limits and integration: Generator is a starting point; signup, authorization and account lifecycle require product decisions. - https://guides.rubyonrails.org/getting_started.html - https://github.com/varvet/pundit - https://github.com/heartcombo/devise Alternatives: Existing resource-level policy implementation; keep authentication separate ### Jobs: Active Job + Solid Queue Database-backed jobs avoid a mandatory separate broker. Limits and integration: Configure worker capacity, retry limits and idempotency; separate queue DB does not guarantee atomic app-write/enqueue. - https://guides.rubyonrails.org/active_job_basics.html Alternatives: Another Active Job backend only for measured operational needs ### Tests: Minitest + Rails integration/system tests Exercise authorization, database constraints and essential browser flows. Limits and integration: Browser tests need their driver/browser; unit tests alone miss UI and transaction races. - https://guides.rubyonrails.org/testing.html Alternatives: Keep RSpec in an established RSpec repository ### Lint and security: RuboCop + Brakeman + bundler-audit Style, application scanning and dependency advisories cover different risks. Limits and integration: Scans do not establish security; test tenant isolation and unsafe uploads. bundler-audit has GPL-3.0 licensing. - https://guides.rubyonrails.org/getting_started.html - https://guides.rubyonrails.org/security.html - https://github.com/rubysec/bundler-audit Alternatives: Preserve existing compatible project tooling ### Deployment: Kamal + generated Dockerfile + PostgreSQL backups Portable container deployment with application-owned configuration. Limits and integration: Requires registry/server credentials and persistent data strategy; backups and restore drills remain operator work. - https://kamal-deploy.org/docs/installation/ - https://guides.rubyonrails.org/getting_started.html Alternatives: Managed container hosting when server operations are undesirable ### Agent tooling: Generators + routes/schema/test feedback + version-matched Rails guides Conventions make edits easier to locate and verify. Limits and integration: Agent productivity is an inference; no cross-framework coding-success benchmark established. - https://rubyonrails.org/ai Alternatives: Add only a reviewed MCP integration with a concrete need ### Licensing and hosting: Rails MIT; self-hostable No mandatory proprietary Rails hosting service. Limits and integration: Dependency licenses remain separate; do not infer all gems are MIT. - https://github.com/rails/rails/blob/main/MIT-LICENSE Alternatives: Paid infrastructure/support when operationally useful ### Transactional email: Action Mailer Framework mailers integrate templates and queued delivery Limits and integration: Configure provider transport and sender; use deliver_later when delivery must be queued; test content and failure behavior. Provider acceptance is not inbox delivery. - https://guides.rubyonrails.org/action_mailer_basics.html Alternatives: Preserve an existing compatible project choice ### Uploads and object storage: Active Storage Framework attachments support external storage and direct uploads Limits and integration: 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. - https://guides.rubyonrails.org/active_storage_overview.html Alternatives: Preserve an existing compatible project choice ### Realtime transport: Action Cable Rails channels integrate WebSocket messages with application code Limits and integration: Configure chosen cable adapter and connection/channel authorization; test reconnect, revoked membership and host proxy behavior. Broadcast is not durable event history. - https://guides.rubyonrails.org/action_cable_overview.html Alternatives: Preserve an existing compatible project choice ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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. ### Translations to 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. ### Architecture sources - [Getting Started with Rails](https://guides.rubyonrails.org/getting_started.html): Rails 8.1 examples, MVC/Active Record, model and authentication generators, migration and console commands. - [Active Record Migrations](https://guides.rubyonrails.org/active_record_migrations.html): Schema migration files, database constraints, reversal and rollback semantics. - [Active Job Basics](https://guides.rubyonrails.org/active_job_basics.html): Active Job serialization, Solid Queue default and process roles, bin/jobs, separate database default, enqueue timing, recurring tasks and retry handling. - [Securing Rails Applications](https://guides.rubyonrails.org/security.html): CookieStore, signing/encryption rotation, replay/fixation and session expiration considerations. - [Action Cable Overview](https://guides.rubyonrails.org/action_cable_overview.html): Cable connections/channels, adapter configuration, async locality, Solid Cable, origins and server deployment. - [Caching with Rails](https://guides.rubyonrails.org/caching_with_rails.html): Rails cache interfaces, SQL cache lifetime, Solid Cache and alternative stores. - [Turbo introduction](https://turbo.hotwired.dev/handbook/introduction): Drive, Frames and Streams extend server-rendered HTML navigation and updates. - [Turbo Streams](https://turbo.hotwired.dev/handbook/streams): DOM target operations and stream transport options. - [Sidekiq Best Practices](https://github.com/sidekiq/sidekiq/wiki/Best-Practices): Jobs must be idempotent; execution is at least once rather than exactly once. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### Data and schema **Inspect the source:** 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. **During 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 design:** 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. **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. **Benefits and prerequisites** - Recommendation: conventional migrations and model access can concentrate schema work in one maintained application. Requires: 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 before transfer** - 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. - https://guides.rubyonrails.org/active_record_migrations.html - https://guides.rubyonrails.org/getting_started.html ### Jobs and schedules **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: stop new producers before restoring old routing; retain both consumers through the rollback window and reconcile completed external effects before re-enqueueing. **Benefits and prerequisites** - SQL-backed job persistence may allow retirement of a dedicated broker. Requires: 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 before transfer** - 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. - https://guides.rubyonrails.org/active_job_basics.html - https://github.com/sidekiq/sidekiq/wiki/Best-Practices ### Identity and authorization **Inspect the source:** 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. **During 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 design:** An intentionally selected Rails authentication implementation with application authorization. CookieStore stores session data on the client; account/session lifecycle rules must be designed separately. **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. **Benefits and prerequisites** - Recommendation: coherent account and session ownership can preserve login continuity during feature migration. Requires: 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 before transfer** - 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. - https://guides.rubyonrails.org/security.html - https://guides.rubyonrails.org/getting_started.html ### Realtime transport **Inspect the source:** 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. **During 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 design:** 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. **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. **Benefits and prerequisites** - HTML updates can reuse server-rendered partials. Requires: 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 before transfer** - 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. - https://guides.rubyonrails.org/action_cable_overview.html - https://turbo.hotwired.dev/handbook/streams ### Caching and shared state **Inspect the source:** 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. **During 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 design:** 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. **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. **Benefits and prerequisites** - Database-backed caching can remove a dedicated cache service when it is the last use. Requires: 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 before transfer** - 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. - https://guides.rubyonrails.org/caching_with_rails.html ### Delivery and recovery **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: freeze producers and scheduler ownership transfers, restore the previous process configuration, then reconcile work accepted by the new deployment. **Benefits and prerequisites** - Recommendation: visible process and schedule ownership makes failures and recovery boundaries reviewable. Requires: 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 before transfer** - 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. - https://guides.rubyonrails.org/active_job_basics.html - https://guides.rubyonrails.org/action_cable_overview.html Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. 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. 2. Run rails new product -d postgresql; enter product; configure development/test database access without committing credentials. 3. Run bin/rails generate authentication; add Pundit via bundle add pundit and run bin/rails generate pundit:install; implement signup and resource policies deliberately. 4. 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. 5. Add bundler-audit to the development group if absent; preserve Gemfile.lock. Define authorization, duplicate-job and migration tests. 6. 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 below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text 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 ``` ## 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 - [Hotwire: HTML Over The Wire](https://hotwired.dev/) - [Active Record Migrations](https://guides.rubyonrails.org/active_record_migrations.html) - [Getting Started with Rails](https://guides.rubyonrails.org/getting_started.html) - [Pundit README](https://github.com/varvet/pundit) - [Devise README](https://github.com/heartcombo/devise) - [Active Job Basics](https://guides.rubyonrails.org/active_job_basics.html) - [Testing Applications](https://guides.rubyonrails.org/testing.html) - [Securing Rails Applications](https://guides.rubyonrails.org/security.html) - [bundler-audit README and license](https://github.com/rubysec/bundler-audit) - [Kamal Installation](https://kamal-deploy.org/docs/installation/) - [Rails and AI](https://rubyonrails.org/ai) - [Rails MIT License](https://github.com/rails/rails/blob/main/MIT-LICENSE) - [Rails Action Mailer](https://guides.rubyonrails.org/action_mailer_basics.html) - [Rails Active Storage](https://guides.rubyonrails.org/active_storage_overview.html) - [Rails Action Cable](https://guides.rubyonrails.org/action_cable_overview.html) Keep the project README current and link the selected guidance; preserve existing project instructions. --- # Laravel + Livewire PHP product applications with a cohesive UI, auth and queue toolset. Language: PHP | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: web UI: server Deployment: server ## Use cases - SaaS - Administrative and business applications - Server-driven interactive products ## Fit - PHP team or Laravel ecosystem fit is strong. - Integrated auth, queues and concrete agent inspection tools reduce assembly work. ## Choose something else 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. ## 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. ## 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. ## Tools ### UI: Official Livewire starter kit + Blade/Tailwind One supported starter establishes coherent UI/auth integration. Limits and integration: Starter includes Flux; distinguish its free components from paid Pro assets. - https://laravel.com/framework/docs/13.x/starter-kits - https://fluxui.dev/pricing Alternatives: Official React/Vue/Svelte Inertia kits for heavier client interactions ### Database and migrations: PostgreSQL + Eloquent + Laravel migrations Conventional ORM and migrations with a production relational store. Limits and integration: Use constraints; production-engine integration tests; never use migrate:fresh against retained data. - https://laravel.com/framework/docs/13.x/database - https://laravel.com/framework/docs/13.x/migrations Alternatives: SQLite for local/small deployments; existing MySQL where operationally established ### Authentication: Starter-kit Fortify auth Existing authentication flow plus resource-level authorization. Limits and integration: Policies remain application work; managed identity adds external terms/cost. - https://laravel.com/framework/docs/13.x/starter-kits - https://laravel.com/framework/docs/13.x/authorization Alternatives: WorkOS starter variant for managed identity requirements ### Authorization: Laravel policies and gates Existing authentication flow plus resource-level authorization. Limits and integration: Policies remain application work; managed identity adds external terms/cost. - https://laravel.com/framework/docs/13.x/starter-kits - https://laravel.com/framework/docs/13.x/authorization Alternatives: Existing explicit resource-level authorization implementation; identity providers still require policies ### Queues: Laravel database queue + supervised workers Simple starting infrastructure with explicit scale-up options. Limits and integration: Use after-commit dispatch, idempotent jobs, finite retries and worker restarts. Horizon requires Redis. - https://laravel.com/framework/docs/13.x/queues - https://laravel.com/framework/docs/13.x/horizon Alternatives: Redis + Horizon for queue dashboards/balancing; SQS for an established managed queue ### Tests: Pest or PHPUnit from starter; Dusk for key browser flows Application and browser verification complement each other. Limits and integration: Use a dedicated test database and install Dusk only in development. - https://laravel.com/framework/docs/13.x/testing - https://laravel.com/framework/docs/13.x/dusk Alternatives: Keep the existing test runner rather than changing syntax for its own sake ### Lint, static analysis and security: Pint + Larastan/PHPStan + Composer audit Formatting, static checks and dependency advisory checks expose different failures. Limits and integration: Install a compatible Larastan version and configure its extension; no audit substitutes for authorization tests. - https://laravel.com/framework/docs/13.x/pint - https://github.com/larastan/larastan - https://getcomposer.org/doc/03-cli.md#audit Alternatives: Existing equivalent tooling if already maintained ### Deployment: PHP-FPM web service + worker supervisor + scheduler on chosen host A conventional process model is a practical default. Limits and integration: Serve only public/; APP_DEBUG=false; persist uploads; reload workers after releases; paid platforms are optional. - https://laravel.com/framework/docs/13.x/deployment Alternatives: Laravel Cloud for managed operation; Forge for server management ### Agent tooling: Laravel Boost development dependency Version-aware documentation and route/schema/log inspection provide concrete context. Limits and integration: 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. - https://laravel.com/framework/docs/13.x/ai Alternatives: Normal CLI/docs when MCP is unavailable ### Licensing and hosting: Laravel framework MIT; self-hostable Framework use does not mandate a hosting subscription. Limits and integration: Check each optional asset/package/service license separately. - https://github.com/laravel/framework/blob/13.x/LICENSE.md - https://fluxui.dev/pricing Alternatives: Optional paid Flux Pro and managed services ### Transactional email: Laravel Mail Mailables and queue integration keep delivery in application conventions Limits and integration: 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. - https://laravel.com/framework/docs/13.x/mail Alternatives: Preserve an existing compatible project choice ### Uploads and object storage: Laravel Storage / Flysystem Storage disks support private local or S3-backed files Limits and integration: 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. - https://laravel.com/framework/docs/13.x/filesystem Alternatives: Preserve an existing compatible project choice ### Realtime transport: Laravel broadcasting + Reverb when self-hosted sockets are required Private channels integrate realtime application events Limits and integration: 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. - https://laravel.com/framework/docs/13.x/broadcasting Alternatives: Preserve an existing compatible project choice ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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. ### Translations to 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. ### Architecture sources - [Laravel 13 Database Migrations](https://laravel.com/docs/13.x/migrations): Schema migration and rollback commands. - [Laravel 13 Queues](https://laravel.com/docs/13.x/queues): Connections versus queues, model serialization, after-commit dispatch, workers and timeout/retry_after interaction. - [Laravel 13 HTTP Session](https://laravel.com/docs/13.x/session): Database session default, driver/table prerequisites and session-blocking requirements. - [Laravel 13 Authentication](https://laravel.com/docs/13.x/authentication): Guard/provider architecture, sessions, logout and authentication configuration. - [Laravel 13 Broadcasting](https://laravel.com/docs/13.x/broadcasting): Broadcast drivers, ShouldBroadcast/queue execution, private authorization and after-commit dispatch. - [Laravel 13 Cache](https://laravel.com/docs/13.x/cache): Backend capabilities, atomic lock prerequisites and prefix-independent cache flush. - [Laravel 13 Scheduling](https://laravel.com/docs/13.x/scheduling): Scheduler operation, timezones, overlap prevention and shared-store onOneServer locking. - [Livewire 4 Components](https://livewire.laravel.com/docs/4.x/components): PHP/Blade components and make:livewire format options. - [Livewire 4 Security](https://livewire.laravel.com/docs/4.x/security): Client-controlled properties/actions require validation and authorization. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### Data and schema **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: restore the old writer before contracting fields; preserve additive schema and reconcile writes accepted by Laravel. **Benefits and prerequisites** - Recommendation: conventional schema and application ownership can make changes reviewable in one maintained application. Requires: 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 before transfer** - 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. - https://laravel.com/docs/13.x/migrations ### Jobs and schedules **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: stop the new producer, keep consumers for accepted payload versions and reconcile external effects before restoring old queue routing. **Benefits and prerequisites** - Recommendation: a job category can move without rebuilding the entire backlog. Requires: 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 before transfer** - 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. - https://laravel.com/docs/13.x/queues ### Identity and authorization **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: retain old session/exchange support until the cohort can return, while preserving every revocation and account mapping. **Benefits and prerequisites** - Recommendation: explicit session/account ownership can preserve user continuity during feature migration. Requires: 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 before transfer** - 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. - https://laravel.com/docs/13.x/authentication - https://laravel.com/docs/13.x/session - https://livewire.laravel.com/docs/4.x/security ### Realtime transport **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: preserve old event names/endpoints and stop new publication before restoring the old publisher; reconcile already-visible state. **Benefits and prerequisites** - Recommendation: backend events can update multiple authorized clients. Requires: 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 before transfer** - 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. - https://laravel.com/docs/13.x/broadcasting - https://laravel.com/docs/13.x/queues ### Caching and shared state **Inspect the source:** Inventory cached values, serialization, TTLs and invalidation separately from locks, unique jobs, scheduler coordination and sessions. Laravel supports several cache stores with different capabilities. **During 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 design:** 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. **Rollback:** Recommendation: restore previous cache routing and rebuild from domain data; preserve lock/session store ownership until a separate qualified transition. **Benefits and prerequisites** - Recommendation: a cache backend can change independently of domain storage when contents are reconstructible. Requires: Verified invalidation, serialization and coordination inventory. Tradeoffs: Lock owners and dependent scheduler/session features may still prevent retiring the old backend. **Checks before transfer** - 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. - https://laravel.com/docs/13.x/cache ### Delivery and recovery **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: stop the Laravel schedule before restoring the old owner; reconcile accepted jobs and completed effects before replay. **Benefits and prerequisites** - Recommendation: explicit schedule and worker ownership can prevent accidental duplicate production during rollout. Requires: 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 before transfer** - 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. - https://laravel.com/docs/13.x/scheduling - https://laravel.com/docs/13.x/queues Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. 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. 2. 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. 3. Configure .env database/mail/queue settings and confirm application key generation; do not commit secrets. Run php artisan migrate against the intended development database. 4. Run npm install then npm run build; run composer run dev. Configure a supervised queue worker and scheduler separately for production. 5. 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. 6. 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. 7. 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 below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text 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 ``` ## 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 - [Laravel Starter Kits](https://laravel.com/framework/docs/13.x/starter-kits) - [Flux Pricing and Component Tiers](https://fluxui.dev/pricing) - [Laravel Database: Getting Started](https://laravel.com/framework/docs/13.x/database) - [Laravel Database Migrations](https://laravel.com/framework/docs/13.x/migrations) - [Laravel Authorization](https://laravel.com/framework/docs/13.x/authorization) - [Laravel Queues](https://laravel.com/framework/docs/13.x/queues) - [Laravel Horizon](https://laravel.com/framework/docs/13.x/horizon) - [Testing Applications](https://laravel.com/framework/docs/13.x/testing) - [Laravel Dusk](https://laravel.com/framework/docs/13.x/dusk) - [Laravel Pint](https://laravel.com/framework/docs/13.x/pint) - [Larastan README](https://github.com/larastan/larastan) - [Composer CLI: Audit](https://getcomposer.org/doc/03-cli.md#audit) - [Laravel Deployment](https://laravel.com/framework/docs/13.x/deployment) - [AI Assisted Development](https://laravel.com/framework/docs/13.x/ai) - [Laravel Framework MIT License](https://github.com/laravel/framework/blob/13.x/LICENSE.md) - [Laravel Mail](https://laravel.com/framework/docs/13.x/mail) - [Laravel file storage](https://laravel.com/framework/docs/13.x/filesystem) - [Laravel broadcasting](https://laravel.com/framework/docs/13.x/broadcasting) Keep the project README current and link the selected guidance; preserve existing project instructions. --- # Django Data-heavy products with an ORM, forms, accounts and admin. Language: Python | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: web UI: server Deployment: server ## Use cases - CRUD-heavy SaaS - Internal products and admin tools - Server-rendered business applications ## Fit - Accounts, forms, admin and database workflows are central - A cohesive conventional monolith reduces integration decisions ## Choose something else when - Only a small stateless endpoint is needed - The core workload needs a different runtime or hard real-time guarantees ## 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. ## 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. ## Tools ### Packaging and environments: uv + pyproject.toml + committed uv.lock One project entry point for dependencies, Python selection, execution and reproducible sync. Limits and integration: 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. - https://docs.astral.sh/uv/guides/projects/ Alternatives: Preserve an existing maintained packaging workflow ### Lint and format: Ruff Fast lint and formatting feedback with one configuration. Limits and integration: Ruff does not replace static typing, tests, authorization checks or runtime validation. - https://docs.astral.sh/ruff/installation/ Alternatives: Preserve existing configured formatter/linter ### Static typing: mypy + django-stubs plugin Django-aware stubs and plugin improve checks around ORM and settings. Limits and integration: Check the django-stubs compatibility table for the selected Django/Python/mypy combination; plugin imports application settings. - https://github.com/typeddjango/django-stubs - https://mypy.readthedocs.io/en/stable/getting_started.html Alternatives: ty for isolated plain-Python modules after validation ### Testing: pytest + pytest-django Database fixtures and Django integration while retaining pytest conventions. Limits and integration: Set DJANGO_SETTINGS_MODULE; use isolated PostgreSQL tests for constraints and transactions. Unit tests alone miss request and migration behavior. - https://docs.pytest.org/en/stable/getting-started.html - https://pytest-django.readthedocs.io/en/latest/ Alternatives: Django built-in test runner ### Database and migrations: PostgreSQL + Django ORM/migrations + Psycopg Use the framework's existing data layer and schema history. Limits and integration: Review schema/data migrations and query counts; run production-relevant DB tests. Do not introduce SQLAlchemy as a second default ORM. - https://docs.djangoproject.com/en/6.0/topics/migrations/ Alternatives: SQLite for low-concurrency local products ### Validation: Django Forms/ModelForms plus domain checks and DB constraints Form lifecycle handles submitted values and field errors. Limits and integration: Model saving is not a substitute for form/domain validation; enforce invariants at the appropriate transaction boundary. - https://docs.djangoproject.com/en/6.0/ref/forms/validation/ - https://pydantic.dev/docs/validation/latest/concepts/strict_mode/ Alternatives: Pydantic at external JSON/tool boundaries ### Authentication: Django auth, sessions, permissions and CSRF protection Built-in accounts and session conventions fit browser products. Limits and integration: Object/tenant permissions still need explicit implementation and tests; do not expose the admin as the product UI by default. - https://docs.djangoproject.com/en/6.0/topics/auth/ - https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/ Alternatives: OIDC integration when an existing identity provider owns login ### Background jobs: Celery + a configured durable broker Documented Django integration for off-request work. Limits and integration: 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. - 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/ Alternatives: Django Tasks plus a reviewed production backend; Temporal for durable orchestration ### Long-running durable agents: Temporal Python SDK when recovery across restarts is required Persisted workflow orchestration and separate worker processes suit retries, pauses and human waits. Limits and integration: 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. - https://docs.temporal.io/develop/python - https://docs.celeryq.dev/en/stable/userguide/tasks.html Alternatives: Celery for independent queued jobs; direct function for bounded work ### Deployment: Container or managed Python service; WSGI for sync applications, ASGI when justified Use the Django production deployment interface and checklist. Limits and integration: Choose/pin a compatible application server at implementation; never deploy runserver. Configure secrets, HTTPS, static assets, health checks and backups. - 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/ Alternatives: Existing organization deployment platform ### Application logging: Python logging with configured handlers Shared standard logging captures application and dependency diagnostics Limits and integration: 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. - https://docs.python.org/3/library/logging.html Alternatives: Preserve an existing compatible project choice ### Bounded external-call retries: Tenacity only for retryable transient failures Explicit stop/wait/filter rules support controlled retries Limits and integration: 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. - https://tenacity.readthedocs.io/en/latest/ Alternatives: Provider SDK retry policy when sufficient ### Transactional email: django.core.mail + selected SMTP backend Built-in mail wrappers and test backends fit account/product messages Limits and integration: Configure TLS, sender and backend; test HTML/text content and enqueue required delivery. Delivery and bounce monitoring remain provider responsibilities. - https://docs.djangoproject.com/en/6.0/topics/email/ Alternatives: Preserve an existing compatible project choice ### Uploads and file storage: Django FileField + configured storage backend Framework file APIs separate model metadata from storage Limits and integration: 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. - https://docs.djangoproject.com/en/6.0/topics/files/ Alternatives: Preserve an existing compatible project choice ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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. ### Translations to 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. ### Architecture sources - [Django first application](https://docs.djangoproject.com/en/6.0/intro/tutorial01/): Project/application generator commands and development server boundary. - [Django Migrations](https://docs.djangoproject.com/en/6.0/topics/migrations/): Migration commands, history, data migrations and reversibility. - [Django Transactions](https://docs.djangoproject.com/en/6.0/topics/db/transactions/): Autocommit, atomic, on_commit timing/failure and application-state rollback limitations. - [Django 6 Tasks](https://docs.djangoproject.com/en/6.0/topics/tasks/): Task API, no built-in worker, backend requirements, argument conversion and commit timing. - [Django Sessions](https://docs.djangoproject.com/en/6.0/topics/http/sessions/): Database/cache/cached_db/cookie choices, persistence, eviction and serialization. - [Django Authentication](https://docs.djangoproject.com/en/6.0/topics/auth/default/): Authentication, login/logout and permissions. - [Django Cache](https://docs.djangoproject.com/en/6.0/topics/cache/): Backend setup, key versions, per-process local memory and filesystem security concerns. - [Channels Channel Layers](https://channels.readthedocs.io/en/stable/topics/channel_layers.html): Official production channels_redis and lack of cross-process delivery in memory. - [Celery Tasks](https://docs.celeryq.dev/en/stable/userguide/tasks.html): Task naming/serialization, retries, acknowledgement and idempotency concerns. - [Celery Periodic Tasks](https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html): Single scheduler ownership, schedule timezone and overlap concerns. - [Celery First Steps](https://docs.celeryq.dev/en/stable/getting-started/first-steps-with-celery.html): Worker command and distinction between broker and result backend. - [Django Deployment Checklist](https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/): Production settings, check --deploy and deployment responsibilities. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### Data and schema **Inspect the source:** 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. **During 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 design:** Django models/migrations with explicit transaction.atomic boundaries for related database writes. Recommendation: delay field deletion until the rollback reader retires. **Rollback:** Recommendation: restore the old writer while retaining additive fields; rehearse reverse migrations on a disposable copy and reconcile non-reversible data operations. **Benefits and prerequisites** - Recommendation: coherent model and migration ownership makes a domain boundary reviewable. Requires: Tested schema mapping and explicit writer transfer. Tradeoffs: Database reversal may be irreversible for data operations; application objects/cache state also need reconciliation. **Checks before transfer** - 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. - https://docs.djangoproject.com/en/6.0/topics/migrations/ - https://docs.djangoproject.com/en/6.0/topics/db/transactions/ ### Jobs and schedules **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: pause new producers, retain consumers for accepted payloads and reconcile completed effects before switching categories back. **Benefits and prerequisites** - Recommendation: execution can migrate by task category while the old backlog remains executable. Requires: 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 before transfer** - 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. - 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 ### Identity and authorization **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: preserve previous identity/session contracts through the rollback window and retain revocation state during traffic reversal. **Benefits and prerequisites** - Recommendation: a durable session authority can preserve access through cache eviction. Requires: 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 before transfer** - 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. - https://docs.djangoproject.com/en/6.0/topics/http/sessions/ - https://docs.djangoproject.com/en/6.0/topics/auth/default/ ### Realtime transport **Inspect the source:** Capture WebSocket protocol, group/event names, authentication and required missed-event behavior. Channels channel layers carry application-level events, not a universal client protocol. **During 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 design:** Channels with channels_redis when using the documented official production channel layer. Recommendation: reconstruct/replay from persistent domain state when missed broadcasts matter. **Rollback:** Recommendation: retain the previous endpoint/event envelope and route cohorts back including their reconnects; avoid replaying already-applied effects. **Benefits and prerequisites** - Recommendation: a shared channel layer enables cross-process fanout. Requires: Configured Redis layer, matching consumers/events and authorized subscriptions. Tradeoffs: Redis remains operated; transient fanout alone does not provide durable business-message recovery. **Checks before transfer** - 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. - https://channels.readthedocs.io/en/stable/topics/channel_layers.html ### Caching and shared state **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: restore old namespace/backend routing and repopulate from authoritative data without treating cache contents as business records. **Benefits and prerequisites** - Recommendation: reconstructible caching can change independently of domain writes. Requires: Defined staleness, invalidation and data ownership. Tradeoffs: Per-process caches duplicate state; sensitive filesystem cache locations/serialization require care as the docs explain. **Checks before transfer** - 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. - https://docs.djangoproject.com/en/6.0/topics/cache/ - https://docs.djangoproject.com/en/6.0/topics/db/transactions/ ### Delivery and recovery **Inspect the source:** 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. **During 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 design:** An explicitly configured deployment following Django’s checklist, plus independently supervised selected workers and scheduler. Recommendation: document restored database/session/queue consistency. **Rollback:** Recommendation: restore old routing/settings and schedule ownership explicitly; preserve accepted tasks and reconcile effects before replay. **Benefits and prerequisites** - Recommendation: production checks and role ownership make recovery responsibilities visible. Requires: Actual production settings and a rehearsed restore/restart. Tradeoffs: check --deploy detects configuration issues, not end-to-end job, permission or restore correctness. **Checks before transfer** - 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. - https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/ - https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. 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. 2. uv add --dev ruff mypy django-stubs pytest pytest-django 3. uv run django-admin startproject config . ; then uv run python manage.py startapp core 4. Configure installed apps, PostgreSQL credentials from the environment, auth/session settings, pytest DJANGO_SETTINGS_MODULE and the django-stubs mypy plugin/settings module. 5. 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. 6. Add Celery only for actual queued work; configure broker, worker and after-commit enqueueing. Add Temporal only when durable multi-step recovery is required. 7. Document application server, static asset collection, migration release ordering, worker start/restart and rollback. Run verification below before deployment. ## Verification Commands below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text 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? ## Sources - [uv projects](https://docs.astral.sh/uv/guides/projects/) - [Ruff installation](https://docs.astral.sh/ruff/installation/) - [django-stubs](https://github.com/typeddjango/django-stubs) - [mypy getting started](https://mypy.readthedocs.io/en/stable/getting_started.html) - [pytest getting started](https://docs.pytest.org/en/stable/getting-started.html) - [pytest-django](https://pytest-django.readthedocs.io/en/latest/) - [Django migrations](https://docs.djangoproject.com/en/6.0/topics/migrations/) - [Django form validation](https://docs.djangoproject.com/en/6.0/ref/forms/validation/) - [Pydantic strict mode](https://pydantic.dev/docs/validation/latest/concepts/strict_mode/) - [Django authentication](https://docs.djangoproject.com/en/6.0/topics/auth/) - [Django deployment checklist](https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/) - [Celery Django integration](https://docs.celeryq.dev/en/stable/django/first-steps-with-django.html) - [Celery tasks](https://docs.celeryq.dev/en/stable/userguide/tasks.html) - [Django Tasks](https://docs.djangoproject.com/en/6.0/topics/tasks/) - [Temporal Python SDK](https://docs.temporal.io/develop/python) - [Django deployment](https://docs.djangoproject.com/en/6.0/howto/deployment/) - [uv Docker](https://docs.astral.sh/uv/guides/integration/docker/) - [Python logging](https://docs.python.org/3/library/logging.html) - [Tenacity documentation](https://tenacity.readthedocs.io/en/latest/) - [Django sending email](https://docs.djangoproject.com/en/6.0/topics/email/) - [Django files](https://docs.djangoproject.com/en/6.0/topics/files/) Keep the project README current and link the selected guidance; preserve existing project instructions. --- # Go service HTTP APIs and backend services with a straightforward binary deployment. Language: Go | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: api UI: none Deployment: binary ## Use cases - APIs - control planes - concurrent network services - background workers ## Fit - Prefer explicit service code and standard tooling - Kubernetes or Go infrastructure integration matters - PostgreSQL already owns business state ## Choose something else when - Need a batteries-included product framework - Hard real-time or no-GC constraints - Rich client UI is the primary product ## 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. ## 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. ## Tools ### HTTP server: net/http Standard handlers and request contexts minimize routing infrastructure. Limits and integration: Set request/body limits, deadlines and graceful shutdown; middleware and authorization remain application work. - https://pkg.go.dev/net/http Alternatives: Existing project router when justified ### Optional server-rendered UI: templ + HTMX Compiled components and HTML-fragment updates suit forms and dashboards. Limits and integration: Generation adds a build step; advanced client state still needs browser-side design and testing. - https://templ.guide/ - https://htmx.org/docs/ Alternatives: No UI for API-only services ### Database and migrations: PostgreSQL + pgx + sqlc + goose Visible SQL, generated typed access and one migration owner. Limits and integration: Generators do not prove query efficiency; review transaction boundaries, pool budgets and online migration behavior. Never mix migration owners. - https://github.com/jackc/pgx - https://docs.sqlc.dev/en/latest/ - https://github.com/pressly/goose - https://github.com/golang-migrate/migrate Alternatives: pgx without sqlc for small query sets; golang-migrate when already established ### Configuration: Typed settings loaded with os.LookupEnv Explicit startup validation and standard structured logs. Limits and integration: Define precedence; reject malformed required values; redact secrets. Environment access alone is not validation or secret management. - https://pkg.go.dev/os - https://pkg.go.dev/flag - https://pkg.go.dev/log/slog Alternatives: flag for small command surfaces ### Application logging: log/slog Explicit startup validation and standard structured logs. Limits and integration: Define precedence; reject malformed required values; redact secrets. Environment access alone is not validation or secret management. - https://pkg.go.dev/os - https://pkg.go.dev/flag - https://pkg.go.dev/log/slog ### Tests and static checks: testing; go vet; race detector; govulncheck Standard toolchain feedback plus exercised concurrency and known-vulnerability checks. Limits and integration: Race detector requires supported target/toolchain and exercised code; no scanner proves absence of vulnerabilities. - 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/ ### HTTP and database integration tests: httptest + real disposable PostgreSQL Exercise protocols and actual SQL/migrations. Limits and integration: Database tests need an isolated database; mocks cannot establish PostgreSQL semantics. - https://pkg.go.dev/net/http/httptest - https://github.com/jackc/pgx Alternatives: In-process handler tests for pure routing ### Durable work: River for PostgreSQL-backed jobs Transactional enqueueing ties work to committed business data. Limits and integration: External effects need idempotency. Default resumable checkpoints may be lost on crash; use transactional checkpoints where required. Inspect Pro feature boundaries. - https://riverqueue.com/docs/transactional-enqueueing - https://riverqueue.com/docs/resumable-jobs - https://docs.temporal.io/develop/go Alternatives: Temporal Go SDK for workflow requirements needing its service ### Deployment and distribution: Go build binary in a supervised process or container; GoReleaser for releases Small explicit runtime boundary; release automation builds target artifacts. Limits and integration: Target OS/architecture, libc/cgo, CA certificates, timezone data and signing need explicit verification. Snapshot builds are not publication. - https://goreleaser.com/getting-started/quick-start/ ### Browser identity: go-oidc + existing OIDC provider Provider discovery and ID-token verification support owned login sessions Limits and integration: 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. - https://github.com/coreos/go-oidc Alternatives: Preserve an existing compatible project choice ### Transactional email: go-mail + project-selected SMTP provider Typed mail construction and SMTP transport support application messages Limits and integration: 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. - https://pkg.go.dev/github.com/wneessen/go-mail Alternatives: Preserve an existing compatible project choice ### Uploads and object storage: AWS SDK for Go S3 client Durable object storage avoids dependence on service-local disk Limits and integration: 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. - https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/go_s3_code_examples.html Alternatives: Preserve an existing compatible project choice ### Realtime transport: coder/websocket WebSocket support fits bidirectional connected clients Limits and integration: 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. - https://pkg.go.dev/github.com/coder/websocket Alternatives: Server-sent events for one-way feeds; Polling for infrequent updates ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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. ### Translations to 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. ### Architecture sources - [Go 1.27 release notes](https://go.dev/doc/go1.27): Identifies the August 2026 release; runtime/tool behavior and JSON v2 are documented with compatibility caveats. - [Managing Go dependencies](https://go.dev/doc/modules/managing-dependencies): go.mod and go.sum own module dependency versions. - [sqlc transactions](https://docs.sqlc.dev/en/latest/howto/transactions.html): Generated WithTx binds queries to a transaction; pgx/v5 example is documented. - [Go SQL connection management](https://go.dev/doc/database/manage-connections): sql.DB is a concurrent pool; limits can cause waits and deadlocks. - [River transactional enqueue](https://riverqueue.com/docs/transactional-enqueueing): Enqueue with domain changes in one transaction avoids a two-store commit gap. - [River retries](https://riverqueue.com/docs/job-retries): Retry attempts and delays are configurable; errors lead to repeated execution. - [River Ruby integration](https://riverqueue.com/docs/ruby): Current documentation describes a shared River schema and explicit job kinds/JSON arguments. - [net/http server shutdown](https://pkg.go.dev/net/http#Server.Shutdown): HTTP drain does not close or await hijacked WebSocket connections. - [errgroup](https://pkg.go.dev/golang.org/x/sync/errgroup): WithContext cancellation and SetLimit support bounded concurrent work. - [os/signal](https://pkg.go.dev/os/signal#NotifyContext): NotifyContext connects OS signals to context cancellation. - [coder/websocket README](https://github.com/coder/websocket): Go WebSocket transport supports contexts and close handshakes; application protocol is separate. - [Redis Pub/Sub](https://redis.io/docs/latest/develop/pubsub/): Pub/Sub delivery is at-most-once; disconnected subscribers miss events. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### Data and schema **Inspect the source:** Inventory the old schema, isolation, identifiers, null handling, timestamps and transaction invariants before changing language or driver. **During 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 design:** 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. **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. **Benefits and prerequisites** - Typed query access and concurrent pool usage can improve maintainability and remove an unnecessary application-wide lock. Requires: 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 before transfer** - 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. - https://docs.sqlc.dev/en/latest/howto/transactions.html - https://go.dev/doc/database/manage-connections ### Jobs and schedules **Inspect the source:** Capture existing queue kind, JSON arguments, retry/schedule/dead-letter states and external-effect idempotency. Redis/Resque or Sidekiq payloads are not River payloads. **During 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 design:** 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. **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. **Benefits and prerequisites** - Atomic enqueue closes the gap between committing domain state and creating work. Requires: 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 before transfer** - 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. - https://riverqueue.com/docs/transactional-enqueueing - https://riverqueue.com/docs/job-retries - https://riverqueue.com/docs/ruby ### Delivery and recovery **Inspect the source:** Preserve response/error behavior, overload rules, deadlines and restart guarantees; establish separate budgets for HTTP and background jobs. **During 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 design:** Recommendation: signal.NotifyContext, bounded admission/fan-out, Server.Shutdown with a fresh timeout context, tracked worker termination and pool closure after accepted work ends. **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. **Benefits and prerequisites** - Cooperative cancellation limits work that callers no longer need and makes planned shutdown observable. Requires: 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 before transfer** - 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. - https://pkg.go.dev/net/http#Server.Shutdown - https://pkg.go.dev/golang.org/x/sync/errgroup - https://pkg.go.dev/os/signal#NotifyContext ### Realtime transport **Inspect the source:** Preserve authentication, subscription identifiers, frame formats, ordering, reconnect cursors and cross-runtime fan-out. A WebSocket transport does not implement Action Cable automatically. **During 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 design:** 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. **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. **Benefits and prerequisites** - Explicit connection ownership and queue limits bound slow-client resource use. Requires: 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 before transfer** - 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. - https://github.com/coder/websocket - https://redis.io/docs/latest/develop/pubsub/ - https://pkg.go.dev/net/http#Server.Shutdown Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. Start in a new source checkout in a local development workspace; run go mod init example.com/project using the real module path. 2. Resolve and record Go/tool versions and dependencies; go get github.com/jackc/pgx/v5; add River only if jobs are needed. 3. Create cmd/server plus application packages, typed settings, explicit http.Server limits, health/readiness and shutdown handling. 4. Install selected sqlc and goose releases; write migrations and sqlc configuration; run sqlc generate. Configure a disposable PostgreSQL database through environment/secrets. 5. With GOOSE_DRIVER=postgres and GOOSE_DBSTRING targeting only the disposable database, run goose -dir migrations up. Add business transaction and River enqueue tests. 6. 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 below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text gofmt -l . go test ./... go test -race ./... go vet ./... govulncheck ./... sqlc generate goose -dir migrations status go build ./cmd/server ``` ## 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? ## Sources - [Go net/http](https://pkg.go.dev/net/http) - [templ](https://templ.guide/) - [HTMX](https://htmx.org/docs/) - [pgx PostgreSQL driver](https://github.com/jackc/pgx) - [sqlc documentation](https://docs.sqlc.dev/en/latest/) - [goose migrations](https://github.com/pressly/goose) - [golang-migrate](https://github.com/golang-migrate/migrate) - [Go os configuration primitives](https://pkg.go.dev/os) - [Go flag](https://pkg.go.dev/flag) - [Go structured logging](https://pkg.go.dev/log/slog) - [Go testing](https://pkg.go.dev/testing) - [Go data race detector](https://go.dev/doc/articles/race_detector) - [golangci-lint quick start](https://golangci-lint.run/docs/welcome/quick-start/) - [Go vulnerability management](https://go.dev/doc/security/vuln/) - [Go HTTP testing](https://pkg.go.dev/net/http/httptest) - [River transactional enqueueing](https://riverqueue.com/docs/transactional-enqueueing) - [River resumable jobs](https://riverqueue.com/docs/resumable-jobs) - [Temporal Go SDK](https://docs.temporal.io/develop/go) - [GoReleaser quick start](https://goreleaser.com/getting-started/quick-start/) - [go-oidc repository](https://github.com/coreos/go-oidc) - [go-mail documentation](https://pkg.go.dev/github.com/wneessen/go-mail) - [AWS Go S3 examples](https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/go_s3_code_examples.html) - [coder/websocket documentation](https://pkg.go.dev/github.com/coder/websocket) Keep the project README current and link the selected guidance; preserve existing project instructions. --- # Rust service Services where runtime control and explicit resource handling matter. Language: Rust | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: api UI: none Deployment: binary ## Use cases - Native network services - resource-sensitive APIs - services sharing a Rust core ## Fit - Memory/resource control or Rust library reuse is important - Team accepts ownership/async complexity for compile-time guarantees ## Choose something else when - Primary goal is conventional CRUD delivery with minimal framework assembly - Team cannot maintain Rust async code - A full product framework is needed immediately ## 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. ## 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. ## Tools ### HTTP server: Axum + Tokio + tower-http Typed extractors/state and Tower middleware compose with Tokio networking. Limits and integration: Configure limits, timeout/error mapping and graceful shutdown. Blocking work must not monopolize async workers. - https://docs.rs/axum/latest/axum/ - https://tokio.rs/ Alternatives: Direct Hyper only for transport-specific needs ### Database and migrations: PostgreSQL + SQLx; sqlx-cli migrations SQL-oriented async access with optional checked query macros and migration tooling. Limits and integration: 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. - https://docs.rs/sqlx/latest/sqlx/ - https://github.com/transact-rs/sqlx/blob/main/sqlx-cli/README.md ### Configuration: Serde-backed settings + config Typed settings plus structured events/spans. Limits and integration: Set precedence explicitly; validate semantics; install a tracing subscriber; never log secrets. - https://docs.rs/config/latest/config/ - https://doc.rust-lang.org/std/env/fn.var.html - https://docs.rs/tracing/latest/tracing/ Alternatives: std::env for a small fixed settings set ### Application logging: tracing + configured subscriber Typed settings plus structured events/spans. Limits and integration: Set precedence explicitly; validate semantics; install a tracing subscriber; never log secrets. - https://docs.rs/config/latest/config/ - https://doc.rust-lang.org/std/env/fn.var.html - https://docs.rs/tracing/latest/tracing/ ### Tests and static checks: cargo test; rustfmt; Clippy; cargo audit Compiler, style, behavior and known-advisory checks complement each other. Limits and integration: Audit coverage is advisory-driven; compile success does not establish behavior or security. Test supported feature combinations rather than blindly enabling incompatible features. - 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/ ### Durable work: None for request-only service; Restate Rust SDK when durable workflows are required Durable handlers and persisted workflow progress address work outliving a process. Limits and integration: Requires a Restate service and adoption test. Journal external operations correctly; idempotency and business transactions remain explicit. Tokio tasks alone are not durable. - https://docs.rs/restate-sdk/latest/restate_sdk/ ### Deployment: cargo build --release --locked in a target-specific build pipeline Reproducible dependency resolution from committed lockfile; native executable artifact. Limits and integration: Not universally static: verify libc, TLS/native libraries, target support, certificates and container runtime needs. - https://doc.rust-lang.org/cargo/commands/cargo-build.html Alternatives: Container with explicit runtime libraries ### API token verification: jsonwebtoken + selected identity provider contract Typed claims and signature checks fit JWT-bearing service APIs Limits and integration: 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. - https://docs.rs/jsonwebtoken/latest/jsonwebtoken/ Alternatives: Preserve an existing compatible project choice ### Transactional email: lettre + project-selected SMTP provider Typed mail construction and SMTP transport support application messages Limits and integration: 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. - https://docs.rs/lettre/latest/lettre/ Alternatives: Preserve an existing compatible project choice ### Uploads and object storage: AWS SDK for Rust S3 client Durable object storage avoids dependence on service-local disk Limits and integration: 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. - https://docs.aws.amazon.com/sdk-for-rust/latest/dg/rust_s3_code_examples.html Alternatives: Preserve an existing compatible project choice ### Realtime transport: Axum WebSocket extractor WebSocket support fits bidirectional connected clients Limits and integration: 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. - https://docs.rs/axum/latest/axum/extract/ws/index.html Alternatives: Server-sent events for one-way feeds; Polling for infrequent updates ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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. ### Translations to avoid - Avoid Arc> 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. ### Architecture sources - [Axum 0.8.9](https://docs.rs/axum/latest/axum/): Typed extractors/State and Tower middleware form the HTTP composition. - [Tower limits](https://docs.rs/tower/latest/tower/limit/index.html): Concurrency and rate-limit middleware exist; admission/error policy needs application design. - [Tokio graceful shutdown](https://tokio.rs/tokio/topics/shutdown): CancellationToken and TaskTracker coordinate shutdown and task completion. - [Tokio channels](https://tokio.rs/tokio/tutorial/channels): Bounded mpsc coordinates tasks; capacity/backpressure is explicit, not disk persistence. - [Tokio spawn_blocking](https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html): CPU work needs a parallelism limit; started blocking tasks cannot be aborted. - [SQLx 0.9.0 query macro](https://docs.rs/sqlx/latest/sqlx/macro.query.html): Literal queries need a matching database schema or offline metadata; engine binding and nullability have limits. - [SQLx pool](https://docs.rs/sqlx/latest/sqlx/struct.Pool.html): A shared async pool supports reuse; a mutex around one connection creates serialization; close should be awaited. - [SQLx CLI README](https://github.com/transact-rs/sqlx/blob/main/sqlx-cli/README.md): Migrations and prepare/prepare --check maintain offline query metadata. - [Tokio broadcast](https://docs.rs/tokio/latest/tokio/sync/broadcast/index.html): A bounded local channel drops older values and reports lagging receivers. - [River cross-language schema statement](https://riverqueue.com/docs/ruby): Current Ruby guide explicitly names Go, Rust and TypeScript sharing a schema; Rust API itself is unqualified here. - [Redis Pub/Sub](https://redis.io/docs/latest/develop/pubsub/): Ephemeral shared fan-out remains at-most-once and needs a separate recovery path. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### Data and schema **Inspect the source:** Capture the old SQL schema, transactions, tenant filters, nullable values and database engine behavior. **During 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 design:** 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. **Rollback:** Recommendation: route writes back while retaining additive schema and a previous compatible binary. Delay destructive migrations; reconcile new-only persisted values before rollback. **Benefits and prerequisites** - Compile-time query/type checks can expose SQL/API mismatches before deployment. Requires: 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 before transfer** - 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. - 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 ### Jobs and schedules **Inspect the source:** Preserve old broker serialization, acknowledgement, delayed/retry states, concurrency and effect IDs. Durable Redis workers cannot be replaced transparently by tokio::spawn. **During 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 design:** 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. **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. **Benefits and prerequisites** - A retained worker boundary allows the HTTP layer to change without dropping backlog or broker guarantees. Requires: 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 before transfer** - 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. - https://tokio.rs/tokio/tutorial/channels - https://docs.rs/sqlx/latest/sqlx/macro.query.html - https://riverqueue.com/docs/ruby ### Delivery and recovery **Inspect the source:** Define HTTP admission/error behavior, task ownership, shutdown deadline and behavior for unavoidable CPU/blocking operations. **During 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 design:** 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. **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. **Benefits and prerequisites** - Tracked tasks and explicit admission limits make resource use and planned termination easier to reason about. Requires: 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 before transfer** - 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. - 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 ### Realtime transport **Inspect the source:** Preserve subscriptions, authorization revocation, event versions, reconnect behavior and cross-instance fan-out. **During 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 design:** 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. **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. **Benefits and prerequisites** - Local bounded fan-out can prevent slow receivers from retaining unbounded memory. Requires: 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 before transfer** - 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. - https://docs.rs/axum/latest/axum/ - https://docs.rs/tokio/latest/tokio/sync/broadcast/index.html - https://redis.io/docs/latest/develop/pubsub/ Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. Create source in a local development workspace: cargo new service; enter service and commit the generated application Cargo.lock after dependency resolution. 2. Run cargo add axum; cargo add tokio --features macros,rt-multi-thread; add required tower-http middleware after selecting compatible releases. 3. Add SQLx selecting PostgreSQL, Tokio and a supported TLS configuration from that release; install matching sqlx-cli. Create config validation and tracing subscriber. 4. Use a disposable database in DATABASE_URL. Create migrations with sqlx migrate add initial; write SQL and run sqlx migrate run. 5. For checked query macros, run cargo sqlx prepare after schema/query changes and commit offline metadata. Implement HTTP, real-database and cancellation tests. 6. Introduce Restate only after a separate restart/retry/idempotency proof. Pin toolchain and release targets. These instructions were not executed. ## Verification Commands below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text 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 ``` ## 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? ## Sources - [Axum](https://docs.rs/axum/latest/axum/) - [Tokio](https://tokio.rs/) - [SQLx](https://docs.rs/sqlx/latest/sqlx/) - [SQLx CLI](https://github.com/transact-rs/sqlx/blob/main/sqlx-cli/README.md) - [Rust config crate](https://docs.rs/config/latest/config/) - [Rust environment variables](https://doc.rust-lang.org/std/env/fn.var.html) - [Rust tracing](https://docs.rs/tracing/latest/tracing/) - [Cargo test](https://doc.rust-lang.org/cargo/commands/cargo-test.html) - [rustfmt](https://github.com/rust-lang/rustfmt) - [Clippy usage](https://doc.rust-lang.org/clippy/usage.html) - [RustSec](https://rustsec.org/) - [assert_cmd](https://docs.rs/assert_cmd/latest/assert_cmd/) - [Restate Rust SDK](https://docs.rs/restate-sdk/latest/restate_sdk/) - [Cargo build](https://doc.rust-lang.org/cargo/commands/cargo-build.html) - [jsonwebtoken API](https://docs.rs/jsonwebtoken/latest/jsonwebtoken/) - [lettre documentation](https://docs.rs/lettre/latest/lettre/) - [AWS Rust S3 examples](https://docs.aws.amazon.com/sdk-for-rust/latest/dg/rust_s3_code_examples.html) - [Axum WebSocket extractor documentation](https://docs.rs/axum/latest/axum/extract/ws/index.html) Keep the project README current and link the selected guidance; preserve existing project instructions. --- # FastAPI Typed Python APIs alongside Python integrations, data or AI libraries. Language: Python | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: api UI: none Deployment: server ## Use cases - Typed JSON APIs - Integration services - HTTP endpoints for model or worker products ## Fit - API contracts and Python integrations matter more than built-in product/admin UI - A separate frontend or service boundary already exists ## Choose something else 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 ## 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. ## 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. ## Tools ### Packaging and environments: uv + pyproject.toml + committed uv.lock One project entry point for dependencies, Python selection, execution and reproducible sync. Limits and integration: 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. - https://docs.astral.sh/uv/guides/projects/ Alternatives: Preserve an existing maintained packaging workflow ### Lint and format: Ruff Fast lint and formatting feedback with one configuration. Limits and integration: Ruff does not replace static typing, tests, authorization checks or runtime validation. - https://docs.astral.sh/ruff/installation/ Alternatives: Preserve existing configured formatter/linter ### Static typing: mypy Explicit checks on application boundaries with a conservative established checker. Limits and integration: Configure strictness and third-party stubs; unchecked Any and untyped functions reduce coverage. No checker performance comparison was run. - https://mypy.readthedocs.io/en/stable/getting_started.html - https://docs.astral.sh/ty/type-checking/ Alternatives: ty after project-specific compatibility trial ### Testing: pytest + HTTPX / FastAPI TestClient Test contract failures, auth and integration boundaries. Limits and integration: Run startup/shutdown lifespan when relevant; include PostgreSQL and external-service fault tests. - https://docs.pytest.org/en/stable/getting-started.html - https://fastapi.tiangolo.com/deployment/docker/ Alternatives: Async client tests for async application lifecycles ### Database and migrations: PostgreSQL + SQLAlchemy + Psycopg + Alembic Explicit transactions and versioned relational changes. Limits and integration: Session per thread / AsyncSession per task. Review generated migrations, especially renames and data changes; a passing migration check does not prove production lock safety. - https://docs.sqlalchemy.org/en/21/orm/session_basics.html - https://alembic.sqlalchemy.org/en/latest/autogenerate.html Alternatives: SQLite for local single-user work; no DB for stateless services ### Validation: Pydantic request/response models; strict validation where coercion is unsafe Typed schemas clarify external contracts and generated documentation. Limits and integration: Coercion is configurable; schema validity is not authorization or business correctness. Avoid returning unrestricted ORM objects. - https://pydantic.dev/docs/validation/latest/concepts/strict_mode/ Alternatives: Explicit domain validation functions ### Authentication: Existing OIDC provider; validate access tokens and authorization in dependencies Keep identity lifecycle with its owner while enforcing permissions at the API. Limits and integration: 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. - https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/ - https://docs.authlib.org/en/v1.7.0/oauth2/client/web/index.html Alternatives: Authlib for browser OIDC client flow; First-party session authentication if architecture requires it ### Jobs: Separate Celery workers for queued jobs Separate request latency from heavy or retried work. Limits and integration: BackgroundTasks does not establish durable execution. Make job effects idempotent and set retry/deadline limits. - https://fastapi.tiangolo.com/tutorial/background-tasks/ - https://docs.celeryq.dev/en/stable/userguide/tasks.html - https://docs.temporal.io/develop/python Alternatives: Temporal for restart-safe multi-step workflows; BackgroundTasks for small best-effort post-response work ### Long-running durable agents: Temporal Python SDK when recovery across restarts is required Persisted workflow orchestration and separate worker processes suit retries, pauses and human waits. Limits and integration: 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. - https://docs.temporal.io/develop/python - https://docs.celeryq.dev/en/stable/userguide/tasks.html Alternatives: Celery for independent queued jobs; direct function for bounded work ### Serving and deployment: FastAPI standard CLI / Uvicorn in a container Official deployment path with explicit process and container choices. Limits and integration: Build from a supported base rather than deprecated framework images; choose process count to match deployment/memory, and run schema migration once per release. - https://fastapi.tiangolo.com/deployment/docker/ - https://docs.astral.sh/uv/guides/integration/docker/ - https://fastapi.tiangolo.com/async/ Alternatives: Managed ASGI platform ### Application logging: Python logging with configured handlers Shared standard logging captures application and dependency diagnostics Limits and integration: 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. - https://docs.python.org/3/library/logging.html Alternatives: Preserve an existing compatible project choice ### Bounded external-call retries: Tenacity only for retryable transient failures Explicit stop/wait/filter rules support controlled retries Limits and integration: 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. - https://tenacity.readthedocs.io/en/latest/ Alternatives: Provider SDK retry policy when sufficient ### Uploads: FastAPI UploadFile Spooling file interface avoids eagerly materializing all content in application memory Limits and integration: Install python-multipart; enforce request/file limits and authorization, stream to durable storage and clean partial writes. Multipart parsing does not establish file safety. - https://fastapi.tiangolo.com/tutorial/request-files/ Alternatives: Preserve an existing compatible project choice ### Realtime transport: FastAPI WebSocket endpoints Native ASGI endpoint support fits connected API clients Limits and integration: 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. - https://fastapi.tiangolo.com/advanced/websockets/ Alternatives: Preserve an existing compatible project choice ### Object storage: Boto3 S3 client when durable objects are required Official SDK supports file transfer to S3 Limits and integration: 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. - https://docs.aws.amazon.com/boto3/latest/guide/s3-uploading-files.html Alternatives: Preserve an existing compatible project choice ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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. ### Translations to 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. ### Architecture sources - [FastAPI Concurrency](https://fastapi.tiangolo.com/async/): Choice of async handlers versus normal def for awaitable/blocking libraries. - [FastAPI SQL Databases](https://fastapi.tiangolo.com/tutorial/sql-databases/): Request-scoped database dependency examples and external SQL library choice. - [SQLAlchemy Session Basics](https://docs.sqlalchemy.org/en/20/orm/session_basics.html): Mutable transaction/session lifecycle and prohibition on sharing across concurrent threads/tasks. - [Alembic Tutorial](https://alembic.sqlalchemy.org/en/latest/tutorial.html): Revision, upgrade/downgrade, current/history commands and schema revision ownership. - [FastAPI Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/): Same-process task examples and separate Celery/queue recommendation for larger execution boundaries. - [Celery Tasks](https://docs.celeryq.dev/en/stable/userguide/tasks.html): Task serialization, retry/acknowledgement and idempotency concerns. - [Celery Periodic Tasks](https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html): Only one scheduler per schedule to prevent duplicate production. - [Celery First Steps](https://docs.celeryq.dev/en/stable/getting-started/first-steps-with-celery.html): Broker, worker and optional result backend are separate roles. - [FastAPI OAuth2/JWT example](https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/): Token/password validation and expiry example, not cross-framework session interoperability. - [Starlette Middleware](https://starlette.dev/middleware/): Signed readable sessions, session cookie configuration and secure transport option. - [FastAPI WebSockets](https://fastapi.tiangolo.com/advanced/websockets/): Handler authentication/dependencies and explicit single-process limitation of in-memory connection list. - [FastAPI Lifespan](https://fastapi.tiangolo.com/advanced/events/): Startup/shutdown resource ownership through lifespan. - [FastAPI Server Workers](https://fastapi.tiangolo.com/deployment/server-workers/): FastAPI/Uvicorn worker commands and deployment process topology choices. - [FastAPI Testing](https://fastapi.tiangolo.com/tutorial/testing/): TestClient and pytest request checks. - [Redis redis-py guide](https://redis.io/docs/latest/develop/clients/redis-py/): Maintained Python client for Redis with sync/async documentation links. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### Data and schema **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: restore the old writer while preserving backward-readable schema; use downgrade only for a rehearsed reversible change and reconcile accepted new data. **Benefits and prerequisites** - Recommendation: explicit sessions and migrations expose the persistence boundary to review. Requires: 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 before transfer** - 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. - 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 ### Jobs and schedules **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: stop new task production, retain consumers for accepted payload versions and reconcile external effects before restoring old routing. **Benefits and prerequisites** - Recommendation: durable work can move independently of the HTTP service. Requires: 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 before transfer** - 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. - 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 ### Identity and authorization **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: preserve account mapping and old credential/exchange support without reversing revocations; return routing only when validation remains compatible. **Benefits and prerequisites** - Recommendation: a shared identity authority can preserve access across service boundaries. Requires: 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 before transfer** - 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. - https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/ - https://starlette.dev/middleware/ - https://fastapi.tiangolo.com/advanced/websockets/ ### Realtime transport **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: preserve old endpoint/message compatibility through reconnects; return the cohort and reconcile current domain state instead of reissuing effects. **Benefits and prerequisites** - Recommendation: an API service can take ownership of a realtime boundary incrementally. Requires: 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 before transfer** - 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. - https://fastapi.tiangolo.com/advanced/websockets/ - https://fastapi.tiangolo.com/deployment/server-workers/ ### Caching and shared state **Inspect the source:** List reconstructible values and representation/TTL/invalidation separately from identities, jobs, counters and locks. Multiple application workers have distinct in-memory resource ownership. **During 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 design:** 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. **Rollback:** Recommendation: restore old key/backend routing and repopulate from domain data; preserve shared coordination ownership throughout. **Benefits and prerequisites** - Recommendation: cache choices can evolve without transferring domain ownership. Requires: 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 before transfer** - 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. - https://redis.io/docs/latest/develop/clients/redis-py/ - https://fastapi.tiangolo.com/deployment/server-workers/ - https://fastapi.tiangolo.com/advanced/events/ ### Delivery and recovery **Inspect the source:** 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. **During 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 design:** 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. **Rollback:** Recommendation: preserve the old release and compatible schema, transfer role ownership before restoring traffic, and reconcile work accepted by the new service. **Benefits and prerequisites** - Recommendation: process/resource ownership makes multi-worker behavior reviewable. Requires: 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 before transfer** - 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. - 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 Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. In a new local source directory: uv init; pin a compatible Python minor; uv add 'fastapi[standard]' sqlalchemy 'psycopg[binary]' alembic pydantic-settings 2. uv add --dev ruff mypy pytest httpx 3. Create an importable app package with app/main.py exporting app = FastAPI(), request/response models and a health endpoint. 4. uv run alembic init migrations; configure environment-based connection URL and target_metadata. Implement per-request/task sessions and domain transaction boundaries. 5. uv run alembic revision --autogenerate -m 'initial schema'; manually review, then uv run alembic upgrade head against the development DB. 6. Configure the selected identity provider and token verification; implement tenant/object authorization before adding protected endpoints. 7. 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 below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text 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? ## Sources - [uv projects](https://docs.astral.sh/uv/guides/projects/) - [Ruff installation](https://docs.astral.sh/ruff/installation/) - [mypy getting started](https://mypy.readthedocs.io/en/stable/getting_started.html) - [ty type checking](https://docs.astral.sh/ty/type-checking/) - [pytest getting started](https://docs.pytest.org/en/stable/getting-started.html) - [FastAPI containers](https://fastapi.tiangolo.com/deployment/docker/) - [SQLAlchemy session basics](https://docs.sqlalchemy.org/en/21/orm/session_basics.html) - [Alembic autogeneration](https://alembic.sqlalchemy.org/en/latest/autogenerate.html) - [Pydantic strict mode](https://pydantic.dev/docs/validation/latest/concepts/strict_mode/) - [FastAPI JWT tutorial](https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/) - [Authlib OAuth web clients](https://docs.authlib.org/en/v1.7.0/oauth2/client/web/index.html) - [FastAPI background tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/) - [Celery tasks](https://docs.celeryq.dev/en/stable/userguide/tasks.html) - [Temporal Python SDK](https://docs.temporal.io/develop/python) - [uv Docker](https://docs.astral.sh/uv/guides/integration/docker/) - [FastAPI concurrency](https://fastapi.tiangolo.com/async/) - [Python logging](https://docs.python.org/3/library/logging.html) - [Tenacity documentation](https://tenacity.readthedocs.io/en/latest/) - [FastAPI request files](https://fastapi.tiangolo.com/tutorial/request-files/) - [FastAPI WebSockets](https://fastapi.tiangolo.com/advanced/websockets/) - [Boto3 uploads](https://docs.aws.amazon.com/boto3/latest/guide/s3-uploading-files.html) Keep the project README current and link the selected guidance; preserve existing project instructions. --- # Go CLI + TUI Command-line applications and terminal interfaces distributed as binaries. Language: Go | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: cli UI: terminal Deployment: binary ## Use cases - Shipped command-line products - infrastructure administration tools - terminal dashboards ## Fit - Want compiled distribution with Go ecosystem access - Command structure and terminal UX matter more than tight low-level control ## Choose something else when - Primarily a short disposable script - Host SDK or native UI framework mandates another language - Strict no-GC constraints ## 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. ## 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. ## Tools ### Command parsing: Cobra Command/help/completion structure plus event-driven terminal UI. Limits and integration: Keep noninteractive and machine-readable modes; test TTY absence, cancellation and terminal restoration. - https://github.com/spf13/cobra - https://github.com/charmbracelet/bubbletea - https://pkg.go.dev/flag Alternatives: flag for a small single command ### Terminal UI: Bubble Tea only for interactive screens Command/help/completion structure plus event-driven terminal UI. Limits and integration: Keep noninteractive and machine-readable modes; test TTY absence, cancellation and terminal restoration. - https://github.com/spf13/cobra - https://github.com/charmbracelet/bubbletea - https://pkg.go.dev/flag Alternatives: Line-oriented output when no interactive screen is needed ### HTTP client: net/http Client Standard client with contexts and transport reuse. Limits and integration: Set timeouts, bound responses and close bodies; retry only when operation semantics allow. - https://pkg.go.dev/net/http ### Persistence and migrations: None for stateless tools Avoid introducing a database into a command wrapper. Limits and integration: Local durable state requires a separately selected storage/schema policy; never assume flat-file writes are atomic. - https://pkg.go.dev/os Alternatives: Use service API for shared state ### Configuration: Typed settings loaded with os.LookupEnv Explicit startup validation and standard structured logs. Limits and integration: Define precedence; reject malformed required values; redact secrets. Environment access alone is not validation or secret management. - https://pkg.go.dev/os - https://pkg.go.dev/flag - https://pkg.go.dev/log/slog Alternatives: flag for small command surfaces ### Application logging: log/slog Explicit startup validation and standard structured logs. Limits and integration: Define precedence; reject malformed required values; redact secrets. Environment access alone is not validation or secret management. - https://pkg.go.dev/os - https://pkg.go.dev/flag - https://pkg.go.dev/log/slog ### Tests and static checks: testing; go vet; race detector; govulncheck Standard toolchain feedback plus exercised concurrency and known-vulnerability checks. Limits and integration: Race detector requires supported target/toolchain and exercised code; no scanner proves absence of vulnerabilities. - 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/ ### Durable work: Delegate long jobs to a service; persist its job ID Work survives the terminal process only through an explicit durable owner. Limits and integration: A goroutine or TUI background command dies with the process; reconnection needs a stable job identity. - https://riverqueue.com/docs/transactional-enqueueing - https://github.com/charmbracelet/bubbletea Alternatives: River-backed Go service ### Distribution: GoReleaser Target builds and release artifact automation. Limits and integration: Review generated release actions, supported targets, signing and updater policy. cgo can complicate cross-building. - https://goreleaser.com/getting-started/quick-start/ Alternatives: Manual go build for one internal target ### Machine-readable output: encoding/json/v2 on a supporting pinned Go toolchain Stable JSON output lets scripts consume commands without parsing terminal text Limits and integration: 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. - https://pkg.go.dev/encoding/json - https://pkg.go.dev/encoding/json/v2 Alternatives: encoding/json for established output contracts or older supported toolchains ### Cancellation and shutdown: signal.NotifyContext User interrupts should cancel outbound work and leave terminal/files usable Limits and integration: 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. - https://pkg.go.dev/os/signal Alternatives: Preserve an existing compatible project choice ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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. ### Translations to 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. ### Architecture sources - [Cobra flag guide](https://cobra.dev/docs/how-to-guides/working-with-flags/): Flag scoping, validation, deprecation and optional configuration integration are explicit. - [Bubble Tea upstream](https://github.com/charmbracelet/bubbletea): The TUI uses Model/Update/View with commands for effects. - [Go JSON decoder](https://pkg.go.dev/encoding/json#Decoder.DisallowUnknownFields): Typed decoding and DisallowUnknownFields are available; schema policy is the application responsibility. - [os.Exit](https://pkg.go.dev/os#Exit): Process exit skips deferred calls; exit-code meanings need an application contract. - [errgroup](https://pkg.go.dev/golang.org/x/sync/errgroup): Group limit and cancellation support bounded batch execution. - [os/signal](https://pkg.go.dev/os/signal#NotifyContext): NotifyContext exposes signal cancellation. - [GoReleaser workflow](https://goreleaser.com/getting-started/how-it-works/): Release configuration and build/package/publish workflow are described; snapshot behavior has its own source. - [GoReleaser Go builds](https://goreleaser.com/customization/builds/go/): GOOS/GOARCH matrix and environment/CGO settings are configurable. - [GoReleaser notarization](https://goreleaser.com/customization/sign/notarize/): Signing/notarization requires Apple credentials; the native package flow is Pro and uses Apple tools. Cross-platform binary notarization is a separate documented flow. - [GoReleaser snapshots](https://goreleaser.com/customization/publish/snapshots/): Snapshot mode builds review artifacts without publishing to a release channel. - [GoReleaser quick start](https://goreleaser.com/getting-started/quick-start/): goreleaser check validates config; release --snapshot --clean builds local review artifacts. - [GoReleaser OSS installation](https://goreleaser.com/getting-started/install/oss/): Current source installation requires Go 1.27; verified prebuilt binaries are another documented installation method. - [Go 1.27 release notes](https://go.dev/doc/go1.27): Introduces encoding/json/v2 with changed defaults; serializer replacement requires compatibility review. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### CLI and pipe contracts **Inspect the source:** Capture scripts consuming current flags, positional arguments, stdout/stderr, exit codes and completion output. **During 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 design:** 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. **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. **Benefits and prerequisites** - A stable CLI protocol permits automation and humans to share one executable. Requires: 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 before transfer** - 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. - https://cobra.dev/docs/how-to-guides/working-with-flags/ - https://pkg.go.dev/encoding/json#Decoder.DisallowUnknownFields - https://pkg.go.dev/os#Exit ### Data and schema **Inspect the source:** Inventory config paths, default values, flag/environment precedence, secret fields and old readers. **During 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 design:** 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. **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. **Benefits and prerequisites** - A versioned configuration contract makes upgrades and later rollback predictable. Requires: 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 before transfer** - 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. - https://pkg.go.dev/encoding/json#Decoder.DisallowUnknownFields - https://cobra.dev/docs/how-to-guides/working-with-flags/ ### Jobs and schedules **Inspect the source:** Preserve per-item effects, retry decisions, ordering and interrupt behavior for batch commands; a process-local queue has no restart history. **During 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 design:** 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. **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. **Benefits and prerequisites** - Bounded fan-out can overlap independent I/O while maintaining a clear cancellation boundary. Requires: 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 before transfer** - 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. - https://pkg.go.dev/golang.org/x/sync/errgroup - https://pkg.go.dev/os/signal#NotifyContext - https://pkg.go.dev/os#Exit ### Delivery and recovery **Inspect the source:** Preserve command name, install path, OS/architecture support, update channel and downgrade compatibility. **During 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 design:** 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. **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. **Benefits and prerequisites** - A repeatable artifact matrix reduces manual release assembly. Requires: 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 before transfer** - 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. - 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/ Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. Start in a source checkout; go mod init example.com/tool using its intended module path. 2. Run go get github.com/spf13/cobra; resolve a supported Bubble Tea release only if a TUI is required. 3. Build cmd/tool with injectable I/O, configuration validation, stable exit codes and explicit noninteractive behavior. 4. Write command tests covering malformed input, stdout/stderr, cancellation and safe retries; use isolated temporary paths. 5. Run goreleaser init, then review and pin the generated configuration and target matrix. No setup or publishing has been executed. ## Verification Commands below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text gofmt -l . go test ./... go test -race ./... go vet ./... govulncheck ./... go build ./cmd/tool goreleaser check goreleaser build --snapshot --clean ``` ## 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? ## Sources - [Cobra](https://github.com/spf13/cobra) - [Bubble Tea](https://github.com/charmbracelet/bubbletea) - [Go flag](https://pkg.go.dev/flag) - [Go net/http](https://pkg.go.dev/net/http) - [Go os configuration primitives](https://pkg.go.dev/os) - [Go structured logging](https://pkg.go.dev/log/slog) - [Go testing](https://pkg.go.dev/testing) - [Go data race detector](https://go.dev/doc/articles/race_detector) - [golangci-lint quick start](https://golangci-lint.run/docs/welcome/quick-start/) - [Go vulnerability management](https://go.dev/doc/security/vuln/) - [River transactional enqueueing](https://riverqueue.com/docs/transactional-enqueueing) - [GoReleaser quick start](https://goreleaser.com/getting-started/quick-start/) - [Go JSON API](https://pkg.go.dev/encoding/json) - [Go signal API](https://pkg.go.dev/os/signal) - [Go JSON v2](https://pkg.go.dev/encoding/json/v2) Keep the project README current and link the selected guidance; preserve existing project instructions. --- # Rust CLI + TUI Portable command-line tools with explicit memory and resource control. Language: Rust | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: cli UI: terminal Deployment: binary ## Use cases - Fast native developer tools - parsers and analyzers - shipped terminal applications ## Fit - Need native performance or reuse of Rust libraries - Want ownership/type checks around complex transformations ## Choose something else when - Disposable automation would be simpler in Python or shell - Build latency and cross-toolchains outweigh runtime needs ## 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. ## 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. ## Tools ### Command parsing: clap Typed commands plus a mature terminal widget/rendering ecosystem. Limits and integration: Keep domain code separate from rendering and support non-TTY output; restore terminal on errors and interruption. - https://docs.rs/clap/latest/clap/ - https://ratatui.rs/ Alternatives: A simple std::env argument parser for tiny internal tools ### Terminal UI: Ratatui only for interactive screens Typed commands plus a mature terminal widget/rendering ecosystem. Limits and integration: Keep domain code separate from rendering and support non-TTY output; restore terminal on errors and interruption. - https://docs.rs/clap/latest/clap/ - https://ratatui.rs/ Alternatives: Line-oriented output when no interactive screen is needed ### HTTP client: reqwest Reusable typed HTTP client APIs. Limits and integration: Choose blocking or async deliberately; configure timeouts, TLS and response bounds. Never call blocking client inside an async runtime indiscriminately. - https://docs.rs/reqwest/latest/reqwest/ Alternatives: No network dependency for offline tools ### Persistence and migrations: None for stateless tools Start without a database; add schema ownership only for persistent products. Limits and integration: SQLite feature/driver and migration setup require target testing; durable local state is not shared distributed workflow state. - https://docs.rs/sqlx/latest/sqlx/ - https://github.com/transact-rs/sqlx/blob/main/sqlx-cli/README.md Alternatives: SQLx with SQLite when local relational state is a real requirement ### Configuration: Serde-backed settings + config Typed settings plus structured events/spans. Limits and integration: Set precedence explicitly; validate semantics; install a tracing subscriber; never log secrets. - https://docs.rs/config/latest/config/ - https://doc.rust-lang.org/std/env/fn.var.html - https://docs.rs/tracing/latest/tracing/ Alternatives: std::env for a small fixed settings set ### Application logging: tracing + configured subscriber Typed settings plus structured events/spans. Limits and integration: Set precedence explicitly; validate semantics; install a tracing subscriber; never log secrets. - https://docs.rs/config/latest/config/ - https://doc.rust-lang.org/std/env/fn.var.html - https://docs.rs/tracing/latest/tracing/ ### Tests and static checks: cargo test; rustfmt; Clippy; cargo audit Compiler, style, behavior and known-advisory checks complement each other. Limits and integration: Audit coverage is advisory-driven; compile success does not establish behavior or security. Test supported feature combinations rather than blindly enabling incompatible features. - 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/ ### Executable behavior tests: assert_cmd Tests real exit codes, stdout/stderr and command contracts. Limits and integration: Snapshot changes need review; also test actual error and side-effect behavior. - https://docs.rs/assert_cmd/latest/assert_cmd/ - https://docs.rs/clap/latest/clap/ Alternatives: clap-linked snapshot tools for stable help output ### Durable work: Delegate to a durable service; retain resumable job identity CLI lifetime does not own remote work lifetime. Limits and integration: Checkpoint schema, atomic persistence and external idempotency must be designed; async execution alone adds no durability. - https://docs.rs/restate-sdk/latest/restate_sdk/ Alternatives: Local checkpoints for explicitly local resumable work ### Distribution: dist (formerly cargo-dist) + Cargo release builds Generates multi-platform release pipelines and installers. Limits and integration: Review generated CI before tags can publish; test installers and target-native dependencies. Signing and notarization are separate platform work. - https://github.com/axodotdev/cargo-dist - https://doc.rust-lang.org/cargo/commands/cargo-build.html Alternatives: Manual artifacts for one internal target ### Machine-readable output: serde_json Stable JSON output lets scripts consume commands without parsing terminal text Limits and integration: 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. - https://docs.rs/serde_json/latest/serde_json/ Alternatives: Preserve an existing compatible project choice ### Cancellation and shutdown: Tokio signal handling for async commands User interrupts should cancel outbound work and leave terminal/files usable Limits and integration: 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. - https://docs.rs/tokio/latest/tokio/signal/index.html Alternatives: Existing synchronous shutdown strategy in synchronous Rust tools ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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. ### Translations to 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. ### Architecture sources - [clap 4.6.7](https://docs.rs/clap/latest/clap/): Parser/derive command definition supports a typed command boundary. - [clap errors](https://docs.rs/clap/latest/clap/error/struct.Error.html): Usage errors generally print to stderr with code 2; help-like output uses stdout and success. - [Rust ExitCode](https://doc.rust-lang.org/std/process/struct.ExitCode.html): ExitCode can be returned by main; arbitrary numeric code meanings are platform-specific. - [Serde container attributes](https://serde.rs/container-attrs.html): deny_unknown_fields rejects unknown inputs and is incompatible with flatten; version policy is application-owned. - [Ratatui panic hooks](https://ratatui.rs/recipes/apps/panic-hooks/): Terminal restoration must be arranged around error/panic paths. - [Tokio shutdown](https://tokio.rs/tokio/topics/shutdown): Track/notify/await tasks for planned completion. - [Tokio blocking tasks](https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html): Started blocking tasks cannot be aborted; capacity is a separate concern. - [dist simple application guide](https://axodotdev.github.io/cargo-dist/book/workspaces/simple-guide.html): init generates config/workflows, can overwrite manual edits, and plan previews artifacts. - [dist configuration reference](https://axodotdev.github.io/cargo-dist/book/reference/config.html): Targets, installers and CI/download/update settings are configured explicitly. - [Cargo build](https://doc.rust-lang.org/cargo/commands/cargo-build.html): Locked and target-specific builds have defined semantics; build success is not target execution. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### CLI and pipe contracts **Inspect the source:** Record current commands, option defaults, exit codes, stdout/stderr, JSON field names and shell completions consumed by callers. **During 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 design:** 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. **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. **Benefits and prerequisites** - Typed parsing and a stable output envelope make command automation explicit. Requires: 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 before transfer** - 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. - 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 ### Data and schema **Inspect the source:** Inventory configuration file locations, schema versions, defaults, permissions and old binaries' ability to read newer files. **During 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 design:** 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. **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. **Benefits and prerequisites** - Explicit config migration decouples executable upgrades from accidental data loss. Requires: 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 before transfer** - 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. - https://serde.rs/container-attrs.html ### Jobs and schedules **Inspect the source:** Preserve ordering, per-item effects, timeout and interrupt semantics for batch/network subcommands. **During 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 design:** 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. **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. **Benefits and prerequisites** - Bounded parallel execution can overlap independent work without unlimited task creation. Requires: 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 before transfer** - 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. - https://tokio.rs/tokio/topics/shutdown - https://docs.rs/tokio/latest/tokio/task/fn.spawn_blocking.html - https://ratatui.rs/recipes/apps/panic-hooks/ ### Delivery and recovery **Inspect the source:** Capture existing target triples, libc/native dependencies, install path, package metadata and update/downgrade contracts. **During 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 design:** 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. **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. **Benefits and prerequisites** - Generated release plans coordinate binary artifacts and installers across targets. Requires: 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 before transfer** - 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. - 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 Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. Create source in a local development workspace with cargo new tool; enter tool; run cargo add clap --features derive. 2. Resolve Ratatui and its supported terminal backend only if interactive rendering is required; add reqwest only if network access is needed. 3. Implement typed commands, injected/configured settings, stable output/exit codes and domain logic independent of terminal rendering. 4. Add tests with cargo add --dev assert_cmd; cover missing files, invalid input, stdin, cancellation, stdout/stderr and terminal cleanup. 5. 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 below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text cargo fmt --all -- --check cargo clippy --workspace --all-targets --locked -- -D warnings cargo test --workspace --locked cargo audit cargo build --release --locked ``` ## 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? ## Sources - [clap](https://docs.rs/clap/latest/clap/) - [Ratatui](https://ratatui.rs/) - [reqwest](https://docs.rs/reqwest/latest/reqwest/) - [SQLx](https://docs.rs/sqlx/latest/sqlx/) - [SQLx CLI](https://github.com/transact-rs/sqlx/blob/main/sqlx-cli/README.md) - [Rust config crate](https://docs.rs/config/latest/config/) - [Rust environment variables](https://doc.rust-lang.org/std/env/fn.var.html) - [Rust tracing](https://docs.rs/tracing/latest/tracing/) - [Cargo test](https://doc.rust-lang.org/cargo/commands/cargo-test.html) - [rustfmt](https://github.com/rust-lang/rustfmt) - [Clippy usage](https://doc.rust-lang.org/clippy/usage.html) - [RustSec](https://rustsec.org/) - [assert_cmd](https://docs.rs/assert_cmd/latest/assert_cmd/) - [Restate Rust SDK](https://docs.rs/restate-sdk/latest/restate_sdk/) - [dist binary distribution](https://github.com/axodotdev/cargo-dist) - [Cargo build](https://doc.rust-lang.org/cargo/commands/cargo-build.html) - [Rust JSON API](https://docs.rs/serde_json/latest/serde_json/) - [Rust signal API](https://docs.rs/tokio/latest/tokio/signal/index.html) Keep the project README current and link the selected guidance; preserve existing project instructions. --- # Python automation + AI Scripts, integrations and workers close to the Python data and AI ecosystem. Language: Python | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: automation UI: none Deployment: server ## Use cases - Reusable automation scripts - Scheduled imports and transformations - Model/tool orchestration workers ## Fit - The deliverable is a bounded task or worker rather than a web product - Python SDKs or data libraries materially simplify integrations ## Choose something else when - A one-off script is being expanded into an undocumented product backend - Hard real-time deadlines or a native deployment requirement dominate ## 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. ## 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. ## Tools ### Packaging and environments: uv + pyproject.toml + committed uv.lock One project entry point for dependencies, Python selection, execution and reproducible sync. Limits and integration: 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. - https://docs.astral.sh/uv/guides/projects/ Alternatives: Preserve an existing maintained packaging workflow ### Lint and format: Ruff Fast lint and formatting feedback with one configuration. Limits and integration: Ruff does not replace static typing, tests, authorization checks or runtime validation. - https://docs.astral.sh/ruff/installation/ Alternatives: Preserve existing configured formatter/linter ### Static typing: mypy Explicit checks on application boundaries with a conservative established checker. Limits and integration: Configure strictness and third-party stubs; unchecked Any and untyped functions reduce coverage. No checker performance comparison was run. - https://mypy.readthedocs.io/en/stable/getting_started.html - https://docs.astral.sh/ty/type-checking/ Alternatives: ty after project-specific compatibility trial ### Testing: pytest with deterministic fake external services and captured fixtures Fast repeatable tests can verify parsing, permissions and retry decisions. Limits and integration: Add adversarial outputs and partial-failure cases for agents; do not confuse output snapshots with task success. - https://docs.pytest.org/en/stable/getting-started.html Alternatives: Integration suites against sandbox services ### Validation: Pydantic at configuration, tool-input and model-output boundaries Reject malformed external structures before effects. Limits and integration: Define strictness intentionally; a validated plan still needs permission and domain checks. - https://pydantic.dev/docs/validation/latest/concepts/strict_mode/ Alternatives: Standard-library dataclasses for trusted internal values ### External I/O: Provider-supported Python SDK or HTTPX with explicit timeouts and bounded concurrency Centralize transport settings, credentials and test seams. Limits and integration: Configure total task deadlines as well as network inactivity timeouts; avoid retry storms and duplicated writes; redact credentials from logs. - https://www.python-httpx.org/advanced/timeouts/ Alternatives: Standard-library clients for small dependency-free work ### Persistence and migrations: No database for stateless scripts; PostgreSQL + SQLAlchemy/Alembic for shared durable business state Avoid introducing infrastructure before state ownership requires it. Limits and integration: Files need atomic writes/checkpoints; database state does not automatically resume execution. Review migrations and use task-local sessions. - https://docs.sqlalchemy.org/en/21/orm/session_basics.html - https://alembic.sqlalchemy.org/en/latest/autogenerate.html Alternatives: SQLite for one-machine local state ### Auth and credentials: Scoped service credentials injected by the execution platform Workers generally need service authorization rather than user login UI. Limits and integration: Credential storage/provider is deployment-specific and unselected; keep secrets out of source, fixtures, task payloads and output. - https://docs.astral.sh/uv/guides/integration/docker/ - https://www.python-httpx.org/advanced/timeouts/ Alternatives: Delegated user OAuth when required by the integration ### Long-running durable agents: Temporal Python SDK when recovery across restarts is required Persisted workflow orchestration and separate worker processes suit retries, pauses and human waits. Limits and integration: 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. - https://docs.temporal.io/develop/python - https://docs.celeryq.dev/en/stable/userguide/tasks.html Alternatives: Celery for independent queued jobs; direct function for bounded work ### Execution and deployment: uv-managed package and explicit CLI entry point; separate managed worker process for persistent workers Make inputs, exit codes and restart behavior reproducible. Limits and integration: Scheduler/platform is unselected; document non-overlap and checkpoint semantics. Do not add a web server just to run a job. - https://docs.astral.sh/uv/guides/projects/ - https://docs.astral.sh/uv/guides/scripts/ - https://docs.astral.sh/uv/guides/integration/docker/ Alternatives: uv script metadata for a small standalone file; Scheduled container for bounded jobs ### Application logging: Python logging with configured handlers Shared standard logging captures application and dependency diagnostics Limits and integration: 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. - https://docs.python.org/3/library/logging.html Alternatives: Preserve an existing compatible project choice ### Bounded external-call retries: Tenacity only for retryable transient failures Explicit stop/wait/filter rules support controlled retries Limits and integration: 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. - https://tenacity.readthedocs.io/en/latest/ Alternatives: Provider SDK retry policy when sufficient ### Object storage: Boto3 S3 client when durable objects are required Official SDK supports file transfer to S3 Limits and integration: 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. - https://docs.aws.amazon.com/boto3/latest/guide/s3-uploading-files.html Alternatives: Preserve an existing compatible project choice ### HTTP timeouts: HTTPX client timeouts and connection limits Connect/read/write/pool deadlines prevent unbounded remote waits Limits and integration: Configure shared client timeout and limits; retain overall operation deadline separately because read timeout measures inactivity between chunks. Close clients and redact request logs. - https://www.python-httpx.org/advanced/timeouts/ Alternatives: Preserve an existing compatible project choice ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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 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. ### Translations to 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. ### Architecture sources - [uv projects](https://docs.astral.sh/uv/guides/projects/): Project/package entry points, lockfile-based execution and dependency management are documented. - [uv Docker](https://docs.astral.sh/uv/guides/integration/docker/): Locked/no-dev sync and build/runtime environment setup are explicit. - [Python sqlite3](https://docs.python.org/3/library/sqlite3.html): Transactions and persisted local state are available; transaction control and concurrency need deliberate configuration. - [Python os.replace](https://docs.python.org/3/library/os.html#os.replace): Replacement can be atomic on success and can fail across filesystems; sync/durability is separate. - [Python asyncio tasks](https://docs.python.org/3/library/asyncio-task.html): TaskGroup/timeout require 3.11+ and use cancellation; swallowing cancellation breaks structured behavior. - [Python asyncio synchronization](https://docs.python.org/3/library/asyncio-sync.html): Semaphore supports bounded task access and is not thread-safe. - [HTTPX timeouts](https://www.python-httpx.org/advanced/timeouts/): Connect/read/write/pool timeouts are separate; read timeout concerns waiting for chunks. - [HTTPX resource limits](https://www.python-httpx.org/advanced/resource-limits/): Connection and keepalive pool bounds are configurable. - [Celery 5.6.3 tasks](https://docs.celeryq.dev/en/stable/userguide/tasks.html): Idempotency, acknowledgements, retries and worker-loss behavior need explicit policy; late ack has exceptions. - [Temporal Python Workflow basics](https://docs.temporal.io/develop/python/workflows/basics): Workflow code must respect deterministic/replay constraints. - [Temporal Activity basics](https://docs.temporal.io/develop/python/activities/basics): Activity definitions and worker registration place external work outside deterministic Workflow code; idempotency has a separate concept source. - [Temporal Activity timeouts](https://docs.temporal.io/develop/python/activities/timeouts): Activity timeouts, retry policies and heartbeats support bounded/recoverable execution. - [Temporal Python testing](https://docs.temporal.io/develop/python/best-practices/testing-suite): Replay checks history compatibility; Activity and time-skipping environments support recovery testing. - [Temporal Activity idempotency](https://docs.temporal.io/activity-definition): 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. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### CLI and pipe contracts **Inspect the source:** Capture old script arguments, environment/config precedence, file paths, exit codes and scheduler invocation behavior. **During 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 design:** 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. **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. **Benefits and prerequisites** - An importable locked package makes repeated automation easier to test and invoke consistently. Requires: 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 before transfer** - 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. - https://docs.astral.sh/uv/guides/projects/ - https://docs.astral.sh/uv/guides/integration/docker/ ### Data and schema **Inspect the source:** Identify source pagination/cursors, input revisions, item identifiers, partial outputs and acknowledged versus uncertain effects. **During 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 design:** 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. **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. **Benefits and prerequisites** - Durable progress records allow targeted restart and investigation instead of blind replay. Requires: 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 before transfer** - 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. - https://docs.python.org/3/library/sqlite3.html - https://docs.python.org/3/library/os.html#os.replace ### Delivery and recovery **Inspect the source:** Preserve provider rate limits, retry budgets, total run deadline and cleanup/cancellation behavior; SDK inactivity timeout is not a whole-run deadline. **During 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 design:** 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. **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. **Benefits and prerequisites** - Bounded concurrency and total deadlines prevent unlimited waiting work and reduce abandoned I/O. Requires: 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 before transfer** - 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. - 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/ ### Jobs and schedules: Independent jobs with Celery **Inspect the source:** Capture independent task payload versions, broker durability, acknowledgement timing, retries, dead-letter handling and scheduler overlap. **During 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 design:** 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. **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. **Benefits and prerequisites** - A qualified queue permits independent worker restart and retry for bounded jobs. Requires: 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 before transfer** - 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. - https://docs.celeryq.dev/en/stable/userguide/tasks.html ### Jobs and schedules: Recoverable multi-step workflows with Temporal **Inspect the source:** Capture long-lived operation IDs, timer/human-wait behavior, provider effects and history/checkpoint schema before adopting durable orchestration. **During 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 design:** 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. **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. **Benefits and prerequisites** - Persisted workflow history can resume orchestration across worker restarts and represent long waits. Requires: 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 before transfer** - 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. - 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 Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. 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 2. uv add --dev ruff mypy pytest; define an importable worker_app package and a pyproject.toml CLI entry point. 3. Implement explicit inputs, a dry-run or fixture mode, bounded external calls, structured result/error output, and credentials injected by the environment. 4. 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. 5. 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. 6. 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 below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text 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? ## Sources - [uv projects](https://docs.astral.sh/uv/guides/projects/) - [Ruff installation](https://docs.astral.sh/ruff/installation/) - [mypy getting started](https://mypy.readthedocs.io/en/stable/getting_started.html) - [ty type checking](https://docs.astral.sh/ty/type-checking/) - [pytest getting started](https://docs.pytest.org/en/stable/getting-started.html) - [Pydantic strict mode](https://pydantic.dev/docs/validation/latest/concepts/strict_mode/) - [HTTPX timeouts](https://www.python-httpx.org/advanced/timeouts/) - [SQLAlchemy session basics](https://docs.sqlalchemy.org/en/21/orm/session_basics.html) - [Alembic autogeneration](https://alembic.sqlalchemy.org/en/latest/autogenerate.html) - [uv Docker](https://docs.astral.sh/uv/guides/integration/docker/) - [Temporal Python SDK](https://docs.temporal.io/develop/python) - [Celery tasks](https://docs.celeryq.dev/en/stable/userguide/tasks.html) - [uv scripts](https://docs.astral.sh/uv/guides/scripts/) - [Python logging](https://docs.python.org/3/library/logging.html) - [Tenacity documentation](https://tenacity.readthedocs.io/en/latest/) - [Boto3 uploads](https://docs.aws.amazon.com/boto3/latest/guide/s3-uploading-files.html) Keep the project README current and link the selected guidance; preserve existing project instructions. --- # Swift + SwiftUI Native iPhone and iPad apps using Apple's UI and platform APIs. Language: Swift | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: ios UI: native Deployment: native ## Use cases - iPhone and iPad products - Native Apple integrations - Accessible mobile clients for a shared service ## Fit - Apple-native UI and platform capabilities are requirements - A Mac/Xcode build environment and Apple distribution ownership are available ## Choose something else when - The requirement is a single shared UI across iOS and Android - There is no supported macOS/Xcode build environment ## 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. ## 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. ## Tools ### UI and state: SwiftUI + Observation; small @MainActor observable presentation models; explicit services Native controls and platform conventions; keep domain and transport logic out of views Limits and integration: SwiftUI/Observation availability must match the minimum OS; Observation is not persistence or automatic thread safety - https://developer.apple.com/swiftui/ - https://developer.apple.com/documentation/swiftui/model-data Alternatives: UIKit for unsupported UI or existing UIKit apps; ObservableObject for older deployment targets ### Structured local persistence: SwiftData Framework-integrated models and persistence with a small dependency footprint Limits and integration: Validate migrations, relationship behavior and deployment availability; local persistence does not implement cross-platform sync - https://developer.apple.com/documentation/swiftdata/modelcontext Alternatives: Core Data for established stores or older targets; explicit SQLite for requirements SwiftData does not meet ### Nonsecret preferences: UserDefaults Framework-integrated models and persistence with a small dependency footprint Limits and integration: Validate migrations, relationship behavior and deployment availability; local persistence does not implement cross-platform sync - https://developer.apple.com/documentation/swiftdata/modelcontext Alternatives: Existing explicit nonsecret preferences storage; structured databases have a separate persistence job ### Networking and API contract: URLSession + Codable behind an injected API client Native HTTP client and async APIs; share API schemas and fixtures with Android Limits and integration: Check status codes, cancellation, timeouts and decoding; do not put provider secrets in the client; server owns authorization - https://developer.apple.com/documentation/foundation/urlsession Alternatives: Generated Swift client from a versioned API contract when its generator is proven ### Concurrency and background work: Swift structured concurrency, cancellation and actor isolation; server for durable agent runs Keep rendering responsive and avoid tying durable business work to a view lifetime Limits and integration: async does not mean CPU work runs off the main actor; OS may suspend apps and does not guarantee exact background scheduling - https://developer.apple.com/documentation/foundation/urlsession - https://developer.apple.com/documentation/backgroundtasks Alternatives: BackgroundTasks or background URLSession for eligible OS-managed local work ### Credentials: Keychain for app credentials Use platform secret storage rather than preferences or database fields Limits and integration: Define accessibility and logout/revocation behavior; backend service credentials never belong in app binaries - https://developer.apple.com/documentation/security/keychain-services Alternatives: In-memory credentials when persistence is unnecessary ### Unit and integration tests: Swift Testing for new domain/API tests; XCTest where needed Test deterministic state transitions, fixtures, decoding, persistence and failures Limits and integration: Do not mix Swift Testing and XCTest assertions inside a single test; simulator tests do not validate all hardware behavior - https://developer.apple.com/documentation/xcode/testing Alternatives: Keep established XCTest suites ### UI and accessibility: XCTest/XCUIAutomation; per-screen accessibility audits; VoiceOver and Dynamic Type review Exercise navigation, permission states, keyboard/focus, screen-reader order and large text Limits and integration: Automated audits cover the current screen and do not establish usability or complete accessibility; hardware checks remain necessary - https://developer.apple.com/documentation/xcode/testing - https://developer.apple.com/documentation/accessibility/performing-accessibility-audits-for-your-app Alternatives: Accessibility Inspector for interactive audit ### Build, CI and distribution: Xcode + Swift Package Manager; xcodebuild on pinned macOS/Xcode CI; TestFlight before App Store One reproducible toolchain, recorded test results, signed archives and beta verification Limits and integration: 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 - https://developer.apple.com/xcode-cloud/ - https://developer.apple.com/library/archive/technotes/tn2339/_index.html Alternatives: Xcode Cloud for managed Apple CI ### Navigation: SwiftUI NavigationStack Platform navigation keeps back behavior and destinations in native UI Limits and integration: 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. - https://developer.apple.com/documentation/swiftui/navigationstack Alternatives: Preserve an existing compatible project choice ### Notifications: UserNotifications Native notifications support reminders with explicit user permission Limits and integration: 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. - https://developer.apple.com/documentation/usernotifications/asking-permission-to-use-notifications Alternatives: Preserve an existing compatible project choice ### Media selection: PhotosUI PhotosPicker Native picker lets users choose image/video assets Limits and integration: iOS 16+; load selected representations with cancellation/error handling and bound file size before upload. Selection is not immediate local-file availability. - https://developer.apple.com/documentation/photosui/photospicker Alternatives: Preserve an existing compatible project choice ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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=' -resultBundlePath .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. ### Translations to 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. ### Architecture sources - [SwiftUI Managing Model Data](https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app): Observation connects model changes to UI and requires iOS/iPadOS 17+; it is not local persistence. - [SwiftData SchemaMigrationPlan](https://developer.apple.com/documentation/swiftdata/schemamigrationplan): Versioned schemas and migration stages explicitly model local schema evolution; iOS/iPadOS 17+. - [SwiftData VersionedSchema](https://developer.apple.com/documentation/swiftdata/versionedschema): A schema records a particular version and its model set. - [Foundation URLSession](https://developer.apple.com/documentation/foundation/urlsession): Configured sessions own data/upload/download/WebSocket tasks, authentication callbacks and asynchronous transfer behavior. - [Background Tasks](https://developer.apple.com/documentation/backgroundtasks): Register and schedule task handlers for eligible background processing; the framework has multiple task types. - [Choosing Background Strategies](https://developer.apple.com/documentation/backgroundtasks/choosing-background-strategies-for-your-app): Select task strategy by workload, handle expiration and completion; the OS decides refresh/processing launch time. - [Downloading Files in the Background](https://developer.apple.com/documentation/foundation/downloading-files-in-the-background): Background sessions require delegates/stable identifiers, support file-backed uploads and need completion-file lifecycle handling. - [Keychain Services](https://developer.apple.com/documentation/security/keychain-services): Encrypted Keychain items can store small credential secrets. - [App Store Connect Phased Release](https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases/): Automatic updates progress over seven days; manual downloads remain possible and phases can be paused. - [Xcode Testing](https://developer.apple.com/documentation/xcode/testing): Swift Testing and XCTest/UI tests have complementary roles; testing is separate from distribution. - [Archived Xcode Command-line FAQ](https://developer.apple.com/library/archive/technotes/tn2339/_index.html): Documents command shapes for scheme/project/destination tests and archives; recheck options with the pinned Xcode toolchain. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### Browser and installed clients **Inspect the source:** Installed versions, minimum OS, URLSession DTOs/errors, deep links, auth expiry and old/offline writes. **During 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 design:** Recommendation: Separate API DTOs from local models and use capability negotiation for optional features; authorization remains backend-owned. **Rollback:** Disable the new server feature and retain both API contracts; already-installed clients require a compatible forward fix when needed. **Benefits and prerequisites** - Independent backend/client deployment can preserve supported installations. Requires: 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 before transfer** - 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. - https://developer.apple.com/documentation/foundation/urlsession - https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases/ ### Data and schema **Inspect the source:** Existing on-device store versions, entity meaning, relationships, pending local writes and upgrade paths. **During coexistence:** Recommendation: Add compatible fields/stages before removing representations; migration fixtures include every supported historical store and unacknowledged operations. **Target design:** Recommendation: Use SwiftData VersionedSchema and SchemaMigrationPlan when OS support permits; preserve the established Core Data/store choice if migration value is unproven. **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. **Benefits and prerequisites** - An explicit schema history makes upgrade behavior inspectable. Requires: 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 before transfer** - 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. - https://developer.apple.com/documentation/swiftdata/schemamigrationplan - https://developer.apple.com/documentation/swiftdata/versionedschema ### Caching and shared state **Inspect the source:** Local reads, pending offline changes, tombstones/cursors and server conflict semantics. **During 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 design:** 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. **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. **Benefits and prerequisites** - Users can retain local work through intermittent connectivity. Requires: 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 before transfer** - 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. - https://developer.apple.com/documentation/swiftdata/schemamigrationplan - https://developer.apple.com/documentation/foundation/urlsession ### Jobs and schedules **Inspect the source:** Foreground task cancellation, pending intents and any existing background task identifiers/handlers. **During coexistence:** Recommendation: Retain old handler identifiers and persisted payload readers while new code is installed; use one owner per sync operation. **Target design:** Recommendation: Choose BGAppRefreshTask/BGProcessingTask for eligible opportunistic device work, foreground tasks for interactive work and backend durable jobs for server completion obligations. **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. **Benefits and prerequisites** - Eligible refresh/maintenance can execute while the app is backgrounded. Requires: 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 before transfer** - 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. - https://developer.apple.com/documentation/backgroundtasks - https://developer.apple.com/documentation/backgroundtasks/choosing-background-strategies-for-your-app ### Files and objects **Inspect the source:** Existing upload/download IDs, authorized object keys, file hashes, task identifiers and completion acknowledgements. **During coexistence:** Recommendation: Keep server upload endpoints/object ownership compatible; persist mapping from background task to logical operation and retain file-backed upload payloads. **Target design:** Recommendation: Use an identified background URLSession for eligible HTTP(S) transfer; recreate it after system termination and move completed temporary downloads before delegate return. **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. **Benefits and prerequisites** - Transfers can continue during suspension without holding the app process. Requires: 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 before transfer** - 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. - https://developer.apple.com/documentation/foundation/downloading-files-in-the-background ### Delivery and recovery **Inspect the source:** Store release ownership, supported devices, adoption, crash reports and persisted-data compatibility. **During coexistence:** Recommendation: Verify TestFlight install-over-existing fixtures; retain server compatibility through phased adoption and include manual downloads in risk assessment. **Target design:** Recommendation: Use phased release with explicit crash/data-loss/compatibility stop criteria; assess adoption before retiring old API behavior. **Rollback:** Pause further distribution and disable affected server capabilities if safe; ship a compatible repair rather than assuming an installed-version/store downgrade. **Benefits and prerequisites** - Gradual automatic-update distribution can limit initial exposure. Requires: 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 before transfer** - 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. - https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases/ Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. Start in a source checkout in a local development workspace. Record minimum iOS/iPadOS versions, bundle ID, required capabilities, API schema and signing owner. 2. 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. 3. 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. 4. Separate views, observable presentation state, repositories and API DTOs. Add migration fixtures and versioned network fixtures; use a fake API for tests. 5. Run local simulator checks and CI using an actual destination ID. Then verify representative physical devices, offline/reconnect, permissions, VoiceOver and large text. 6. 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 below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text 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=" -resultBundlePath .xcresult xcodebuild archive -project App.xcodeproj -scheme App -destination "generic/platform=iOS" -archivePath .xcarchive xcodebuild -exportArchive -archivePath .xcarchive -exportPath -exportOptionsPlist .plist ``` ## 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? ## Sources - [SwiftUI](https://developer.apple.com/swiftui/) - [SwiftUI model data](https://developer.apple.com/documentation/swiftui/model-data) - [SwiftData ModelContext](https://developer.apple.com/documentation/swiftdata/modelcontext) - [URLSession](https://developer.apple.com/documentation/foundation/urlsession) - [Testing with Xcode](https://developer.apple.com/documentation/xcode/testing) - [Performing accessibility audits](https://developer.apple.com/documentation/accessibility/performing-accessibility-audits-for-your-app) - [Xcode Cloud](https://developer.apple.com/xcode-cloud/) - [Xcode command-line FAQ (archived; check local help)](https://developer.apple.com/library/archive/technotes/tn2339/_index.html) - [Keychain services](https://developer.apple.com/documentation/security/keychain-services) - [Background Tasks](https://developer.apple.com/documentation/backgroundtasks) - [SwiftUI NavigationStack](https://developer.apple.com/documentation/swiftui/navigationstack) - [Apple notification permission](https://developer.apple.com/documentation/usernotifications/asking-permission-to-use-notifications) - [PhotosPicker](https://developer.apple.com/documentation/photosui/photospicker) Keep the project README current and link the selected guidance; preserve existing project instructions. --- # Kotlin + Compose Native Android apps with platform UI, lifecycle and storage integration. Language: Kotlin | Reviewed: 2026-10-10 | Evidence: documentation-reviewed Core guidance checked: 2026-10-13. See /research-freshness.json for review scope. These recipes and selected dependency combinations need qualification in the actual project. ## Application role Components: android UI: native Deployment: native ## Use cases - Android phones, tablets and foldables - Native Android integrations - Accessible mobile clients for a shared service ## Fit - Android-native UI and platform behavior are requirements - The team can own an Android SDK, emulator/device and signed release pipeline ## Choose something else when - The requirement is a single shared UI for Android and iOS - No Android device or emulator verification can be performed ## 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. ## 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. ## Tools ### UI and state: Jetpack Compose + Material 3; screen ViewModels exposing immutable StateFlow with lifecycle-aware collection Unidirectional data flow separates user events and rendered state; repositories own data access Limits and integration: ViewModels do not survive process death; persist important state and test restoration; add domain layers only for actual complexity - https://developer.android.com/topic/architecture/recommendations Alternatives: Android Views for existing apps or unsupported controls ### Structured local persistence: Room Compile-time SQL checking, migrations and observable local data Limits and integration: Choose compatible Room/KSP/Kotlin versions; test upgrades; neither Room nor DataStore automatically supplies encryption or backend sync - https://developer.android.com/training/data-storage/room - https://developer.android.com/topic/libraries/architecture/datastore Alternatives: Direct SQLite only when Room cannot satisfy measured requirements ### Preferences: DataStore Compile-time SQL checking, migrations and observable local data Limits and integration: Choose compatible Room/KSP/Kotlin versions; test upgrades; neither Room nor DataStore automatically supplies encryption or backend sync - https://developer.android.com/training/data-storage/room - https://developer.android.com/topic/libraries/architecture/datastore Alternatives: Existing supported preferences implementation with an explicit data migration ### Networking and API contract: Retrofit + OkHttp + kotlinx.serialization behind a repository Typed HTTP interfaces with explicit DTOs and a replaceable client Limits and integration: Pin compatible versions and converter; share schemas/fixtures with iOS rather than UI; test auth refresh, errors and cancellation - https://github.com/lysine-dev/retrofit Alternatives: Ktor Client when deliberate multiplatform business-code sharing justifies it ### Concurrency and background work: Coroutines/Flow in lifecycle-owned scopes; WorkManager for eligible persistent deferrable work Cancellation follows lifecycle while scheduled local sync uses a persistent work system Limits and integration: WorkManager is OS-constrained and not an exact scheduler; coroutine launch alone is not durable across process death - https://developer.android.com/topic/architecture/recommendations - https://developer.android.com/develop/background-work/background-tasks/persistent Alternatives: Server-side durable jobs for long agent runs ### Credentials: Android Keystore-backed cryptographic keys protecting app-private credential material Use OS key protection and explicitly scoped encrypted storage Limits and integration: Keystore stores keys, not arbitrary bearer tokens; define encryption, backup exclusions and revocation; no backend provider secrets in APKs - https://developer.android.com/privacy-and-security/keystore Alternatives: In-memory sessions when no persisted credentials are needed ### Unit and integration tests: JUnit + coroutine test utilities; fake repositories/API; Room migration tests Deterministically verify state, retries, decoding, migrations and process-restoration assumptions Limits and integration: Host unit tests cannot prove Android framework/device behavior; emulator tests supplement them - https://developer.android.com/topic/architecture/recommendations - https://developer.android.com/training/data-storage/room Alternatives: Established project test framework when compatible ### UI and accessibility: Compose UI tests + AndroidX accessibility checks; TalkBack and large-font/device review Verify semantic actions, navigation and permission flows with the actual platform UI Limits and integration: Automatic checks require supported test dependencies/API environment and do not replace screen-reader usability; test tablets/foldables if supported - https://developer.android.com/develop/ui/compose/testing - https://developer.android.com/develop/ui/compose/accessibility/testing Alternatives: Espresso for mixed Views/Compose apps ### Build, CI and distribution: Android Studio + Gradle wrapper/Kotlin DSL; pinned JDK/SDK CI; signed Android App Bundle and Play internal testing Reproduce build inputs and separate local tests, device tests and signed release artifacts Limits and integration: AGP/Gradle/JDK/Kotlin/Compose must be compatible; release requires upload-key custody and Play account access; build success is not store publication - https://developer.android.com/build/building-cmdline - https://developer.android.com/studio/publish/app-signing Alternatives: Managed device or device-farm testing where the project needs a broader matrix ### Navigation: Navigation Compose Navigation host/controller handle screen back stacks and deep links Limits and integration: Add compatible navigation-compose dependency; pass minimal route identifiers and test process recreation/back behavior. Preserve Fragment navigation during partial Compose migration. - https://developer.android.com/guide/navigation Alternatives: Preserve an existing compatible project choice ### Notifications: Android notification channels + runtime permission Native notifications keep user delivery preferences under system control Limits and integration: Declare/request POST_NOTIFICATIONS where required; create appropriate channels, handle denial and test release API levels. Remote transport/server enrollment is a separate integration. - https://developer.android.com/develop/ui/compose/notifications/notification-permission Alternatives: Preserve an existing compatible project choice ### Media selection: Android Photo Picker System picker grants access to selected media Limits and integration: Use Activity result contracts; handle fallback devices, URI access lifetime and upload size limits. Prefer selected access over requesting broad media-library permissions. - https://developer.android.com/training/data-storage/shared/photo-picker Alternatives: Preserve an existing compatible project choice ## Architecture and developer workflow 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. 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. Reviewed: 2026-10-11 | Evidence: documentation-reviewed ### Architecture boundaries - 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. ### Tools and feedback - 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. ### Translations to 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. ### Architecture sources - [Android Architecture Recommendations](https://developer.android.com/topic/architecture/recommendations): Separate UI/data layers, repositories, immutable state and lifecycle-aware collection are documented recommendations. - [Android Offline-first Architecture](https://developer.android.com/topic/architecture/data-layer/offline-first): Local sources, queues, sync and conflict resolution need explicit policies; offline reads need not imply offline writes. - [Migrate Your Room Database](https://developer.android.com/training/data-storage/room/migrating-db-versions): Migration testing should cover all paths; destructive fallback can permanently delete local table data. - [Android WorkManager Task Scheduling](https://developer.android.com/develop/background-work/background-tasks/persistent): Work is persisted and rescheduled across reboots with constraints/retries; it is not an exact timer or all immediate work. - [Android Keystore System](https://developer.android.com/privacy-and-security/keystore): Keystore protects cryptographic key material and usage constraints; arbitrary credentials need their own protected storage design. - [Build Android Apps from the Command Line](https://developer.android.com/build/building-cmdline): Gradle wrapper build/test tasks and signed release artifacts require configured inputs. - [Play Console Staged Rollouts](https://support.google.com/googleplay/android-developer/answer/6346149): Halting stops additional staged installs; already-updated users remain on that version. ## Transition options Proposed designs and checks; these are not executed compatibility results. ### Browser and installed clients **Inspect the source:** Supported installed APK versions/OS levels, DTOs/errors, auth, deep links and delayed old-client operations. **During coexistence:** Recommendation: Deploy backward-compatible server behavior first; run old/new clients against it and retain contracts through explicit adoption/support gates. **Target design:** Recommendation: Version API DTOs independently of Room entities and gate optional features by negotiated capability; keep backend authorization authoritative. **Rollback:** Disable the new capability and preserve old/new APIs; repair already-installed clients with a compatible higher-version release when needed. **Benefits and prerequisites** - Client releases and backend changes can progress independently. Requires: Installed-version inventory, shared API fixtures and support ownership. Tradeoffs: Maintaining old contracts costs work; Compose adoption does not upgrade installed clients. **Checks before transfer** - 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. - https://developer.android.com/topic/architecture/recommendations - https://support.google.com/googleplay/android-developer/answer/6346149 ### Data and schema **Inspect the source:** Room schema versions, exported schemas, all upgrade paths and user-owned unsynced records. **During coexistence:** Recommendation: Add migrations without discarding old fields until adoption permits; include direct upgrades from every supported starting version. **Target design:** Recommendation: Keep exported Room schemas and explicit migration tests; use automatic or manual migrations according to the actual change. **Rollback:** Ship a forward repair when older code cannot read the new store; any restore requires reconciling writes made after upgrade. **Benefits and prerequisites** - Reviewed migrations preserve local user data across updates. Requires: 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 before transfer** - 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. - https://developer.android.com/training/data-storage/room/migrating-db-versions ### Caching and shared state **Inspect the source:** Local source-of-truth reads, pending offline operations, revision/cursor/tombstone and conflict rules. **During coexistence:** Recommendation: Use one repository and one reconciler for each data category; persist queued mutations with operation IDs before reporting success. **Target design:** 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. **Rollback:** Stop the new synchronizer and retain its queue; map remaining operations/cursors to old semantics before resume. **Benefits and prerequisites** - Cached local data can keep required reads available and preserve offline intent. Requires: 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 before transfer** - 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. - https://developer.android.com/topic/architecture/data-layer/offline-first ### Jobs and schedules **Inspect the source:** Existing queued Worker class names, input Data versions, unique-work identities and external effects. **During coexistence:** Recommendation: Retain readers/worker entry points for already-enqueued payloads; transfer one job category and prevent duplicate schedulers. **Target design:** Recommendation: Use WorkManager for eligible persistent device work with constraints/backoff; keep server completion obligations in a backend durable job. **Rollback:** Cancel new scheduling and account for pending/running work; keep compatibility workers until drained or safely transformed. **Benefits and prerequisites** - Scheduled work persists across restart and device reboot. Requires: 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 before transfer** - 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. - https://developer.android.com/develop/background-work/background-tasks/persistent - https://developer.android.com/topic/architecture/data-layer/offline-first ### Identity and authorization **Inspect the source:** Existing stored credential encryption, key alias/access constraints, backup exclusions, issuer expiry/revocation. **During coexistence:** Recommendation: Retain the backend issuer and read old encrypted credential formats during a bounded transition; isolate account-local data. **Target design:** Recommendation: Use Keystore-backed cryptographic keys with reviewed encrypted app-private credential storage and backend revocation. **Rollback:** Retain compatibility decryption only while secure; require sign-in if the old format/key cannot be restored safely. **Benefits and prerequisites** - OS key protection can reduce key extraction exposure. Requires: 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 before transfer** - 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. - https://developer.android.com/privacy-and-security/keystore ### Delivery and recovery **Inspect the source:** Play tracks, signing/version codes, adoption, crash metrics and schema/API compatibility. **During coexistence:** Recommendation: Verify an internal/closed-track update over supported old builds and preserve compatible backend behavior for the whole mixed-version population. **Target design:** Recommendation: Use a staged rollout with explicit crash/data-loss thresholds and a higher-version compatible repair path. **Rollback:** Halt additional rollout and disable the affected capability if safe; publish a compatible fixed build without assuming a downgrade of installed clients. **Benefits and prerequisites** - Percentage-based adoption can limit initial exposure. Requires: Signed build, account/track owner, telemetry and recovery artifact. Tradeoffs: Halting only prevents further rollout; users who already updated remain on that version. **Checks before transfer** - Install-over-old-build retains unsynced data and auth. - Track failures by app/OS/schema version. - Halt/recovery rehearsal keeps already-updated users functional. - https://support.google.com/googleplay/android-developer/answer/6346149 Rewrite workflow: /rewrite/guide.md Shared contracts and phases: /rewrite/contracts.json ## Setup 1. 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. 2. 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. 3. 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. 4. Run JVM tests, lint and a debug build. Start a documented emulator or attach an authorized device, then run instrumentation/Compose checks. 5. Exercise process death, offline/reconnect, rotation, permission denial, TalkBack, large fonts and each supported form factor on appropriate devices. 6. 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 below require the selected tools and project configuration. Replace example paths, schemes and IDs; distinguish tests from builds and interactive startup. These are instructions, not recorded passes. ```text ./gradlew --version ./gradlew tasks --all ./gradlew :app:lintDebug :app:testDebugUnitTest :app:assembleDebug adb devices ./gradlew :app:connectedDebugAndroidTest ./gradlew :app:bundleRelease ``` ## 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? ## Sources - [Android architecture recommendations](https://developer.android.com/topic/architecture/recommendations) - [Room persistence](https://developer.android.com/training/data-storage/room) - [DataStore](https://developer.android.com/topic/libraries/architecture/datastore) - [Retrofit maintained repository; square/retrofit redirects here](https://github.com/lysine-dev/retrofit) - [Persistent background work](https://developer.android.com/develop/background-work/background-tasks/persistent) - [Compose testing](https://developer.android.com/develop/ui/compose/testing) - [Compose accessibility testing](https://developer.android.com/develop/ui/compose/accessibility/testing) - [Android command-line build](https://developer.android.com/build/building-cmdline) - [Android app signing](https://developer.android.com/studio/publish/app-signing) - [Android Keystore system](https://developer.android.com/privacy-and-security/keystore) - [Android Navigation](https://developer.android.com/guide/navigation) - [Android notification permission](https://developer.android.com/develop/ui/compose/notifications/notification-permission) - [Android Photo Picker](https://developer.android.com/training/data-storage/shared/photo-picker) Keep the project README current and link the selected guidance; preserve existing project instructions.