# Loco + SeaORM + PostgreSQL (Rails-Style Rust SaaS) — AI Agent Guidelines & Architecture Rules

> Rails-style Rust SaaS rules for Loco: generators, SeaORM models and migrations, Tera views or htmx scaffolds, JWT auth, background workers and mailers.
> Technologies: Rust, Loco, Axum, SeaORM, PostgreSQL, Tokio, HTMX, Docker

---

## AGENTS.md
```markdown
# Project Architecture & Guidelines (Loco + SeaORM + PostgreSQL)

## 1. System Architecture
- **Framework**: Loco 1.x ("Rails for Rust"), built on Axum and Tokio. Convention over configuration: follow the generated layout instead of inventing a new one.
- **ORM**: SeaORM, with entities generated from the database (`cargo loco db entities`) and behaviour added in `src/models/<name>.rs`.
- **Database**: PostgreSQL in development and production (SQLite only for throwaway prototypes).
- **Rendering**: server-rendered Tera views (`ViewEngine<TeraView>`) or the htmx scaffold; a separate SPA only if the product needs one.
- **Jobs and mail**: Loco background workers and mailers; queue backed by Redis or Postgres in production.
- **Config**: `config/{development,test,production}.yaml` with `{{ get_env(name="...") }}` for secrets.

## 2. Generators First
- New resource: `cargo loco generate scaffold <name> field:type ... --htmx` (or `--html`, `--api`).
- Schema change: `cargo loco generate migration <name> field:type`, then `cargo loco db migrate`, then `cargo loco db entities`.
- Background job: `cargo loco generate worker <name>`; email: `cargo loco generate mailer <name>`; one-off task: `cargo loco generate task <name>`.
- Never hand-edit files in `src/models/_entities/`; they are regenerated. Put model logic in `src/models/<name>.rs` (`impl ActiveModelBehavior`, finders, validations).

## 3. Controllers and Views
- Controllers in `src/controllers/<name>.rs` expose `pub fn routes() -> Routes` and are registered in `src/app.rs` (`AppRoutes::with_default_routes().add_route(...)`).
- Handlers return `Result<Response>` or `Result<impl IntoResponse>` using Loco's `Error`; use `format::json`, `format::render().view(...)` and `format::redirect`.
- Keep handlers thin: load params, call a model method, render. Business rules live on the model.
- Views: templates in `assets/views/<name>/`, view helpers in `src/views/<name>.rs`.
- Protected routes take `auth: auth::JWT` (or the cookie-based auth in your starter) as an extractor; load the user with `users::Model::find_by_pid`.

## 4. Workers, Mailers and Tasks
- Anything slower than ~100 ms or calling a third party goes to a worker (`BackgroundWorker::perform_later`).
- Workers are idempotent and take serialisable args (IDs, not models).
- Mailers render templates from `src/mailers/<name>/`; send from workers, never inline in a request.

## 5. Agent Loop (run after every change)
1. `cargo check` until clean.
2. `cargo clippy --all-targets -- -D warnings`.
3. `cargo test` (request and model tests, including `insta` snapshots; review snapshot diffs instead of blindly accepting them).
4. `cargo loco doctor` after config or dependency changes; `cargo loco routes` to confirm new endpoints are mounted.
- Prefer the generator over writing boilerplate by hand; the generated tests are the starting point.
- No `unwrap()` in controllers, workers or models; propagate with `?`.

## 6. Testing
- Request tests use Loco's `request::<App, _, _>` helper with `#[serial]`; model tests run against a migrated test database.
- Seed fixtures in `src/fixtures/*.yaml`; load them with `cargo loco db seed` (`--reset` for a clean dev/test database).
- Snapshot tests (`insta`) for JSON and HTML responses; redact timestamps and IDs.

## 7. Deploy
- `cargo loco generate deployment` for a Dockerfile (or Shuttle / Nginx configs).
- Run migrations on start in `production.yaml` (`auto_migrate: true`) or as a release step; never `dangerously_recreate`.
- Ship one binary plus `assets/` and `config/`; set `LOCO_ENV=production`.
```

---

## CLAUDE.md
```markdown
# CLAUDE.md — Loco + SeaORM + PostgreSQL

@AGENTS.md

## Commands
- `cargo loco start` - run the app (add `--server-and-worker` to run jobs in-process)
- `cargo loco generate scaffold <name> field:type --htmx` - full CRUD resource
- `cargo loco generate migration <name>` / `cargo loco db migrate` / `cargo loco db entities`
- `cargo loco generate worker|mailer|task <name>`
- `cargo loco routes` - list mounted routes
- `cargo loco doctor` - check config, database and queue connectivity
- `cargo check`, `cargo clippy --all-targets -- -D warnings`, `cargo test`

## Non-negotiables
- Use generators before writing boilerplate.
- Never edit `src/models/_entities/`; regenerate with `cargo loco db entities`.
- Slow or external work goes to a worker.
```

---

## .cursor/rules/stack.mdc
```markdown
---
description: Loco + SeaORM Rails-style Rust SaaS rules
globs: ["src/**/*.rs", "migration/**/*.rs", "config/*.yaml", "assets/views/**/*"]
alwaysApply: false
---

# Loco + SeaORM + PostgreSQL

- Follow Loco conventions; generate with `cargo loco generate scaffold|migration|worker|mailer|task`.
- `src/models/_entities/` is generated (`cargo loco db entities`); model logic goes in `src/models/<name>.rs`.
- Controllers expose `routes()` and are registered in `src/app.rs`; keep handlers thin.
- Render with `format::render().view(...)` (Tera) or the htmx scaffold; JSON with `format::json`.
- Slow work in `BackgroundWorker`s with ID-only args; mail from workers.
- After each change: `cargo check`, clippy `-D warnings`, `cargo test`; `cargo loco doctor` after config changes.
```

---

## Architecture Overview & Best Practices
## Architecture Overview

**Rails conventions with a Rust compiler.** Loco gives you `cargo loco generate scaffold`, SeaORM models and migrations, Tera or htmx views, JWT auth, background workers, mailers and tasks, all on top of Axum and Tokio. It is the shortest path from "I know Rails" to a working Rust SaaS.

### Why it suits AI coding agents

- **Generators remove the guesswork.** The agent creates a resource the same way every time, and the generated request tests become its first safety net.
- **Clear places for code.** Entities are generated, behaviour lives on the model, handlers stay thin, slow work goes to workers; every rule in the AGENTS.md maps to a directory.
- **The compiler still checks everything.** SeaORM entities are typed, so a renamed column breaks the build after `cargo loco db entities`.

### Trade-offs

Loco's community and plugin ecosystem are far smaller than Rails', and you inherit its choices (SeaORM, Tera, its auth). For a server-rendered app where you pick each crate yourself, see [Axum + htmx + Askama](/rules/rust-axum-htmx-askama). Why Rails developers are looking at Rust right now: [Building web apps in Rust in 2026](/insights/rust-web-apps-ai-agents-2026).