Scaffold the workspace
Every chapter in this track adds one layer to a 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 workspace database, the provisioning job, and the route guards all attach to in the
chapters that follow.
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 :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.1-alpha.12
netscript --help
netscript --help should list the 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 (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 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.
| Name | Type | Description |
|---|---|---|
--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:
http://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 --helplists the public command groups. - [ ]
my-workspace/exists withservices/workspace/,plugins/,database/, andaspire/. - [ ]
aspire startis up;postgresandredisare green in the dashboard on:18888. - [ ]
curl http://localhost:3001/healthreturns a healthy response. - [ ]
deno task checkpasses.
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. Next you add authentication on top of it.