start-vibing-stacks 2.3.0 → 2.4.1

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
@@ -78,6 +80,24 @@ project/
78
80
  └── CLAUDE.md # This file
79
81
  ```
80
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
+
81
101
  ## Critical Rules
82
102
 
83
103
  - **PHP >= 8.3** — readonly, enums, typed constants, match expressions
@@ -94,18 +114,80 @@ project/
94
114
  - **Config immutable** — never use `config()` to SET values at runtime
95
115
  - **Request object** — use `$request->input()`, never `$_GET`/`$_POST`/`$_SESSION`
96
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
+ ```
166
+
97
167
  ## FORBIDDEN
98
168
 
99
- ### Backend
169
+ ### Security (CRITICAL)
100
170
 
101
171
  | Action | Reason |
102
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) |
103
178
  | Dynamic code execution functions | Remote code execution risk |
104
- | `DB::raw()` with user input | SQL injection risk |
105
- | `{!! $userInput !!}` | XSS — use `{{ }}` instead |
106
- | Mass assignment without `$fillable` | Uncontrolled field injection |
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
+ |--------|--------|
107
190
  | Business logic in controllers | Move to Service classes |
108
- | `env()` outside config files | Returns null when config is cached |
109
191
  | `static` properties on services | Memory leaks in Octane workers |
110
192
  | Global variables / superglobals | Stale state in Octane |
111
193
  | `die()` / `exit()` | Kills the Octane worker process |
@@ -113,11 +195,13 @@ project/
113
195
  | `migrate:fresh` / `db:wipe` / `db:reset` | Destroys production data |
114
196
  | `app()` / `resolve()` in constructors | Use constructor DI instead |
115
197
  | `Inertia::render()` after POST/PUT/DELETE | Use `redirect()->route()` instead |
198
+ | `dd()` / `dump()` in production code | Use structured `Log::info()` |
116
199
 
117
200
  ### Frontend (React)
118
201
 
119
202
  | Action | Reason |
120
203
  |--------|--------|
204
+ | Call external APIs with secrets from JS | Exposes tokens — route through Laravel API |
121
205
  | `__()` inside JSX / render | Hook violation — define as CONST before hooks |
122
206
  | `fetch()` / `axios` for page data | Bypasses Inertia — use props from controller |
123
207
  | `<a href>` for internal links | Full page reload — use `<Link>` |
@@ -160,8 +244,45 @@ $results = DB::select('SELECT * FROM users WHERE id = ?', [$id]);
160
244
 
161
245
  ## Workflow
162
246
 
163
- 1. Create feature branch
164
- 2. Implement with types, strict mode, Octane-safe patterns
165
- 3. Run PHPStan + PHPUnit
166
- 4. Update domains & CLAUDE.md
167
- 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`