Skip to main content
0.0.x

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 — Postgres, the Redis cache, and an example service all running together behind one dashboard.

  1. 1 · Scaffold
  2. 2 · Catalog service
  3. 3 · Cart contracts
  4. 4 · Checkout saga
  5. 5 · Shipping webhook
  6. 6 · Storefront UI
  7. 7 · 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 2.x on your PATH — check with deno --version.
  • The Aspire CLI — 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:

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:

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:

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:

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
NameTypeDescription
--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. See Contracts & type flow.
  • 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.
  • apps/dashboard/ — a Fresh app for your storefront UI, already wired to consume contracts. The @netscript/fresh 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.
  • 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.

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:

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:

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:

curl http://localhost:3001/health

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:

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.

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.