# §59 — The full-stack app with an admin

Pages for the people who use it, and a generated CRUD surface for the person who has to fix a row at eleven at night.

The admin is derived from the same `defineSchema` the app already uses, so it cannot drift from the tables. Search fields, filters, bulk actions and read-only models are configuration, not a second application.

It mounts behind your auth. It is a full administrative surface over your database — treat an unprotected `basePath` as a public database.

## What you are carrying

- `@atlas/server` — Routes and static serving.
- `@atlas/db` — Schemas the admin reads its shape from.
- `@atlas/auth` — Who gets in, and who gets into `/admin`.
- `@atlas/admin` — Generated list, detail, create, filters, bulk actions.
- `@atlas/ui` — React blocks for the half people see.

## Start it

```bash
atlas init -n myapp --template admin
```

## What it looks like

`src/admin.ts`

```ts
import { admin, model } from "@atlas/admin"
import { users, uploads } from "./schema"

const panel = admin({
  db,
  basePath: "/admin",
  auth: { secret: config.secret },   // not optional in production
  models: [
    model({ schema: users, searchFields: ["email", "name"], filterFields: ["createdAt"] }),
    model({ schema: uploads, searchFields: ["filename"], readOnly: true }),
  ],
})

serve({ port: 3000, routes: [...appRoutes, ...panel.mount([])] })
```

## Where now

- Put it online — turn to §100 (Appendix A)
- Hand it to an agent — turn to §102 (Appendix C)
- Walk it again from the start — turn to §1
