tsykvas_rails_template 0.1.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.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +200 -0
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +589 -0
  6. data/Rakefile +17 -0
  7. data/lib/generators/tsykvas_rails_template/companions/companions_generator.rb +273 -0
  8. data/lib/generators/tsykvas_rails_template/concept/concept_generator.rb +145 -0
  9. data/lib/generators/tsykvas_rails_template/concept/templates/component/edit.html.slim.tt +5 -0
  10. data/lib/generators/tsykvas_rails_template/concept/templates/component/edit.rb.tt +11 -0
  11. data/lib/generators/tsykvas_rails_template/concept/templates/component/index.html.slim.tt +5 -0
  12. data/lib/generators/tsykvas_rails_template/concept/templates/component/index.rb.tt +11 -0
  13. data/lib/generators/tsykvas_rails_template/concept/templates/component/new.html.slim.tt +5 -0
  14. data/lib/generators/tsykvas_rails_template/concept/templates/component/new.rb.tt +11 -0
  15. data/lib/generators/tsykvas_rails_template/concept/templates/component/show.html.slim.tt +4 -0
  16. data/lib/generators/tsykvas_rails_template/concept/templates/component/show.rb.tt +11 -0
  17. data/lib/generators/tsykvas_rails_template/concept/templates/controller.rb.tt +45 -0
  18. data/lib/generators/tsykvas_rails_template/concept/templates/operation/create.rb.tt +31 -0
  19. data/lib/generators/tsykvas_rails_template/concept/templates/operation/destroy.rb.tt +13 -0
  20. data/lib/generators/tsykvas_rails_template/concept/templates/operation/edit.rb.tt +10 -0
  21. data/lib/generators/tsykvas_rails_template/concept/templates/operation/index.rb.tt +9 -0
  22. data/lib/generators/tsykvas_rails_template/concept/templates/operation/new.rb.tt +10 -0
  23. data/lib/generators/tsykvas_rails_template/concept/templates/operation/show.rb.tt +10 -0
  24. data/lib/generators/tsykvas_rails_template/concept/templates/operation/update.rb.tt +31 -0
  25. data/lib/generators/tsykvas_rails_template/install/bootstrap_installer.rb +225 -0
  26. data/lib/generators/tsykvas_rails_template/install/install_generator.rb +298 -0
  27. data/lib/generators/tsykvas_rails_template/install/templates/.claude/agents/buddy.md +157 -0
  28. data/lib/generators/tsykvas_rails_template/install/templates/.claude/agents/code-reviewer.md +117 -0
  29. data/lib/generators/tsykvas_rails_template/install/templates/.claude/agents/security-reviewer.md +113 -0
  30. data/lib/generators/tsykvas_rails_template/install/templates/.claude/agents/tech-lead.md +150 -0
  31. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/check.md +51 -0
  32. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/code-review.md +60 -0
  33. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/docs-create.md +102 -0
  34. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/pr-review.md +81 -0
  35. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/pushit.md +160 -0
  36. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/refactor.md +132 -0
  37. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/task-sum.md +47 -0
  38. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/tests.md +67 -0
  39. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/tsykvas-claude.md +262 -0
  40. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/update-docs.md +78 -0
  41. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/update-rules.md +102 -0
  42. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/update-tests.md +135 -0
  43. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/architecture.md +315 -0
  44. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/authentication.md +96 -0
  45. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/background-jobs.md +135 -0
  46. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/code-style.md +101 -0
  47. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/commands.md +34 -0
  48. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/companions.md +128 -0
  49. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/concepts-refactoring.md +194 -0
  50. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/database.md +135 -0
  51. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/deployment.md +138 -0
  52. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/design-system.md +322 -0
  53. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/documentation.md +89 -0
  54. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/forms.md +174 -0
  55. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/i18n.md +165 -0
  56. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/routing-and-namespaces.md +114 -0
  57. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/security.md +122 -0
  58. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/stimulus-controllers.md +166 -0
  59. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/testing-examples.md +180 -0
  60. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/testing.md +117 -0
  61. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/tsykvas_rails_template.md +280 -0
  62. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/ui-components.md +196 -0
  63. data/lib/generators/tsykvas_rails_template/install/templates/CLAUDE.md.tt +81 -0
  64. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/base/component/base.rb +6 -0
  65. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/base/operation/base.rb +124 -0
  66. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/base/operation/result.rb +56 -0
  67. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/home/component/index.html.slim +49 -0
  68. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/home/component/index.rb +11 -0
  69. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/home/operation/index.rb +17 -0
  70. data/lib/generators/tsykvas_rails_template/install/templates/app/controllers/concerns/operations_methods.rb +148 -0
  71. data/lib/generators/tsykvas_rails_template/install/templates/app/controllers/home_controller.rb +10 -0
  72. data/lib/generators/tsykvas_rails_template/install/templates/app/policies/application_policy.rb +33 -0
  73. data/lib/generators/tsykvas_rails_template/install/templates/app/policies/home_policy.rb +8 -0
  74. data/lib/tasks/tsykvas.rake +11 -0
  75. data/lib/tsykvas_rails_template/probe.rb +236 -0
  76. data/lib/tsykvas_rails_template/railtie.rb +13 -0
  77. data/lib/tsykvas_rails_template/version.rb +5 -0
  78. data/lib/tsykvas_rails_template.rb +18 -0
  79. metadata +183 -0
