genesis-stack 1.2.1 → 1.3.1
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 +15 -3
- package/package.json +1 -1
- package/stacks/pieces/django-mysql.md +79 -0
- package/stacks/pieces/django-postgresql.md +78 -0
- package/stacks/pieces/django-sqlite.md +55 -0
- package/stacks/pieces/django.md +166 -0
- package/stacks/pieces/express.md +143 -0
- package/stacks/pieces/java.md +1 -2
- package/stacks/pieces/laravel.md +16 -1
- package/stacks/pieces/nextjs.md +153 -0
- package/stacks/pieces/nodejs.md +2 -1
- package/stacks/pieces/python.md +3 -5
- package/stacks/pieces/rails-mysql.md +76 -0
- package/stacks/pieces/rails-postgresql.md +74 -0
- package/stacks/pieces/rails-sqlite.md +60 -0
- package/stacks/pieces/rails.md +161 -0
- package/stacks/pieces/ruby.md +1 -4
- package/stacks/pieces/spring-boot-mysql.md +74 -0
- package/stacks/pieces/spring-boot-postgresql.md +68 -0
- package/stacks/pieces/spring-boot.md +148 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Stack piece: nextjs
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Next.js React application conventions: App Router or Pages Router, the
|
|
6
|
+
`next` CLI, Server Actions, middleware, environment variables, builds and
|
|
7
|
+
production serving. A Next.js application has `next` in `package.json`
|
|
8
|
+
dependencies and usually a `next.config.js`, `next.config.mjs` or
|
|
9
|
+
`next.config.ts` file and an `app/` or `pages/` directory. Authoritative
|
|
10
|
+
framework documentation: https://nextjs.org/docs
|
|
11
|
+
|
|
12
|
+
## Requires
|
|
13
|
+
|
|
14
|
+
- `nodejs`
|
|
15
|
+
|
|
16
|
+
## Conflicts
|
|
17
|
+
|
|
18
|
+
- `express`
|
|
19
|
+
|
|
20
|
+
## Guidance
|
|
21
|
+
|
|
22
|
+
- Match the installed Next.js major version and the router the application
|
|
23
|
+
already uses (`app/` App Router or `pages/` Pages Router). Recent releases
|
|
24
|
+
ship version-matched documentation in `node_modules/next/dist/docs/`; read
|
|
25
|
+
the relevant guide there before relying on remembered APIs. `next dev` may
|
|
26
|
+
write a framework-owned agent-rules block into `AGENTS.md`; commit it rather
|
|
27
|
+
than repeatedly removing it.
|
|
28
|
+
- Bind the development server to the host and port it is given:
|
|
29
|
+
`next dev --hostname <host> --port <port>` (the proposed Run passes them
|
|
30
|
+
through `npm run dev --`). Without `--hostname`, `next dev` and `next start`
|
|
31
|
+
listen on every interface. Never hard-code a port in `package.json` scripts.
|
|
32
|
+
- Behind a development reverse proxy on loopback that rewrites `Host` and sends
|
|
33
|
+
`X-Forwarded-Host`, `X-Forwarded-Proto` and `X-Forwarded-Port`, Next.js
|
|
34
|
+
builds request URLs from the forwarded headers. The development server blocks
|
|
35
|
+
requests for its own development resources (the `/_next/hmr` WebSocket and
|
|
36
|
+
other `/_next/*` dev endpoints) whose `Origin` hostname is not `localhost`,
|
|
37
|
+
the hostname it was started with, or an `allowedDevOrigins` entry. A proxy
|
|
38
|
+
that rewrites the browser's `Origin` to the loopback address needs no entry;
|
|
39
|
+
otherwise add the browser-facing hostname pattern to `allowedDevOrigins`,
|
|
40
|
+
read from an environment variable rather than hard-coded. The HMR client
|
|
41
|
+
connects through the page's own origin; do not hard-code an asset prefix or
|
|
42
|
+
WebSocket host for the proxy.
|
|
43
|
+
- Server Actions reject a POST whose `Origin` host differs from
|
|
44
|
+
`X-Forwarded-Host` (or `Host` without it) with "Invalid Server Actions
|
|
45
|
+
request". When a development proxy rewrites `Origin` to the loopback address
|
|
46
|
+
while forwarding the browser host, admit exactly that loopback host in
|
|
47
|
+
`experimental.serverActions.allowedOrigins` in development only, for example
|
|
48
|
+
`` process.env.NODE_ENV === "development" && process.env.PORT ? [`127.0.0.1:${process.env.PORT}`] : [] ``
|
|
49
|
+
(ports cannot be wildcarded). The list also applies in production; never
|
|
50
|
+
admit arbitrary origins there.
|
|
51
|
+
- `NEXT_PUBLIC_*` variables are inlined into client bundles at build time:
|
|
52
|
+
never put secrets in them, and their production values must exist when
|
|
53
|
+
`next build` runs, not only at start. Server-only values are read from
|
|
54
|
+
`process.env` at request time. Next.js reads `.env*` files but the
|
|
55
|
+
environment wins; keep real values out of committed `.env*` files.
|
|
56
|
+
- With Auth.js (`next-auth` v5), supply `AUTH_SECRET` through the environment
|
|
57
|
+
(generate with `openssl rand -base64 33`; `npx auth secret` writes it into a
|
|
58
|
+
file instead) and set `AUTH_TRUST_HOST=true` when the app is served behind a
|
|
59
|
+
trusted reverse proxy, so callback and redirect URLs use the forwarded
|
|
60
|
+
origin. Other auth libraries need their equivalent trusted-host setting.
|
|
61
|
+
- Readiness and health probes must reach a public route: middleware (or
|
|
62
|
+
`proxy`) that redirects `/` to a login page makes a `GET /` probe fail.
|
|
63
|
+
Exclude the probe path from the auth matcher, or add a small public route
|
|
64
|
+
handler (for example `app/health/route.ts`) and point the Outputs and
|
|
65
|
+
Deployment readiness checks at it.
|
|
66
|
+
- Database access goes through the application's ORM (Prisma, Drizzle, Kysely
|
|
67
|
+
or another). Its schema migrations are application-owned: deployment runs the
|
|
68
|
+
non-interactive apply command (for example `prisma migrate deploy`), never
|
|
69
|
+
`prisma migrate dev` or `prisma db push` against supplied data. Seed scripts
|
|
70
|
+
must be idempotent. Tests use a disposable database supplied for them, never
|
|
71
|
+
the development or production database. Declare the database Resources in
|
|
72
|
+
the project Stack; this piece does not choose a database.
|
|
73
|
+
- Production: `next build` then `next start`. `next start` reads `PORT` but not
|
|
74
|
+
`HOST`; bind it explicitly (`next start --hostname <host>`), as the proposed
|
|
75
|
+
Serve does. Set `NODE_ENV=production` only through the production
|
|
76
|
+
environment, never as a project-wide default; `next build` and `next start`
|
|
77
|
+
set it themselves. `output: "standalone"` changes the start command to
|
|
78
|
+
`node .next/standalone/server.js` (which reads `HOSTNAME` and `PORT`) and
|
|
79
|
+
requires copying `public/` and `.next/static/`; update Deployment if the
|
|
80
|
+
application uses it. `output: "export"` produces static files with no server.
|
|
81
|
+
- Do not run `next build` into the same `.next` directory a running `next dev`
|
|
82
|
+
uses unless the installed major isolates development output (Next.js 16 and
|
|
83
|
+
later write development output to `.next/dev`); with older majors stop the
|
|
84
|
+
development server first or build into a separate `distDir`.
|
|
85
|
+
- When the application has login, seed one administrator and one ordinary user
|
|
86
|
+
for development through an idempotent seed script with credentials from the
|
|
87
|
+
environment, and keep role checks on the server (Server Components, route
|
|
88
|
+
handlers, Server Actions), not only in client components.
|
|
89
|
+
|
|
90
|
+
## Adoption
|
|
91
|
+
|
|
92
|
+
- Inventory the real files before changing project contracts: the installed
|
|
93
|
+
`next` version in the lockfile, `app/` or `pages/`, `next.config.*` (`output`,
|
|
94
|
+
`basePath`, `distDir`, `experimental`), `middleware.*`/`proxy.*`, the auth
|
|
95
|
+
library and its environment names, the ORM and its migration commands, and
|
|
96
|
+
the real `dev`, `build`, `start`, `lint` and `test` scripts.
|
|
97
|
+
- Identify the package manager from the lockfile and replace every proposed
|
|
98
|
+
`npm` line when the project uses pnpm, Yarn or Bun. Next.js 16 removed
|
|
99
|
+
`next lint`; if the `lint` script is missing, remove that Verification line
|
|
100
|
+
instead of inventing one, and add the project's real test command when it
|
|
101
|
+
has one.
|
|
102
|
+
- Replace the readiness path when `/` is not publicly reachable, a `basePath`
|
|
103
|
+
is set, or a dedicated health route exists. Replace the Serve line for
|
|
104
|
+
`output: "standalone"`, a custom server, or `output: "export"`.
|
|
105
|
+
- A custom Next.js server built on Express is a project-owned decision: keep
|
|
106
|
+
this piece and describe that server's real commands in the project's own
|
|
107
|
+
sections.
|
|
108
|
+
|
|
109
|
+
## Workspace setup
|
|
110
|
+
|
|
111
|
+
- Prepare `Install dependencies` with `nodejs` when `package.json` exists: `npm` `install`
|
|
112
|
+
|
|
113
|
+
## Outputs
|
|
114
|
+
|
|
115
|
+
### Target `app`: Run Next.js app
|
|
116
|
+
|
|
117
|
+
- Default.
|
|
118
|
+
- Mode: `interactive`
|
|
119
|
+
- Runtimes: `nodejs`
|
|
120
|
+
- Run `Develop`: `npm` `run` `dev` `--` `--hostname` `{host}` `--port` `{port}`
|
|
121
|
+
|
|
122
|
+
#### Presentation
|
|
123
|
+
|
|
124
|
+
- Kind: `web`
|
|
125
|
+
- Preferred port: `3000`
|
|
126
|
+
- URL path: `/`
|
|
127
|
+
- Ready when: `GET` `/` returns `200`
|
|
128
|
+
|
|
129
|
+
## Verification
|
|
130
|
+
|
|
131
|
+
- Verify `lint`: `npm` `run` `lint`
|
|
132
|
+
- Verify `build`: `npm` `run` `build`
|
|
133
|
+
|
|
134
|
+
## Deployment
|
|
135
|
+
|
|
136
|
+
- Runtimes: `nodejs`
|
|
137
|
+
- Recreate on restore: `node_modules` `.next/cache`
|
|
138
|
+
- Ready when: `GET` `/` returns `200`
|
|
139
|
+
- Prepare `Install dependencies`: `npm` `ci`
|
|
140
|
+
- Build `Build`: `npm` `run` `build`
|
|
141
|
+
- Serve `Start`: `npm` `start` `--` `--hostname` `127.0.0.1`
|
|
142
|
+
|
|
143
|
+
## Deslop
|
|
144
|
+
|
|
145
|
+
- Keep data fetching in Server Components, route handlers and Server Actions
|
|
146
|
+
where the router supports it; remove client-side fetch wrappers that only
|
|
147
|
+
duplicate a server read.
|
|
148
|
+
- Keep `"use client"` boundaries as low in the tree as possible and do not mark
|
|
149
|
+
whole layouts as client components to reach one interactive widget.
|
|
150
|
+
- Use the framework's `Link`, `Image`, `Script`, metadata and font facilities
|
|
151
|
+
instead of hand-written equivalents.
|
|
152
|
+
- Remove abandoned starter content, unused route segments and duplicate
|
|
153
|
+
environment readers only when routes, redirects and tests stay unchanged.
|
package/stacks/pieces/nodejs.md
CHANGED
|
@@ -43,7 +43,8 @@ Node.js package, command, module, dependency, and test conventions.
|
|
|
43
43
|
connected source root. An ordinary `npm ci` restores the published packages.
|
|
44
44
|
- Long-running web processes accept their listen host and port from arguments
|
|
45
45
|
or the environment rather than hard-coding them, and fail if the port is
|
|
46
|
-
taken instead of silently choosing another.
|
|
46
|
+
taken instead of silently choosing another. For Express or Next.js select
|
|
47
|
+
`express` or `nextjs`; that piece owns the framework traps.
|
|
47
48
|
|
|
48
49
|
## Adoption
|
|
49
50
|
|
package/stacks/pieces/python.md
CHANGED
|
@@ -44,11 +44,9 @@ Python package, module, callable, dependency, and test conventions.
|
|
|
44
44
|
`[tool.uv.sources]` and lockfile changes.
|
|
45
45
|
- Running a web process: bind the supplied listen host and port, trust forwarded
|
|
46
46
|
headers only from a loopback proxy, and read secrets from the environment.
|
|
47
|
-
Django
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
proxy, and read `SECRET_KEY` from the environment. Flask uses Werkzeug's
|
|
51
|
-
`ProxyFix`; Uvicorn uses `--proxy-headers --forwarded-allow-ips 127.0.0.1`.
|
|
47
|
+
For Django select `django`; its piece owns the framework traps. Flask uses
|
|
48
|
+
Werkzeug's `ProxyFix`; Uvicorn uses `--proxy-headers --forwarded-allow-ips
|
|
49
|
+
127.0.0.1`.
|
|
52
50
|
|
|
53
51
|
## Connected development
|
|
54
52
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Stack piece: rails-mysql
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Rails MySQL connection, Active Record migration, and database environment conventions.
|
|
6
|
+
|
|
7
|
+
## Requires
|
|
8
|
+
|
|
9
|
+
- `rails`
|
|
10
|
+
- `mysql`
|
|
11
|
+
|
|
12
|
+
## Conflicts
|
|
13
|
+
|
|
14
|
+
- `rails-postgresql`
|
|
15
|
+
- `rails-sqlite`
|
|
16
|
+
|
|
17
|
+
## Environment defaults
|
|
18
|
+
|
|
19
|
+
- Default `DB_HOST`: `127.0.0.1`
|
|
20
|
+
- Default `DB_PORT`: `3306`
|
|
21
|
+
- Default `DB_DATABASE`: `rails`
|
|
22
|
+
- Default `DB_USERNAME`: `root`
|
|
23
|
+
|
|
24
|
+
## Resources
|
|
25
|
+
|
|
26
|
+
```json genesis-resource
|
|
27
|
+
{
|
|
28
|
+
"id": "database",
|
|
29
|
+
"kind": "mysql",
|
|
30
|
+
"environmentAlternatives": [
|
|
31
|
+
{
|
|
32
|
+
"bindings": {
|
|
33
|
+
"database": "DB_DATABASE",
|
|
34
|
+
"host": "DB_HOST",
|
|
35
|
+
"password": "DB_PASSWORD",
|
|
36
|
+
"port": "DB_PORT",
|
|
37
|
+
"username": "DB_USERNAME"
|
|
38
|
+
},
|
|
39
|
+
"allowEmpty": ["password"],
|
|
40
|
+
"preferred": true
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Guidance
|
|
47
|
+
|
|
48
|
+
- `rails new -d mysql` (adapter `mysql2`) or `-d trilogy` hard-codes database
|
|
49
|
+
names. Make `config/database.yml` read the resource names: under `default`,
|
|
50
|
+
`host: <%= ENV.fetch("DB_HOST", "127.0.0.1") %>`,
|
|
51
|
+
`port: <%= ENV.fetch("DB_PORT", 3306) %>`,
|
|
52
|
+
`username: <%= ENV["DB_USERNAME"] %>`, `password: <%= ENV["DB_PASSWORD"] %>`;
|
|
53
|
+
and `database: <%= ENV["DB_DATABASE"] %>` for development and the
|
|
54
|
+
production primary. Keep `test` on its own disposable database name.
|
|
55
|
+
- Keep `encoding: utf8mb4`. `mysql2` compiles against the MySQL client
|
|
56
|
+
library; `trilogy` (Rails 7.1+) is pure Ruby and avoids it. Do not switch an
|
|
57
|
+
existing app's adapter without testing it.
|
|
58
|
+
- `bin/rails test` purges and recreates the test database, which needs
|
|
59
|
+
`CREATE`/`DROP` privileges unless the test database is supplied and
|
|
60
|
+
disposable.
|
|
61
|
+
- Rails 8 production declares separate `cache`, `queue` and `cable`
|
|
62
|
+
databases. When only one database is supplied, follow the Solid Cache, Solid
|
|
63
|
+
Queue and Solid Cable single-database instructions (their schemas become
|
|
64
|
+
ordinary migrations and their `connects_to` settings are removed) instead of
|
|
65
|
+
inventing extra database names.
|
|
66
|
+
- Use the inherited Rails migration and seed guidance. Keep connection,
|
|
67
|
+
integration and payment records in this database through Active Record
|
|
68
|
+
migrations and transactions; test uniqueness and concurrent updates on MySQL
|
|
69
|
+
itself.
|
|
70
|
+
|
|
71
|
+
## Adoption
|
|
72
|
+
|
|
73
|
+
- Confirm the adapter, every environment's database, username, password, host
|
|
74
|
+
and port expressions in `config/database.yml`, and whether `DATABASE_URL` is
|
|
75
|
+
read, before declaring readiness or connecting. Align the project Resource
|
|
76
|
+
bindings with the names the file actually reads.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Stack piece: rails-postgresql
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Rails PostgreSQL connection, Active Record migration, and database environment conventions.
|
|
6
|
+
|
|
7
|
+
## Requires
|
|
8
|
+
|
|
9
|
+
- `rails`
|
|
10
|
+
- `postgresql`
|
|
11
|
+
|
|
12
|
+
## Conflicts
|
|
13
|
+
|
|
14
|
+
- `rails-mysql`
|
|
15
|
+
- `rails-sqlite`
|
|
16
|
+
|
|
17
|
+
## Environment defaults
|
|
18
|
+
|
|
19
|
+
- Default `DB_HOST`: `127.0.0.1`
|
|
20
|
+
- Default `DB_PORT`: `5432`
|
|
21
|
+
- Default `DB_DATABASE`: `rails`
|
|
22
|
+
- Default `DB_USERNAME`: `postgres`
|
|
23
|
+
|
|
24
|
+
## Resources
|
|
25
|
+
|
|
26
|
+
```json genesis-resource
|
|
27
|
+
{
|
|
28
|
+
"id": "database",
|
|
29
|
+
"kind": "postgresql",
|
|
30
|
+
"environmentAlternatives": [
|
|
31
|
+
{
|
|
32
|
+
"bindings": {
|
|
33
|
+
"database": "DB_DATABASE",
|
|
34
|
+
"host": "DB_HOST",
|
|
35
|
+
"password": "DB_PASSWORD",
|
|
36
|
+
"port": "DB_PORT",
|
|
37
|
+
"username": "DB_USERNAME"
|
|
38
|
+
},
|
|
39
|
+
"allowEmpty": ["password"],
|
|
40
|
+
"preferred": true
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Guidance
|
|
47
|
+
|
|
48
|
+
- `rails new -d postgresql` hard-codes database names and reads only a
|
|
49
|
+
production password variable. Make `config/database.yml` read the resource
|
|
50
|
+
names: under `default`, `host: <%= ENV.fetch("DB_HOST", "127.0.0.1") %>`,
|
|
51
|
+
`port: <%= ENV.fetch("DB_PORT", 5432) %>`,
|
|
52
|
+
`username: <%= ENV["DB_USERNAME"] %>`, `password: <%= ENV["DB_PASSWORD"] %>`;
|
|
53
|
+
and `database: <%= ENV["DB_DATABASE"] %>` for development and the
|
|
54
|
+
production primary. Keep `test` on its own disposable database name.
|
|
55
|
+
- `bin/rails test` purges and recreates the test database, which needs the
|
|
56
|
+
`CREATEDB` privilege unless the test database is supplied and disposable.
|
|
57
|
+
- Rails 8 production declares separate `cache`, `queue` and `cable`
|
|
58
|
+
databases. When only one database is supplied, follow the Solid Cache, Solid
|
|
59
|
+
Queue and Solid Cable single-database instructions (their schemas become
|
|
60
|
+
ordinary migrations and their `connects_to` settings are removed) instead of
|
|
61
|
+
inventing extra database names.
|
|
62
|
+
- The `pg` gem compiles against libpq unless the locked version ships a
|
|
63
|
+
precompiled gem for the platform.
|
|
64
|
+
- Use the inherited Rails migration and seed guidance. Keep connection,
|
|
65
|
+
integration and payment records in this database through Active Record
|
|
66
|
+
migrations and transactions; test uniqueness and concurrent updates on
|
|
67
|
+
PostgreSQL itself.
|
|
68
|
+
|
|
69
|
+
## Adoption
|
|
70
|
+
|
|
71
|
+
- Confirm the adapter, every environment's database, username, password, host
|
|
72
|
+
and port expressions in `config/database.yml`, and whether `DATABASE_URL` is
|
|
73
|
+
read, before declaring readiness or connecting. Align the project Resource
|
|
74
|
+
bindings with the names the file actually reads.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Stack piece: rails-sqlite
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Rails SQLite connection, Active Record migration, and database filename conventions.
|
|
6
|
+
|
|
7
|
+
## Requires
|
|
8
|
+
|
|
9
|
+
- `rails`
|
|
10
|
+
- `sqlite`
|
|
11
|
+
|
|
12
|
+
## Conflicts
|
|
13
|
+
|
|
14
|
+
- `rails-mysql`
|
|
15
|
+
- `rails-postgresql`
|
|
16
|
+
|
|
17
|
+
## Resources
|
|
18
|
+
|
|
19
|
+
```json genesis-resource
|
|
20
|
+
{
|
|
21
|
+
"id": "database",
|
|
22
|
+
"kind": "sqlite",
|
|
23
|
+
"environmentAlternatives": [
|
|
24
|
+
{
|
|
25
|
+
"bindings": {
|
|
26
|
+
"database": "DB_DATABASE"
|
|
27
|
+
},
|
|
28
|
+
"preferred": true
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Guidance
|
|
35
|
+
|
|
36
|
+
- `rails new` (SQLite is the default) writes repository-relative files under
|
|
37
|
+
`storage/`, and Rails 8.1 leaves the production files unset. Make the
|
|
38
|
+
development and production primary read the supplied filename with the
|
|
39
|
+
generated name as fallback, for example
|
|
40
|
+
`database: <%= ENV.fetch("DB_DATABASE", "storage/development.sqlite3") %>`.
|
|
41
|
+
A bare `ENV.fetch("DB_DATABASE")` raises while `database.yml` loads and
|
|
42
|
+
breaks generators and asset builds that run without the variable. Keep `test`
|
|
43
|
+
on its own file such as `storage/test.sqlite3`.
|
|
44
|
+
- Rails 8 production also declares `cache`, `queue` and `cable` SQLite
|
|
45
|
+
databases. Keep them next to the primary file, for example
|
|
46
|
+
`<%= File.join(File.dirname(ENV.fetch("DB_DATABASE", "storage/production.sqlite3")), "production_cache.sqlite3") %>`,
|
|
47
|
+
so they persist with it; never leave them in a disposable release directory.
|
|
48
|
+
- Do not replace a supplied filename with a repository-relative default or
|
|
49
|
+
delete an existing file. `bin/rails db:prepare` creates a missing file and
|
|
50
|
+
its schema and migrates an existing one.
|
|
51
|
+
- The `sqlite3` gem normally installs a precompiled native gem; a source build
|
|
52
|
+
needs the SQLite headers. Use the inherited Rails migration and seed
|
|
53
|
+
guidance and test concurrent writes on SQLite itself.
|
|
54
|
+
|
|
55
|
+
## Adoption
|
|
56
|
+
|
|
57
|
+
- Read `config/database.yml` for every environment's filename, including the
|
|
58
|
+
Rails 8 cache, queue and cable files, and preserve existing data: snapshot
|
|
59
|
+
it before moving to a supplied filename. Do not switch an existing app to an
|
|
60
|
+
empty database.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Stack piece: rails
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Ruby on Rails application, Bundler, Active Record, Action Pack, assets, and
|
|
6
|
+
framework lifecycle conventions. Identified by `Gemfile.lock` listing `rails`,
|
|
7
|
+
`bin/rails`, `config/application.rb`, and `config/database.yml`.
|
|
8
|
+
Authoritative framework documentation: https://guides.rubyonrails.org/
|
|
9
|
+
|
|
10
|
+
## Requires
|
|
11
|
+
|
|
12
|
+
- `ruby`
|
|
13
|
+
|
|
14
|
+
## Guidance
|
|
15
|
+
|
|
16
|
+
- Use the Rails version locked in `Gemfile.lock` and its matching guides and
|
|
17
|
+
API documentation. Preserve Rails conventions (MVC, Active Record, concerns,
|
|
18
|
+
jobs, mailers, generators, `bin/rails` tasks) instead of adding parallel
|
|
19
|
+
framework plumbing.
|
|
20
|
+
- The development server binds the supplied host and port:
|
|
21
|
+
`bin/rails server -b <host> -p <port>`. Without `-p` Rails reads `PORT`;
|
|
22
|
+
it never reads `HOST` (only `BINDING`, and production defaults to
|
|
23
|
+
`0.0.0.0`), so pass `-b` explicitly. A server reachable only on loopback
|
|
24
|
+
is what makes trusting proxy headers safe.
|
|
25
|
+
- Behind a loopback development reverse proxy that rewrites `Host` and sends
|
|
26
|
+
`X-Forwarded-Host`, `X-Forwarded-Proto` and `X-Forwarded-Port`, Rails derives
|
|
27
|
+
`request.host`, `request.base_url` and generated URLs from those headers
|
|
28
|
+
natively (loopback is a trusted proxy by default). Do not hard-code
|
|
29
|
+
`default_url_options` hosts for development.
|
|
30
|
+
- Host authorization then sees the browser-facing host and answers "Blocked
|
|
31
|
+
hosts". In development, list that host (or `.parent.domain`) in
|
|
32
|
+
`RAILS_DEVELOPMENT_HOSTS`, or, when the server binds only loopback, add
|
|
33
|
+
`config.hosts.clear` to `config/environments/development.rb` only. In
|
|
34
|
+
production set `config.hosts` explicitly from the environment and exclude the
|
|
35
|
+
health route:
|
|
36
|
+
`config.host_authorization = { exclude: ->(request) { request.path == "/up" } }`.
|
|
37
|
+
- CSRF compares the `Origin` header with `request.base_url`. Some development
|
|
38
|
+
proxies rewrite a same-origin `Origin` to the upstream loopback address while
|
|
39
|
+
forwarding the browser host; form posts then fail with "HTTP Origin header
|
|
40
|
+
... didn't match request.base_url". Only in that case, and only in
|
|
41
|
+
`development.rb`, set
|
|
42
|
+
`config.action_controller.forgery_protection_origin_check = false`; the
|
|
43
|
+
authenticity token still protects forms. Action Cable compares origins the
|
|
44
|
+
same way: allow the observed development origin in
|
|
45
|
+
`config.action_cable.allowed_request_origins` rather than disabling its
|
|
46
|
+
forgery protection.
|
|
47
|
+
- Secrets: development uses `tmp/local_secret.txt`. Production needs
|
|
48
|
+
`SECRET_KEY_BASE` (generate with `bin/rails secret`) or `RAILS_MASTER_KEY`
|
|
49
|
+
for `config/credentials.yml.enc`, supplied through the deployment
|
|
50
|
+
environment, never committed. `assets:precompile` in production also aborts
|
|
51
|
+
without it; a build that must not see the real secret can use
|
|
52
|
+
`SECRET_KEY_BASE_DUMMY=1`. When an
|
|
53
|
+
imported app lacks `config/master.key`, never run `bin/rails credentials:edit`
|
|
54
|
+
or delete the encrypted file to "fix" it: that destroys the existing values.
|
|
55
|
+
Ask for the key or move the needed values to environment variables.
|
|
56
|
+
- `bin/rails db:prepare` creates the database, loads the schema and runs
|
|
57
|
+
`db/seeds.rb` when it is new, and migrates it otherwise, so repeated setup is
|
|
58
|
+
safe. Seeds must be idempotent (`find_or_create_by!`). Commit generated
|
|
59
|
+
migrations and `db/schema.rb`; never run `db:reset`, `db:setup`,
|
|
60
|
+
`db:schema:load`, `db:drop` or edit an applied migration as routine setup.
|
|
61
|
+
- `DATABASE_URL` overrides the connection of every environment, including
|
|
62
|
+
`test`. Keep it unset where tests run, and point `test` in
|
|
63
|
+
`config/database.yml` at its own disposable database (a supplied disposable
|
|
64
|
+
test database name when the environment declares one), never at the
|
|
65
|
+
development or production database. `bin/rails test` recreates the test
|
|
66
|
+
schema.
|
|
67
|
+
- Mode is set per environment: `RAILS_ENV=production` belongs in the
|
|
68
|
+
production environment and its commands, never in a project-wide default.
|
|
69
|
+
- Assets: never commit `public/assets`; a stale local `public/assets` shadows
|
|
70
|
+
development changes. Propshaft/Sprockets serve sources in development;
|
|
71
|
+
`tailwindcss-rails`, `cssbundling-rails` and `jsbundling-rails` need their
|
|
72
|
+
build or watcher (`bin/dev` runs them from `Procfile.dev`). When the Develop
|
|
73
|
+
command becomes `bin/dev`, confirm its web process still binds loopback and
|
|
74
|
+
the supplied `PORT`. Rails before 7.1 needs `RAILS_SERVE_STATIC_FILES=1` in
|
|
75
|
+
production without a front web server.
|
|
76
|
+
- Native gems need a C toolchain and headers: `psych` needs libyaml, `pg`
|
|
77
|
+
needs libpq, `mysql2` needs the MySQL client library, `sqlite3` usually ships
|
|
78
|
+
a precompiled gem. Dependency installation therefore also uses `cpp`.
|
|
79
|
+
`trilogy` avoids the MySQL client library. A `Gemfile.lock` resolved only on
|
|
80
|
+
another platform needs `bundle lock --add-platform x86_64-linux` (or the
|
|
81
|
+
deployment platform) before frozen deployment installs.
|
|
82
|
+
- Production: `bin/rails server -e production` reads `PORT`; bind loopback
|
|
83
|
+
with `-b`. Rails 8 enables `assume_ssl`/`force_ssl`; with `force_ssl` but no
|
|
84
|
+
`assume_ssl`, exclude `/up` from the redirect:
|
|
85
|
+
`config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } }`.
|
|
86
|
+
Rails 8 runs Solid Queue jobs inside Puma only with `SOLID_QUEUE_IN_PUMA=1`
|
|
87
|
+
in the production environment; otherwise run `bin/jobs` as its own process.
|
|
88
|
+
- Keep the `/up` health route (`rails/health#show`, Rails 7.1+) unauthenticated.
|
|
89
|
+
Older apps add an equivalent route and update the Outputs and Deployment
|
|
90
|
+
readiness.
|
|
91
|
+
- Login: Rails 8 `bin/rails generate authentication`, Devise or the app's own
|
|
92
|
+
`has_secure_password`. Seed one administrator (an `admin` boolean or role)
|
|
93
|
+
and one ordinary user idempotently in `db/seeds.rb` for development only,
|
|
94
|
+
with passwords from the environment; never seed production credentials.
|
|
95
|
+
- The JavaScript dependency step assumes npm. A `yarn.lock` or `bun.lockb`
|
|
96
|
+
means that line uses the matching tool; importmap apps have no
|
|
97
|
+
`package.json` and skip it.
|
|
98
|
+
|
|
99
|
+
## Adoption
|
|
100
|
+
|
|
101
|
+
- Read `Gemfile`, `Gemfile.lock` (Rails and Ruby versions, database adapter
|
|
102
|
+
gem, asset and JavaScript tooling), `config/database.yml`,
|
|
103
|
+
`config/environments/*.rb`, `config/puma.rb`, `Procfile.dev`/`bin/dev`,
|
|
104
|
+
`config/routes.rb` (health route) and whether `config/master.key` or
|
|
105
|
+
`config/credentials/*.key` exist before changing project contracts.
|
|
106
|
+
- Replace each proposed setup, Outputs, Verification and Deployment line that
|
|
107
|
+
does not match the app: RSpec apps verify with `bundle` `exec` `rspec`;
|
|
108
|
+
API-only apps have no `assets:precompile`; a different health route changes
|
|
109
|
+
both readiness lines; a different JavaScript package manager changes the
|
|
110
|
+
install step.
|
|
111
|
+
- Select the matching database integration (`rails-postgresql`,
|
|
112
|
+
`rails-mysql` or `rails-sqlite`) and align `config/database.yml` with its
|
|
113
|
+
environment names. Preserve existing data and the credentials file.
|
|
114
|
+
|
|
115
|
+
## Workspace setup
|
|
116
|
+
|
|
117
|
+
- Prepare `Install Ruby dependencies` with `ruby` `cpp` when `Gemfile` exists: `bundle` `install`
|
|
118
|
+
- Prepare `Install JavaScript dependencies` with `nodejs` if `package.json` exists: `npm` `install`
|
|
119
|
+
- Prepare `Prepare database` with `ruby` when `bin/rails` exists: `bin/rails` `db:prepare`
|
|
120
|
+
|
|
121
|
+
## Outputs
|
|
122
|
+
|
|
123
|
+
### Target `app`: Run Rails app
|
|
124
|
+
|
|
125
|
+
- Default.
|
|
126
|
+
- Mode: `interactive`
|
|
127
|
+
- Runtimes: `ruby`
|
|
128
|
+
- Run `Develop`: `bin/rails` `server` `-b` `{host}` `-p` `{port}`
|
|
129
|
+
|
|
130
|
+
#### Presentation
|
|
131
|
+
|
|
132
|
+
- Kind: `web`
|
|
133
|
+
- Preferred port: `3000`
|
|
134
|
+
- URL path: `/`
|
|
135
|
+
- Ready when: `GET` `/up` returns `200`
|
|
136
|
+
|
|
137
|
+
## Verification
|
|
138
|
+
|
|
139
|
+
- Verify `application`: `bin/rails` `test`
|
|
140
|
+
|
|
141
|
+
## Deployment
|
|
142
|
+
|
|
143
|
+
- Runtimes: `ruby` `cpp`
|
|
144
|
+
- Recreate on restore: `vendor/bundle` `node_modules` `tmp` `log`
|
|
145
|
+
- Ready when: `GET` `/up` returns `200`
|
|
146
|
+
- Prepare `Use deployment bundle`: `bundle` `config` `set` `--local` `deployment` `true`
|
|
147
|
+
- Prepare `Exclude development gems`: `bundle` `config` `set` `--local` `without` `development test`
|
|
148
|
+
- Prepare `Install Ruby dependencies`: `bundle` `install`
|
|
149
|
+
- Build `Precompile assets`: `bin/rails` `assets:precompile` `RAILS_ENV=production`
|
|
150
|
+
- Migrate `Prepare database`: `bin/rails` `db:prepare` `RAILS_ENV=production`
|
|
151
|
+
- Serve `Start`: `bin/rails` `server` `-e` `production` `-b` `127.0.0.1`
|
|
152
|
+
|
|
153
|
+
## Deslop
|
|
154
|
+
|
|
155
|
+
- Preserve Rails conventions: models, concerns, controllers, callbacks,
|
|
156
|
+
validations, strong parameters, jobs, mailers and routes stay where Rails
|
|
157
|
+
expects them.
|
|
158
|
+
- Remove service objects, decorators or wrappers that only forward to Active
|
|
159
|
+
Record or Action Pack without protecting a real application seam.
|
|
160
|
+
- Preserve migration history, `db/schema.rb`, credentials and seed
|
|
161
|
+
idempotence; cleanup is not permission for destructive schema changes.
|
package/stacks/pieces/ruby.md
CHANGED
|
@@ -45,10 +45,7 @@ Ruby module, class, callable, dependency, lifecycle, and test conventions.
|
|
|
45
45
|
only git sources. Verify that each spec loads from its source root.
|
|
46
46
|
- Running a web process: bind the supplied listen host and port, trust forwarded
|
|
47
47
|
headers only from a loopback proxy, and read secrets from the environment.
|
|
48
|
-
Rails
|
|
49
|
-
(Rails honours `X-Forwarded-Host`), read `SECRET_KEY_BASE` from the
|
|
50
|
-
environment (generate it with `bin/rails secret`), and use
|
|
51
|
-
`bin/rails db:prepare` for setup.
|
|
48
|
+
For Rails select `rails`; its piece owns the framework traps.
|
|
52
49
|
|
|
53
50
|
## Connected development
|
|
54
51
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Stack piece: spring-boot-mysql
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Spring Boot MySQL or MariaDB datasource, JDBC driver, Flyway, JPA, and database
|
|
6
|
+
environment conventions.
|
|
7
|
+
|
|
8
|
+
## Requires
|
|
9
|
+
|
|
10
|
+
- `spring-boot`
|
|
11
|
+
- `mysql`
|
|
12
|
+
|
|
13
|
+
## Conflicts
|
|
14
|
+
|
|
15
|
+
- `spring-boot-postgresql`
|
|
16
|
+
|
|
17
|
+
## Environment defaults
|
|
18
|
+
|
|
19
|
+
- Default `DB_HOST`: `127.0.0.1`
|
|
20
|
+
- Default `DB_PORT`: `3306`
|
|
21
|
+
- Default `DB_NAME`: `spring`
|
|
22
|
+
- Default `DB_USERNAME`: `root`
|
|
23
|
+
|
|
24
|
+
## Resources
|
|
25
|
+
|
|
26
|
+
```json genesis-resource
|
|
27
|
+
{
|
|
28
|
+
"id": "database",
|
|
29
|
+
"kind": "mysql",
|
|
30
|
+
"environmentAlternatives": [
|
|
31
|
+
{
|
|
32
|
+
"bindings": {
|
|
33
|
+
"database": "DB_NAME",
|
|
34
|
+
"host": "DB_HOST",
|
|
35
|
+
"password": "DB_PASSWORD",
|
|
36
|
+
"port": "DB_PORT",
|
|
37
|
+
"username": "DB_USERNAME"
|
|
38
|
+
},
|
|
39
|
+
"allowEmpty": ["password"],
|
|
40
|
+
"preferred": true
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"optionalBindings": {
|
|
44
|
+
"testDatabase": "TEST_DB_NAME"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Guidance
|
|
50
|
+
|
|
51
|
+
- Compose the JDBC URL from the individual names in `application.properties`:
|
|
52
|
+
`spring.datasource.url=jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}`,
|
|
53
|
+
`spring.datasource.username=${DB_USERNAME}` and
|
|
54
|
+
`spring.datasource.password=${DB_PASSWORD:}`. A `mysql://` connection URL is
|
|
55
|
+
not a JDBC URL; do not feed one to `spring.datasource.url`.
|
|
56
|
+
- Match the driver to the server: check `SELECT VERSION()`. MySQL uses the
|
|
57
|
+
`com.mysql:mysql-connector-j` runtime driver. A MariaDB server needs
|
|
58
|
+
`org.mariadb.jdbc:mariadb-java-client` with a `jdbc:mariadb://` URL;
|
|
59
|
+
`mysql-connector-j` can fail against current MariaDB while Hibernate reads
|
|
60
|
+
connection metadata ("Unable to determine Dialect"). Flyway 10 and later
|
|
61
|
+
also need `org.flywaydb:flyway-mysql`, which covers both servers.
|
|
62
|
+
- Create databases with `utf8mb4`.
|
|
63
|
+
- When `TEST_DB_NAME` is supplied, the `test` profile's
|
|
64
|
+
`src/test/resources/application-test.properties` sets
|
|
65
|
+
`spring.datasource.url` to the same JDBC URL with `${TEST_DB_NAME}` in place
|
|
66
|
+
of `${DB_NAME}`. Flyway migrates that existing database; the database user
|
|
67
|
+
may lack permission to create databases. Never point tests at `DB_NAME`.
|
|
68
|
+
|
|
69
|
+
## Adoption
|
|
70
|
+
|
|
71
|
+
- Confirm the server (MySQL or MariaDB), the datasource properties, the
|
|
72
|
+
environment names they read, the driver and Flyway or Liquibase modules, and
|
|
73
|
+
every profile's overrides from source before declaring readiness or
|
|
74
|
+
connecting to the database.
|