# Scaffold the storefront

This is chapter 1 of the storefront track. Before you can sell anything you need a workspace on disk and a running system to grow it in. In this chapter you create `my-shop/` with the `netscript` CLI, tour what it generated, and bring the whole thing up under [Aspire](https://rickylabs.github.io/netscript/explanation/aspire/) — Postgres, the Redis cache, and an example service all running together behind one dashboard.

1. [1 · Scaffold](https://rickylabs.github.io/netscript/netscript/tutorials/storefront/01-scaffold/)
2. [2 · Catalog service](https://rickylabs.github.io/netscript/netscript/tutorials/storefront/02-catalog-service/)
3. [3 · Cart contracts](https://rickylabs.github.io/netscript/netscript/tutorials/storefront/03-cart-contracts/)
4. [4 · Checkout saga](https://rickylabs.github.io/netscript/netscript/tutorials/storefront/04-checkout-saga/)
5. [5 · Shipping webhook](https://rickylabs.github.io/netscript/netscript/tutorials/storefront/05-shipping-webhook/)
6. [6 · Storefront UI](https://rickylabs.github.io/netscript/netscript/tutorials/storefront/06-storefront-ui/)
7. [7 · Deploy](https://rickylabs.github.io/netscript/netscript/tutorials/storefront/07-deploy/)

## What you will build

By the end of this chapter you will have a real NetScript workspace named `my-shop/` on disk — with a shared `contracts/` workspace, a `products` service, a Fresh app, and a Postgres database — and you will have watched it boot under a single `aspire start`, with the Aspire dashboard live on the runtime URL printed by Aspire and Postgres plus Redis reporting healthy.

## Before you begin

This is the first chapter, so the only prerequisites are a working local toolchain. You need:

- **[Deno](https://deno.com/) 2.x** on your `PATH` — check with `deno --version`.
- The **[Aspire CLI](https://aspire.dev)** — check with `aspire --version`. NetScript uses Aspire to provision your database and cache locally, so you never wire up Docker containers by hand.
- **Docker** running, so Aspire can start the Postgres and Redis containers. Confirm with `docker info` — it should print engine details, not a connection error.

Install the NetScript CLI from JSR once:

```sh
deno install -g -A -f -n netscript --minimum-dependency-age=0 jsr:@netscript/cli@0.0.6
```

`--minimum-dependency-age=0` allows the pinned release to install on publication day, and `-f` replaces an older global `netscript` executable.

Confirm it resolves and inspect the command groups:

```sh
netscript --help
```

You should see the public groups: `agent`, `config`, `contract`, `db`, `deploy`, `generate`, `init`, `marketplace`, `plugin`, `service`, and the `ui:*` group (`ui:list`, `ui:add`, `ui:update`, `ui:remove`). If `netscript` is not found, make sure Deno's install directory (printed by `deno install`) is on your `PATH`, then open a fresh terminal.

## Step 1 — Preview the scaffold with a dry run

Before writing any files, ask the CLI what it *would* create. `--dry-run` plans the scaffold and prints the result without touching disk:

```sh
netscript init my-shop --dry-run
```

`netscript init` validates your options, then runs an ordered pipeline that lays down the project root, Aspire orchestration, the shared contracts workspace, a Fresh app, an empty plugin registry, and — when you ask for them — a database workspace and an example service. The dry run reports file and directory totals per phase, so you can see the project's shape before committing to it. A clean dry run is your green light to scaffold for real.

## Step 2 — Create the workspace

Scaffold `my-shop/` with an example service named `products` on port **3001** (note: this tutorial pins the port to 3001 for consistency; in unpinned scaffolds, each project is allocated its own randomized high-range ports) and a Postgres database, so you have something real to run and a place for the catalog you build next chapter:

```sh
netscript init my-shop --service --service-name products --service-port 3001 --db postgres
cd my-shop
```

This scaffolds `my-shop/`, formats the output with `deno fmt`, and initializes a git repository. On completion the CLI prints a **next steps** summary tailored to your options — keep it handy; the steps below mirror the common path.

This track uses Postgres, but the database is polyglot: swap `--db postgres` for `mysql`, `mssql`, or `sqlite` and the scaffold wires Prisma for that engine instead (sqlite is file-backed, with no Aspire container). Keep `--db postgres` to follow along.

A few `init` options you will reach for (run `netscript init --help` for the full list):

**Common netscript init options**

| Name | Type | Description |
| --- | --- | --- |
| `--service --service-name  --service-port ` | `flag group` | Include an example oRPC service on the given port. We use products on 3001. |
| `--db ` | `flag` | Scaffold a Prisma-backed database workspace. First-class engines: postgres (default for this track), mysql, mssql, sqlite. Omit or use --db none to skip database tooling. |
| `--no-aspire` | `flag` | Skip the Aspire orchestration files — you would then wire infrastructure yourself. Do NOT pass this for the track; we rely on aspire start. |
| `--editor ` | `flag` | Generate editor settings for the chosen editor. |
| `--dry-run` | `flag` | Plan the scaffold and print totals without writing any files. |

## Step 3 — Tour what you got

Open `my-shop/` and you will find this shape:

- my-shop/

  - apps/dashboard/ # Fresh frontend (defineFreshApp)
  - contracts/ # Shared oRPC contracts, versioned under versions/v1/
  - services/products/ # The example oRPC service (src/main.ts, router.ts, routers/)
  - plugins/ # Plugin registry + manifests — empty until chapter 4
  - database/ # Postgres workspace (Prisma schema + migrations) — initialize before editing
  - tests/ # Workspace-level test suite scaffolded alongside the project
  - aspire/

    - apphost.mts # Entry point for aspire start
    - aspire.config.json # AppHost language + SDK pin
  - appsettings.json # Infrastructure config (Services / Databases / Persistent)
  - deno.json # Workspace root (members, tasks, dependency catalog)
  - netscript.config.ts # Framework config (defineConfig)

What each piece is for:

- **`contracts/`** — the typed seam between your services and any client. Contracts are oRPC + Zod, versioned under `versions/v1/`. Everything else derives its types from here. You add the cart contract here in [chapter 3](https://rickylabs.github.io/netscript/tutorials/storefront/03-cart-contracts/). See [Contracts & type flow](https://rickylabs.github.io/netscript/explanation/contracts/).
- **`services/products/`** — a working oRPC service. `src/main.ts` calls `defineService(...)`; handlers live under `src/routers/`. You make it a real catalog in [chapter 2](https://rickylabs.github.io/netscript/tutorials/storefront/02-catalog-service/).
- **`apps/dashboard/`** — a Fresh app for your storefront UI, already wired to consume contracts. The [`@netscript/fresh`](https://rickylabs.github.io/netscript/web-layer/fresh-ui/) meta-framework powers it. This track stays on the backend, so you will not edit it.
- **`plugins/`** — where background capabilities (workers, sagas, triggers, streams) register. Empty until you add the sagas plugin in [chapter 4](https://rickylabs.github.io/netscript/tutorials/storefront/04-checkout-saga/).
- **`database/`** — the Postgres-backed database workspace: the Prisma schema and migrations that back `context.db` in your handlers. You initialize it below before changing the catalog.
- **`tests/`** — the workspace-level test suite scaffolded alongside the project. Extend it as you add handlers and contracts.
- **`aspire/`** — the orchestrator. `aspire start` reads `apphost.mts` and starts every resource your app declares — Postgres, the Redis cache, your services — with one command.
- **`appsettings.json`** — the infrastructure manifest Aspire reads: which services, databases, and persistent resources to provision.
- **`netscript.config.ts`** — declares paths, plugins, logging, and database wiring via `defineConfig`. See the [config reference](https://rickylabs.github.io/netscript/reference/config/).

> Where is packages/?
>
> If you scaffolded from a checkout of the NetScript repo you may see a vendored
>
> packages/
>
> directory. A normal JSR install does not have one — your project pulls
>
> @netscript/*
>
> from the registry. Ignore
>
> packages/
>
> in this track.

## Step 4 — Bring up orchestration

This is the step that turns a folder of files into a running system — and the one most people miss. **Aspire provisions your database and cache; you do not start containers by hand, and you run it before any `netscript db` command.** Run it from the `aspire/` subfolder so the CLI finds `apphost.mts`:

```sh
cd aspire
aspire restore   # once per machine: restores the Aspire SDK modules into .aspire/
deno task aspire:start   # starts the AppHost and every declared resource
```

`deno task aspire:start` — the wrapper the CLI's own printed next steps recommend, which sets a 300-second cold-start budget while container images download on first run — brings up the Postgres database, the Redis cache, and your `products` service together, then prints a URL and a one-time login token for the **Aspire dashboard**.

In an interactive terminal, leave it running in this terminal — it is your storefront's control plane for the rest of the track. (If your terminal is not interactive, it detaches without printing a login token; resolve resource endpoints with `aspire describe --apphost ./apphost.mts --format Json --non-interactive --nologo`, or MCP `list_api_services`, rather than the dashboard.) Aspire assigns free ports at runtime, so use the URLs in the dashboard (or MCP `list_api_services`) instead of memorising a dashboard or app port.

### Initialize the database before customising

The Postgres container only exists while `aspire start` is running. Open a second terminal at the `my-shop/` project root and run:

```sh
netscript db init --name init
netscript db generate
netscript db seed
```

`db init` creates and applies the initial migration, `db generate` produces the Prisma client and Zod model schemas, and `db seed` runs the generated seed script. A successful initialization proves the resource graph, connection string, Prisma schema, and migration path agree before chapter 2 adds catalog behavior.

## Verify your progress

The example `products` service exposes a plain health endpoint. In a second terminal — leave `aspire start` going in the first — confirm the service answers on port **3001**:

```sh
curl http://localhost:3001/health
```

> Endpoints are HTTP/1.1 — HTTP/2 is opt-in
>
> You reach services over plaintext
>
> HTTP/1.1
>
> at
>
> http://localhost:3001
>
> — that is the default. HTTP/2 is opt-in and requires TLS: configure it with
>
> ServiceTlsOptions
>
> (or the
>
> NETSCRIPT_TLS_CERT_FILE
>
> /
>
> NETSCRIPT_TLS_KEY_FILE
>
> environment variables). See
>
> Aspire & the AppHost
>
> for the local-versus-deployed runtime model.

You should get a healthy JSON response. Then type-check the whole workspace from the project root to confirm the scaffold, contracts, and service all line up:

```sh
deno task check
```

A clean check, plus a healthy `curl`, means the scaffold is sound.

- [ ] `netscript --help` lists the public command groups (`agent`, `config`, `contract`, `db`, `deploy`, `generate`, `init`, `marketplace`, `plugin`, `service`, `ui:*`).
- [ ] `my-shop/` exists with `contracts/`, `services/products/`, `database/`, `plugins/`, `aspire/`, and `tests/`.
- [ ] `aspire start` is up; its printed dashboard URL (or MCP `list_api_services`) shows `products`, `postgres`, and `redis` healthy.
- [ ] `netscript db init --name init` succeeded and the initial migration exists.
- [ ] `curl http://localhost:3001/health` returns healthy JSON.
- [ ] Opening the Fresh app URL from the dashboard (or MCP status) with `/design` appended renders the generated design reference (it returns an HTTP 302 redirect to `/design/composition`, so scripted checks require `curl -L`).
- [ ] `deno task check` passes with no errors.

**Do not begin customising until every box is ticked.** An unverified base makes every later failure look like your code.

> If something is not green
>
> Three quick checks cover most first-run snags: (1) is
>
> aspire start
>
> still up in its terminal, with
>
> postgres
>
> and
>
> redis
>
> healthy in the
>
> dashboard
>
> ? (2) is Docker running (
>
> docker info
>
> )? (3) did you
>
> cd aspire
>
> before
>
> aspire start
>
> , so it found
>
> apphost.mts
>
> ? Note that
>
> aspire restore
>
> /
>
> start
>
> can occasionally time out under heavy system load with
>
> Failed to prepare: A task was canceled
>
> ; re-running the start command usually succeeds. If operating headlessly without a browser, inspect failure diagnostics via the MCP
>
> get_recent_errors
>
> or
>
> list_api_services
>
> tools rather than guessing process state.

## What you built

A real NetScript workspace, `my-shop/`: a shared `contracts/` workspace, a `products` service, a Fresh app, and a Postgres database plus Redis cache — all orchestrated by Aspire and visible in one dashboard. Next, you turn that placeholder `products` service into a real, typed catalog.

[Storefront](https://rickylabs.github.io/netscript/netscript/tutorials/storefront/) [2 · Catalog service](https://rickylabs.github.io/netscript/netscript/tutorials/storefront/02-catalog-service/)
