Start here
Technology stack
A practical map of the libraries, processes and storage behind this installation.
One application, two long-running processes
The application combines the administration, authenticated APIs and public website in a Next.js App Router project. React supplies the user interface, and TypeScript describes the contracts used across forms, services and stored snapshots. Editors do not need to install these libraries separately: the deployed website already contains the appropriate browser code. Developers use the repository and its committed lockfile to build the matching server and browser output.
The production package runs a web process and a separate worker. Web handles requests; the worker executes scheduled publication and consumes publication-effect jobs. A separate one-off migration command prepares the database before either starts. The Docker web image uses Next.js standalone output, whereas the operations image retains TypeScript tooling for worker and maintenance commands. Both are built from the same dependency lockfile and run as a non-root user.
Sources: Pinned dependencies and commands; Web and operations image definitions; Production process and PostgreSQL configuration; Self-hosting Next.js.
Versions are pinned in the repository
Use these versions as the documented build baseline, not an instruction to replace individual dependencies with whichever version an external tutorial now uses. The Node engine accepts the 24.x series; the production Dockerfile pins a specific Node image. npm ci installs the lockfile rather than resolving a new combination. A future update should change the dependency files deliberately and repeat the relevant verification.
| Part | Pinned baseline | Responsibility |
|---|---|---|
| Node.js | 24.x; Docker 24.21.0 | Server JavaScript runtime |
| Next.js / React | 16.3.4 / 19.3.0 | Application routing and interface rendering |
| TypeScript | 6.0.3 | Compile-time contract checks |
| Puck | 0.23.0 | Visual composition editor |
| PostgreSQL | 18.6-bookworm | Persistent content, identity and jobs |
| Drizzle ORM / Kit | 0.45.2 / 0.31.10 | Typed SQL access and migration generation |
| node-postgres / pg-boss | 8.23.0 / 12.30.0 | Database connection and durable job processing |
| Better Auth / Drizzle adapter | 1.7.4 / 1.7.4 | Authentication and session persistence |
| Sharp / sanitize-html / Zod | 0.35.4 / 2.17.7 / 4.6.1 | Image normalization, HTML sanitation and validation |
Sources: Pinned dependencies and commands; Web and operations image definitions; Production process and PostgreSQL configuration.
PostgreSQL stores decisions as well as content
PostgreSQL holds resources, immutable revisions, taxonomy and media references, routes, publication history, review requests, schedules, account records and queue data. Drizzle expresses the relational schema and provides typed queries. Generated migrations are only part of the integrity model: the migration runner also installs custom pointer constraints, immutable-revision protection, search-vector infrastructure and runtime privilege restrictions. Reading only a generated SQL file would miss those additional contracts.
Published search uses a current-head projection. Publication updates that projection in the same transaction as the public revision, rather than asking search to examine every retained historical body. The public loader then combines eligible content with the relevant template and reference closure. This is a deliberate application design, not an automatic feature provided by choosing PostgreSQL or Drizzle. Preserve it when adding queries, migrations or alternative storage.
Sources: Relational CMS schema; Migration, integrity and privilege setup; Public eligibility and search queries; Drizzle schema declarations.
Editing libraries do not replace CMS policy
Puck supplies the interactive composition workspace. GroCMS supplies its supported components, fields, defaults and renderers, then validates the resulting saved document on the server. The same component configuration supports editing and published rendering. Adding a new visual block therefore requires more than drawing a control: its stored properties, validation, relationships and public rendering must agree. The native rich-text integration belongs to this controlled composition path.
Better Auth supplies the authentication integration, while GroCMS adds invitations, role checks, disabled-account handling and scoped API authority around the application services. A session identifies an account; it does not grant every action. Current authority is checked at the point of use. Likewise, Sharp can normalize an uploaded image, but the CMS decides which media version may be delivered publicly and which retained revisions protect it from deletion.
Sources: Shared Puck component configuration; Server-side content validation; Authentication integration contract; Getting Started; Next.js integration.
Different checks prove different properties
Vitest exercises the domain and real PostgreSQL integration boundaries. Playwright and axe-based checks cover browser behavior and automated accessibility findings. The npm run verify command performs type checking, linting, tests and a production build; it does not automatically reproduce every browser, recovery or load exercise. Those have separate commands and evidence. A build passing without a live database is useful packaging evidence, but it does not prove a running deployment is ready.
The 11 September 2026 engineering run used 20 readers for ten minutes under the documented four-CPU/eight-GiB allocation. The 10,000-record fixture completed 116,090 HTML responses with a 119 ms p95 and no errors. Following query improvements, the 100,000-record fixture completed 29,432 responses without errors, but its 778 ms p95 still missed the 750 ms target. A separate phrase-heavy search workload reached 2.196 seconds p95. These results do not establish a supported 100,000-record tier. A tested local restore likewise does not establish off-host recovery or an ongoing recovery-point commitment. Independent agency installation and real-site trials remain pending.
For an upgrade, start from the pinned baseline, read the affected upstream migration guidance and preserve old stored-document compatibility. Re-run the tests that could detect lost revisions, incorrect permissions, draft exposure, stale schedules or broken media. Record the new image and source revision with the evidence. Package names explain responsibilities; the code and measured checks establish what this installation actually supports.
Sources: Pinned dependencies and commands; Verification and acceptance evidence; Measured performance and limits; Executed operations and recovery evidence.