Skip to main content
Alpha

Scaffold the dashboard workspace

Every track starts with a real project on disk. In this chapter you create my-dashboard/ — a NetScript workspace with a Fresh frontend, an example service, and a Postgres database — then boot the whole thing under Aspire so the rest of the track has a running system to build on.

  1. 1 · Scaffold
  2. 2 · Contract to service
  3. 3 · Cache-first query
  4. 4 · definePage + island
  5. 5 · Live stream
  6. 6 · Deploy

What you will build

A my-dashboard/ workspace on disk: shared contracts, an example orders service on port 3002, a Fresh app, and a Postgres database — all orchestrated by Aspire. By the end the Aspire dashboard at :18888 shows every resource running, and you understand which generated directory does what. You will reuse this same workspace for every later chapter.

Before you begin

This is the first chapter; the only prerequisite is the toolchain from the track index. Confirm the CLI is installed and reachable:

netscript --help

You should see the public command groups: init, contract, db, deploy, generate, marketplace, plugin, service, ui:add, and ui:init. If netscript is not found, make sure Deno's install directory is on your PATH and open a fresh terminal.

Step 1 — Preview the scaffold with a dry run

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

netscript init my-dashboard --dry-run

netscript init validates your options, then runs an ordered pipeline that lays down the project root, Aspire orchestration, contracts, the Fresh app workspace, an empty plugin registry, and (optionally) a database workspace and an example service. The dry run reports file and directory totals per phase, so you see the project's shape before committing to it.

Step 2 — Create the workspace

Scaffold for real, with an example service and a Postgres database so the dashboard has live data to read later. This track names the example service orders and runs it on port 3002:

netscript init my-dashboard --service --service-name orders --service-port 3002 --db postgres
cd my-dashboard

This writes my-dashboard/, 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.

init options this track uses (run netscript init --help for the full list)
NameTypeDescription
--service --service-name orders --service-port 3002 flags Include an example oRPC service named orders on port 3002 — the read-model the dashboard consumes.
--db postgres flag Scaffold a Postgres database workspace. The orders read-model is persisted here. Postgres is this track's stack; swap --db postgres for mysql, mssql, or sqlite for a different engine.
--dry-run flag Plan the scaffold and print totals without writing any files (Step 1).

Step 3 — Tour what you got

Open my-dashboard/. The shape that matters for this track:

  • apps/
    • dashboard/ # The Fresh frontend — defineFreshApp, your dashboard UI lives here
  • contracts/ # Shared oRPC + Zod contracts, versioned under versions/v1/
  • services/
    • orders/ # The example oRPC service (src/main.ts, router.ts, routers/)
  • plugins/ # Plugin registry + manifests — empty until you add one
  • aspire/
    • apphost.mts # Entry point for aspire start (TypeScript/Node, not C#)
  • appsettings.json # Infrastructure manifest Aspire reads
  • deno.json # Workspace root: members, tasks, dependency catalog
  • netscript.config.ts # Framework config (defineConfig)

The two directories this track lives in:

  • apps/dashboard/ — your Fresh app. Its entry point is main.ts, which calls defineFreshApp; its build is configured by vite.config.ts. Chapters 4 and 5 add routes and islands here. This is the heart of the track.
  • services/orders/ and contracts/ — the typed read-model your dashboard reads. You shape these in chapter 2, then consume them from the Fresh app in chapters 3–5.

For a guided walk through every generated directory, see the Storefront scaffold chapter — this track keeps the tour short on purpose.

Step 4 — Look at the Fresh app entry point

Before booting, read the two files that define how the Fresh app starts. You do not edit them yet — this is orientation for chapters 4 and 5.

The app entry point registers the KV adapter and creates the app. The order matters: the Redis/Garnet KV adapter import must run before any code that reaches for KV, so it sits at the very top of the file:

// apps/dashboard/main.ts
// Register Redis/Garnet KV adapter — must run before any getKv() call.
import '@netscript/kv/redis';
import { defineFreshApp } from '@netscript/fresh/server';
import type { State } from '@app/utils.ts';

export const app = defineFreshApp<State>({ name: 'dashboard' });

The Vite config wires NetScript's Fresh build plugin alongside the Fresh and Tailwind plugins. createNetScriptVitePlugin from @netscript/fresh/vite is what teaches Vite about NetScript's route manifest, workspace aliases, and watch paths:

// apps/dashboard/vite.config.ts (trimmed to the NetScript-specific wiring)
import { fresh } from '@fresh/plugin-vite';
import tailwindCSS from '@tailwindcss/vite';
import { createNetScriptVitePlugin } from '@netscript/fresh/vite';
import { defineConfig } from 'vite';

export default defineConfig(() => ({
  plugins: [
    fresh(),
    tailwindCSS(),
    createNetScriptVitePlugin({
      appRoot,
      workspaceRoot,
      aliasEntries,
      watchPaths: [/* packages, contracts, plugins */],
      routeManifest: {},
    }),
  ],
}));

Step 5 — Bring up orchestration

This is the step that turns a folder of files into a running system. Aspire provisions your database and cache; 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: restores the Aspire SDK modules into .aspire/
aspire start       # starts the AppHost and every declared resource

aspire start brings up the Postgres database, the Redis cache, your orders service, and the Fresh app together, then prints a URL and login token for the Aspire dashboard:

http://localhost:18888

Leave aspire start running in this terminal; it is your control plane for the rest of the track.

Verify your progress

In a second terminal (leave aspire start going in the first), confirm the orders service answers its health endpoint:

curl http://localhost:3002/health

You should get a healthy JSON response. Then type-check the whole workspace from the project root:

deno task check

A clean check confirms the scaffold, contracts, and service line up.

  • [ ] netscript --help lists the public command groups.
  • [ ] my-dashboard/ exists with apps/dashboard/, contracts/, and services/orders/.
  • [ ] aspire start is up; the dashboard at :18888 lists postgres, redis, and orders.
  • [ ] curl http://localhost:3002/health returns a healthy response.
  • [ ] deno task check is clean.

What you built

A real NetScript workspace — my-dashboard/ — with a Fresh app, an orders service on :3002, and a Postgres database, all orchestrated by Aspire and visible at :18888. Next you will shape the orders read-model the dashboard consumes.