Skip to main content
0.0.x

Scaffold the workspace

You are building the team layer of an operations workspace — the part that will decide who is on the team, where team records live, and which routes a caller may reach. Every chapter in this track adds one layer to that single app. This first chapter lays the foundation: a real NetScript workspace on disk named my-workspace/, with an example service and a Postgres database, booted under Aspire. You will not write auth yet — you will create the base that the auth backend, the team database, the provisioning job, and the route guards all attach to in the chapters that follow. Everything that later fails closed or provisions off-path attaches to what you scaffold here, so the checkpoint at the end of this chapter — a healthy service and a clean type-check — is the ground truth the rest of the track builds on.

  1. 1 · Scaffold
  2. 2 · Auth
  3. 3 · Workspace data
  4. 4 · Provision job
  5. 5 · Route authz
  6. 6 · Deploy

What you will build

A working my-workspace/ directory: a typed workspace service on its own port, a Postgres database, the Aspire orchestration that provisions Postgres and the Redis cache, and a clean deno task check. By the end you will have the Aspire dashboard open on https://localhost:18888 showing your service, database, and cache running together — the control plane you keep up for the rest of the track.

Before you begin

This is the first chapter, so there is no prior project state to check — but your local toolchain must be ready. You need Deno 2.x, the Aspire CLI, and Docker running so Aspire can start the Postgres and Redis containers. Verify all three:

deno --version     # Deno 2.x
aspire --version   # the .NET Aspire CLI
docker info        # prints engine details, not a connection error

Install the NetScript CLI from JSR once, then confirm it is on your PATH:

deno install --global --allow-all --name netscript jsr:@netscript/cli@0.0.6
netscript --help

netscript --help should list the command groups agent, config, deploy, init, contract, db, generate, marketplace, plugin, service, ui:add, ui:init, ui:list, ui:update, and 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

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

netscript init my-workspace --service --service-name workspace --service-port 3001 --db postgres --dry-run

A clean dry run validates your flag combination — it rejects bad mixes (an unknown --db engine, for example) here, before any files exist. Treat a clean plan as a green light to scaffold for real.

This track uses --db postgres, the recommended default. The database is polyglot, so you can swap --db postgres for mysql, mssql, or sqlite and follow along the same way (sqlite is file-backed, so it has no Aspire container).

Step 2 — Create my-workspace/

Run the same command without --dry-run. This track uses an example service named workspace on port 3001 (note: this tutorial pins the port to 3001; in unpinned scaffolds, each project is allocated its own randomized high-range ports) and a Postgres database, so you have something real to authenticate and protect later:

netscript init my-workspace --service --service-name workspace --service-port 3001 --db postgres
cd my-workspace

This scaffolds my-workspace/, formats the output with deno fmt, and initializes a git repository. On completion the CLI prints a next steps summary tailored to your options.

netscript init options used here
NameTypeDescription
--service --service-name workspace --service-port 3001 example service Include an example oRPC service named 'workspace' on port 3001 — the service you protect in chapter 5.
--db postgres database workspace Scaffold a Postgres database workspace. The auth plugin's auth.prisma migration (chapter 2) aggregates into this primary datasource.
--dry-run plan only Plan the scaffold and print totals without writing any files (Step 1).

Step 3 — Tour what you got

Open my-workspace/ and you will find this shape. These are the directories the rest of the track edits:

  • my-workspace/
    • apps/dashboard/ # Fresh frontend (defineFreshApp)
    • contracts/ # Shared oRPC + Zod contracts, versioned under versions/v1/
    • services/workspace/ # The example oRPC service (src/main.ts, router.ts) — guarded in chapter 5
    • plugins/ # Plugin registry — empty until you add the auth plugin in chapter 2
    • database/ # The primary Postgres workspace; a second db is added in chapter 3
    • aspire/ # Aspire TypeScript orchestration (isolated Node runtime)
    • appsettings.json # Infrastructure config (Services / Databases / Persistent)
    • deno.json # Workspace root (members, tasks, dependency catalog)
    • netscript.config.ts # Framework config (defineConfig)

The two pieces you will return to most: services/workspace/ is the oRPC service whose routes you protect in chapter 5, and plugins/ is where the auth plugin lands in chapter 2. Everything derives its types from contracts/ — the typed seam between your services and any client.

Step 4 — Bring up orchestration

This is the step that turns a folder of files into a running system. 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
aspire start       # starts the AppHost and every declared resource

aspire start brings up the Postgres database, the Redis cache, and your workspace service together, then prints the Aspire dashboard URL and a one-time login token. Open it:

https://localhost:18888

Leave aspire start running in this terminal — it is your app's control plane for the entire track. The dashboard's resource list is the authority for the exact port each resource bound.

Verify your progress

In a second terminal (leave aspire start going in the first), confirm the workspace service is up and the workspace type-checks:

curl http://localhost:3001/health
deno task check

curl should return a healthy JSON response, and deno task check should finish clean — confirming the scaffold, contracts, and service all line up.

  • [ ] netscript --help lists the public command groups.
  • [ ] my-workspace/ exists with services/workspace/, plugins/, database/, and aspire/.
  • [ ] aspire start is up; postgres and redis are green in the dashboard at https://localhost:18888.
  • [ ] curl http://localhost:3001/health returns a healthy response.
  • [ ] deno task check passes.

What you built

A real NetScript workspace at my-workspace/: a typed workspace service on :3001, shared contracts, a Postgres database, and a Redis cache — all orchestrated by Aspire and visible in one dashboard. This is the base — and right now it answers absolutely anyone. Next you fix that: you add an identity layer, so the app can tell a team member from a stranger.