genesis-stack 1.3.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -3
- package/genesis.templates.json +48 -0
- package/package.json +1 -1
- package/stacks/pieces/django.md +7 -7
- package/stacks/pieces/express.md +23 -5
- package/stacks/pieces/jskit.md +31 -1
- package/stacks/pieces/nextjs.md +35 -7
- package/stacks/pieces/nodejs.md +11 -0
- package/stacks/pieces/python.md +15 -0
- package/stacks/pieces/rails-mysql.md +10 -5
- package/stacks/pieces/rails-postgresql.md +16 -4
- package/stacks/pieces/rails.md +36 -9
- package/stacks/pieces/spring-boot.md +6 -0
- package/stacks/pieces/sqlite.md +6 -0
package/README.md
CHANGED
|
@@ -37,10 +37,15 @@ any resolvable package may declare one when selecting that piece should install
|
|
|
37
37
|
that skill. Documentation alone does not require a skill declaration or a
|
|
38
38
|
catalog dependency.
|
|
39
39
|
|
|
40
|
-
With Genesis 1.4 or newer, `genesis templates list` also lists the
|
|
41
|
-
in `genesis.templates.json`.
|
|
40
|
+
With Genesis 1.4 or newer, `genesis templates list` also lists the starters
|
|
41
|
+
in `genesis.templates.json`. The JSKIT ones come first, from
|
|
42
42
|
the [JSKIT seed repository](https://github.com/vibe64-dev/seed-jskit):
|
|
43
|
-
`official:jskit/public`
|
|
43
|
+
`official:jskit/public`, `official:jskit/database`, `official:jskit/accounts`
|
|
44
|
+
and `official:jskit/accounts-hub`.
|
|
45
|
+
Then each framework component has one Basic app, from the `basic` branch of its
|
|
46
|
+
`vibe64-dev/seed-<technology>` repository: `official:django/basic`,
|
|
47
|
+
`official:rails/basic`, `official:spring-boot/basic`, `official:express/basic`
|
|
48
|
+
and `official:nextjs/basic`. Apply one to an empty
|
|
44
49
|
Git/Genesis bootstrap project with `genesis templates apply <id>`. Template IDs
|
|
45
50
|
name complete applications; selecting a Skill never silently chooses a starter.
|
|
46
51
|
|
package/genesis.templates.json
CHANGED
|
@@ -24,6 +24,54 @@
|
|
|
24
24
|
"description": "Sign-up, login, a private home, MySQL persistence and isolated database/browser tests.",
|
|
25
25
|
"repository": "https://github.com/vibe64-dev/seed-jskit.git",
|
|
26
26
|
"branch": "accounts"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "jskit/accounts-hub",
|
|
30
|
+
"technology": "jskit",
|
|
31
|
+
"name": "JSKIT · Accounts hub",
|
|
32
|
+
"description": "One sign-in for all your apps: your own accounts service with email sign-in, optional Google, and an Apps page where you approve each app.",
|
|
33
|
+
"repository": "https://github.com/vibe64-dev/seed-jskit.git",
|
|
34
|
+
"branch": "accounts-hub"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "django/basic",
|
|
38
|
+
"technology": "django",
|
|
39
|
+
"name": "Django · Basic app",
|
|
40
|
+
"description": "Notes form persisted to SQLite, admin site, unit and HTTP tests. No accounts.",
|
|
41
|
+
"repository": "https://github.com/vibe64-dev/seed-django.git",
|
|
42
|
+
"branch": "basic"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": "rails/basic",
|
|
46
|
+
"technology": "rails",
|
|
47
|
+
"name": "Rails · Basic app",
|
|
48
|
+
"description": "Notes form saved to SQLite, sign-in with a seeded development account, ready model and HTTP tests.",
|
|
49
|
+
"repository": "https://github.com/vibe64-dev/seed-rails.git",
|
|
50
|
+
"branch": "basic"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": "spring-boot/basic",
|
|
54
|
+
"technology": "spring-boot",
|
|
55
|
+
"name": "Spring Boot · Basic app",
|
|
56
|
+
"description": "Notes page with a CSRF-protected form, MySQL/MariaDB via JPA and Flyway, and ready unit and HTTP tests. No accounts.",
|
|
57
|
+
"repository": "https://github.com/vibe64-dev/seed-spring-boot.git",
|
|
58
|
+
"branch": "basic"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "express/basic",
|
|
62
|
+
"technology": "express",
|
|
63
|
+
"name": "Express · Basic app",
|
|
64
|
+
"description": "A small Express notes app that saves a form to SQLite, with unit and HTTP tests. No accounts.",
|
|
65
|
+
"repository": "https://github.com/vibe64-dev/seed-express.git",
|
|
66
|
+
"branch": "basic"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"id": "nextjs/basic",
|
|
70
|
+
"technology": "nextjs",
|
|
71
|
+
"name": "Next.js · Basic app",
|
|
72
|
+
"description": "A Next.js app with one form that saves notes to SQLite through a Server Action. No accounts.",
|
|
73
|
+
"repository": "https://github.com/vibe64-dev/seed-nextjs.git",
|
|
74
|
+
"branch": "basic"
|
|
27
75
|
}
|
|
28
76
|
]
|
|
29
77
|
}
|
package/package.json
CHANGED
package/stacks/pieces/django.md
CHANGED
|
@@ -70,10 +70,9 @@ https://docs.djangoproject.com/
|
|
|
70
70
|
after `SecurityMiddleware`; `runserver` serves static files only while
|
|
71
71
|
`DEBUG` is on. Keep `STATIC_ROOT` and media uploads out of Git.
|
|
72
72
|
- Tests: `manage.py test` creates `test_<NAME>` and needs permission to
|
|
73
|
-
create databases
|
|
74
|
-
database
|
|
75
|
-
|
|
76
|
-
dropping one. Never point tests at the development or production database.
|
|
73
|
+
create databases; the database integration says how a supplied test
|
|
74
|
+
database replaces it. Never point tests at the development or production
|
|
75
|
+
database.
|
|
77
76
|
Suites that create users spend most of their time hashing passwords: set
|
|
78
77
|
`PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"]` only
|
|
79
78
|
in a test settings module or under `if sys.argv[1:2] == ["test"]:`; never
|
|
@@ -87,9 +86,10 @@ https://docs.djangoproject.com/
|
|
|
87
86
|
review `manage.py check --deploy`. It rejects the console email backend that
|
|
88
87
|
recent `startproject` templates configure (`MAILERS` or `EMAIL_BACKEND`), so
|
|
89
88
|
select the production email backend and its credentials from the
|
|
90
|
-
environment. When `SECURE_SSL_REDIRECT` is on,
|
|
91
|
-
readiness path
|
|
92
|
-
|
|
89
|
+
environment. When `SECURE_SSL_REDIRECT` is on, exempt the
|
|
90
|
+
readiness path so a plain loopback probe is not redirected; entries are
|
|
91
|
+
regexes matched against the path without its leading slash, so use
|
|
92
|
+
`SECURE_REDIRECT_EXEMPT = [r"^admin/login/$"]`.
|
|
93
93
|
- The proposed readiness path is the admin login page `/admin/login/`. An
|
|
94
94
|
application without `django.contrib.admin` adds a small unauthenticated
|
|
95
95
|
health view and updates its Outputs and Deployment readiness to it.
|
package/stacks/pieces/express.md
CHANGED
|
@@ -49,10 +49,19 @@ documentation: https://expressjs.com/
|
|
|
49
49
|
for form posts; an `Origin` check must accept the origin built from the
|
|
50
50
|
trusted forwarded host as well as the raw `Host`, because a development
|
|
51
51
|
proxy may present same-origin requests with a loopback `Origin`. A host or
|
|
52
|
-
CORS allow-list must also admit loopback for the health probe.
|
|
52
|
+
CORS allow-list must also admit loopback for the health probe. helmet's
|
|
53
|
+
default `Referrer-Policy: no-referrer` makes browsers send `Origin: null` on
|
|
54
|
+
same-origin form posts, so an `Origin` check refuses every form: set
|
|
55
|
+
`referrerPolicy: { policy: 'same-origin' }` when the app checks `Origin`.
|
|
56
|
+
- helmet sends `X-Frame-Options: SAMEORIGIN` and a Content-Security-Policy with
|
|
57
|
+
`frame-ancestors 'self'`, so a development tool that shows the application
|
|
58
|
+
inside a frame on another origin stays blank. Only when `NODE_ENV` is not
|
|
59
|
+
`production`, pass `frameguard: false` and
|
|
60
|
+
`contentSecurityPolicy: { directives: { frameAncestors: null } }`; production
|
|
61
|
+
keeps both.
|
|
53
62
|
- Sessions use `express-session` with `secret: process.env.SESSION_SECRET`,
|
|
54
|
-
generated with `openssl rand -base64 32`, supplied through the environment
|
|
55
|
-
never committed
|
|
63
|
+
generated with `openssl rand -base64 32`, supplied through the environment
|
|
64
|
+
and never committed (a dotenv file holding it stays ignored); refuse to
|
|
56
65
|
start in production without it. Development may fall back to a random
|
|
57
66
|
per-process secret, which ends sessions on restart. Use
|
|
58
67
|
`cookie: { secure: 'auto', httpOnly: true, sameSite: 'lax' }`; `'auto'`
|
|
@@ -65,8 +74,12 @@ documentation: https://expressjs.com/
|
|
|
65
74
|
with another health path changes both.
|
|
66
75
|
- Serve static files with `express.static(path.join(__dirname, 'public'))`
|
|
67
76
|
or the ESM equivalent. A bundler or TypeScript build adds a Workspace setup
|
|
68
|
-
step and a Deployment Build step and serves the compiled output
|
|
69
|
-
|
|
77
|
+
step and a Deployment Build step and serves the compiled output; build tools
|
|
78
|
+
are usually devDependencies, so Deployment then installs with plain `npm ci`,
|
|
79
|
+
builds, and may prune with `npm prune --omit=dev` before Serve.
|
|
80
|
+
- Express has no ORM. Select the database component, declare its database
|
|
81
|
+
Resource in the project Stack with the environment names the app reads (no
|
|
82
|
+
Express database component declares it for you), and record the app's own
|
|
70
83
|
migration tool (Prisma, Drizzle, Knex, Sequelize, TypeORM) as Workspace
|
|
71
84
|
setup and Deployment Migrate steps, for example `prisma migrate deploy` or
|
|
72
85
|
`knex migrate:latest`. Never run `prisma migrate dev`, `prisma db push` or
|
|
@@ -85,6 +98,11 @@ documentation: https://expressjs.com/
|
|
|
85
98
|
role. Seed one development administrator and one ordinary user through an
|
|
86
99
|
idempotent script that reads their passwords from the environment; never
|
|
87
100
|
hard-code production credentials.
|
|
101
|
+
- Commands that run outside the server (migrations, seeds, administrative or
|
|
102
|
+
development sign-in helpers) use the server's database and secrets from the
|
|
103
|
+
same environment variables. A command started without that environment loads
|
|
104
|
+
the ignored dotenv the host generates with `process.loadEnvFile()` rather than
|
|
105
|
+
falling back to a different database file or connection.
|
|
88
106
|
|
|
89
107
|
## Adoption
|
|
90
108
|
|
package/stacks/pieces/jskit.md
CHANGED
|
@@ -32,6 +32,15 @@ https://mobily-enterprises.github.io/jskit-ai/
|
|
|
32
32
|
`AUTH_LOCAL_SESSION_SECRET` as a required environment name in the project's
|
|
33
33
|
established environment contract and committed environment example. Never
|
|
34
34
|
commit or invent its value.
|
|
35
|
+
- An application with accounts always has the host's browser-preview login,
|
|
36
|
+
without waiting to be asked: when adding authentication, add the
|
|
37
|
+
`auth/auth-surface` pattern's executable `tools/preview-identity` and copy its
|
|
38
|
+
exact `#### Preview identity` block (Command `tools/preview-identity`,
|
|
39
|
+
Protocol `vibe64.preview-identity.command.v1`, Identity types `email`
|
|
40
|
+
`user-id`, Enabled environment `AUTH_DEV_BYPASS_ENABLED`, Secret environment
|
|
41
|
+
`AUTH_DEV_BYPASS_SECRET`, Runtimes `nodejs`) under the web `Outputs` target.
|
|
42
|
+
Which existing accounts the preview uses stays the person's choice; never
|
|
43
|
+
create users for it.
|
|
35
44
|
- Before creating or modifying JSKIT Vue/Vuetify UI, read the Material 3
|
|
36
45
|
contract at
|
|
37
46
|
`https://mobily-enterprises.github.io/jskit-ai/guide/framework/material-3`
|
|
@@ -77,6 +86,25 @@ https://mobily-enterprises.github.io/jskit-ai/
|
|
|
77
86
|
input fields never grant administrator access. Verify the requested provider
|
|
78
87
|
outcomes and denied access with controlled fixtures. Genesis transports
|
|
79
88
|
guidance and opaque declarations; it does not execute integrations or payments.
|
|
89
|
+
- Shipping the app to phones ("install on my phone"): the host-owned
|
|
90
|
+
`## Packaging` section is written only when the person adds a mobile target.
|
|
91
|
+
It declares a separate `web-bundle` package whose Build produces the bundled
|
|
92
|
+
client (Output its build folder) with the absolute HTTPS API base the client
|
|
93
|
+
calls, then a `capacitor` package with `Content: package <that id>`,
|
|
94
|
+
`Platforms: android`, a permanent reverse-DNS `Id`, `Name`, a committed
|
|
95
|
+
1024x1024 PNG `Icon` without transparency, `Version from: package.json` and
|
|
96
|
+
one `Permission` line, with a plain reason, per native capability. The host
|
|
97
|
+
generates and discards the native project on every build: never commit
|
|
98
|
+
`android/`, `ios/`, `capacitor.config.*`, Gradle files, build numbers or
|
|
99
|
+
signing keys. Native plugins are ordinary client dependencies at the exact
|
|
100
|
+
versions in `package-lock.json`, and the host's shell is Capacitor 8; it
|
|
101
|
+
blocks a lockfile mismatch or another major. `@jskit-ai/mobile-capacitor` is
|
|
102
|
+
still on Capacitor 7, so propose mobile packaging for a JSKIT client only
|
|
103
|
+
once its Capacitor dependencies are 8.x. A deep-link scheme and app-link
|
|
104
|
+
domains live once in `## Environment defaults` (for example `APP_URL_SCHEME`,
|
|
105
|
+
`APP_LINK_DOMAINS`) and Packaging names them with `Deep link scheme from` and
|
|
106
|
+
`App link domains from`; the server's CORS and OAuth callbacks must accept
|
|
107
|
+
the app's origin and scheme.
|
|
80
108
|
|
|
81
109
|
## Adoption
|
|
82
110
|
|
|
@@ -96,7 +124,9 @@ https://mobily-enterprises.github.io/jskit-ai/
|
|
|
96
124
|
component when the script or preparation file does not exist.
|
|
97
125
|
- When the project declares an application-owned identity exchange for a host's
|
|
98
126
|
browser preview, preserve its command, selectors, protocol, environment names,
|
|
99
|
-
runtime and timeout in the project's existing section.
|
|
127
|
+
runtime and timeout in the project's existing section. When an application
|
|
128
|
+
with JSKIT accounts lacks it, add it from the `auth/auth-surface` pattern as
|
|
129
|
+
in Guidance.
|
|
100
130
|
A host-saved identity name/value is not a substitute for this application
|
|
101
131
|
contract.
|
|
102
132
|
- Treat generator descriptors, receipts, sync commands, legacy service
|
package/stacks/pieces/nextjs.md
CHANGED
|
@@ -42,12 +42,19 @@ framework documentation: https://nextjs.org/docs
|
|
|
42
42
|
WebSocket host for the proxy.
|
|
43
43
|
- Server Actions reject a POST whose `Origin` host differs from
|
|
44
44
|
`X-Forwarded-Host` (or `Host` without it) with "Invalid Server Actions
|
|
45
|
-
request".
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
(ports cannot be wildcarded)
|
|
50
|
-
admit arbitrary origins
|
|
45
|
+
request". A proxy that forwards both unchanged, or presents a same-origin
|
|
46
|
+
request entirely on the loopback origin (loopback `Origin` and `Host`, no
|
|
47
|
+
forwarded host), needs no setting. Add an exact host to
|
|
48
|
+
`experimental.serverActions.allowedOrigins` only for a real reported
|
|
49
|
+
mismatch, in development only (ports cannot be wildcarded); the list also
|
|
50
|
+
applies in production, so never admit arbitrary origins.
|
|
51
|
+
- Redirect with relative paths. A Server Action's redirect travels in a
|
|
52
|
+
framework response header, not `Location`, so a proxy does not rewrite it,
|
|
53
|
+
and Auth.js `signIn`/`signOut` with `redirectTo` build an absolute URL from
|
|
54
|
+
the request's host headers, which a proxy may present as the loopback
|
|
55
|
+
address. Call them with `redirect: false`, then `redirect("/path")`.
|
|
56
|
+
`request.nextUrl` in `proxy`/middleware names the server's own host, so an
|
|
57
|
+
Auth.js `callbackUrl` may be a loopback URL: use only its path.
|
|
51
58
|
- `NEXT_PUBLIC_*` variables are inlined into client bundles at build time:
|
|
52
59
|
never put secrets in them, and their production values must exist when
|
|
53
60
|
`next build` runs, not only at start. Server-only values are read from
|
|
@@ -58,6 +65,13 @@ framework documentation: https://nextjs.org/docs
|
|
|
58
65
|
file instead) and set `AUTH_TRUST_HOST=true` when the app is served behind a
|
|
59
66
|
trusted reverse proxy, so callback and redirect URLs use the forwarded
|
|
60
67
|
origin. Other auth libraries need their equivalent trusted-host setting.
|
|
68
|
+
- With `cacheComponents` enabled (the recent `create-next-app` default),
|
|
69
|
+
pages that read the session must render at request time: call
|
|
70
|
+
`await connection()` before `auth()`, wrap the read in `<Suspense>`, or
|
|
71
|
+
export `instant = false`; otherwise `next build` fails. Gate protected
|
|
72
|
+
routes in `proxy`/middleware (Auth.js `authorized` callback), not only with
|
|
73
|
+
`redirect()` during render: the client router can replay a cached
|
|
74
|
+
render-time redirect to the login page after sign-in.
|
|
61
75
|
- Readiness and health probes must reach a public route: middleware (or
|
|
62
76
|
`proxy`) that redirects `/` to a login page makes a `GET /` probe fail.
|
|
63
77
|
Exclude the probe path from the auth matcher, or add a small public route
|
|
@@ -86,6 +100,20 @@ framework documentation: https://nextjs.org/docs
|
|
|
86
100
|
for development through an idempotent seed script with credentials from the
|
|
87
101
|
environment, and keep role checks on the server (Server Components, route
|
|
88
102
|
handlers, Server Actions), not only in client components.
|
|
103
|
+
- Shipping the app to phones ("install on my phone") needs a static client:
|
|
104
|
+
`output: "export"` (no Server Actions, route handlers, middleware or
|
|
105
|
+
request-time rendering in that build), with API calls going to an absolute
|
|
106
|
+
HTTPS base read from a `NEXT_PUBLIC_*` variable. The host-owned
|
|
107
|
+
`## Packaging` section, written only when the person adds a mobile target,
|
|
108
|
+
declares a `web-bundle` package (Build `npm` `run` `build`, Output `out`)
|
|
109
|
+
and a `capacitor` package with `Content: package <that id>`,
|
|
110
|
+
`Platforms: android`, a permanent reverse-DNS `Id`, `Name`, a committed
|
|
111
|
+
1024x1024 PNG `Icon` without transparency, `Version from: package.json` and
|
|
112
|
+
one `Permission` line per native capability. Native plugins are ordinary
|
|
113
|
+
dependencies at exact `package-lock.json` versions on Capacitor 8; the host
|
|
114
|
+
generates and discards the native project, so never commit `android/`,
|
|
115
|
+
`capacitor.config.*` or signing keys. A server-rendered app is not yet
|
|
116
|
+
supported as a phone app: it needs a separate static client first.
|
|
89
117
|
|
|
90
118
|
## Adoption
|
|
91
119
|
|
|
@@ -138,7 +166,7 @@ framework documentation: https://nextjs.org/docs
|
|
|
138
166
|
- Ready when: `GET` `/` returns `200`
|
|
139
167
|
- Prepare `Install dependencies`: `npm` `ci`
|
|
140
168
|
- Build `Build`: `npm` `run` `build`
|
|
141
|
-
- Serve `Start`: `
|
|
169
|
+
- Serve `Start`: `sh` `-c` `exec npm start -- --hostname "$HOST"`
|
|
142
170
|
|
|
143
171
|
## Deslop
|
|
144
172
|
|
package/stacks/pieces/nodejs.md
CHANGED
|
@@ -41,6 +41,17 @@ Node.js package, command, module, dependency, and test conventions.
|
|
|
41
41
|
`package.json` and `package-lock.json` stay unchanged; Verify resolves each
|
|
42
42
|
package from the application root and fails unless it resolves to its
|
|
43
43
|
connected source root. An ordinary `npm ci` restores the published packages.
|
|
44
|
+
- Publishing a library to npm: the host-owned `## Packaging` section declares
|
|
45
|
+
the package (`npm` packer, its Workdir, `Version from: package.json`) only
|
|
46
|
+
when a publishing target is added; the host builds with `npm pack` from the
|
|
47
|
+
saved commit and owns tags, credentials and uploads. Keep `name`, `version`,
|
|
48
|
+
`license`, `files` (or `.npmignore`) and an `exports`/`main` entry correct in
|
|
49
|
+
`package.json`; never commit tarballs, tokens or `.npmrc` credentials, and
|
|
50
|
+
remove `"private": true` only for a package that is really published. A
|
|
51
|
+
build step before packing (TypeScript, bundling) is a declared Build command
|
|
52
|
+
such as `npm run build`, not a `prepublishOnly` script. A project using
|
|
53
|
+
Changesets or release-please keeps that tool and declares
|
|
54
|
+
`Version from: external`.
|
|
44
55
|
- Long-running web processes accept their listen host and port from arguments
|
|
45
56
|
or the environment rather than hard-coding them, and fail if the port is
|
|
46
57
|
taken instead of silently choosing another. For Express or Next.js select
|
package/stacks/pieces/python.md
CHANGED
|
@@ -42,6 +42,21 @@ Python package, module, callable, dependency, and test conventions.
|
|
|
42
42
|
PEP 610 `direct_url.json` is editable with the source root's `file:` URL and
|
|
43
43
|
that its modules import from there. Do not use `uv sync`, which needs tracked
|
|
44
44
|
`[tool.uv.sources]` and lockfile changes.
|
|
45
|
+
- Publishing a library to PyPI: the host-owned `## Packaging` section declares
|
|
46
|
+
the package (`python-dist` packer, `Runtimes: python`, its `dist` Output,
|
|
47
|
+
`Version from: pyproject.toml`) only when a publishing target is added; the
|
|
48
|
+
host builds the sdist and wheel from the saved commit and owns tags,
|
|
49
|
+
credentials and uploads. The build runs in a clean copy where `build` is
|
|
50
|
+
not installed, and managed Pythons refuse a bare `pip install` (PEP 668), so
|
|
51
|
+
a plain `python3 -m build` fails. The package installs its own throwaway
|
|
52
|
+
tools: Prepare `python3 -m venv .build-tools`, Prepare
|
|
53
|
+
`.build-tools/bin/python -m pip install --quiet build`, Build
|
|
54
|
+
`.build-tools/bin/python -m build`; add `.build-tools/` to `.gitignore`. Keep a PEP 621
|
|
55
|
+
`[project]` table with a static `version`, `readme`, `license` and
|
|
56
|
+
`requires-python` so `twine check --strict` passes; versions use PEP 440
|
|
57
|
+
(`1.5.0rc1`). Never commit `dist/`, tokens or `.pypirc`. A project with a
|
|
58
|
+
dynamic version (setuptools-scm, hatch-vcs) declares
|
|
59
|
+
`Version from: external`.
|
|
45
60
|
- Running a web process: bind the supplied listen host and port, trust forwarded
|
|
46
61
|
headers only from a loopback proxy, and read secrets from the environment.
|
|
47
62
|
For Django select `django`; its piece owns the framework traps. Flask uses
|
|
@@ -39,7 +39,10 @@ Rails MySQL connection, Active Record migration, and database environment conven
|
|
|
39
39
|
"allowEmpty": ["password"],
|
|
40
40
|
"preferred": true
|
|
41
41
|
}
|
|
42
|
-
]
|
|
42
|
+
],
|
|
43
|
+
"optionalBindings": {
|
|
44
|
+
"testDatabase": "TEST_DB_NAME"
|
|
45
|
+
}
|
|
43
46
|
}
|
|
44
47
|
```
|
|
45
48
|
|
|
@@ -51,13 +54,15 @@ Rails MySQL connection, Active Record migration, and database environment conven
|
|
|
51
54
|
`port: <%= ENV.fetch("DB_PORT", 3306) %>`,
|
|
52
55
|
`username: <%= ENV["DB_USERNAME"] %>`, `password: <%= ENV["DB_PASSWORD"] %>`;
|
|
53
56
|
and `database: <%= ENV["DB_DATABASE"] %>` for development and the
|
|
54
|
-
production primary.
|
|
57
|
+
production primary. Point `test` at
|
|
58
|
+
`<%= ENV.fetch("TEST_DB_NAME", "<app>_test") %>`, never at the development
|
|
59
|
+
or production database.
|
|
55
60
|
- Keep `encoding: utf8mb4`. `mysql2` compiles against the MySQL client
|
|
56
61
|
library; `trilogy` (Rails 7.1+) is pure Ruby and avoids it. Do not switch an
|
|
57
62
|
existing app's adapter without testing it.
|
|
58
|
-
- `bin/rails test` purges
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
- `bin/rails test` purges the test database whenever its schema is out of
|
|
64
|
+
date by dropping and recreating it, so the user needs `CREATE` and `DROP`
|
|
65
|
+
on that database name even when `TEST_DB_NAME` names it.
|
|
61
66
|
- Rails 8 production declares separate `cache`, `queue` and `cable`
|
|
62
67
|
databases. When only one database is supplied, follow the Solid Cache, Solid
|
|
63
68
|
Queue and Solid Cable single-database instructions (their schemas become
|
|
@@ -39,7 +39,10 @@ Rails PostgreSQL connection, Active Record migration, and database environment c
|
|
|
39
39
|
"allowEmpty": ["password"],
|
|
40
40
|
"preferred": true
|
|
41
41
|
}
|
|
42
|
-
]
|
|
42
|
+
],
|
|
43
|
+
"optionalBindings": {
|
|
44
|
+
"testDatabase": "TEST_DB_NAME"
|
|
45
|
+
}
|
|
43
46
|
}
|
|
44
47
|
```
|
|
45
48
|
|
|
@@ -51,9 +54,18 @@ Rails PostgreSQL connection, Active Record migration, and database environment c
|
|
|
51
54
|
`port: <%= ENV.fetch("DB_PORT", 5432) %>`,
|
|
52
55
|
`username: <%= ENV["DB_USERNAME"] %>`, `password: <%= ENV["DB_PASSWORD"] %>`;
|
|
53
56
|
and `database: <%= ENV["DB_DATABASE"] %>` for development and the
|
|
54
|
-
production primary.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
production primary. Point `test` at
|
|
58
|
+
`<%= ENV.fetch("TEST_DB_NAME", "<app>_test") %>`, never at the development
|
|
59
|
+
or production database.
|
|
60
|
+
- `bin/rails test` purges the test database whenever its schema is out of
|
|
61
|
+
date by dropping and recreating it, so the role needs `CREATEDB` (and must
|
|
62
|
+
own the database) even when `TEST_DB_NAME` names it.
|
|
63
|
+
- After loading fixtures, Rails checks their foreign keys
|
|
64
|
+
(`verify_foreign_keys_for_fixtures`, on by default) by updating
|
|
65
|
+
`pg_catalog.pg_constraint`, which only a superuser may do. With an ordinary
|
|
66
|
+
`CREATEDB` role every fixture test fails with `permission denied for table
|
|
67
|
+
pg_constraint`; set `config.active_record.verify_foreign_keys_for_fixtures =
|
|
68
|
+
false` in `config/environments/test.rb` rather than granting superuser.
|
|
57
69
|
- Rails 8 production declares separate `cache`, `queue` and `cable`
|
|
58
70
|
databases. When only one database is supplied, follow the Solid Cache, Solid
|
|
59
71
|
Queue and Solid Cable single-database instructions (their schemas become
|
package/stacks/pieces/rails.md
CHANGED
|
@@ -44,6 +44,11 @@ Authoritative framework documentation: https://guides.rubyonrails.org/
|
|
|
44
44
|
same way: allow the observed development origin in
|
|
45
45
|
`config.action_cable.allowed_request_origins` rather than disabling its
|
|
46
46
|
forgery protection.
|
|
47
|
+
- Rails sends `X-Frame-Options: SAMEORIGIN`, so a host that shows development
|
|
48
|
+
pages inside a frame on another origin gets a blank frame. Only in
|
|
49
|
+
`development.rb`, drop it with
|
|
50
|
+
`config.action_dispatch.default_headers.delete("X-Frame-Options")`;
|
|
51
|
+
production keeps the header.
|
|
47
52
|
- Secrets: development uses `tmp/local_secret.txt`. Production needs
|
|
48
53
|
`SECRET_KEY_BASE` (generate with `bin/rails secret`) or `RAILS_MASTER_KEY`
|
|
49
54
|
for `config/credentials.yml.enc`, supplied through the deployment
|
|
@@ -55,13 +60,19 @@ Authoritative framework documentation: https://guides.rubyonrails.org/
|
|
|
55
60
|
Ask for the key or move the needed values to environment variables.
|
|
56
61
|
- `bin/rails db:prepare` creates the database, loads the schema and runs
|
|
57
62
|
`db/seeds.rb` when it is new, and migrates it otherwise, so repeated setup is
|
|
58
|
-
safe.
|
|
63
|
+
safe. It seeds only a database without a `schema_migrations` table: one that
|
|
64
|
+
already has it (a development server's pending-migration check creates it on
|
|
65
|
+
the first request) is only migrated, so setup also runs `bin/rails db:seed`.
|
|
66
|
+
Seeds must therefore be idempotent (`find_or_create_by!`) and guard
|
|
67
|
+
development-only records with `Rails.env.development?`. In development every
|
|
68
|
+
request, including `/up`, fails with a pending-migration error until
|
|
69
|
+
`db:prepare` has run against the supplied database. Commit generated
|
|
59
70
|
migrations and `db/schema.rb`; never run `db:reset`, `db:setup`,
|
|
60
71
|
`db:schema:load`, `db:drop` or edit an applied migration as routine setup.
|
|
61
72
|
- `DATABASE_URL` overrides the connection of every environment, including
|
|
62
73
|
`test`. Keep it unset where tests run, and point `test` in
|
|
63
|
-
`config/database.yml` at its own disposable database (
|
|
64
|
-
test database
|
|
74
|
+
`config/database.yml` at its own disposable database (the database
|
|
75
|
+
integration's test database binding when it is supplied), never at the
|
|
65
76
|
development or production database. `bin/rails test` recreates the test
|
|
66
77
|
schema.
|
|
67
78
|
- Mode is set per environment: `RAILS_ENV=production` belongs in the
|
|
@@ -78,9 +89,18 @@ Authoritative framework documentation: https://guides.rubyonrails.org/
|
|
|
78
89
|
a precompiled gem. Dependency installation therefore also uses `cpp`.
|
|
79
90
|
`trilogy` avoids the MySQL client library. A `Gemfile.lock` resolved only on
|
|
80
91
|
another platform needs `bundle lock --add-platform x86_64-linux` (or the
|
|
81
|
-
deployment platform) before frozen deployment installs.
|
|
82
|
-
|
|
83
|
-
|
|
92
|
+
deployment platform) before frozen deployment installs. `rails new` also
|
|
93
|
+
adds `image_processing`, which needs the libvips library for Active Storage
|
|
94
|
+
variants: provide libvips where variants are used, or remove the gem.
|
|
95
|
+
- Install gems into the project's `vendor/bundle` (the proposed Prepare sets
|
|
96
|
+
`bundle config set --local path vendor/bundle`), as deployment does: the
|
|
97
|
+
Ruby installation's own gem directory is often read-only (a system or
|
|
98
|
+
packaged Ruby), and `bundle install` then fails with
|
|
99
|
+
`Bundler::PermissionError`. Keep `/vendor/bundle` and `/.bundle` in
|
|
100
|
+
`.gitignore`.
|
|
101
|
+
- Production: `bin/rails server -e production` reads `PORT` but not `HOST`;
|
|
102
|
+
pass the supplied host with `-b`, as the proposed Serve does. Rails 7.1+
|
|
103
|
+
generates `force_ssl` and Rails 8 also `assume_ssl`; with `force_ssl` but no
|
|
84
104
|
`assume_ssl`, exclude `/up` from the redirect:
|
|
85
105
|
`config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } }`.
|
|
86
106
|
Rails 8 runs Solid Queue jobs inside Puma only with `SOLID_QUEUE_IN_PUMA=1`
|
|
@@ -89,12 +109,17 @@ Authoritative framework documentation: https://guides.rubyonrails.org/
|
|
|
89
109
|
Older apps add an equivalent route and update the Outputs and Deployment
|
|
90
110
|
readiness.
|
|
91
111
|
- Login: Rails 8 `bin/rails generate authentication`, Devise or the app's own
|
|
92
|
-
`has_secure_password`.
|
|
112
|
+
`has_secure_password`. Controllers generated after authentication require a
|
|
113
|
+
signed-in user, so their tests sign in first (`sign_in_as(users(:one))` from
|
|
114
|
+
the generated session test helper). Seed one administrator (an `admin` boolean or role)
|
|
93
115
|
and one ordinary user idempotently in `db/seeds.rb` for development only,
|
|
94
116
|
with passwords from the environment; never seed production credentials.
|
|
95
117
|
- The JavaScript dependency step assumes npm. A `yarn.lock` or `bun.lockb`
|
|
96
118
|
means that line uses the matching tool; importmap apps have no
|
|
97
|
-
`package.json` and skip it.
|
|
119
|
+
`package.json` and skip it. The proposed Deployment assumes importmap: with
|
|
120
|
+
`jsbundling-rails`, `cssbundling-rails` or another `package.json` build, add
|
|
121
|
+
`nodejs` to its Runtimes and a Prepare `npm ci` step before
|
|
122
|
+
`assets:precompile`.
|
|
98
123
|
|
|
99
124
|
## Adoption
|
|
100
125
|
|
|
@@ -114,9 +139,11 @@ Authoritative framework documentation: https://guides.rubyonrails.org/
|
|
|
114
139
|
|
|
115
140
|
## Workspace setup
|
|
116
141
|
|
|
142
|
+
- Prepare `Keep gems inside the project` with `ruby` when `Gemfile` exists: `bundle` `config` `set` `--local` `path` `vendor/bundle`
|
|
117
143
|
- Prepare `Install Ruby dependencies` with `ruby` `cpp` when `Gemfile` exists: `bundle` `install`
|
|
118
144
|
- Prepare `Install JavaScript dependencies` with `nodejs` if `package.json` exists: `npm` `install`
|
|
119
145
|
- Prepare `Prepare database` with `ruby` when `bin/rails` exists: `bin/rails` `db:prepare`
|
|
146
|
+
- Prepare `Seed development data` with `ruby` when `bin/rails` exists: `bin/rails` `db:seed`
|
|
120
147
|
|
|
121
148
|
## Outputs
|
|
122
149
|
|
|
@@ -148,7 +175,7 @@ Authoritative framework documentation: https://guides.rubyonrails.org/
|
|
|
148
175
|
- Prepare `Install Ruby dependencies`: `bundle` `install`
|
|
149
176
|
- Build `Precompile assets`: `bin/rails` `assets:precompile` `RAILS_ENV=production`
|
|
150
177
|
- Migrate `Prepare database`: `bin/rails` `db:prepare` `RAILS_ENV=production`
|
|
151
|
-
- Serve `Start`: `bin/rails
|
|
178
|
+
- Serve `Start`: `sh` `-c` `exec bin/rails server -e production -b "$HOST" -p "$PORT"`
|
|
152
179
|
|
|
153
180
|
## Deslop
|
|
154
181
|
|
|
@@ -48,6 +48,12 @@ https://docs.spring.io/spring-boot/
|
|
|
48
48
|
such a proxy. A proxy may present same-origin requests with an `Origin`
|
|
49
49
|
rewritten to the loopback address; keep CORS configuration for genuine
|
|
50
50
|
cross-origin clients rather than comparing `Origin` with the request host.
|
|
51
|
+
- Spring Security answers `X-Frame-Options: DENY`, so a development tool that
|
|
52
|
+
shows the application inside a frame stays blank. When that is needed,
|
|
53
|
+
disable frame options only through a property set in the `dev` profile
|
|
54
|
+
(for example `app.allow-framing=true`, read by the security configuration
|
|
55
|
+
before `http.headers(h -> h.frameOptions(f -> f.disable()))`); production
|
|
56
|
+
keeps `DENY`.
|
|
51
57
|
- Add `spring-boot-starter-actuator`, expose
|
|
52
58
|
`management.endpoints.web.exposure.include=health`, and let Spring Security
|
|
53
59
|
`permitAll` `/actuator/health`; the proposed readiness checks use it. Its
|
package/stacks/pieces/sqlite.md
CHANGED
|
@@ -21,6 +21,12 @@ SQLite file-backed persistence, migrations, and backup conventions.
|
|
|
21
21
|
persistent database filename through the `database` resource semantic and
|
|
22
22
|
the environment name the application actually reads. A driver selector such
|
|
23
23
|
as `DB_CONNECTION=sqlite` is configuration, not a database filename.
|
|
24
|
+
- When no framework database component declares that resource (an Express,
|
|
25
|
+
Next.js or plain Node.js app, for example), the project Stack declares it
|
|
26
|
+
under `## Resources` as one fenced `json genesis-resource` block, such as
|
|
27
|
+
`{"id": "database", "kind": "sqlite", "environmentAlternatives": [{"bindings": {"database": "DB_DATABASE"}, "preferred": true}]}`.
|
|
28
|
+
The application opens the filename in that variable; a gitignored
|
|
29
|
+
repository-relative file is only a fallback for a checkout without it.
|
|
24
30
|
- Keep durable database files outside disposable build and release directories.
|
|
25
31
|
A host may supply a persistent filename; do not replace that value with a
|
|
26
32
|
repository-relative default or recreate an existing database during setup.
|