# {{ service_name }}

Generated by `tonin service new --lang rust`. Read `AGENTS.md` first if
you're a coding agent; this README is for humans landing on the repo.

## Layout

```
{{ service_name }}/
├── proto/            (1) wire contract — language-agnostic
├── server/           (2) the service binary (Rust + tonin)
├── client-rust/      (3) typed Rust SDK — peers depend on this
├── client-python/    (3b) only if scaffolded with --client-lang python
├── client-ts/        (3c) only if scaffolded with --client-lang ts
├── tonin.toml        service config (db, cache, mesh, etc.)
├── Dockerfile        builds server/
├── k8s/              rendered manifests (regenerate via `tonin k8s generate`)
└── docs/             living documentation; see docs/README.md
```

Each top-level folder is **independently buildable** with its own native
toolchain. There is no Cargo workspace at the root: a peer service that
only wants the typed client compiles `client-rust/` in seconds without
touching `server/`'s heavyweight deps.

## How to develop

### Build + test the server

```sh
cd server
cargo build                       # compile
cargo nextest run                 # unit + e2e (real tonic client + TCP)
cargo nextest run --profile ci    # CI profile: retries, junit.xml output
cargo run                         # bind on 0.0.0.0:50051
```

Tests use [cargo-nextest](https://nexte.st). Install once:
`cargo install cargo-nextest --locked`. Nextest config lives at
`server/.config/nextest.toml`.

### Build the Rust client (for tests, or as a sanity check)

```sh
cd client-rust
cargo build
```

### Regenerate k8s manifests after editing tonin.toml

```sh
# Run from the repo root.
tonin k8s generate
```

## How a peer service depends on this client

```toml
# In some-other-service/Cargo.toml
[dependencies]
{{ service_name }}-client = { git = "https://github.com/<org>/{{ service_name }}", branch = "main" }
```

Cargo finds the package by walking the repo for a `Cargo.toml` with
`name = "{{ service_name }}-client"` — that lives in `client-rust/`.

## State (DB + cache)

The scaffold's `main.rs` opens connections lazily from env at startup:

| Env var          | Activates                                            |
|------------------|------------------------------------------------------|
| `DATABASE_URL`   | `state.pg()` returns a live `sqlx::PgPool`           |
| `REDIS_URL`      | `state.redis()` returns a live `redis::Client`       |

Neither set → state stays empty, `state.pg()` / `state.redis()` return
`Error::Config("…not set")`. No background reconnect — if the dep is
configured but unreachable at boot, the service fails to start (this
is intentional; a 4xx-at-handler-time storm is worse than a fast crash).

These env vars are auto-injected by the deployment template when
`tonin.toml` has a `[database]` / `[cache]` block. Local dev: export
them yourself, or run `docker compose up postgres redis`.

Pool tuning: `TONIN_PG_MAX_CONNECTIONS` (default `10`).

## Background jobs

If you scaffolded with `--with-job <name>`, each job is a separate
binary in `server/src/bin/<name>.rs`:

```sh
cargo run --bin {{ service_name }}-<job>     # local
```

Each job calls `tonin::job::bootstrap("{{ service_name }}-<job>")`,
which:

1. Inits OTel (same exporters as the main server).
2. Mints a **service-identity** `AuthCtx` — set `TONIN_AUTH_SERVICE_TOKEN_URL`
   to point at your auth-service mint endpoint.
3. Builds `State` from `DATABASE_URL` / `REDIS_URL`.

When calling other services from a job, propagate the minted ctx:

```rust
let mut req = tonic::Request::new(SomeRequest { ... });
ctx.auth.propagate(&mut req);
client.some_rpc(req).await?;
```

## Auth

Auth is wired by default. The scaffold uses `tonin::auth::JwtValidator`
to verify every inbound JWT (sig + expiry + iss + aud). Configure via:

- `TONIN_AUTH_ISSUER`
- `TONIN_AUTH_AUDIENCE`
- `TONIN_AUTH_JWKS_URL`
- `TONIN_AUTH_INSECURE_DEV=1` (local dev only — logs a loud WARN)

To swap to a different verifier (Okta SDK, API keys, etc.), edit
`server/src/auth.rs`. The framework owns the interceptor + propagation;
you only pick the verifier.

## What's next

See `docs/roadmap.md` for active and planned features. The scaffold
ships with one capability (`docs/capabilities/greeter.md`) — extend
the proto, the handler in `server/src/server.rs`, and update
`docs/capabilities/` as you add more.
