Skip to content

Commit ca0c8a3

Browse files
committed
build app form skill WIP
1 parent 4be5877 commit ca0c8a3

1 file changed

Lines changed: 356 additions & 0 deletions

File tree

  • skills/build-strata-application-form
Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
---
2+
name: build-strata-application-form
3+
description: Adds a Strata SDK application form to a scaffolded Strata Rails app. Use when extending a Strata Rails project with a government intake form (unemployment, SNAP, Medicaid, etc.) via the strata_sdk_rails gem.
4+
---
5+
6+
# Build Strata Application Form
7+
8+
## Overview
9+
10+
Extends an existing Strata Rails app (typically scaffolded by the `build-strata-rails-app` skill) with a Strata SDK application form. Installs the `strata_sdk_rails` gem, generates agent rules, generates the form model + migration + views, and wires up an entry point chosen by the user.
11+
12+
**Scope (currently):** application forms only. Other Strata features (cases, business processes, tasks) are out of scope for this skill.
13+
14+
**TDD is mandatory.** Every step that produces or modifies Ruby code (model, migration, controller, views, routes) must follow the `test-driven-development` skill: write a failing RSpec spec, run `make test` to watch it fail, write minimal Ruby, run `make test` to watch it pass, then `make lint`. Generator output (model stubs, migration stubs, scaffold view specs) is NOT a substitute — replace generator-stub specs with real failing specs before adding behavior. See `skills/test-driven-development/SKILL.md` and `skills/test-driven-development/testing-anti-patterns.md`.
15+
16+
## Step 1: Confirm intent
17+
18+
Ask the user exactly this:
19+
20+
> **Are you building a government application/intake form (e.g. unemployment, SNAP, Medicaid)? (reply "skip" to exit, otherwise say yes)**
21+
22+
- Reply declines / "skip" / "no" → stop. Do not run any commands.
23+
- Reply confirms → tell the user the Strata SDK is a good fit for this and proceed.
24+
25+
## Step 2: Locate the Rails app directory
26+
27+
The project may be a monorepo — the Rails app likely lives in a subdirectory (e.g. `apps/<app_name>/`, `<app_name>/`), not necessarily the current working directory. Find it before doing anything else.
28+
29+
**2a. Check if cwd is already the Rails app:**
30+
31+
```sh
32+
test -f Gemfile && test -f bin/rails && grep -q "rails" Gemfile
33+
```
34+
35+
- All checks pass → cwd is the Rails app. Save `<RAILS_DIR>=.` and proceed to Step 3.
36+
- Any check fails → continue to 2b.
37+
38+
**2b. Search for Rails app directories under cwd (depth ≤ 3):**
39+
40+
```sh
41+
find . -maxdepth 3 -type f -name "Gemfile" -not -path "*/node_modules/*" -not -path "*/.git/*" -exec sh -c 'test -f "$(dirname "$1")/bin/rails" && grep -q "rails" "$1" && dirname "$1"' _ {} \;
42+
```
43+
44+
Interpret the output:
45+
46+
- **Zero matches** → not a Rails project anywhere reachable. Tell the user this skill must run from a scaffolded Strata Rails app (see the `build-strata-rails-app` skill). Stop.
47+
- **Exactly one match** → confirm with the user:
48+
> Found Rails app at `<path>`. Use this one? (yes / pick another)
49+
50+
Save the path as `<RAILS_DIR>` on yes.
51+
- **Multiple matches** → list them and ask:
52+
> Found multiple Rails apps: `<path1>`, `<path2>`, ... Which one is the Strata app? (number or path)
53+
54+
Save the chosen path as `<RAILS_DIR>`.
55+
56+
**2c. All subsequent commands** in this skill (Step 5 onward) **must run from inside `<RAILS_DIR>`**. Either `cd <RAILS_DIR>` once at the start of Step 5, or prefix each command (e.g. `cd <RAILS_DIR> && bundle install`). Edits to `Gemfile`, `config/routes.rb`, models, views, etc. all target paths under `<RAILS_DIR>`.
57+
58+
## Step 3: Pick the feature
59+
60+
Tell the user the Strata SDK supports several features (application forms, cases, business processes, tasks, determinations) but this skill currently only helps with **application forms**. Confirm:
61+
62+
> **Build an application form? (yes / no)**
63+
64+
Only proceed on yes.
65+
66+
## Step 4: Ask which AI coding agent
67+
68+
Ask:
69+
70+
> **Which AI coding agent are you using? (claude / cursor / copilot / other)**
71+
72+
Map answer to a `--agent` flag:
73+
74+
| Answer | Flag | Rules dir |
75+
|--------|------|-----------|
76+
| claude | `--agent claude` | `.claude/rules/strata-sdk/` |
77+
| cursor | `--agent cursor` | `.cursor/rules/strata-sdk/` |
78+
| copilot | `--agent copilot` | `.copilot/rules/strata-sdk/` |
79+
| other / unsure | *(omit flag)* | `.agents/rules/strata-sdk/` |
80+
81+
Save the chosen flag as `<AGENT_FLAG>` (may be empty).
82+
83+
## Step 5: Verify Ruby version matches the project
84+
85+
Before installing any gems, confirm the active Ruby matches what the project requires. Mismatched Ruby is a common cause of confusing `bundle install` failures.
86+
87+
**Follow the shared reference: [`references/ruby-version-check.md`](../../references/ruby-version-check.md)** (relative to the repo root of this skills repository).
88+
89+
It walks through:
90+
91+
- **A.** read `.ruby-version` / `Gemfile` / `.tool-versions``<REQUIRED_RUBY>`
92+
- **B.** compare against `ruby -v`
93+
- **C.** ask the user which version manager they use (rbenv / asdf / rvm / chruby / other)
94+
- **D.** install the version if missing, then activate it (per-manager commands in the reference's table)
95+
- **E.** verify `bundle -v`
96+
97+
Run all of `<RAILS_DIR>` paths in the reference relative to the directory chosen in Step 2. Do not proceed to Step 6 until `ruby -v` matches `<REQUIRED_RUBY>` and `bundle -v` succeeds.
98+
99+
## Step 6: Install the strata_sdk_rails gem
100+
101+
Add the gem to the `Gemfile` (idempotent — skip if already present):
102+
103+
```ruby
104+
# Strata Government Digital Services SDK Rails engine
105+
gem "strata", git: "https://github.com/navapbc/strata-sdk-rails.git"
106+
```
107+
108+
**6a. Install locally:**
109+
110+
```sh
111+
bundle install
112+
```
113+
114+
If `bundle install` fails, stop and report the exact error.
115+
116+
**6b. Rebuild the Docker image so the container has the new gem.** `bundle install` only updates the host's `vendor/bundle` (or system gem path); the running container still has the old gem set. Without this step, the next `bin/rails generate strata:...` invocation inside the container will fail with "command not found" or the gem will be missing.
117+
118+
```sh
119+
make build
120+
```
121+
122+
Stop and report on failure.
123+
124+
**6c. Verify the existing test suite still passes** with the new gem installed (no behavior should have changed yet — only the dependency set):
125+
126+
```sh
127+
make lint
128+
make test
129+
```
130+
131+
If `make test` regresses, the gem may conflict with an existing dependency. Stop and report. Do not move on with a broken baseline — every later step assumes a green starting point.
132+
133+
## Step 7: Generate SDK rules
134+
135+
Run the rules generator so the agent picks up Strata-specific guidance:
136+
137+
```sh
138+
bin/rails generate strata:rules all <AGENT_FLAG>
139+
```
140+
141+
(Omit `<AGENT_FLAG>` if the user picked "other / unsure".)
142+
143+
After it succeeds, **read the generated `application_form` rule file** (e.g. `.claude/rules/strata-sdk/application_form.md`) before proceeding. The rule file is the recipe for everything that follows; the steps below are a high-level guide and must defer to the rule file when they conflict.
144+
145+
## Step 8: Identify the application type
146+
147+
Ask:
148+
149+
> **What kind of application is this? (e.g. unemployment benefits, SNAP, Medicaid, housing assistance, passport, business license, appeal, other)**
150+
151+
Use the answer to drive the model name and attribute suggestions. Examples:
152+
153+
| Type | Suggested form name |
154+
|------|---------------------|
155+
| Unemployment | `UnemploymentApplicationForm` |
156+
| SNAP | `SnapApplicationForm` |
157+
| Medicaid | `MedicaidApplicationForm` |
158+
| Housing | `HousingApplicationForm` |
159+
| Other | `<DomainName>ApplicationForm` |
160+
161+
## Step 9: Propose attributes, iterate, confirm
162+
163+
Suggest a starting set of attributes appropriate for the application type, using **Strata attribute types** (see the rule file). Common starter set:
164+
165+
| Attribute | Strata type | Notes |
166+
|-----------|-------------|-------|
167+
| `name` | `name` | Applicant full name |
168+
| `birth_date` | `memorable_date` | DOB |
169+
| `ssn` | `tax_id` | If program requires SSN |
170+
| `residential_address` | `address` | Mailing/residential |
171+
| `email` | `email` | Contact |
172+
| `phone` | `phone` | Contact |
173+
174+
Tailor by program (examples — confirm with the user, do not invent silently):
175+
176+
- **Unemployment:** last employer, last day worked, reason for separation, weekly earnings
177+
- **SNAP:** household size, monthly income, household members, expenses
178+
- **Medicaid:** household size, income, citizenship status, disability status
179+
180+
Go back and forth with the user until the attribute list is final, then ask:
181+
182+
> **Confirm this attribute list? (yes / edit)**
183+
184+
Only proceed on yes. Save the final list as `<ATTRS>` formatted as `name:strata_type` pairs separated by spaces.
185+
186+
## Step 10: Validate against generated rules, then generate the model
187+
188+
**10a. Re-read the rule files generated in Step 7** before invoking any generator. List and read every file under the rules dir chosen in Step 4:
189+
190+
```sh
191+
ls <RULES_DIR>
192+
```
193+
194+
At minimum, read:
195+
196+
- `<RULES_DIR>/application_form.md` — recipe for the form model
197+
- Any rule file covering attributes / data modeling (commonly `strata_attributes.md`, `data_modeler.md`, or similar — names depend on the installed gem version)
198+
- Any rule file covering migrations (commonly `migration.md` or `data_modeler.md`)
199+
200+
`<RULES_DIR>` is the agent dir from Step 4 (`.claude/rules/strata-sdk/`, `.cursor/rules/strata-sdk/`, `.copilot/rules/strata-sdk/`, or `.agents/rules/strata-sdk/`).
201+
202+
**10b. Validate the proposed model + attributes against the rules.** Check at least:
203+
204+
| Check | What to verify |
205+
|-------|----------------|
206+
| Form name | Matches the naming convention the rule file requires (typically `<Domain>ApplicationForm`) |
207+
| Parent class | Rule file confirms model must extend `Strata::ApplicationForm` |
208+
| Attribute types | Every attribute in `<ATTRS>` uses a Strata type listed in the rules (e.g. `name`, `memorable_date`, `tax_id`, `address`, `email`, `phone`, `integer`, etc.) — flag any that aren't supported |
209+
| Required base columns | Rules confirm `status`, `user_id`, `submitted_at` are needed in the migration (used in Step 11) |
210+
| Attribute naming | Matches conventions in the rule file (snake_case, no reserved names, etc.) |
211+
| Anything else the rule file calls out | Read carefully — rules may require specific validations, callbacks, or associations |
212+
213+
**10c. If any check fails**, do not run the generator. Report the conflict to the user, propose a fix (rename attribute, swap type, drop unsupported attribute, etc.), and re-confirm:
214+
215+
> Rule `<rule_file>` requires `<X>` but the plan has `<Y>`. Change to `<proposal>`? (yes / edit)
216+
217+
Loop back to Step 9 if attribute changes are needed. Only proceed once every check passes.
218+
219+
**10d. Write failing model specs FIRST (TDD).** Before running the generator, write RSpec specs for the form model under `spec/models/strata/<form_name>_spec.rb` covering at least:
220+
221+
- Extends `Strata::ApplicationForm`
222+
- Each `<ATTRS>` entry is declared as the right Strata type
223+
- Required-attribute validations the rule file specifies
224+
- Status transitions (`in_progress``submitted`) and the immutability rule (no edits after `submitted`)
225+
226+
Run `make test` and confirm these specs **fail** (model doesn't exist yet). See the `test-driven-development` skill — do not skip the watch-it-fail step.
227+
228+
**10e. Generate the model:**
229+
230+
```sh
231+
bin/rails generate strata:application_form <FormName> <ATTRS>
232+
```
233+
234+
Example:
235+
236+
```sh
237+
bin/rails generate strata:application_form SnapApplicationForm name:name birth_date:memorable_date residential_address:address household_size:integer
238+
```
239+
240+
**10f. Verify and finish the model.** Open `app/models/strata/<form_name>.rb`:
241+
242+
- Extends `Strata::ApplicationForm` (not `ApplicationRecord`) — fix if not.
243+
- Each attribute uses `strata_attribute :<name>, :<type>` per the rule file.
244+
- Add any rule-mandated validations, scopes, associations the generator didn't.
245+
246+
If the generator created stub specs, replace or fold them into the specs from 10d. Run `make test` until the specs from 10d pass, then `make lint`. Do not move on while either fails.
247+
248+
## Step 11: Generate and run the migration
249+
250+
The migration **must** include the `ApplicationForm` base columns plus the form's attributes:
251+
252+
```sh
253+
bin/rails generate strata:migration status:integer user_id:uuid submitted_at:datetime <ATTRS>
254+
```
255+
256+
Then:
257+
258+
```sh
259+
bin/rails db:migrate
260+
```
261+
262+
If the migration fails, stop and report.
263+
264+
**Re-run TDD checkpoint:** the model specs from Step 10d still need to pass against the now-migrated schema. Run:
265+
266+
```sh
267+
make test
268+
make lint
269+
```
270+
271+
If specs that previously passed now fail because of the migration (missing column, wrong type, etc.), fix the migration — do not weaken the specs.
272+
273+
## Step 12: Ask how users reach the form (entry point)
274+
275+
Before generating views, ask:
276+
277+
> **How will users reach this form?**
278+
>
279+
> 1. Landing page after login (root for authenticated users)
280+
> 2. Link or card on an existing dashboard
281+
> 3. Button on a specific page (which one?)
282+
> 4. Other (describe)
283+
284+
Save the answer as `<ENTRY_POINT>`. Do not invent — if the user is unclear, ask follow-ups.
285+
286+
## Step 13: Generate views and wire up the entry point (TDD)
287+
288+
Follow the **generated `application_form` rule file's recipe** for views (controllers, views, routes). Apply TDD throughout — see `test-driven-development` skill.
289+
290+
**13a. Write failing request and system specs FIRST.** Cover at least:
291+
292+
- `GET <form>/new` returns 200 for an authenticated user, redirects/denies otherwise (per rule file's auth expectations)
293+
- `POST <form>` with valid `<ATTRS>` creates a record with `status: 'in_progress'`
294+
- `POST <form>` with invalid params re-renders the form and shows the error
295+
- A system spec for `<ENTRY_POINT>`:
296+
- **Option 1 (post-login landing):** after sign-in, user lands on the form
297+
- **Option 2 (dashboard link/card):** dashboard shows the link/card and clicking it reaches the form
298+
- **Option 3 (button on a page):** the named page shows the button and clicking it reaches the form
299+
- **Option 4 (other):** spec mirrors what the user described
300+
301+
Run `make test` — confirm all of the above **fail** for the right reasons (route missing, controller missing, link absent).
302+
303+
**13b. Implement minimum to pass each spec, one at a time:**
304+
305+
1. Generate or hand-write the controller + views per the rule file (the SDK may provide a scaffold-style generator — prefer it if so).
306+
2. Add the route in `config/routes.rb`.
307+
3. Wire the entry point per `<ENTRY_POINT>`:
308+
- **Option 1 (post-login landing):** point the authenticated root route at the new form's `new` action.
309+
- **Option 2 (dashboard link/card):** add a link or card on the existing dashboard view.
310+
- **Option 3 (button on a page):** add a button to the page the user named, linking to the form's `new` action.
311+
- **Option 4 (other):** implement what the user described, ask if unclear.
312+
313+
Show the route changes and view edits to the user before saving.
314+
315+
**13c. After each pass, run:**
316+
317+
```sh
318+
make test
319+
make lint
320+
```
321+
322+
Both must be green before moving to the next spec. If a spec passes immediately without an implementation change, the spec is wrong — rewrite it.
323+
324+
## Step 14: Verify
325+
326+
Run the project's standard checks:
327+
328+
```sh
329+
make lint
330+
make test
331+
```
332+
333+
If either fails, stop and report. The user can then decide next steps (fix tests, adjust the form, etc.).
334+
335+
## Step 15: Report
336+
337+
Tell the user:
338+
339+
> **Application form ready.** Run `make start-container` (or the project's normal start command) and visit the entry point you chose. The form lives at `app/models/strata/<form_name>.rb` and its rule file at `<rules_dir>/application_form.md` — re-run the rules generator after upgrading the gem.
340+
341+
## Common pitfalls
342+
343+
| Problem | Fix |
344+
|---------|-----|
345+
| `bin/rails generate strata:...` says command not found | Gem not installed — re-run `bundle install` |
346+
| Model extends `ApplicationRecord` instead of `Strata::ApplicationForm` | Edit the model file, re-run tests |
347+
| Migration missing `status` / `user_id` / `submitted_at` | Re-generate the migration with the base columns included |
348+
| User picked an agent not in the table | Use `--agent <answer>` if the gem supports it; otherwise omit the flag and use `.agents/rules/strata-sdk/` |
349+
| Rule file recipe conflicts with this skill | Rule file wins — it reflects the installed gem version |
350+
351+
## Reference
352+
353+
- Strata SDK Rails (gem): https://github.com/navapbc/strata-sdk-rails
354+
- Intake application forms guide: `docs/intake-application-forms.md` in the gem repo
355+
- Strata attribute types: `docs/strata-attributes.md` in the gem repo
356+
- Rules generator: `bin/rails generate strata:rules --help`

0 commit comments

Comments
 (0)