Releases: septagon-oss/platformkit
Release list
v1.0.0
Image: ghcr.io/septagon-oss/platformkit:v1.0.0@sha256:07f81a5a1aa2242c63895c5d04d6063c869a342fe4a4730533030d33b48ae13b
Full Changelog: v0.15.1...v1.0.0
v0.14.1 — concurrent replicas can boot on Postgres
The PlatformKit OSS front door: one binary composing the nine-module starter.
Install
go install github.com/septagon-oss/platformkit@latestChanges
Concurrent replicas can boot on Postgres. A fix for a real failure in the profile v0.13.0 introduced as the production one.
Measured before the fix: six replicas starting simultaneously against a virgin database produced one success and five failures.
ensure schema: ERROR: duplicate key value violates unique constraint
"pg_type_typname_nsp_index" (SQLSTATE 23505)
CREATE TABLE IF NOT EXISTS reads as idempotent, and within one process it is — but on Postgres it is not concurrency-safe: competing backends collide inside the system catalog and all but one lose. Any rollout that starts several pods at once against a new database would have most of them crash-loop until one happened to finish first.
A session-scoped advisory lock is now held for the whole boot rather than around a single call, because schema is created in three separate places: the built-in module stores, the bootstrap-identity ledger, and any contributed module's own constructor (WithModules runs DDL the starter cannot see). Locking them one at a time would leave whichever site is added next unprotected. Seeding falls inside the lock too, so first-boot inserts serialize as well. A replica that crashes mid-boot releases the lock automatically, because the lock dies with its session.
Verified with this binary: six real processes racing a virgin Postgres all start, health answers, and the tenant and administrator are seeded exactly once. Two regression tests also run against real Postgres — six replicas on a virgin database, and six restarting against a populated one.
SQLite is unaffected: the embedded profile is a single process over one file, with the handle already pinned to one connection.
Compatibility
- Go 1.26 or newer.
- Pre-1.0 — pin this version. A minor release may change public API deliberately.
- No API or configuration change. On Postgres, boots now serialize their schema phase.
Links
| 📖 Documentation | https://septagon-oss.github.io/pk-docs/ |
| 💬 Discussions | https://github.com/septagon-oss/platformkit/discussions |
| 🔒 Security policy | https://github.com/septagon-oss/platformkit/blob/main/SECURITY.md |
| ⚖️ License | https://github.com/septagon-oss/platformkit/blob/main/LICENSE |
v0.14.0 — cross-site mutations refused; SQL rewriter retired
The PlatformKit OSS front door: one binary composing the nine-module starter.
Install
go install github.com/septagon-oss/platformkit@latestChanges
A security review of the surface added in v0.13.0 produced two changes.
Cross-origin state-changing requests are refused
The session cookie is SameSite=Lax, which stops a cross-site POST — the common attack — but "site" means registrable domain, not origin. Every sibling subdomain is same-site, so a deployment serving customer content, a preview host, or anything attacker-influenceable next to the console could forge authenticated mutations. That one attribute was also the only barrier: nothing failed if a later route accepted a mutation on GET, or if the cookie profile changed.
Unsafe methods that rely on the ambient session cookie must now be same-origin, checked via Sec-Fetch-Site with an Origin fallback. The rule is narrow on purpose:
- Safe methods pass — handlers already enforce that GET does not mutate.
- Requests presenting an
Authorizationheader pass untouched. A bearer token cannot be attached by a cross-site page, so SPAs on another host, mobile clients, CI, andcurlare unaffected by origin policy. - Everything else is a browser relying on cookies, and must be same-origin.
Verified with this binary: the console's own same-origin mutation succeeds (201), a cross-site forgery carrying the same cookie is refused (403), a same-site forgery from a sibling subdomain is refused (403), and a token client works from any origin (201).
SECURITY.md now states this posture explicitly.
The boot-path SQL rewriter is retired
It kept one SQLite spelling of each boot statement and translated it for Postgres at runtime. That is string surgery on a language with string literals and comments in it, and a probe found three defects immediately: a ? inside a comment consumed a placeholder number so real placeholders numbered past the argument count; a blanket type-name replacement corrupted any identifier merely containing the word (last_datetime became last_TIMESTAMPTZ); and appending ON CONFLICT DO NOTHING to a statement ending in a comment put the clause inside the comment, silently dropping insert-if-absent semantics with no error.
None could fire on the five statements that existed — all verified to translate correctly — but they were landmines for the sixth, and the type rewrite was already dead code. Each engine now carries its statements explicitly, matching how the rest of the project treats engines: an adapter per engine, never a translation at runtime.
Compatibility
- Go 1.26 or newer.
- Pre-1.0 — pin this version. A minor release may change public API deliberately.
- Behavior change: a browser request that changes state, carries the session cookie, and is not same-origin now receives
403. Token-authenticated clients are unaffected.
Links
| 📖 Documentation | https://septagon-oss.github.io/pk-docs/ |
| 💬 Discussions | https://github.com/septagon-oss/platformkit/discussions |
| 🔒 Security policy | https://github.com/septagon-oss/platformkit/blob/main/SECURITY.md |
| ⚖️ License | https://github.com/septagon-oss/platformkit/blob/main/LICENSE |
v0.13.1 — documents the scaffolder
The PlatformKit OSS front door: one binary composing the nine-module starter.
Install
go install github.com/septagon-oss/platformkit@latestChanges
Documentation only — no code change.
platformkit new app and platformkit new module shipped in v0.13.0 with no changelog entry, README section, or release note: a working command nobody could discover. This release documents it, and v0.13.0's notes below have been corrected to record it where it landed.
platformkit new app acme && cd acme
platformkit new module invoice
make verify # go vet + go test -race, including the generated module's tests
go run . # your app, your name on the consoleA scaffolded application carries a container image, a Makefile whose verify target is this project's own gate, a config.example.yaml that keeps secrets in the environment, and an agent pack (AGENTS.md, llms.txt) that teaches an AI coding agent the rules for extending it safely. Generated modules register themselves, so adding one never edits main.go; each ships tenant-scoped queries, per-route scope checks, canonical entity IDs, append-only migrations, and a test that fails the moment tenant isolation breaks.
The README also gains a Choose a database section for the Postgres profile introduced in v0.13.0.
Compatibility
- Go 1.26 or newer.
- Pre-1.0 — pin this version. A minor release may change public API deliberately.
Links
| 📖 Documentation | https://septagon-oss.github.io/pk-docs/ |
| 💬 Discussions | https://github.com/septagon-oss/platformkit/discussions |
| 🔒 Security policy | https://github.com/septagon-oss/platformkit/blob/main/SECURITY.md |
| ⚖️ License | https://github.com/septagon-oss/platformkit/blob/main/LICENSE |
v0.13.0 — Postgres is a supported database
The PlatformKit OSS front door: one binary composing the nine-module starter.
Install
go install github.com/septagon-oss/platformkit@latestChanges
Corrected after publication: this release also shipped
platformkit new,
which was omitted from these notes. See v0.13.1.
One command turns the kit into your product. platformkit new app <name> writes a Go application that boots this starter and is ready for your own modules, with a container image, a Makefile whose verify target is this project's own gate, and an agent pack (AGENTS.md, llms.txt) for AI coding agents. platformkit new module <name> generates a tenant-scoped module — contract, store, migration, routes, and a test that fails the moment tenant isolation breaks — that registers itself, so adding one never edits main.go.
PlatformKit runs on Postgres. Point database.driver at postgres, give it a DSN, and the whole application — all nine modules — runs there. The binary registers both drivers, so choosing an engine needs no code change and no rebuild.
database:
driver: postgres
dsn: "postgres://user:pass@host:5432/db?sslmode=require"SQLite remains the zero-setup default for local development and small single-node deployments, and that path is unchanged.
This is not a DSN swap dressed up as support. Every module store has a real Postgres adapter that passes the same store conformance suite the SQLite adapters pass — tenant-scoped list, tenant immutability on update, retired rows hidden — against a real Postgres, so tenant isolation is held by an executable check on both engines. The Postgres profile uses a real connection pool; SQLite keeps its single-connection pin because it is a single-writer engine.
Also in this release: the pre-v0.4 bootstrap migration path is deleted (~3,900 lines of SQLite-coupled machinery that could never run, since PlatformKit has not launched and no deployment carries that data). The durable bootstrap identity ledger it wrapped — the part that keeps a database's tenant and user IDs stable across restarts — survives intact.
Verified with this binary before tagging: production-mode boot on Postgres with the password supplied through PK_ADMIN_PASSWORD, tables created, seed, login, and create/open/publish/delete over the canonical opaque-segment API; then the same binary zero-config on SQLite.
See the CHANGELOG.
Compatibility
- Go 1.26 or newer.
- Pre-1.0 — pin this version. A minor release may change public API deliberately.
Links
| 📖 Documentation | https://septagon-oss.github.io/pk-docs/ |
| 💬 Discussions | https://github.com/septagon-oss/platformkit/discussions |
| 🔒 Security policy | https://github.com/septagon-oss/platformkit/blob/main/SECURITY.md |
| ⚖️ License | https://github.com/septagon-oss/platformkit/blob/main/LICENSE |
v0.12.0 — the list page is one pk-ui organism
The PlatformKit OSS front door: one binary composing the nine-module starter.
Install
go install github.com/septagon-oss/platformkit@latestChanges
The admin's resource list page is now a single pk-ui DataGrid organism — toolbar, sortable table, cursor pagination — with the page's live status region and empty panels slotted into the organism's children seam. Atomic design runs the full ladder in the shipped product: atoms → molecules → organism → page. Also carries pk-modules v0.14.0's store conformance checks (list scope, tenant immutability, retired rows).
Verified live before tagging: boot, health, session login, canonical-segment console operations, and the organism page's sort/search/pagination bindings in a real browser.
See the CHANGELOG for details.
Compatibility
- Go 1.26 or newer.
- Pre-1.0 — pin this version. A minor release may change breaking API deliberately.
Links
| 📖 Documentation | https://septagon-oss.github.io/pk-docs/docs/current-design-system/ |
| 💬 Discussions | https://github.com/septagon-oss/platformkit/discussions |
| 🔒 Security policy | https://github.com/septagon-oss/platformkit/blob/main/SECURITY.md |
| ⚖️ License | https://github.com/septagon-oss/platformkit/blob/main/LICENSE |
v0.11.0 — sortable tables, honest pagination, a console of pure pk-ui composition
The PlatformKit OSS front door: one binary composing the nine-module starter.
Install
go install github.com/septagon-oss/platformkit@latestChanges
Resource tables sort: every column header is a keyboard-operable button with aria-sort, ordering the loaded page with shareable state in the URL hash. Pagination is honest cursor paging: Previous disabled on the first page, controls on data-pk-pagination hooks, the label announced politely.
Underneath, the console now composes only pk-ui components (pk-modules v0.12.0, pk-apps v0.11.0, pk-ui v0.2.4): the shell declares no component styling of its own, runtime-built rows and badges wear complete pk-ui class lists via the embedded bridge, the sign-in page's controls are pk-ui renderers with the lime call to action re-colored by a page-scoped role remap, and the 403 interstitial retires the product's last html/template. pk-ui's variant styling is collision-free by construction, enforced by a structural guard test.
Verified live before tagging: boot, health, session login, the four console operations through the canonical opaque-segment API, sorting and pagination in a real browser against a seeded instance, and the cobra CLI surface.
See the CHANGELOG for details.
Compatibility
- Go 1.26 or newer.
- Pre-1.0 — pin this version. A minor release may change public API deliberately.
Links
| 📖 Documentation | https://septagon-oss.github.io/pk-docs/docs/current-design-system/ |
| 💬 Discussions | https://github.com/septagon-oss/platformkit/discussions |
| 🔒 Security policy | https://github.com/septagon-oss/platformkit/blob/main/SECURITY.md |
| ⚖️ License | https://github.com/septagon-oss/platformkit/blob/main/LICENSE |
v0.9.0 — the whole console renders on the design system
The PlatformKit OSS front door: one binary composing the nine-module starter.
Install
go install github.com/septagon-oss/platformkit@latestChanges
The console's template era ends: every admin page — shell, overview, resource lists, entity forms, and now the sign-in page — is a typed Go view on the design system (pk-modules v0.11.0, pk-apps v0.10.0). Components are tw class lists shared with every module admin page; the console's editorial voice stays product chrome on the same --pk-* tokens; the login page's palette is generated from themes.Default() rather than hand-copied hex. Mobile resource tables scroll with the header row visible instead of transforming into cards.
Verified live before tagging: boot, health, session login, and the four console operations — open, edit, publish, delete — through the canonical opaque-segment API.
See the CHANGELOG for details.
Compatibility
- Go 1.26 or newer.
- Pre-1.0 — pin this version. A minor release may change public API deliberately.
Links
| 📖 Documentation | https://septagon-oss.github.io/pk-docs/docs/current-design-system/ |
| 💬 Discussions | https://github.com/septagon-oss/platformkit/discussions |
| 🔒 Security policy | https://github.com/septagon-oss/platformkit/blob/main/SECURITY.md |
| ⚖️ License | https://github.com/septagon-oss/platformkit/blob/main/LICENSE |
platformkit v0.8.0
A runnable, open-source Go foundation for multi-tenant SaaS.
Install
go run github.com/septagon-oss/platformkit@v0.8.0Changes
The design system becomes the frontend baseline. The admin stylesheet carries four layers — pk-design theme tokens, role variables, the full tw utility layer, and the shell rules — and reference/polls proves a module-owned admin page rendered entirely from pk-ui with zero authored CSS. Three repositories join the family: pk-ui, tw, styleengine. The frontend stack is Go end to end: no Node, no Tailwind build, no bundler. See the design-system guide.
Compatibility
- Go 1.26 or newer.
- Pre-1.0 — pin this version. A minor release may change public API deliberately.
Links
| 📖 Documentation | https://septagon-oss.github.io/pk-docs/docs/current-design-system/ |
| 💬 Discussions | https://github.com/septagon-oss/platformkit/discussions |
| 🔒 Security policy | https://github.com/septagon-oss/platformkit/blob/main/SECURITY.md |
| ⚖️ License | https://github.com/septagon-oss/platformkit/blob/main/LICENSE |
v0.7.0
Security
- Sessions and API keys no longer outlive their owner: deleting or deactivating a user immediately stops their existing credentials from authenticating (pk-apps v0.8.0).
- A user can no longer delete their own account —
DELETE /api/v1/users/{id}returns 409 for the caller's own subject (pk-modules v0.9.0). - The shipped binary can finally reach production configuration.
config.yamlnext to the process (orPK_CONFIG=/path/config.yaml) is loaded throughLoadConfig, which fails closed toenvironment: productionand therefore requiresseed.admin_password. Previously the released binary was permanently development mode with a published, self-re-asserting password — including when bound to a network interface viaPK_HTTP_ADDR.
Changed
- Downstream modules may claim
/and/favicon.icoinstead of colliding with the starter's landing page.