data/README.md ADDED
@@ -0,0 +1,589 @@
1
+ # tsykvas_rails_template
2
+
3
+ Opinionated Rails skeleton + Claude Code tooling, shipped as a gem with three
4
+ generators. Drop it into a fresh `rails new` (or an existing app), run the
5
+ install generator, and you get the same architectural baseline across every
6
+ project: thin controllers, plain-Ruby Operation/Component pattern, ViewComponent
7
+ + Slim, Pundit, and a pre-loaded `.claude/` directory tailored to the host
8
+ stack on first run.
9
+
10
+ ## What it ships
11
+
12
+ Four pillars:
13
+
14
+ 1. **Thin-controller / `endpoint` DSL.** Controllers become one-liners:
15
+ `endpoint Crm::Property::Operation::Index, Crm::Property::Component::Index`.
16
+ The DSL handles HTML / JS / JSON / `format.any` dispatch, flash, redirects,
17
+ and Pundit authorization-check enforcement.
18
+ 2. **`Base::Operation::Base` + `Base::Operation::Result`.** Plain-Ruby
19
+ alternative to Trailblazer. `authorize!` / `policy_scope` / `notice` /
20
+ `redirect_path=` / `model=` / `run_operation` baked in.
21
+ 3. **`app/concepts/<feature>/{operation,component}/` layout.** Generators
22
+ scaffold this for you; `config.autoload_paths` is wired automatically.
23
+ `<Concept>::Form` documented for complex forms (virtual attributes,
24
+ sub-operation calls, multi-record submits).
25
+ 4. **`.claude/` payload.** 4 subagents (`buddy`, `code-reviewer`,
26
+ `security-reviewer`, `tech-lead`), 12 slash commands (including
27
+ `/tsykvas-claude` which audits the host with a deterministic Ruby
28
+ probe and refreshes probe-driven sections in CLAUDE.md and the
29
+ architecture docs), and **20 architecture docs** that ship at install
30
+ under `.claude/docs/` (including the gem-canonical
31
+ `tsykvas_rails_template.md`, `forms.md`, and `companions.md`, plus 17
32
+ stack-tailoring references — `architecture`, `authentication`,
33
+ `background-jobs`, `code-style`, `commands`, `concepts-refactoring`,
34
+ `database`, `deployment`, `design-system`, `documentation`, `i18n`,
35
+ `routing-and-namespaces`, `security`, `stimulus-controllers`,
36
+ `testing`, `testing-examples`, `ui-components`).
37
+
38
+ ## Compatibility
39
+
40
+ | Component | Required version |
41
+ |------------------|------------------|
42
+ | Ruby | `>= 3.2.0` |
43
+ | Rails | `>= 7.1` |
44
+ | Pundit | `>= 2.3` |
45
+ | view_component | `>= 3.0` |
46
+ | slim-rails | `>= 3.6` |
47
+ | bootstrap | `~> 5.3` |
48
+ | dartsass-rails | `>= 0.5` |
49
+
50
+ The CI matrix exercises Ruby 3.2 / 3.3 / 3.4 against Rails 7.1 / 7.2 / 8.0
51
+ (9 cells, `fail-fast: false`), plus a smoke job that generates a fresh
52
+ Rails app, installs the gem from path, and exercises every generator.
53
+
54
+ ## Quickstart
55
+
56
+ From a fresh `rails new` to a Bootstrap-styled home page in five commands.
57
+
58
+ ### 1. Create a fresh Rails app
59
+
60
+ ```bash
61
+ rails new myapp
62
+ cd myapp
63
+ ```
64
+
65
+ Verify Ruby (`>= 3.2.0`) and Rails (`>= 7.1`) versions:
66
+
67
+ ```bash
68
+ bin/rails -v
69
+ ruby -v
70
+ ```
71
+
72
+ You also need PostgreSQL running locally — the install generator swaps `sqlite3` → `pg` by default. (Pass `--keep-sqlite` to `:install` to opt out.) `pg_isready` should return success; if not, `brew services start postgresql@16` (or your version).
73
+
74
+ ### 2. Add the gem
75
+
76
+ ```bash
77
+ bundle add tsykvas_rails_template
78
+ ```
79
+
80
+ For local-path iteration on the gem itself:
81
+
82
+ ```bash
83
+ bundle add tsykvas_rails_template --path "/abs/path/to/tsykvas_rails_template"
84
+ ```
85
+
86
+ `bundle add` edits `Gemfile`, validates the source, and runs `bundle install` in one step. Don't `echo >> Gemfile` — it duplicates entries silently.
87
+
88
+ ### 3. Run the install generator
89
+
90
+ ```bash
91
+ bin/rails g tsykvas_rails_template:install
92
+ ```
93
+
94
+ This runs `bundle install` (pulls Bootstrap, dartsass-rails, etc.), `bundle update bootstrap dartsass-rails` (lifts older lock-file pins to latest), `gem install foreman` system-wide if missing (so `bin/dev` works), and `bin/rails dartsass:build` (precompiles Bootstrap to `app/assets/builds/application.css`). The shipped `config/initializers/dartsass.rb` includes `--quiet-deps` and `--silence-deprecation=import` flags, so SCSS warnings don't pollute your terminal.
95
+
96
+ What lands in your app:
97
+
98
+ - `app/concepts/{base,home}/...` — base operation/component classes + a working Home example
99
+ - `app/controllers/application_controller.rb` — `include Pundit::Authorization` + `include OperationsMethods`
100
+ - `app/controllers/home_controller.rb` — one-liner `endpoint Home::Operation::Index, Home::Component::Index`
101
+ - `app/policies/{application,home}_policy.rb` — Pundit baseline + Home example
102
+ - `config/routes.rb` — `root "home#index"`
103
+ - `.claude/{agents,commands,docs}/` (4 subagents, 12 slash commands, **20 docs**) + `CLAUDE.md` (≤ 100 lines, fenced)
104
+ - `Gemfile` + `config/database.yml` — `sqlite3` → `pg` swap (use `--keep-sqlite` to opt out)
105
+ - Bootstrap 5.3: `bootstrap` + `dartsass-rails` gems, `app/assets/stylesheets/application.bootstrap.scss`, `config/initializers/dartsass.rb` build map, importmap pins for `bootstrap` + `@popperjs/core`, `Procfile.dev` with the SCSS watcher line, and `app/assets/builds/application.css` precompiled. Use `--skip-bootstrap` to opt out.
106
+
107
+ ### 4. Create the database
108
+
109
+ ```bash
110
+ bin/rails db:create
111
+ bin/rails db:migrate # nothing to migrate yet, but smoke-checks the connection
112
+ ```
113
+
114
+ ### 5. Boot the server
115
+
116
+ ```bash
117
+ bin/rails server
118
+ ```
119
+
120
+ Open <http://localhost:3000>. **Verify it worked:**
121
+
122
+ - Centered Bootstrap card with shadow.
123
+ - Green success alert: "Bootstrap 5.3 is installed and configured…".
124
+ - Blue "Documentation" button (`.btn-primary`) + outline secondary "Open a Bootstrap modal".
125
+ - Click the modal button → modal slides in, centered. This proves `window.bootstrap` is loaded via importmap.
126
+
127
+ If the page is unstyled, check:
128
+
129
+ ```bash
130
+ ls app/assets/builds/application.css # should be ~230 KB
131
+ bin/rails dartsass:build # silent — re-runs the compile
132
+ ```
133
+
134
+ For live SCSS reload during development, use `bin/dev` (Procfile.dev runs Puma + the dartsass watcher in parallel).
135
+
136
+ ### Optional next steps
137
+
138
+ ```bash
139
+ bin/rails g tsykvas_rails_template:companions # devise + simple_form + rspec stack + ...
140
+ bin/rails g tsykvas_rails_template:concept Crm::Property --controller
141
+ ```
142
+
143
+ Then in Claude Code, run `/tsykvas-claude` to refresh probe-driven sections in `CLAUDE.md` and `.claude/docs/*` against your actual stack (concept folders, gem versions, default branch, locale config). All 20 docs already shipped at install — `/tsykvas-claude` only swaps placeholders for real values; it does not regenerate or trim content.
144
+
145
+ ## Installation
146
+
147
+ Use `bundle add` — it edits `Gemfile`, validates the source, and runs
148
+ `bundle install` in one step. Don't append the line with `echo >> Gemfile`;
149
+ that doesn't dedupe and silently produces a broken Gemfile if you re-run.
150
+
151
+ **Released gem (after `gem push`):**
152
+
153
+ ```bash
154
+ bundle add tsykvas_rails_template
155
+ ```
156
+
157
+ **Local-path during development:**
158
+
159
+ ```bash
160
+ bundle add tsykvas_rails_template --path "/absolute/path/to/tsykvas_rails_template"
161
+ ```
162
+
163
+ If you see `the gem tsykvas_rails_template (>= 0) more than once` from
164
+ `bundle install`, you have a duplicate `gem "..."` line in your `Gemfile`
165
+ — delete the extra one and re-run `bundle install`.
166
+
167
+ Then run the install generator:
168
+
169
+ ```bash
170
+ bin/rails g tsykvas_rails_template:install
171
+ ```
172
+
173
+ The install generator will:
174
+
175
+ - Copy `app/concepts/base/operation/{base,result}.rb` and
176
+ `app/concepts/base/component/base.rb` into the host
177
+ - Copy `app/controllers/concerns/operations_methods.rb` (the `endpoint` DSL)
178
+ - Patch `config/application.rb` with
179
+ `config.autoload_paths += %W[#{config.root}/app/concepts]`
180
+ - Wire `include Pundit::Authorization` + `include OperationsMethods` into
181
+ `ApplicationController` unconditionally (the `endpoint` DSL falls back to
182
+ `try(:current_user)`, so it works on apps that haven't added Devise yet).
183
+ - Generate `app/policies/application_policy.rb` if missing
184
+ - Scaffold a Home example concept (`HomeController#index` one-liner +
185
+ `Home::Operation::Index` + `Home::Component::Index` + `HomePolicy` +
186
+ `root "home#index"` route) showing the canonical pattern end-to-end
187
+ - Drop the full `.claude/{agents,commands,docs}/` payload and a fenced
188
+ `CLAUDE.md` scaffold (≤ 100 lines, token-economy hard cap)
189
+
190
+ ### Install-time flags
191
+
192
+ | Flag | Effect |
193
+ |-------------------------------|--------------------------------------------------------------|
194
+ | `--skip-application-policy` | Don't create `app/policies/application_policy.rb` if absent |
195
+ | `--skip-autoload-paths` | Don't patch `config/application.rb` |
196
+ | `--skip-home-example` | Don't scaffold the Home concept + `root "home#index"` route |
197
+ | `--keep-sqlite` | Don't swap `gem "sqlite3"` for `gem "pg"` in the Gemfile |
198
+ | `--skip-bootstrap` | Don't add `bootstrap` + `dartsass-rails`, SCSS entry, importmap pins, JS import, or `Procfile.dev` watcher |
199
+ | `--skip-claude` | Don't drop `.claude/` payload or `CLAUDE.md` |
200
+
201
+ ## Troubleshooting
202
+
203
+ ### `bundle install` says "the gem ... more than once"
204
+
205
+ Duplicate `gem "..."` line in `Gemfile`. Delete the dupe and re-run `bundle install`. This usually happens when `gem "..."` was appended via `echo >> Gemfile` instead of `bundle add`.
206
+
207
+ ### `bin/dev` says "foreman: command not found"
208
+
209
+ The install generator auto-installs `foreman` system-wide via `gem install foreman --no-document` if missing. If install couldn't reach rubygems.org (sandboxed env, no internet), run that command manually.
210
+
211
+ ### dartsass-rails prints `@import` deprecation warnings
212
+
213
+ The shipped `config/initializers/dartsass.rb` passes `--quiet-deps` (silences warnings from gem load paths — Bootstrap 5.3.x's internal SCSS) and `--silence-deprecation=import` (silences the lone warning on the user's own `@import "bootstrap"`). If you regenerated the initializer manually and lost those flags, re-run `bin/rails g tsykvas_rails_template:install --force` — it canonical-rewrites the initializer.
214
+
215
+ If Rails fails to boot with `SyntaxError` in the dartsass initializer, the file was left in a half-written state. Delete it (`rm config/initializers/dartsass.rb`) and re-run `:install`.
216
+
217
+ ### `bin/rails db:create` fails with "could not connect to server"
218
+
219
+ The install swaps `sqlite3` → `pg` in `Gemfile` and `config/database.yml`. Either start PostgreSQL (`brew services start postgresql@16`) or pass `--keep-sqlite` to `:install`.
220
+
221
+ ### `bin/rails zeitwerk:check` fails after install
222
+
223
+ Most likely an existing `app/concepts/<name>` folder doesn't autoload-clean. Either rename the folder so its constant matches Zeitwerk's expectations or remove the autoload patch from `config/application.rb`.
224
+
225
+ ### `/tsykvas-claude` says probe rake task missing
226
+
227
+ Run `bin/rails g tsykvas_rails_template:install` first — the probe is provided by the gem's railtie, registered when the gem is in `Gemfile`. The slash command also requires `bundle exec rake tsykvas:probe` to be runnable from the host repo root.
228
+
229
+ ### Bootstrap layout doesn't load on first request
230
+
231
+ Run `bin/rails dartsass:build` once before `bin/rails server`, OR use `bin/dev` (`Procfile.dev` runs the dartsass watcher alongside Puma so SCSS recompiles whenever you edit `application.bootstrap.scss`).
232
+
233
+ ### Live changes to SCSS / JS aren't visible in dev (stale `public/assets/`)
234
+
235
+ Propshaft serves files from `public/assets/` whenever `public/assets/.manifest.json` exists, completely bypassing live `app/assets/builds/` and `app/javascript/`. A stale directory from a prior `rails assets:precompile` (perhaps run accidentally, or as part of a deploy rehearsal) silently freezes the dev environment.
236
+
237
+ Fix: delete it. The directory is `.gitignored` by default in Rails 8, so it's safe.
238
+
239
+ ```bash
240
+ rm -rf public/assets
241
+ ```
242
+
243
+ The install generator does this automatically when it sees `public/assets/` listed in `.gitignore`. If your project has the directory but doesn't `.gitignore` it, the generator leaves it alone (assumed checked-in content).
244
+
245
+ ### Home page renders but Bootstrap modal doesn't open
246
+
247
+ `window.bootstrap` is wired via importmap (`pin "bootstrap"`) plus an explicit `import * as bootstrap from "bootstrap"; window.bootstrap = bootstrap` block in `app/javascript/application.js`. If you removed the block, the modal trigger button has nothing to call. Re-run `:install --force` to restore it, or add the import manually.
248
+
249
+ ## Usage
250
+
251
+ ### Recommended companions generator
252
+
253
+ After `:install`, run this to add the recommended gem set
254
+ (devise + simple_form + rspec stack + mini_magick + mission_control-jobs +
255
+ dotenv-rails) and run their `:install` sub-generators:
256
+
257
+ ```bash
258
+ bin/rails g tsykvas_rails_template:companions
259
+ ```
260
+
261
+ What gets added (default — all groups):
262
+
263
+ | Group | Gems | Post-install |
264
+ |---|---|---|
265
+ | `auth` | `devise`, `omniauth-rails_csrf_protection` | `rails g devise:install` (no User model — run `rails g devise User` yourself when ready) |
266
+ | `forms` | `simple_form` | `rails g simple_form:install` (with `--bootstrap` if Probe sees Bootstrap) |
267
+ | `images` | `mini_magick` | none (you must `brew install imagemagick` system-wide) |
268
+ | `jobs-ui` (gated on `:solid_queue`) | `mission_control-jobs` | mounts `MissionControl::Jobs::Engine` at `/jobs` with admin-only constraint (`User#admin?` via Warden) |
269
+ | `test` | `rspec-rails`, `factory_bot_rails`, `faker`, `shoulda-matchers`, `webmock` | `rails g rspec:install`, appends shoulda-matchers + WebMock config to `spec/rails_helper.rb` |
270
+ | `dev` | `dotenv-rails` | appends `.env` rules to `.gitignore` |
271
+
272
+ Opt-out flags: `--skip-auth`, `--skip-forms`, `--skip-images`,
273
+ `--skip-jobs-ui`, `--skip-test`, `--skip-dev`. Plus `--skip-bundle` (don't
274
+ run `bundle install`) and `--skip-post-install` (Gemfile edits only,
275
+ no sub-generators).
276
+
277
+ Idempotent: re-running won't duplicate Gemfile entries, re-run
278
+ sub-generators, or duplicate config injections.
279
+
280
+ If your stack is incompatible (Tailwind instead of Bootstrap with simple_form,
281
+ Minitest instead of RSpec, CanCanCan instead of Pundit), skip `:companions`
282
+ entirely. The gem's core (`:install` + `:concept`) is stack-agnostic.
283
+
284
+ Full per-gem reference: `.claude/docs/companions.md` (after install).
285
+
286
+ ### Concept generator
287
+
288
+ Scaffold a new feature under `app/concepts/<path>/`:
289
+
290
+ ```bash
291
+ bin/rails g tsykvas_rails_template:concept Crm::Property
292
+ bin/rails g tsykvas_rails_template:concept Property --controller
293
+ bin/rails g tsykvas_rails_template:concept Admin::User --actions index show
294
+ ```
295
+
296
+ Resulting tree:
297
+
298
+ ```
299
+ app/concepts/crm/property/
300
+ ├── operation/
301
+ │ ├── index.rb # Crm::Property::Operation::Index
302
+ │ ├── show.rb
303
+ │ ├── new.rb
304
+ │ ├── create.rb # raises NotImplementedError until you fill in `permit`
305
+ │ ├── edit.rb
306
+ │ ├── update.rb # same
307
+ │ └── destroy.rb
308
+ └── component/
309
+ ├── index.rb # Crm::Property::Component::Index
310
+ ├── index.html.slim
311
+ ├── show.rb / show.html.slim
312
+ ├── new.rb / new.html.slim
313
+ └── edit.rb / edit.html.slim
314
+ ```
315
+
316
+ The scaffold deliberately raises `NotImplementedError` from the operation's
317
+ `_params` method — implement permitted attributes inline, or promote into a
318
+ `<Concept>::Form` object as documented in `.claude/docs/forms.md`. Empty
319
+ attribute lists fail loud, never silently save default values.
320
+
321
+ Input validation rejects empty, leading-`::`, or invalid-character names
322
+ with `Thor::Error` before any file is touched.
323
+
324
+ ### Claude Code integration
325
+
326
+ Once `.claude/` is dropped, open the project in Claude Code and run:
327
+
328
+ ```
329
+ /tsykvas-claude
330
+ ```
331
+
332
+ That slash command:
333
+
334
+ 1. Runs `bundle exec rake tsykvas:probe` to get a deterministic JSON inventory
335
+ of your stack (Ruby/Rails versions, default branch, template engine, auth,
336
+ authorization, API presence, Bootstrap presence, test framework, background
337
+ jobs, multi-DB setup, concept folders, ApplicationController includes,
338
+ API-only flag, Engine-host flag).
339
+ 2. Reads existing `<!-- tsykvas-template:start ... -->` /
340
+ `<!-- tsykvas-template:end -->` fences in `CLAUDE.md` so re-runs only touch
341
+ gem-owned content; your hand-written sections outside fences are preserved.
342
+ 3. Builds a refresh plan (placeholder substitutions, no regeneration of
343
+ content), shows you a unified diff (`/tsykvas-claude --dry-run` to
344
+ preview without writing).
345
+ 4. Applies edits only after you confirm.
346
+ 5. Verifies link integrity, fence balance, `bin/rails zeitwerk:check`, the
347
+ probe re-run match, and the **100-line cap on `CLAUDE.md`** (token-economy
348
+ hard gate — `CLAUDE.md` sits in every Claude session's context, so each
349
+ line is a per-prompt token cost; deep content lives in
350
+ `.claude/docs/<topic>.md`, linked from the routing table). If any check
351
+ fails, the run rolls back.
352
+
353
+ All 20 docs ship at install — `/tsykvas-claude` does **not** generate or
354
+ trim them. It only swaps placeholder values (e.g. `<your-app>` →
355
+ `todo_app`, `<app_name>_<env>` → `todo_app_<env>`) so docs reflect your
356
+ real stack. The shipped depth is intentional.
357
+
358
+ The other 11 slash commands (`/check`, `/code-review`, `/pr-review`,
359
+ `/refactor`, `/tests`, `/update-tests`, `/update-docs`, `/update-rules`,
360
+ `/pushit`, `/task-sum`, `/docs-create`) and 4 subagents are stack-agnostic
361
+ and ready to use immediately.
362
+
363
+ ### Probing the host project
364
+
365
+ The `Probe` class is usable directly in scripts and CI:
366
+
367
+ ```bash
368
+ bundle exec rake tsykvas:probe # JSON inventory of the host
369
+ ```
370
+
371
+ ```ruby
372
+ TsykvasRailsTemplate::Probe.run # returns a Hash (schema_version: 2)
373
+ ```
374
+
375
+ Sample output:
376
+
377
+ ```json
378
+ {
379
+ "schema_version": 2,
380
+ "gem_version": "0.1.0",
381
+ "ruby_version": "3.4.7",
382
+ "rails_version": "8.0.2",
383
+ "default_branch": "main",
384
+ "api_only": false,
385
+ "engine_host": false,
386
+ "template_engine": "slim",
387
+ "auth": {
388
+ "devise": true,
389
+ "omniauth": false,
390
+ "omniauth_openid_connect": false,
391
+ "warden": false,
392
+ "jwt": false,
393
+ "basic_auth": false,
394
+ "custom_current_user": false,
395
+ "method": "devise"
396
+ },
397
+ "authorization": "pundit",
398
+ "has_api_v1": false,
399
+ "has_bootstrap": true,
400
+ "test_framework": "rspec",
401
+ "background_jobs": ["solid_queue"],
402
+ "databases": ["primary"],
403
+ "concept_folders": ["admin", "crm"],
404
+ "application_controller_includes": ["Pundit::Authorization", "OperationsMethods"]
405
+ }
406
+ ```
407
+
408
+ ## End-to-end workflow
409
+
410
+ The full pipeline from a fresh `rails new` to a productive feature loop:
411
+
412
+ ```
413
+ rails new ──> bundle add ──> g install ──> g companions ──> g concept ──> /tsykvas-claude
414
+ ↓ ↓
415
+ feature work ←── slash commands
416
+
417
+ architecture evolves
418
+
419
+ /update-rules
420
+
421
+ /pushit
422
+ ```
423
+
424
+ Step-by-step on a hypothetical `todo_app`:
425
+
426
+ 1. **`rails new todo_app && cd todo_app`.**
427
+ 2. **Add the gem:** `bundle add tsykvas_rails_template` (or
428
+ `bundle add tsykvas_rails_template --path "..."` during local development).
429
+ Pulls `pundit`, `view_component`, `slim-rails` as transitive deps and
430
+ runs `bundle install` for you.
431
+ 3. **`bin/rails g tsykvas_rails_template:install`** — copies base classes,
432
+ patches `application.rb`, unconditionally wires `Pundit::Authorization` +
433
+ `OperationsMethods` into `ApplicationController` (the `endpoint` DSL
434
+ uses `try(:current_user)`, so it works with or without Devise), generates
435
+ `ApplicationPolicy` + `HomePolicy`, scaffolds the Home example concept +
436
+ `root "home#index"`, wires Bootstrap 5.3 + dartsass-rails (with silenced
437
+ SCSS deprecation flags) and pre-compiles the CSS bundle, auto-installs
438
+ `foreman` system-wide for `bin/dev`, cleans any stale `public/assets/`
439
+ that would shadow live asset reloads, and drops the full `.claude/`
440
+ payload (4 subagents, 12 slash commands, 20 architecture docs) plus a
441
+ fenced `CLAUDE.md` scaffold. `bin/rails zeitwerk:check` should pass
442
+ cleanly.
443
+ 4. **`bin/rails db:create`** — install swapped `sqlite3` → `pg` in the
444
+ Gemfile and `config/database.yml`, so the host needs PostgreSQL running
445
+ locally and a database created. (Pass `--keep-sqlite` to `:install` if
446
+ you want to stay on SQLite — then this step is unnecessary.)
447
+ 5. **`bin/rails server`** then visit `http://localhost:3000` — the Home
448
+ example renders the canonical `endpoint` flow end-to-end (controller →
449
+ operation → `HomePolicy#index?` → component → Slim template), styled
450
+ with Bootstrap (success alert + card + modal). Use `bin/dev` instead
451
+ when you want live SCSS reload (Procfile.dev runs Puma + dartsass:watch
452
+ in parallel).
453
+ 6. **`bin/rails g tsykvas_rails_template:companions`** (optional) — adds
454
+ recommended gems (devise, simple_form, rspec stack, mini_magick,
455
+ mission_control-jobs, dotenv-rails) and runs their `:install`
456
+ sub-generators. Skip if your stack is incompatible.
457
+ 7. **`bin/rails g tsykvas_rails_template:concept Crm::Property --controller`**
458
+ — scaffolds operations + components + Slim templates + thin controller.
459
+ 8. **Open Claude Code and run `/tsykvas-claude`** — probe inventories
460
+ the project, fence-aware rewrite plan, dry-run diff preview, mandatory
461
+ verify phase. **Refreshes** placeholder values in `.claude/docs/` and
462
+ `CLAUDE.md` against the actual stack (concept folder names, gem
463
+ versions, branch names) — content depth is preserved, not regenerated.
464
+ 9. **Feature work** with slash commands: `/check` before commit, `/refactor`
465
+ to keep code style, `/tests` to write missing specs, `/code-review`
466
+ before PR, `/pushit` to bundle the full pre-push pipeline.
467
+ 10. **When base classes change:** `/update-rules` diffs them against `main`
468
+ and proposes targeted doc updates with a confirmation gate.
469
+
470
+ `.claude/docs/tsykvas_rails_template.md` (gem-canonical reference, ~210
471
+ lines) is the comprehensive guide Claude reads in any host project. Read
472
+ it whenever you want the full picture of how the gem is built.
473
+
474
+ ## Architecture references
475
+
476
+ These docs ship with the gem; after `bin/rails g tsykvas_rails_template:install`
477
+ they appear under `.claude/docs/` in your project.
478
+
479
+ **Gem-canonical (kept verbatim by `/tsykvas-claude`):**
480
+
481
+ - **`tsykvas_rails_template.md`** — comprehensive 10-section gem reference (four pillars, generators, Probe, fences, `/tsykvas-claude` workflow, slash commands, gotchas, cross-doc index).
482
+ - **`forms.md`** — when to promote `_params` into `<Concept>::Form`.
483
+ - **`companions.md`** — per-gem rationale and opt-out matrix for `:companions`.
484
+
485
+ **Stack-tailoring references (refreshed by `/tsykvas-claude` against probe data):**
486
+
487
+ - **`architecture.md`** — Concepts Pattern, `endpoint` mechanics, Pundit, Operations / Components / Sortable.
488
+ - **`authentication.md`** — Devise wiring, custom registration flows, permitted parameters, redirects after sign-up.
489
+ - **`background-jobs.md`** — ActiveJob conventions, naming, recurring tasks, testing.
490
+ - **`code-style.md`** — Ruby / Rails style, I18n, git workflow, antipatterns.
491
+ - **`commands.md`** — dev / test / lint / deploy commands.
492
+ - **`concepts-refactoring.md`** — refactoring legacy controllers into the `endpoint` shape.
493
+ - **`database.md`** — multi-DB layout (primary / cache / queue / cable), migrations, enums, schema snapshot.
494
+ - **`deployment.md`** — Kamal config, secrets, SolidQueue topology, image / volume conventions.
495
+ - **`design-system.md`** — Bootstrap-default tokens, dark-mode switching, component catalog, antipatterns. Customise to your brand.
496
+ - **`documentation.md`** — documentation standards, what belongs where.
497
+ - **`i18n.md`** — locale-file structure, simple_form conventions, full-key rule, plural forms.
498
+ - **`routing-and-namespaces.md`** — REST + non-REST patterns, `crm_*_path` examples, route helpers vs controller fallbacks.
499
+ - **`security.md`** — strong parameters, CSP, Brakeman, bundler-audit, importmap audit, secrets.
500
+ - **`stimulus-controllers.md`** — Stimulus controller patterns, listener cleanup, Bootstrap-Stimulus integration.
501
+ - **`testing.md`** — RSpec setup, what NOT to test, factory traits.
502
+ - **`testing-examples.md`** — copy-paste spec templates (operation / component / model / policy / request).
503
+ - **`ui-components.md`** — `Base::Component::Btn`, `Table`, `TitleRow`, stat cards, forms, layouts.
504
+
505
+ ## Frontend assumptions
506
+
507
+ The shipped `OperationsMethods` concern handles `format.js` for Bootstrap
508
+ modals (used in the new/edit flow). The Bootstrap JS is feature-checked
509
+ (`if (window.bootstrap && window.bootstrap.Modal) { ... }`) so apps without
510
+ Bootstrap globally available degrade silently — no crashes. If your stack
511
+ doesn't use Bootstrap modals at all, delete or replace the `format.js`
512
+ branch in your generated `app/controllers/concerns/operations_methods.rb`.
513
+
514
+ ## Upgrade policy
515
+
516
+ The gem follows [SemVer](https://semver.org/):
517
+
518
+ - **MAJOR.0.0** — breaking changes to the *shape* of files the gem ships:
519
+ signatures of `Base::Operation::Base`, public API of the `endpoint` DSL,
520
+ the directory layout of `app/concepts/`, the schema of `Probe`, the fence
521
+ format in `CLAUDE.md.tt`. Per-version migration recipes will appear under
522
+ the `## Per-version migration` heading below.
523
+ - **0.MINOR.0** — new features, non-breaking. Existing host apps stay green
524
+ with no changes required.
525
+ - **0.0.PATCH** — bug fixes only.
526
+
527
+ ### How to upgrade in general
528
+
529
+ 1. Read the per-version notes below for the version you're moving to.
530
+ 2. Bump the gem in your `Gemfile`: `gem "tsykvas_rails_template", "~> X.Y"`.
531
+ 3. `bundle update tsykvas_rails_template`.
532
+ 4. Re-run `bin/rails g tsykvas_rails_template:install` (it's idempotent —
533
+ won't duplicate `include` directives or `autoload_paths` entries).
534
+ 5. Open Claude Code and run `/tsykvas-claude --dry-run` to preview any
535
+ doc changes inside fenced sections; apply if the diff looks right.
536
+
537
+ ### Probe schema versions
538
+
539
+ | Gem version | Probe `schema_version` | What changed |
540
+ |---|---|---|
541
+ | 0.1.x (initial) | 1 | Initial schema. |
542
+ | 0.1.x (current) | 2 | Added `api_only`, `engine_host`, `databases`, broadened `auth` (now a Hash with `method` classification + `warden` / `jwt` / `basic_auth` / `custom_current_user` flags). |
543
+
544
+ ### Per-version migration
545
+
546
+ #### → 0.1.0 (initial)
547
+
548
+ No prior version. Just install:
549
+
550
+ ```ruby
551
+ # Gemfile
552
+ gem "tsykvas_rails_template", "~> 0.1"
553
+ ```
554
+
555
+ ```bash
556
+ bundle install
557
+ bin/rails g tsykvas_rails_template:install
558
+ ```
559
+
560
+ #### → 0.2.0 (future)
561
+
562
+ When the first non-patch release ships, this section will list deprecation
563
+ warnings, method/file renames with sed-style migration commands,
564
+ fence-marker version bumps, and whether re-running the install generator
565
+ is mandatory or optional.
566
+
567
+ If you bump versions and something breaks that isn't covered here, open an
568
+ issue with the `before` and `after` `bundle exec rake tsykvas:probe` JSON,
569
+ the failing command, and the relevant `Gemfile.lock` diff.
570
+
571
+ ## Development
572
+
573
+ ```bash
574
+ bin/setup # install dev deps
575
+ bundle exec rake # rspec + rubocop
576
+ bundle exec rake build # package the gem
577
+ bundle exec rake audit # bundler-audit security check
578
+ ```
579
+
580
+ ## Contributing
581
+
582
+ Bug reports and pull requests are welcome. See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
583
+
584
+ Before opening a PR, run `bundle exec rake` locally — the same CI matrix
585
+ runs on every push.
586
+
587
+ ## License
588
+
589
+ [MIT](LICENSE.txt). © Yurii Tsykvas.
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ desc "Audit Gemfile.lock against the public ruby-advisory-db for known CVEs"
13
+ task :audit do
14
+ sh "bundle exec bundle-audit check --update"
15
+ end
16
+
17
+ task default: %i[spec rubocop]