Start a suite app
One command writes the Quantum suite wired together — a Nucleus application
whose domain runs on the Quark ORM, with the Orbit admin panel mounted
on top and both bridges between them — and go run . boots it. Start here
if you want the whole suite on the first screen; the
Quickstart starts from the empty framework skeleton instead.
1 — Scaffold
nucleus new store --template suite
cd store
--template suite implies --with orbit,quark,quarkbridge,quarkdatasource:
the four sibling modules are fetched from the module proxy at their
published tags (go get, then go mod tidy), together with the driver
modules for --db (sqlite by default; postgres, mysql, sqlserver
and oracle move both products to that engine). The project builds as
written. --offline skips the network and prints the exact go get … && go mod tidy line to run later.
What is on disk:
.dockerignore
.gitignore
Dockerfile
README.md
go.mod
main.go
migrations/.gitkeep
nucleus.yml
rbac_policy.csv
shop/models.go
shop/module.go
shop/module_test.go
main.goopens the Quark client on the same databasenucleus.ymlnames, migrates and seeds theshopschema, backs Orbit's Data Studio with the Quark models (quarkdatasource), and mounts theshopmodule and the admin panel.shop/is the worked domain: two Quark models (Author,Articlewith abelongs_to), a JSON API, and a test that boots the module in-process.Dockerfileand.dockerignorebuild the project into a container image: a multi-stage build, a static binary, a distroless runtime base pinned by digest, and a process that runs as uid 65532.nucleus doctor --check imagereads that file back — see Deployment.nucleus.ymlandrbac_policy.csvare the framework's own configuration; the scaffold setssession_cookie_secure: falseso the admin login works onhttp://localhost(remove it behind TLS).
2 — Run and try
go run .
curl -s localhost:8080/api/articles
curl -s -X POST localhost:8080/api/articles \
-H 'Content-Type: application/json' \
-d '{"author_id":1,"title":"probe","body":"live feed"}'
The first call lists the seeded article; the second creates one and answers
201 — post the same title twice and the third answers 409, because the
Quark driver module that recognises the engine's duplicate-key error is
linked. A path nothing serves answers 404.
Then open http://localhost:8080/admin — user admin, password
quickstart unless ADMIN_BOOTSTRAP_PASSWORD was set before the first boot
(a development credential; set the variable before the app faces anyone but
you). The live view shows every Quark statement the API ran, correlated
to its request; Data Studio browses and edits Author and Article.
The API describes itself: curl -s localhost:8080/openapi.json is its
OpenAPI document, derived from the shop module's routes. They are typed
endpoints (nucleus.Handle), so the document carries the request and
response types — CreateArticle, Article, ArticleList — and a
TypeScript client for a frontend is one command:
nucleus openapi --client typescript --out web/src/api.ts
go test ./... runs the shop module's test: the same boot path main.go
takes, driven through the test kit's client — the answers decoded into the
module's own Article type — duplicate-title probe included. See
Testing your application.
What the scaffold decided for you
The API is open for development, and it says so. The full application
runs the default-deny enforcer, so every route needs a policy row. The
shop module carries its own rows instead of editing rbac_policy.csv:
import "github.com/jcsvwinston/nucleus/pkg/nucleus"
Policies: []nucleus.PolicyRule{
{Subject: "anonymous", Object: "/api/authors", Action: "read"},
{Subject: "anonymous", Object: "/api/articles", Action: "read"},
{Subject: "anonymous", Object: "/api/articles", Action: "create"},
},
CSRFExempt: []string{"/api/"},
The create row is what lets the curl -X POST above land without a
login; a module written with nucleus generate module opens reads only.
Scope it to a role before the app faces a network — an operator deny in
rbac_policy.csv always overrides. The admin panel needs no rows: Orbit
enforces its own session login under /admin.
The JSON API is exempt from CSRF; the admin login is not. /api/ takes
a header token, which a cross-site form cannot forge, so the module exempts
it and curl works as written. /admin/login is a browser form: a browser
passes the origin check through Sec-Fetch-Site, a bare curl answers
419 — send -H 'Sec-Fetch-Site: same-origin' to script it.
Versions. The suite tags Nucleus before Orbit in every release. Right
after a Nucleus release, the orbit tag on the proxy may still pin the
previous Nucleus minor; go get keeps the higher of the two and the next
Orbit tag closes the gap. Nothing in the scaffold pins a sibling version —
go.mod is what the proxy resolved on the day.
The same thing, piece by piece
--with also works on the other templates:
nucleus new blog --with orbit # mvc + the admin panel under /admin
nucleus new svc --template api --with quark # fetch the ORM and its driver, mount nothing
--with orbit fetches the panel and writes the Mount(orbit.Module(orbit.Config{...}))
call into main.go with the same bootstrap credentials. --with quark
fetches the ORM and its driver module for --db without writing any code:
nothing in the mvc or api scaffold imports them, so the scaffold runs their
go get after go mod tidy (which would drop them) and go.mod keeps them
as indirect requires — nucleus generate module <name> --data quark then
imports them and builds with the versions the scaffold resolved, rather
than whatever the proxy serves that day. The two bridges are only useful
with both products present; only the suite template wires all four.
--with takes every name nucleus add takes — one catalog — so a project
can also start with what it would otherwise add on its first day:
nucleus new blog --with s3,ldap fetches both modules at the
versions released with the CLI, writes their blank imports into main.go,
and ends by naming the keys that select them (storage.provider,
auth_backends). The suite products are the exception to the pin: their
versions belong to the suite's certified set, which is cut after the CLI is
released, so they are fetched at the tag the module proxy calls latest.
Next
- Add a feature:
nucleus generate module notes --mount --data quarkwrites a slice on the same ORM and mounts it. - Using Quark with Nucleus — the ORM inside a module, the bridges, and when to prefer the framework's SQL-first layer.
- Project structure — where things go as the application grows.