start-vibing-stacks 2.2.0 → 2.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 +2 -2
- package/dist/detector.js +23 -11
- package/dist/index.js +78 -5
- package/dist/scanner.d.ts +12 -0
- package/dist/scanner.js +501 -0
- package/dist/setup.js +46 -1
- package/dist/types.d.ts +24 -0
- package/dist/ui.js +6 -5
- package/package.json +1 -1
- package/stacks/_shared/config/security-rules.json +27 -5
- package/stacks/_shared/hooks/user-prompt-submit.ts +26 -2
- package/stacks/frontend/react/skills/preline-ui/SKILL.md +31 -35
- package/stacks/frontend/react/skills/react-standards/SKILL.md +20 -20
- package/stacks/frontend/react/skills/react-ui-patterns/SKILL.md +78 -42
- package/stacks/frontend/react/skills/tailwind-patterns/SKILL.md +1 -1
- package/stacks/frontend/react/skills/zod-validation/SKILL.md +84 -18
- package/stacks/frontend/react-inertia/skills/inertia-react/SKILL.md +342 -0
- package/stacks/frontend/react-inertia/skills/react-standards/SKILL.md +267 -0
- package/stacks/nodejs/skills/nextjs-app-router/SKILL.md +101 -0
- package/stacks/nodejs/stack.json +43 -121
- package/stacks/php/skills/laravel-octane/SKILL.md +155 -53
- package/stacks/php/skills/laravel-patterns/SKILL.md +244 -39
- package/stacks/php/skills/php-patterns/SKILL.md +113 -53
- package/stacks/php/skills/security-scan-php/SKILL.md +161 -43
- package/stacks/php/stack.json +19 -6
- package/templates/CLAUDE-nodejs.md +323 -0
- package/templates/CLAUDE-php.md +233 -33
package/templates/CLAUDE-php.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# {{PROJECT_NAME}}
|
|
2
2
|
|
|
3
|
+
> **CHARACTER LIMIT**: Max 40,000 chars. Validate with `wc -m CLAUDE.md` before commit.
|
|
4
|
+
|
|
3
5
|
## Last Change
|
|
4
6
|
|
|
5
7
|
**Branch:** main
|
|
@@ -16,6 +18,8 @@
|
|
|
16
18
|
|-----------|------------|
|
|
17
19
|
| Language | PHP >= 8.3 |
|
|
18
20
|
| Framework | {{FRAMEWORK}} |
|
|
21
|
+
| Server | Octane + RoadRunner |
|
|
22
|
+
| Frontend | ReactJS 19+ / Inertia.js / TailwindCSS 4+ |
|
|
19
23
|
| Database | {{DATABASE}} |
|
|
20
24
|
| Package Manager | Composer |
|
|
21
25
|
| Static Analysis | PHPStan (level 6) |
|
|
@@ -26,41 +30,186 @@
|
|
|
26
30
|
|
|
27
31
|
```
|
|
28
32
|
project/
|
|
29
|
-
├──
|
|
30
|
-
├──
|
|
31
|
-
├──
|
|
33
|
+
├── app/
|
|
34
|
+
│ ├── Console/ # Artisan commands
|
|
35
|
+
│ ├── Exceptions/ # Exception handlers
|
|
36
|
+
│ ├── Http/
|
|
37
|
+
│ │ ├── Controllers/ # Thin controllers (Inertia::render + Services)
|
|
38
|
+
│ │ ├── Middleware/ # HTTP middleware (HandleInertiaRequests)
|
|
39
|
+
│ │ └── Requests/ # Form request validation
|
|
40
|
+
│ ├── Models/ # Eloquent models (UUIDs, $fillable)
|
|
41
|
+
│ ├── Providers/ # Service providers
|
|
42
|
+
│ ├── Services/ # Business logic (single responsibility)
|
|
43
|
+
│ │ └── Helpers/ # Extracted logic for complex services
|
|
44
|
+
│ ├── Support/ # Helper classes (InertiaShare)
|
|
45
|
+
│ ├── Traits/ # Shared traits (Loggable, FormatsDatesForApi)
|
|
46
|
+
│ └── Jobs/ # Queue jobs (idempotent, chunked)
|
|
47
|
+
├── bootstrap/ # Framework bootstrap
|
|
48
|
+
├── config/ # Configuration (immutable at runtime)
|
|
49
|
+
│ └── translations_inertia.php # Per-page translation mapping
|
|
50
|
+
├── database/
|
|
51
|
+
│ ├── factories/ # Model factories
|
|
52
|
+
│ ├── migrations/ # Incremental migrations ONLY
|
|
53
|
+
│ └── seeders/ # Database seeders
|
|
54
|
+
├── lang/
|
|
55
|
+
│ ├── en/ # English translations
|
|
56
|
+
│ └── pt/ # Portuguese translations
|
|
57
|
+
├── public/ # Web root (index.php)
|
|
58
|
+
├── resources/
|
|
59
|
+
│ ├── views/ # Blade root template (app.blade.php)
|
|
60
|
+
│ ├── css/ # Stylesheets (TailwindCSS)
|
|
61
|
+
│ └── js/
|
|
62
|
+
│ ├── Pages/ # React page components (mapped by Inertia)
|
|
63
|
+
│ ├── Components/ # Reusable React components
|
|
64
|
+
│ ├── Layouts/ # Page layouts (Authenticated, Guest)
|
|
65
|
+
│ ├── Icons/ # SVG icons (import with ?react)
|
|
66
|
+
│ └── Utils/
|
|
67
|
+
│ └── translate.js # __() translation helper
|
|
68
|
+
├── routes/
|
|
69
|
+
│ ├── api.php # API routes (RESTful + action endpoints)
|
|
70
|
+
│ └── web.php # Web routes (Inertia pages)
|
|
71
|
+
├── storage/ # Logs, cache, uploads
|
|
32
72
|
├── tests/
|
|
33
|
-
│ ├── Unit/
|
|
34
|
-
│ └── Feature/
|
|
35
|
-
├──
|
|
36
|
-
├──
|
|
37
|
-
├──
|
|
38
|
-
├──
|
|
39
|
-
|
|
73
|
+
│ ├── Unit/ # PHPUnit unit tests
|
|
74
|
+
│ └── Feature/ # Feature/integration tests
|
|
75
|
+
├── .claude/ # AI agent configuration
|
|
76
|
+
├── artisan # CLI entry point
|
|
77
|
+
├── rr.yaml # RoadRunner config (Octane)
|
|
78
|
+
├── composer.json # Dependencies
|
|
79
|
+
├── phpstan.neon # Static analysis config
|
|
80
|
+
└── CLAUDE.md # This file
|
|
40
81
|
```
|
|
41
82
|
|
|
83
|
+
## CLAUDE.md Update Rules
|
|
84
|
+
|
|
85
|
+
> After ANY implementation, update this file to reflect the current state.
|
|
86
|
+
|
|
87
|
+
| Change Type | Sections to Update |
|
|
88
|
+
|-------------|-------------------|
|
|
89
|
+
| Any file change | Last Change (branch, date, summary) |
|
|
90
|
+
| API/routes | Critical Rules, Architecture |
|
|
91
|
+
| New feature | 30s Overview, Architecture |
|
|
92
|
+
| New gotcha | FORBIDDEN or NRY |
|
|
93
|
+
| New dependency | Stack |
|
|
94
|
+
| Workflow change | Workflow section |
|
|
95
|
+
|
|
96
|
+
1. **Last Change** documents WHAT was done
|
|
97
|
+
2. **Other sections** document HOW things work NOW
|
|
98
|
+
3. **Both must be current** — updating only Last Change is insufficient
|
|
99
|
+
4. Keep only the LATEST Last Change entry (no stacking)
|
|
100
|
+
|
|
42
101
|
## Critical Rules
|
|
43
102
|
|
|
44
|
-
- **PHP >= 8.3** —
|
|
103
|
+
- **PHP >= 8.3** — readonly, enums, typed constants, match expressions
|
|
45
104
|
- **`declare(strict_types=1)`** in EVERY PHP file
|
|
46
|
-
- **
|
|
47
|
-
- **
|
|
48
|
-
- **
|
|
49
|
-
- **
|
|
50
|
-
- **
|
|
105
|
+
- **Octane-safe code** — no static state, no globals, no `die()`/`exit()`
|
|
106
|
+
- **Dependency Injection** — use DI over `app()` or `resolve()`
|
|
107
|
+
- **Thin controllers** — delegate business logic to Service classes
|
|
108
|
+
- **Form Requests** — validate input in dedicated request classes
|
|
109
|
+
- **Type everything** — properties, params, returns (no `mixed` without justification)
|
|
110
|
+
- **UUIDs** — all new models use `HasUuids` trait as primary key
|
|
111
|
+
- **Mass assignment** — always define `$fillable` on models
|
|
112
|
+
- **Auditing** — critical models use `Loggable` trait
|
|
113
|
+
- **Eloquent only** — no raw SQL unless strictly justified with parameter binding
|
|
114
|
+
- **Config immutable** — never use `config()` to SET values at runtime
|
|
115
|
+
- **Request object** — use `$request->input()`, never `$_GET`/`$_POST`/`$_SESSION`
|
|
116
|
+
|
|
117
|
+
### Environment Variables & Secrets (MANDATORY)
|
|
118
|
+
|
|
119
|
+
> **NEVER use `env()` outside config files.** After `config:cache`, `env()` returns null everywhere except config files.
|
|
120
|
+
|
|
121
|
+
| Location | Access | Safe for |
|
|
122
|
+
|----------|--------|----------|
|
|
123
|
+
| `.env` | `env()` inside `config/*.php` only | API keys, DB credentials, secrets |
|
|
124
|
+
| `config/*.php` | `config('services.stripe.key')` | Application code access |
|
|
125
|
+
| Frontend (Inertia) | `InertiaShare` or controller props | Public data ONLY |
|
|
126
|
+
|
|
127
|
+
```php
|
|
128
|
+
// config/services.php — Bridge between .env and application
|
|
129
|
+
return [
|
|
130
|
+
'openai' => [
|
|
131
|
+
'key' => env('OPENAI_KEY'),
|
|
132
|
+
],
|
|
133
|
+
'stripe' => [
|
|
134
|
+
'key' => env('STRIPE_KEY'), // Publishable (sent to frontend)
|
|
135
|
+
'secret' => env('STRIPE_SECRET'), // NEVER send to frontend
|
|
136
|
+
'webhook_secret' => env('STRIPE_WEBHOOK_SECRET'),
|
|
137
|
+
],
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
// In code: ALWAYS use config()
|
|
141
|
+
$apiKey = config('services.openai.key');
|
|
142
|
+
|
|
143
|
+
// FORBIDDEN:
|
|
144
|
+
$apiKey = env('OPENAI_KEY'); // Returns null when config is cached!
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Frontend Secret Isolation (MANDATORY)
|
|
148
|
+
|
|
149
|
+
> **NEVER send API keys, secrets, or tokens to the frontend via Inertia props or JavaScript.**
|
|
150
|
+
|
|
151
|
+
```php
|
|
152
|
+
// WRONG — secret exposed in page source / DevTools
|
|
153
|
+
return Inertia::render('Dashboard', [
|
|
154
|
+
'stripeSecret' => config('services.stripe.secret'),
|
|
155
|
+
'openaiKey' => config('services.openai.key'),
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
// CORRECT — only public/publishable data to frontend
|
|
159
|
+
return Inertia::render('Dashboard', [
|
|
160
|
+
'stripePublicKey' => config('services.stripe.key'), // pk_ only
|
|
161
|
+
]);
|
|
162
|
+
|
|
163
|
+
// For operations requiring secrets: use backend API routes
|
|
164
|
+
// Frontend calls /api/payment → backend uses secret server-side
|
|
165
|
+
```
|
|
51
166
|
|
|
52
167
|
## FORBIDDEN
|
|
53
168
|
|
|
169
|
+
### Security (CRITICAL)
|
|
170
|
+
|
|
171
|
+
| Action | Reason |
|
|
172
|
+
|--------|--------|
|
|
173
|
+
| `env()` outside config files | Returns null when config is cached — use `config()` |
|
|
174
|
+
| Send API keys/secrets via Inertia props | Exposed in page source — keep secrets server-side |
|
|
175
|
+
| `$guarded = []` on models | Allows mass assignment of any field — use `$fillable` |
|
|
176
|
+
| `DB::raw()` with user input | SQL injection — use Eloquent or parameterized queries |
|
|
177
|
+
| `{!! $userInput !!}` | XSS — use `{{ }}` (auto-escaped) |
|
|
178
|
+
| Dynamic code execution functions | Remote code execution risk |
|
|
179
|
+
| `md5()` / `sha1()` for passwords | Weak hashing — use `Hash::make()` |
|
|
180
|
+
| `unserialize()` on user data | Object injection — use JSON with model casts |
|
|
181
|
+
| CORS `allowed_origins: ['*']` | Open API — restrict to your domain |
|
|
182
|
+
| `createToken('x', ['*'])` | Over-privileged — use specific abilities |
|
|
183
|
+
| Trust `X-Forwarded-For` directly | Spoofable — use trusted proxies config |
|
|
184
|
+
| `$_GET` / `$_POST` / `$_SESSION` | Stale in Octane — use `$request->input()` |
|
|
185
|
+
|
|
186
|
+
### Backend
|
|
187
|
+
|
|
188
|
+
| Action | Reason |
|
|
189
|
+
|--------|--------|
|
|
190
|
+
| Business logic in controllers | Move to Service classes |
|
|
191
|
+
| `static` properties on services | Memory leaks in Octane workers |
|
|
192
|
+
| Global variables / superglobals | Stale state in Octane |
|
|
193
|
+
| `die()` / `exit()` | Kills the Octane worker process |
|
|
194
|
+
| `config(['key' => 'val'])` at runtime | Affects all concurrent requests |
|
|
195
|
+
| `migrate:fresh` / `db:wipe` / `db:reset` | Destroys production data |
|
|
196
|
+
| `app()` / `resolve()` in constructors | Use constructor DI instead |
|
|
197
|
+
| `Inertia::render()` after POST/PUT/DELETE | Use `redirect()->route()` instead |
|
|
198
|
+
| `dd()` / `dump()` in production code | Use structured `Log::info()` |
|
|
199
|
+
|
|
200
|
+
### Frontend (React)
|
|
201
|
+
|
|
54
202
|
| Action | Reason |
|
|
55
203
|
|--------|--------|
|
|
56
|
-
|
|
|
57
|
-
| `
|
|
58
|
-
| `
|
|
59
|
-
|
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
| `
|
|
63
|
-
|
|
|
204
|
+
| Call external APIs with secrets from JS | Exposes tokens — route through Laravel API |
|
|
205
|
+
| `__()` inside JSX / render | Hook violation — define as CONST before hooks |
|
|
206
|
+
| `fetch()` / `axios` for page data | Bypasses Inertia — use props from controller |
|
|
207
|
+
| `<a href>` for internal links | Full page reload — use `<Link>` |
|
|
208
|
+
| `window.location` for navigation | Full reload — use `router.visit()` |
|
|
209
|
+
| Inline SVGs in JSX | Bloats components — use SVG files with `?react` |
|
|
210
|
+
| Raw `console.log` | Uncontrolled — use debug constant pattern |
|
|
211
|
+
| Inline Tailwind class soup | Unreadable — use STYLES const object |
|
|
212
|
+
| `axios.post()` for forms | No CSRF/errors — use `useForm().post()` |
|
|
64
213
|
|
|
65
214
|
## Quality Gates
|
|
66
215
|
|
|
@@ -68,21 +217,72 @@ project/
|
|
|
68
217
|
vendor/bin/phpstan analyse --level=6 # Static analysis
|
|
69
218
|
vendor/bin/phpunit # Tests
|
|
70
219
|
vendor/bin/php-cs-fixer fix --dry-run # Code style
|
|
220
|
+
php artisan test # Laravel test runner
|
|
71
221
|
```
|
|
72
222
|
|
|
73
|
-
##
|
|
223
|
+
## Database
|
|
74
224
|
|
|
75
|
-
|
|
225
|
+
Use Eloquent ORM and Query Builder. Raw queries only when strictly necessary with parameter binding:
|
|
76
226
|
|
|
77
227
|
```php
|
|
78
|
-
|
|
79
|
-
$
|
|
228
|
+
// Eloquent (preferred)
|
|
229
|
+
$user = User::findOrFail($id);
|
|
230
|
+
|
|
231
|
+
// Query Builder
|
|
232
|
+
$users = DB::table('users')->where('active', true)->get();
|
|
233
|
+
|
|
234
|
+
// Raw query (last resort — always bind parameters)
|
|
235
|
+
$results = DB::select('SELECT * FROM users WHERE id = ?', [$id]);
|
|
80
236
|
```
|
|
81
237
|
|
|
238
|
+
## Migration Safety
|
|
239
|
+
|
|
240
|
+
- **ALWAYS** use incremental migrations (`make:migration`)
|
|
241
|
+
- **NEVER** execute `migrate:fresh`, `migrate:refresh`, `db:wipe`, `db:reset`
|
|
242
|
+
- If a migration fails, fix the file or create a new one
|
|
243
|
+
- Assume all environments contain critical data
|
|
244
|
+
|
|
82
245
|
## Workflow
|
|
83
246
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
247
|
+
```
|
|
248
|
+
0. TODO LIST → Create detailed todo list from prompt
|
|
249
|
+
1. BRANCH → Create feature/ | fix/ | refactor/ | test/
|
|
250
|
+
2. RESEARCH → Run research-web agent for NEW features
|
|
251
|
+
3. IMPLEMENT → Types, strict mode, Octane-safe, DI
|
|
252
|
+
4. TEST → Run PHPStan + PHPUnit
|
|
253
|
+
5. DOCUMENT → Run documenter agent for modified files
|
|
254
|
+
6. UPDATE → Update THIS FILE (CLAUDE.md) with changes
|
|
255
|
+
7. QUALITY → PHPStan + PHPUnit + PHP-CS-Fixer
|
|
256
|
+
8. COMMIT → Conventional commits, merge to main
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Domain Documentation
|
|
260
|
+
|
|
261
|
+
> Domain docs prevent Claude from re-exploring the codebase every session.
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
.claude/skills/codebase-knowledge/domains/
|
|
265
|
+
├── authentication.md
|
|
266
|
+
├── api.md
|
|
267
|
+
├── database.md
|
|
268
|
+
├── ui-components.md
|
|
269
|
+
└── [domain-name].md
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Each domain file tracks: Files, Connections, Recent Commits, Attention Points, Problems & Solutions.
|
|
273
|
+
|
|
274
|
+
## Configuration
|
|
275
|
+
|
|
276
|
+
Project settings in `.claude/config/` (generated by start-vibing-stacks):
|
|
277
|
+
|
|
278
|
+
- `active-project.json` — Stack, framework, database, skills
|
|
279
|
+
- `domain-mapping.json` — File-to-domain mapping
|
|
280
|
+
- `quality-gates.json` — Quality check commands
|
|
281
|
+
- `testing-config.json` — Test framework config
|
|
282
|
+
- `security-rules.json` — Security audit rules
|
|
283
|
+
- `standards-review.json` — Imported project standards
|
|
284
|
+
|
|
285
|
+
## Setup by start-vibing-stacks
|
|
286
|
+
|
|
287
|
+
This project was set up with `npx start-vibing-stacks`.
|
|
288
|
+
For updates: `npx start-vibing-stacks --force`
|