genesis-stack 1.3.0 → 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 +19 -3
- package/genesis.templates.json +48 -0
- 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 +161 -0
- package/stacks/pieces/java.md +1 -2
- package/stacks/pieces/jskit.md +31 -1
- package/stacks/pieces/nextjs.md +181 -0
- package/stacks/pieces/nodejs.md +13 -1
- package/stacks/pieces/python.md +18 -5
- package/stacks/pieces/rails-mysql.md +81 -0
- package/stacks/pieces/rails-postgresql.md +86 -0
- package/stacks/pieces/rails-sqlite.md +60 -0
- package/stacks/pieces/rails.md +188 -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 +154 -0
- package/stacks/pieces/sqlite.md +6 -0
|
@@ -0,0 +1,188 @@
|
|
|
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
|
+
- 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.
|
|
52
|
+
- Secrets: development uses `tmp/local_secret.txt`. Production needs
|
|
53
|
+
`SECRET_KEY_BASE` (generate with `bin/rails secret`) or `RAILS_MASTER_KEY`
|
|
54
|
+
for `config/credentials.yml.enc`, supplied through the deployment
|
|
55
|
+
environment, never committed. `assets:precompile` in production also aborts
|
|
56
|
+
without it; a build that must not see the real secret can use
|
|
57
|
+
`SECRET_KEY_BASE_DUMMY=1`. When an
|
|
58
|
+
imported app lacks `config/master.key`, never run `bin/rails credentials:edit`
|
|
59
|
+
or delete the encrypted file to "fix" it: that destroys the existing values.
|
|
60
|
+
Ask for the key or move the needed values to environment variables.
|
|
61
|
+
- `bin/rails db:prepare` creates the database, loads the schema and runs
|
|
62
|
+
`db/seeds.rb` when it is new, and migrates it otherwise, so repeated setup is
|
|
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
|
|
70
|
+
migrations and `db/schema.rb`; never run `db:reset`, `db:setup`,
|
|
71
|
+
`db:schema:load`, `db:drop` or edit an applied migration as routine setup.
|
|
72
|
+
- `DATABASE_URL` overrides the connection of every environment, including
|
|
73
|
+
`test`. Keep it unset where tests run, and point `test` in
|
|
74
|
+
`config/database.yml` at its own disposable database (the database
|
|
75
|
+
integration's test database binding when it is supplied), never at the
|
|
76
|
+
development or production database. `bin/rails test` recreates the test
|
|
77
|
+
schema.
|
|
78
|
+
- Mode is set per environment: `RAILS_ENV=production` belongs in the
|
|
79
|
+
production environment and its commands, never in a project-wide default.
|
|
80
|
+
- Assets: never commit `public/assets`; a stale local `public/assets` shadows
|
|
81
|
+
development changes. Propshaft/Sprockets serve sources in development;
|
|
82
|
+
`tailwindcss-rails`, `cssbundling-rails` and `jsbundling-rails` need their
|
|
83
|
+
build or watcher (`bin/dev` runs them from `Procfile.dev`). When the Develop
|
|
84
|
+
command becomes `bin/dev`, confirm its web process still binds loopback and
|
|
85
|
+
the supplied `PORT`. Rails before 7.1 needs `RAILS_SERVE_STATIC_FILES=1` in
|
|
86
|
+
production without a front web server.
|
|
87
|
+
- Native gems need a C toolchain and headers: `psych` needs libyaml, `pg`
|
|
88
|
+
needs libpq, `mysql2` needs the MySQL client library, `sqlite3` usually ships
|
|
89
|
+
a precompiled gem. Dependency installation therefore also uses `cpp`.
|
|
90
|
+
`trilogy` avoids the MySQL client library. A `Gemfile.lock` resolved only on
|
|
91
|
+
another platform needs `bundle lock --add-platform x86_64-linux` (or the
|
|
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
|
|
104
|
+
`assume_ssl`, exclude `/up` from the redirect:
|
|
105
|
+
`config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } }`.
|
|
106
|
+
Rails 8 runs Solid Queue jobs inside Puma only with `SOLID_QUEUE_IN_PUMA=1`
|
|
107
|
+
in the production environment; otherwise run `bin/jobs` as its own process.
|
|
108
|
+
- Keep the `/up` health route (`rails/health#show`, Rails 7.1+) unauthenticated.
|
|
109
|
+
Older apps add an equivalent route and update the Outputs and Deployment
|
|
110
|
+
readiness.
|
|
111
|
+
- Login: Rails 8 `bin/rails generate authentication`, Devise or the app's own
|
|
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)
|
|
115
|
+
and one ordinary user idempotently in `db/seeds.rb` for development only,
|
|
116
|
+
with passwords from the environment; never seed production credentials.
|
|
117
|
+
- The JavaScript dependency step assumes npm. A `yarn.lock` or `bun.lockb`
|
|
118
|
+
means that line uses the matching tool; importmap apps have no
|
|
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`.
|
|
123
|
+
|
|
124
|
+
## Adoption
|
|
125
|
+
|
|
126
|
+
- Read `Gemfile`, `Gemfile.lock` (Rails and Ruby versions, database adapter
|
|
127
|
+
gem, asset and JavaScript tooling), `config/database.yml`,
|
|
128
|
+
`config/environments/*.rb`, `config/puma.rb`, `Procfile.dev`/`bin/dev`,
|
|
129
|
+
`config/routes.rb` (health route) and whether `config/master.key` or
|
|
130
|
+
`config/credentials/*.key` exist before changing project contracts.
|
|
131
|
+
- Replace each proposed setup, Outputs, Verification and Deployment line that
|
|
132
|
+
does not match the app: RSpec apps verify with `bundle` `exec` `rspec`;
|
|
133
|
+
API-only apps have no `assets:precompile`; a different health route changes
|
|
134
|
+
both readiness lines; a different JavaScript package manager changes the
|
|
135
|
+
install step.
|
|
136
|
+
- Select the matching database integration (`rails-postgresql`,
|
|
137
|
+
`rails-mysql` or `rails-sqlite`) and align `config/database.yml` with its
|
|
138
|
+
environment names. Preserve existing data and the credentials file.
|
|
139
|
+
|
|
140
|
+
## Workspace setup
|
|
141
|
+
|
|
142
|
+
- Prepare `Keep gems inside the project` with `ruby` when `Gemfile` exists: `bundle` `config` `set` `--local` `path` `vendor/bundle`
|
|
143
|
+
- Prepare `Install Ruby dependencies` with `ruby` `cpp` when `Gemfile` exists: `bundle` `install`
|
|
144
|
+
- Prepare `Install JavaScript dependencies` with `nodejs` if `package.json` exists: `npm` `install`
|
|
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`
|
|
147
|
+
|
|
148
|
+
## Outputs
|
|
149
|
+
|
|
150
|
+
### Target `app`: Run Rails app
|
|
151
|
+
|
|
152
|
+
- Default.
|
|
153
|
+
- Mode: `interactive`
|
|
154
|
+
- Runtimes: `ruby`
|
|
155
|
+
- Run `Develop`: `bin/rails` `server` `-b` `{host}` `-p` `{port}`
|
|
156
|
+
|
|
157
|
+
#### Presentation
|
|
158
|
+
|
|
159
|
+
- Kind: `web`
|
|
160
|
+
- Preferred port: `3000`
|
|
161
|
+
- URL path: `/`
|
|
162
|
+
- Ready when: `GET` `/up` returns `200`
|
|
163
|
+
|
|
164
|
+
## Verification
|
|
165
|
+
|
|
166
|
+
- Verify `application`: `bin/rails` `test`
|
|
167
|
+
|
|
168
|
+
## Deployment
|
|
169
|
+
|
|
170
|
+
- Runtimes: `ruby` `cpp`
|
|
171
|
+
- Recreate on restore: `vendor/bundle` `node_modules` `tmp` `log`
|
|
172
|
+
- Ready when: `GET` `/up` returns `200`
|
|
173
|
+
- Prepare `Use deployment bundle`: `bundle` `config` `set` `--local` `deployment` `true`
|
|
174
|
+
- Prepare `Exclude development gems`: `bundle` `config` `set` `--local` `without` `development test`
|
|
175
|
+
- Prepare `Install Ruby dependencies`: `bundle` `install`
|
|
176
|
+
- Build `Precompile assets`: `bin/rails` `assets:precompile` `RAILS_ENV=production`
|
|
177
|
+
- Migrate `Prepare database`: `bin/rails` `db:prepare` `RAILS_ENV=production`
|
|
178
|
+
- Serve `Start`: `sh` `-c` `exec bin/rails server -e production -b "$HOST" -p "$PORT"`
|
|
179
|
+
|
|
180
|
+
## Deslop
|
|
181
|
+
|
|
182
|
+
- Preserve Rails conventions: models, concerns, controllers, callbacks,
|
|
183
|
+
validations, strong parameters, jobs, mailers and routes stay where Rails
|
|
184
|
+
expects them.
|
|
185
|
+
- Remove service objects, decorators or wrappers that only forward to Active
|
|
186
|
+
Record or Action Pack without protecting a real application seam.
|
|
187
|
+
- Preserve migration history, `db/schema.rb`, credentials and seed
|
|
188
|
+
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.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Stack piece: spring-boot-postgresql
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Spring Boot PostgreSQL datasource, JDBC driver, Flyway, JPA, and database
|
|
6
|
+
environment conventions.
|
|
7
|
+
|
|
8
|
+
## Requires
|
|
9
|
+
|
|
10
|
+
- `spring-boot`
|
|
11
|
+
- `postgresql`
|
|
12
|
+
|
|
13
|
+
## Conflicts
|
|
14
|
+
|
|
15
|
+
- `spring-boot-mysql`
|
|
16
|
+
|
|
17
|
+
## Environment defaults
|
|
18
|
+
|
|
19
|
+
- Default `DB_HOST`: `127.0.0.1`
|
|
20
|
+
- Default `DB_PORT`: `5432`
|
|
21
|
+
- Default `DB_NAME`: `spring`
|
|
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_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:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}`,
|
|
53
|
+
`spring.datasource.username=${DB_USERNAME}` and
|
|
54
|
+
`spring.datasource.password=${DB_PASSWORD:}`. A `postgres://` connection URL
|
|
55
|
+
is not a JDBC URL; do not feed one to `spring.datasource.url`.
|
|
56
|
+
- Use the `org.postgresql:postgresql` runtime driver. Flyway 10 and later also
|
|
57
|
+
need `org.flywaydb:flyway-database-postgresql` next to the Flyway starter.
|
|
58
|
+
- When `TEST_DB_NAME` is supplied, the `test` profile's
|
|
59
|
+
`src/test/resources/application-test.properties` sets
|
|
60
|
+
`spring.datasource.url` to the same JDBC URL with `${TEST_DB_NAME}` in place
|
|
61
|
+
of `${DB_NAME}`. Flyway migrates that existing database; the database role
|
|
62
|
+
may lack permission to create databases. Never point tests at `DB_NAME`.
|
|
63
|
+
|
|
64
|
+
## Adoption
|
|
65
|
+
|
|
66
|
+
- Confirm the datasource properties, the environment names they read, the
|
|
67
|
+
driver and Flyway or Liquibase modules, and every profile's overrides from
|
|
68
|
+
source before declaring readiness or connecting to the database.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Stack piece: spring-boot
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Spring Boot web application, Spring MVC, Spring Security, Actuator, profiles,
|
|
6
|
+
Maven or Gradle wrapper, and schema-migration conventions. Identified by a
|
|
7
|
+
`pom.xml` or `build.gradle(.kts)` using the Spring Boot parent or plugin and an
|
|
8
|
+
`@SpringBootApplication` class. Authoritative framework documentation:
|
|
9
|
+
https://docs.spring.io/spring-boot/
|
|
10
|
+
|
|
11
|
+
## Requires
|
|
12
|
+
|
|
13
|
+
- `java`
|
|
14
|
+
|
|
15
|
+
## Guidance
|
|
16
|
+
|
|
17
|
+
- Use the Spring Boot version selected by the build and follow its matching
|
|
18
|
+
official documentation. Boot 4 splits auto-configuration into per-technology
|
|
19
|
+
starters (`spring-boot-starter-webmvc`, `spring-boot-starter-flyway`, ...):
|
|
20
|
+
a bare `flyway-core` dependency no longer runs migrations, so add the
|
|
21
|
+
matching starter instead of hand-written configuration. Preserve Spring's
|
|
22
|
+
dependency injection, configuration properties, Spring Data repositories,
|
|
23
|
+
Spring Security and Actuator instead of adding parallel plumbing.
|
|
24
|
+
- Building and running need a full JDK (`javac`), not only a Java runtime.
|
|
25
|
+
Keep the Maven wrapper (`mvnw`, `.mvn/wrapper`) committed and executable;
|
|
26
|
+
the proposed operations call `./mvnw`.
|
|
27
|
+
- Bind the listen address and port from the environment in
|
|
28
|
+
`application.properties`: `server.address=${HOST:127.0.0.1}` and
|
|
29
|
+
`server.port=${PORT:8080}`. Spring reads `SERVER_PORT`, not `PORT`, by
|
|
30
|
+
itself. The proposed development run also passes both as
|
|
31
|
+
`--server.address`/`--server.port` application arguments.
|
|
32
|
+
- Behind a development or production reverse proxy on the same machine that
|
|
33
|
+
rewrites `Host` and sends `X-Forwarded-Host`, `X-Forwarded-Proto` and
|
|
34
|
+
`X-Forwarded-Port`, set `server.forward-headers-strategy=native`,
|
|
35
|
+
`server.tomcat.remoteip.host-header=X-Forwarded-Host` and
|
|
36
|
+
`server.tomcat.remoteip.port-header=X-Forwarded-Port`. Embedded Tomcat then
|
|
37
|
+
trusts those headers only from loopback and private internal proxies, so
|
|
38
|
+
login redirects, `ServletUriComponentsBuilder` URLs and the `Secure` session
|
|
39
|
+
cookie use the browser-facing origin. Without it, Spring Security redirects
|
|
40
|
+
to the loopback address. Use `framework` only for a non-Tomcat server, and
|
|
41
|
+
only while the server is reachable solely through that proxy.
|
|
42
|
+
- Also set `server.tomcat.use-relative-redirects=true`. A proxy may send a
|
|
43
|
+
same-origin form post with the forwarded host and port removed and `Origin`
|
|
44
|
+
rewritten to the loopback address, so Tomcat would turn the redirect after
|
|
45
|
+
login or after any POST into `https://127.0.0.1/...`; a relative `Location`
|
|
46
|
+
lets the browser resolve it against its own origin.
|
|
47
|
+
- Spring Security's CSRF protection is token based (`_csrf`) and works behind
|
|
48
|
+
such a proxy. A proxy may present same-origin requests with an `Origin`
|
|
49
|
+
rewritten to the loopback address; keep CORS configuration for genuine
|
|
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`.
|
|
57
|
+
- Add `spring-boot-starter-actuator`, expose
|
|
58
|
+
`management.endpoints.web.exposure.include=health`, and let Spring Security
|
|
59
|
+
`permitAll` `/actuator/health`; the proposed readiness checks use it. Its
|
|
60
|
+
status includes the datasource, so readiness also proves the database
|
|
61
|
+
connection. An application that must not expose Actuator replaces both
|
|
62
|
+
readiness lines with another unauthenticated route.
|
|
63
|
+
- Select profiles with `SPRING_PROFILES_ACTIVE` set separately in each
|
|
64
|
+
environment (for example `dev` locally); never make a development profile
|
|
65
|
+
the project-wide default, because defaults also reach deployment. Keep
|
|
66
|
+
profile-specific values in `application-<profile>.properties`.
|
|
67
|
+
- Read credentials from the environment through property placeholders; never
|
|
68
|
+
commit passwords or tokens in `application*.properties`. Spring Boot has no
|
|
69
|
+
framework secret key of its own; application secrets, such as a token
|
|
70
|
+
signing key, are generated with `openssl rand -base64 32` and supplied
|
|
71
|
+
through the environment.
|
|
72
|
+
- Flyway or Liquibase owns the schema and runs at application startup, so the
|
|
73
|
+
proposed deployment has no separate migration step. Add new migrations;
|
|
74
|
+
never edit an applied one (its checksum is validated). Use
|
|
75
|
+
`spring.jpa.hibernate.ddl-auto=validate` and never `create`, `create-drop`
|
|
76
|
+
or `update` against supplied data; set `spring.jpa.open-in-view=false`.
|
|
77
|
+
Seeds are idempotent: repeatable migrations or a startup runner that checks
|
|
78
|
+
before inserting.
|
|
79
|
+
- Keep tests off development data: a `test` profile
|
|
80
|
+
(`src/test/resources/application-test.properties`, activated with
|
|
81
|
+
`@ActiveProfiles("test")` or Surefire's `spring.profiles.active`) points the
|
|
82
|
+
datasource at a disposable test database supplied by the environment
|
|
83
|
+
(`TEST_DB_NAME` with the database integrations below). Do not
|
|
84
|
+
add `src/test/resources/application.properties`, which replaces the main file
|
|
85
|
+
on the test classpath. Testcontainers needs a container runtime the
|
|
86
|
+
environment may not provide.
|
|
87
|
+
- Deployment serves the executable jar. Set `<finalName>app</finalName>` in the
|
|
88
|
+
Maven `<build>` so the proposed Serve step finds `target/app.jar`; the jar
|
|
89
|
+
reads `HOST` and `PORT` through the properties above.
|
|
90
|
+
- When the app has login, use Spring Security users with `ADMIN` and `USER`
|
|
91
|
+
roles and a delegating `PasswordEncoder`. Seed one administrator and one
|
|
92
|
+
ordinary user for development from a `dev`-profile runner or seed migration
|
|
93
|
+
that reads the password from the environment and creates each user only
|
|
94
|
+
when absent. Never use `{noop}` passwords or seeded credentials outside
|
|
95
|
+
development.
|
|
96
|
+
- A Gradle project replaces the proposals with the wrapper equivalents:
|
|
97
|
+
`./gradlew` `bootRun` `--args=--server.address={host} --server.port={port}`,
|
|
98
|
+
`./gradlew` `test`, and `./gradlew` `bootJar` with
|
|
99
|
+
`bootJar { archiveFileName = 'app.jar' }` serving `build/libs/app.jar`.
|
|
100
|
+
|
|
101
|
+
## Adoption
|
|
102
|
+
|
|
103
|
+
- Inspect `pom.xml` or `build.gradle(.kts)`, the wrapper, the Spring Boot and
|
|
104
|
+
Java versions, `application.properties`/`application.yml` and every profile
|
|
105
|
+
file, the security configuration, the embedded server, the packaging (`jar`
|
|
106
|
+
or `war`) and the migration tool before changing project contracts. Preserve
|
|
107
|
+
the build tool and Boot major version.
|
|
108
|
+
- Replace any proposed setup, run, readiness, verification or deployment line
|
|
109
|
+
that does not match the application before claiming readiness, including
|
|
110
|
+
the jar name, the health route and the address/port properties.
|
|
111
|
+
- When the app uses PostgreSQL or MySQL, select the matching Spring Boot
|
|
112
|
+
database integration so its datasource environment names become explicit.
|
|
113
|
+
|
|
114
|
+
## Workspace setup
|
|
115
|
+
|
|
116
|
+
- Prepare `Compile application` with `java` when `pom.xml` exists: `./mvnw` `-B` `-DskipTests` `compile`
|
|
117
|
+
|
|
118
|
+
## Outputs
|
|
119
|
+
|
|
120
|
+
### Target `app`: Run Spring Boot app
|
|
121
|
+
|
|
122
|
+
- Default.
|
|
123
|
+
- Mode: `interactive`
|
|
124
|
+
- Runtimes: `java`
|
|
125
|
+
- Run `Develop`: `./mvnw` `-B` `spring-boot:run` `-Dspring-boot.run.arguments=--server.address={host} --server.port={port}`
|
|
126
|
+
|
|
127
|
+
#### Presentation
|
|
128
|
+
|
|
129
|
+
- Kind: `web`
|
|
130
|
+
- Preferred port: `8080`
|
|
131
|
+
- URL path: `/`
|
|
132
|
+
- Ready when: `GET` `/actuator/health` returns `200`
|
|
133
|
+
|
|
134
|
+
## Verification
|
|
135
|
+
|
|
136
|
+
- Verify `application`: `./mvnw` `-B` `test`
|
|
137
|
+
|
|
138
|
+
## Deployment
|
|
139
|
+
|
|
140
|
+
- Runtimes: `java`
|
|
141
|
+
- Ready when: `GET` `/actuator/health` returns `200`
|
|
142
|
+
- Build `Package`: `./mvnw` `-B` `-DskipTests` `package`
|
|
143
|
+
- Serve `Start`: `java` `-jar` `target/app.jar`
|
|
144
|
+
|
|
145
|
+
## Deslop
|
|
146
|
+
|
|
147
|
+
- Preserve Spring's constructor injection, configuration properties,
|
|
148
|
+
component boundaries, Spring Data repositories, transaction boundaries and
|
|
149
|
+
security configuration.
|
|
150
|
+
- Keep `@Transactional` at service boundaries and validation at controller or
|
|
151
|
+
configuration-properties boundaries. Remove service, mapper or DTO layers only
|
|
152
|
+
when they duplicate framework behavior without protecting a real seam.
|
|
153
|
+
- Preserve migration history and entity mappings; cleanup is not permission to
|
|
154
|
+
edit applied migrations or loosen `ddl-auto`.
|
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.
|