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.
@@ -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
- ├── src/ # Application source (PSR-4: App\)
30
- ├── public/ # Web root (index.php)
31
- ├── config/ # Configuration files
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/ # PHPUnit unit tests
34
- │ └── Feature/ # Feature/integration tests
35
- ├── storage/ # Logs, cache, uploads
36
- ├── .claude/ # AI agent configuration
37
- ├── composer.json # Dependencies
38
- ├── phpstan.neon # Static analysis config
39
- └── CLAUDE.md # This file
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** — use modern features (readonly, enums, typed constants)
103
+ - **PHP >= 8.3** — readonly, enums, typed constants, match expressions
45
104
  - **`declare(strict_types=1)`** in EVERY PHP file
46
- - **PSR-4 autoloading** — no manual includes
47
- - **Prepared statements** — NEVER concatenate SQL
48
- - **Type everything** — properties, params, returns
49
- - **htmlspecialchars()** — all user output
50
- - **password_hash/verify** — NEVER md5/sha1
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
- | `eval()` | Remote code execution risk |
57
- | `mysql_*` functions | Deprecated, use PDO |
58
- | `extract($_POST)` | Variable injection |
59
- | `include $_GET[...]` | Local file inclusion |
60
- | SQL without prepared statements | SQL injection |
61
- | `echo $userInput` without escape | XSS |
62
- | `md5($password)` | Weak hashing |
63
- | PHP < 8.3 syntax | Version requirement |
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
- ## HTTP Requests
223
+ ## Database
74
224
 
75
- All database queries MUST use prepared statements:
225
+ Use Eloquent ORM and Query Builder. Raw queries only when strictly necessary with parameter binding:
76
226
 
77
227
  ```php
78
- $stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
79
- $stmt->execute([':id' => $userId]);
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
- 1. Create feature branch
85
- 2. Implement with types, strict mode
86
- 3. Run PHPStan + PHPUnit
87
- 4. Update domains & CLAUDE.md
88
- 5. Commit merge to main
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`