# Scaffold Service

## What this skill covers
How to scaffold a new service on Tawa with `tawa sample`.

> Checked against tawa CLI **0.26.4** (`tawa sample --help`). The old `--api` and `--nextjs`
> templates are gone: the CLI rejects them with `error: unknown option`. If your CLI
> disagrees with this page, trust `tawa sample --help`.

## Templates

| Template | Command | What you get |
|----------|---------|-------------|
| **Eco App** (recommended for web apps) | `tawa sample my-app --eco-app` | Full-stack Next.js 15 app with Bio-ID login (`spec.auth: mode: sso`), MongoDB, Septor audit, Relay email, object storage, cron + queue examples, and an admin dashboard. Uses pnpm, dev port 4140 |
| Static Site | `tawa sample my-site --static` | Static HTML/CSS with Tailwind 4 design tokens, served by nginx. No auth, no database |

There is no API-only template today. For a backend service, start from `--eco-app` and delete
what you don't need, or write a minimal catalog by hand (example below).

## Options

| Flag | What it does |
|------|-------------|
| `--with-storage` | Adds object storage: declares `spec.storage` (`name: default`, `tier: s3-sm`) in the catalog, adds `@insureco/storage@^0.2.0` to `package.json`, raises `catalog-version` to at least `0.3.0`, and writes a `src/storage.ts` example. A catalog that already declares storage (Eco App) is left as it is |
| `--git` | **Creates a NEW private repo** at `git.insureco.io/insureco/<name>`, sets the HTTPS `origin`, adds the auto-deploy webhook, pushes `main`, and protects it (PR-only). From tawa **0.27.0** it also protects release tags (`v*`, `*-v*`): only you and, for an org repository, the org's `Owners` team can create them. See the agile-workflow convention, Release Management. Known gap: when the repo is created under your personal account, the output still prints `insureco/<name>` ([tawa-cli#129](https://git.insureco.io/insureco/tawa-cli/issues/129)); check the real owner in Forgejo before running `tawa git protect` on it |
| `--skip-git` | Skips `git init` entirely |
| `--skip-install` | Skips dependency install. Eco App and Static never auto-install anyway; run `pnpm install` yourself |

### `--with-storage`

Eco App **already includes storage** (`spec.storage` in the catalog, `@insureco/storage@^0.2.0`
in `package.json`), so `--with-storage` adds nothing to it. On `--static` it adds the catalog
entry, the dependency and the `catalog-version` bump.

**On tawa 0.26.3 or earlier** (`tawa --version`) the flag was broken. It added
`tawa-storage@^0.1.0` instead of `@insureco/storage`, and on `--eco-app` it appended a
duplicate `storage:` key. If an older CLI scaffolded your project, fix it by hand:
- `package.json` should depend on **`@insureco/storage` at `^0.2.0`** or later. Remove
  `tawa-storage`. Versions below 0.2.0 read credentials from `process.env`, and those go stale
  in a deployed pod.
- `catalog-info.yaml` needs exactly one `storage:` key under `spec`, and
  `insureco.io/catalog-version: "0.3.0"` or higher, or `spec.storage` is ignored.

See the object-storage convention for how credentials work.

### `--git`: only when the repo doesn't exist yet

`--git` always tries to **create** the repo. If the Forgejo repo already exists (you made it
with `repo_create`, the web UI, or a teammate did), don't pass `--git`. Scaffold locally and
point it at the existing repo:

```bash
tawa sample my-app --eco-app --skip-git
cd my-app
git init -b main
git remote add origin https://git.insureco.io/insureco/my-app.git   # HTTPS, never SSH
git add . && git commit -m "chore: scaffold from tawa sample --eco-app"
git push -u origin main    # only if the remote is empty; otherwise branch + PR
tawa link                  # registers the service with the builder
```

`--git` sets `origin` to the repo's HTTPS URL. If a push fails, run `tawa login`: it stores the
git credential. **On tawa 0.26.3 or earlier**, `--git` set an SSH remote instead. Switch it with
`git remote set-url origin https://git.insureco.io/insureco/<name>.git`.

## Step-by-Step

### 1. Scaffold
```bash
tawa sample my-app --eco-app    # or --static for a marketing site
cd my-app
pnpm install
tawa dev --offline              # writes .env.local, starts local mocks
pnpm dev                        # http://localhost:4140
```

### 2. Review catalog-info.yaml

Eco App ships a complete catalog. Trim it to what you use. A minimal hand-written catalog
looks like this:

```yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: my-new-service
  description: What this service does
  annotations:
    insureco.io/framework: express       # or nextjs, hono, fastify, worker, static
    insureco.io/catalog-version: "0.6.0"
    insureco.io/pod-tier: nano           # start here; upgrade when you have load data
    insureco.io/health-endpoint: /health # REQUIRED (nextjs default is /api/health)
spec:
  type: service
  lifecycle: production
  owner: my-org                          # your org slug

  # ── Add a database ──────────────────────────────────────────────────────────
  databases:
    - type: mongodb    # → MONGODB_URI injected automatically

  # ── Enable user login (Bio-ID OAuth) ────────────────────────────────────────
  # WITHOUT this, BIO_CLIENT_ID and BIO_CLIENT_SECRET are never injected.
  # Listing bio-id as a dependency is NOT the same thing. Don't do that.
  auth:
    mode: sso          # → BIO_CLIENT_ID + BIO_CLIENT_SECRET injected on every deploy

  # ── Expose public API routes ────────────────────────────────────────────────
  routes:
    - path: /api/my-service/data
      methods: [GET, POST]
      auth: required
      gas: 1

  # ── Call NON-platform services ──────────────────────────────────────────────
  # Platform services (septor, iec-queue, iec-wallet, koko, janus, bio-id) are
  # auto-injected: SEPTOR_URL etc. and their NetworkPolicy labels come for free.
  # Do NOT declare them. internalDependencies is deprecated.
  dependencies:
    - service: relay            # → RELAY_URL (+ client credentials for the SDK)
      scopes: [relay:send]
    - service: docman           # → DOCMAN_URL (transport defaults to janus)
```

The health handler must return the running commit: `{ status: 'ok', service: 'my-new-service', commit: process.env.GIT_COMMIT ?? null }`. The builder injects `GIT_COMMIT` on every deploy and warns after deploy if `/health` does not report it. Keep the handler cheap (no DB call, no auth).

### 3. Run preflight
```bash
tawa preflight    # catches config issues before you waste a build
```

### 4. Deploy
```bash
tawa link                        # first time only, if not created with --git
tawa deploy --prod --watch
```

## Next.js with Auth Checklist

Eco App has this wired already. If you are adding login to a different Next.js app:

- [ ] `spec.auth: mode: sso` is in catalog-info.yaml
- [ ] Callback is at `/api/auth/callback` (exactly, no variations)
- [ ] `BioAuth.fromEnv()` reads from env vars, not hardcoded values
- [ ] Every API route passes `request` to `getAuthUser(request)`, not `getAuthUser()`
- [ ] Only the root/dashboard page auto-redirects on 401; sub-pages show a login button
- [ ] Run `/tawa-auth` for the full Next.js auth implementation pattern

## Key Facts
- `metadata.name` becomes your hostname: `my-svc.tawa.pro` (prod)
- You do NOT need a Dockerfile; the builder generates one
- `spec.auth` is the ONLY way to get `BIO_CLIENT_ID` injected. A bio-id dependency won't do it
- `BIO_ID_URL`, `SEPTOR_URL`, `IEC_QUEUE_URL`, `IEC_WALLET_URL` are always injected; never declare them
- See tawa.insureco.io/reference/catalog-info for the full catalog reference
