# Amber V2 Web Template

Amber CLI `2.0.6` generates a complete server-rendered web application with
ECR, Grant ORM, Micrate migrations, and SQLite. The first database-backed
feature needs no database server, Node.js process, or front-end package manager.
The same template includes the released build-time asset manifest, so its
homepage exercises the frontend contract documented for production apps.

**Run from: the parent directory where `my_app/` should be created.**

```bash
amber new my_app --type web
cd my_app
```

Web, ECR, and SQLite are the defaults, so `amber new my_app` is equivalent. Use
`-d pg` or `-d mysql` when the application should start with a server database.

## Where the examples go

Commands on this page run from the generated application root unless a closer
label says otherwise. Every code or tree example names its source file,
generated output, or reference role. Replace `my_app` with the actual generated
target name when a command includes it.

## Generated project

**Generated output: the top-level structure under `my_app/`.**

```text
my_app/
├── .amber.yml
├── .gitignore
├── README.md
├── shard.yml
├── config/
│   ├── application.cr
│   ├── assets.cr
│   ├── database.cr
│   ├── routes.cr
│   └── environments/
│       ├── development.yml
│       ├── production.yml
│       └── test.yml
├── db/
│   ├── migrations/
│   └── seeds.cr
├── app/assets/                                  # authored; source control
│   ├── stylesheets/app.css
│   ├── javascript/app.js
│   ├── images/amber-crystal.svg
│   ├── images/favicon.svg
│   ├── fonts/.gitkeep
│   └── files/.gitkeep
├── public/
│   ├── assets/                                  # generated; gitignored
│   │   ├── manifest.json
│   │   └── ...fingerprinted files...
│   └── robots.txt
├── spec/
│   ├── spec_helper.cr
│   ├── controllers/home_controller_spec.cr
│   └── channels, jobs, mailers, models, requests, schemas/
└── src/
    ├── my_app.cr
    ├── controllers/
    │   ├── application_controller.cr
    │   └── home_controller.cr
    ├── views/
    │   ├── home/index.ecr
    │   └── layouts/application.ecr
    └── channels, jobs, mailers, models, schemas, sockets/
```

The empty extension directories give generators stable destinations. The
generated `README.md` names those destinations again while a developer is
working inside the project.

## Exact dependency contract

**File: `shard.yml` — generated dependency manifest.**

```yaml
crystal: ">= 1.20.0, < 2.0"

dependencies:
  amber:
    github: amberframework/amber
    version: 2.0.0-beta.5
  grant:
    github: crimson-knight/grant
    commit: 2665a978b43ac608c68cde9243821f8f8f053372
  asset_pipeline:
    github: amberframework/asset_pipeline
    version: 0.37.0
  sqlite3:
    github: crystal-lang/crystal-sqlite3
    version: ~> 0.23.0
```

The exact Grant commit is intentional while its V2 release is finalized. Amber
and Grant changes are not pulled from moving branches during application
generation.

The CLI embeds its web scaffold in the executable. `amber new` does not fetch a
template manifest, so updating the CLI changes future projects but never
silently rewrites an existing application.

## Database connection

**File: `config/database.cr` — generated SQLite registration.**

```crystal
require "amber"
require "grant"
require "grant/adapter/sqlite"

Grant::Connections << Grant::Adapter::Sqlite.new(
  name: "primary",
  url: ENV["DATABASE_URL"]? || Amber.settings.database_url
)
```

Every generated Grant model declares `connection primary`. `DATABASE_URL`
overrides the environment YAML, which makes production configuration explicit
without putting credentials in source control.

**File: `config/environments/development.yml` — generated development values.**

```yaml
name: my_app

server:
  host: 127.0.0.1
  port: 3000
  secret_key_base: "generated-development-secret"

database:
  url: "sqlite3:./db/my_app_development.db"

session:
  key: "my_app.session"
  store: "signed_cookie"
  adapter: "memory"
  expires: 0

logging:
  severity: "debug"
  colorize: true
```

`config/environments/test.yml` uses `db/my_app_test.db`. Production leaves the
URL empty so deployment must provide `DATABASE_URL`.

## Generate the first persisted resource

**Run from: the application root beside `shard.yml`.**

```bash
amber generate scaffold Pet name:string:required species:string:required adopted:bool
amber database migrate
AMBER_ENV=test amber database migrate
crystal spec
```

The scaffold command writes:

| Concern | Exact destination |
|---|---|
| Grant model | `src/models/pet.cr` |
| Request schema | `src/schemas/pet_schema.cr` |
| HTML CRUD controller | `src/controllers/pet_controller.cr` |
| Index, show, new, edit, and shared form ECR | `src/views/pet/` |
| Reversible Micrate SQL | `db/migrations/*_create_pets.sql` |
| Model and request specs | `spec/models/pet_spec.cr`, `spec/controllers/pet_controller_spec.cr` |
| Resource routes | `config/routes.cr` |

The generated migration contains `-- +micrate Up` and `-- +micrate Down`
sections. `amber database migrate` applies the development database; setting
`AMBER_ENV=test` applies the separate test database.

Amber CLI `2.0.6` generates an HTML schema that declares
`application/x-www-form-urlencoded`. `PetController` binds it with
`schema :create, PetSchema` and `schema :update, PetSchema`, then reads the
request-local typed values through `validated_as(PetSchema)`. Invalid input is
stopped before the action and re-renders the ECR form with field errors. The
controller does not manually construct and validate a second schema object.
This is the released CLI `2.0.6` and framework `2.0.0-beta.5` path.

**Run from: the application root — useful database maintenance commands.**

```bash
amber database status
amber database rollback
amber database redo
amber database seed
```

## Released frontend and asset contract

The starter uses warm paper colors, faceted geometry, editorial type hierarchy,
and compact status labels. It is authored entirely in the generated ECR and
local CSS.

**File: `src/views/layouts/application.ecr` — generated front-end entry point.**

```ecr
<%= favicon_tag("images/favicon.svg") %>
<%= stylesheet_link_tag("stylesheets/app.css") %>
<%= javascript_importmap_tag(
  {"app" => "javascript/app.js"},
  preload: ["javascript/app.js"]
) %>
<script type="module">import "app";</script>
```

The visible page is `src/views/home/index.ecr`, the component layer is
`app/assets/stylesheets/app.css`, and browser behavior begins in
`app/assets/javascript/app.js`. See [Import maps](../assets/import-maps/) for
adding local ESM modules without a Node.js runtime or bundler.

`amber new` compiles the first manifest before it returns. The generated
boundary is:

**Generated files and authored source — ownership reference:**

```text
my_app/
├── app/assets/                                  # authored; source control
│   ├── stylesheets/app.css
│   ├── javascript/app.js
│   ├── images/amber-crystal.svg
│   ├── images/favicon.svg
│   ├── fonts/.keep
│   └── files/.keep
├── config/assets.cr                             # runtime manifest resolver
├── public/
│   ├── assets/                                  # generated; gitignored
│   │   ├── manifest.json
│   │   └── ...fingerprinted files...
│   └── robots.txt                               # authored
└── src/views/layouts/application.ecr
```

**Run from: the generated application root.**

```bash
amber assets build
amber assets check
```

`amber watch` rebuilds the manifest before application compilation and watches
`app/assets/**/*` alongside Crystal and ECR source. Older applications can use
the explicit `scripts/build_assets.cr` wrapper from the [Asset Pipeline
guide](../assets/) while adopting the same contract.

**File: `config/assets.cr` — generated runtime resolver configuration.**

```crystal
Amber::Assets.configure(
  manifest_path: "public/assets/manifest.json"
)
```

**File: `src/views/layouts/application.ecr` — generated helper usage.**

```ecr
<%= favicon_tag("images/favicon.svg") %>
<%= stylesheet_link_tag("stylesheets/app.css") %>
<%= javascript_importmap_tag(
  {"app" => "javascript/app.js"},
  preload: ["javascript/app.js"]
) %>
<script type="module">import "app";</script>
```

**File: `src/views/home/index.ecr` — generated brand image usage.**

```ecr
<%= image_tag("images/amber-crystal.svg", class: "starter-crystal", alt: "") %>
```

The generated stylesheet references
`../images/amber-crystal.svg`, proving that CSS URLs are rewritten as well as
ECR helpers. Images, fonts, favicons, and arbitrary binaries receive the same
content-addressed manifest treatment as CSS and JavaScript. User uploads do not;
they remain persistent runtime data outside the authored tree.

## Routes and request pipelines

**File: `config/routes.cr` — generated pipeline and route ownership.**

- `web` includes errors, logging, sessions, flash, and CSRF.
- `static` serves files under `public/`.
- `api` is available for explicitly registered API routes.
- `/` initially renders `HomeController#index`.
- `resources "/pets", PetController` is added by the Pet scaffold.

Controller generation alone does not edit routes. Scaffold generation does,
because its controller and views implement the complete resource contract.

## Compile and browser contract

**Run from: the generated application root.**

```bash
shards install
amber assets check
crystal spec
crystal build src/my_app.cr -o bin/my_app
amber watch
```

Open <http://127.0.0.1:3000/> and
<http://127.0.0.1:3000/pets/new>. The release test also submits that generated
form, reads the stored Pet, edits it through `_method=PATCH`, and verifies the
updated record.

The release gate runs `amber assets build` and `amber assets check`, starts the
compiled application with its release directory read-only, and requests the
fingerprinted CSS, JavaScript, image, and font URLs rendered from
`public/assets/manifest.json`. It also verifies SRI, MIME types, immutable cache
headers, gzip negotiation, and persisted Pet create/update behavior.

The supported web-template gate covers macOS, x86-64 Linux, and ARM64 Linux.
Windows x86-64 must compile the same generated database-backed application in
CI, but it does not yet have a CLI release archive. See
[Beta support](../../beta-support/) for the platform boundary and
[Build a Pet Tracker](../pet-tracker/) for the complete first application.