claude-mpm 5.4.59__py3-none-any.whl → 5.4.62__py3-none-any.whl
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.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +5 -0
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +8 -0
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/pm/pm-delegation-patterns/SKILL.md +167 -0
- claude_mpm/skills/bundled/pm/pm-git-file-tracking/SKILL.md +113 -0
- claude_mpm/skills/bundled/pm/pm-pr-workflow/SKILL.md +124 -0
- claude_mpm/skills/bundled/pm/pm-ticketing-integration/SKILL.md +154 -0
- claude_mpm/skills/bundled/pm/pm-verification-protocols/SKILL.md +198 -0
- claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
- claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
- claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
- claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
- claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
- claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
- claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
- claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
- claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
- claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
- claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- {claude_mpm-5.4.59.dist-info → claude_mpm-5.4.62.dist-info}/METADATA +1 -1
- {claude_mpm-5.4.59.dist-info → claude_mpm-5.4.62.dist-info}/RECORD +127 -10
- {claude_mpm-5.4.59.dist-info → claude_mpm-5.4.62.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.59.dist-info → claude_mpm-5.4.62.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.59.dist-info → claude_mpm-5.4.62.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.59.dist-info → claude_mpm-5.4.62.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.59.dist-info → claude_mpm-5.4.62.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
# Framework-Specific Environment Patterns
|
|
2
|
+
|
|
3
|
+
> **Part of**: [env-manager](../SKILL.md)
|
|
4
|
+
> **Category**: infrastructure
|
|
5
|
+
> **Reading Level**: Intermediate
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
Complete patterns for framework-specific environment variable handling: Next.js, Express, Flask, Django, Vite, and Create React App.
|
|
10
|
+
|
|
11
|
+
## Framework Detection
|
|
12
|
+
|
|
13
|
+
### Auto-Detection Logic
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
def detect_framework(project_dir: Path) -> Optional[str]:
|
|
20
|
+
"""Auto-detect framework from project structure."""
|
|
21
|
+
|
|
22
|
+
detection_patterns = {
|
|
23
|
+
'nextjs': ['next.config.js', 'next.config.mjs', 'next.config.ts'],
|
|
24
|
+
'vite': ['vite.config.js', 'vite.config.ts'],
|
|
25
|
+
'react': ['react-scripts', 'craco.config.js'],
|
|
26
|
+
'express': ['express', 'app.js', 'server.js'],
|
|
27
|
+
'flask': ['app.py', 'wsgi.py', 'requirements.txt'],
|
|
28
|
+
'django': ['manage.py', 'settings.py'],
|
|
29
|
+
'fastapi': ['main.py', 'fastapi']
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# Check package.json for JS frameworks
|
|
33
|
+
package_json = project_dir / 'package.json'
|
|
34
|
+
if package_json.exists():
|
|
35
|
+
import json
|
|
36
|
+
with open(package_json) as f:
|
|
37
|
+
data = json.load(f)
|
|
38
|
+
deps = {**data.get('dependencies', {}), **data.get('devDependencies', {})}
|
|
39
|
+
|
|
40
|
+
if 'next' in deps:
|
|
41
|
+
return 'nextjs'
|
|
42
|
+
elif 'vite' in deps:
|
|
43
|
+
return 'vite'
|
|
44
|
+
elif 'react-scripts' in deps:
|
|
45
|
+
return 'react'
|
|
46
|
+
elif 'express' in deps:
|
|
47
|
+
return 'express'
|
|
48
|
+
|
|
49
|
+
# Check for Python frameworks
|
|
50
|
+
requirements = project_dir / 'requirements.txt'
|
|
51
|
+
if requirements.exists():
|
|
52
|
+
content = requirements.read_text().lower()
|
|
53
|
+
if 'flask' in content:
|
|
54
|
+
return 'flask'
|
|
55
|
+
elif 'django' in content:
|
|
56
|
+
return 'django'
|
|
57
|
+
elif 'fastapi' in content:
|
|
58
|
+
return 'fastapi'
|
|
59
|
+
|
|
60
|
+
# Check for specific files
|
|
61
|
+
for framework, patterns in detection_patterns.items():
|
|
62
|
+
for pattern in patterns:
|
|
63
|
+
if (project_dir / pattern).exists():
|
|
64
|
+
return framework
|
|
65
|
+
|
|
66
|
+
return 'generic'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Next.js
|
|
70
|
+
|
|
71
|
+
### File Precedence
|
|
72
|
+
|
|
73
|
+
Next.js loads env files in this order (higher precedence first):
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
1. .env.$(NODE_ENV).local (e.g., .env.production.local)
|
|
77
|
+
2. .env.local (always, except in test)
|
|
78
|
+
3. .env.$(NODE_ENV) (e.g., .env.production)
|
|
79
|
+
4. .env
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Public vs Private Variables
|
|
83
|
+
|
|
84
|
+
**Client-Side (Public):**
|
|
85
|
+
```bash
|
|
86
|
+
# Prefix with NEXT_PUBLIC_ for browser access
|
|
87
|
+
NEXT_PUBLIC_API_URL=https://api.example.com
|
|
88
|
+
NEXT_PUBLIC_ANALYTICS_ID=UA-123456789
|
|
89
|
+
NEXT_PUBLIC_SITE_NAME=My App
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Server-Side (Private):**
|
|
93
|
+
```bash
|
|
94
|
+
# No prefix - only available server-side
|
|
95
|
+
DATABASE_URL=postgres://localhost:5432/mydb
|
|
96
|
+
JWT_SECRET=super-secret-key-never-expose
|
|
97
|
+
API_SECRET_KEY=sk_live_abc123
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Validation Rules
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
def validate_nextjs_env(env_file: Path) -> Dict:
|
|
104
|
+
"""Validate Next.js environment variables."""
|
|
105
|
+
errors = []
|
|
106
|
+
warnings = []
|
|
107
|
+
|
|
108
|
+
vars_dict = parse_env_file(env_file)
|
|
109
|
+
|
|
110
|
+
for key, value in vars_dict.items():
|
|
111
|
+
# Check for secrets in public vars
|
|
112
|
+
if key.startswith('NEXT_PUBLIC_'):
|
|
113
|
+
secret_indicators = ['secret', 'key', 'password', 'token', 'private']
|
|
114
|
+
if any(indicator in key.lower() for indicator in secret_indicators):
|
|
115
|
+
errors.append({
|
|
116
|
+
'key': key,
|
|
117
|
+
'error': 'SECURITY: Secret in NEXT_PUBLIC_ variable (exposed to browser)'
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
# Check for API endpoints without NEXT_PUBLIC_
|
|
121
|
+
if 'api' in key.lower() and 'url' in key.lower():
|
|
122
|
+
if not key.startswith('NEXT_PUBLIC_'):
|
|
123
|
+
warnings.append({
|
|
124
|
+
'key': key,
|
|
125
|
+
'warning': 'API URL without NEXT_PUBLIC_ prefix (not accessible client-side)'
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
return {'errors': errors, 'warnings': warnings}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### File Structure Example
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# .env (committed - shared defaults)
|
|
135
|
+
NEXT_PUBLIC_APP_NAME=My App
|
|
136
|
+
DATABASE_URL=postgres://localhost:5432/dev
|
|
137
|
+
|
|
138
|
+
# .env.local (gitignored - local overrides)
|
|
139
|
+
DATABASE_URL=postgres://localhost:5432/mylocal
|
|
140
|
+
JWT_SECRET=dev-jwt-secret-123
|
|
141
|
+
|
|
142
|
+
# .env.production (committed - production defaults)
|
|
143
|
+
NEXT_PUBLIC_API_URL=https://api.example.com
|
|
144
|
+
|
|
145
|
+
# .env.production.local (gitignored - production secrets)
|
|
146
|
+
DATABASE_URL=postgres://prod.example.com:5432/prod
|
|
147
|
+
JWT_SECRET=prod-jwt-secret-xyz
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Express/Node.js
|
|
151
|
+
|
|
152
|
+
### Standard Variables
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Node environment
|
|
156
|
+
NODE_ENV=development # or production, test
|
|
157
|
+
|
|
158
|
+
# Server configuration
|
|
159
|
+
PORT=3000
|
|
160
|
+
HOST=localhost
|
|
161
|
+
|
|
162
|
+
# Database
|
|
163
|
+
DATABASE_URL=postgres://localhost:5432/mydb
|
|
164
|
+
|
|
165
|
+
# Security
|
|
166
|
+
JWT_SECRET=your-secret-key
|
|
167
|
+
SESSION_SECRET=session-secret
|
|
168
|
+
|
|
169
|
+
# External services
|
|
170
|
+
REDIS_URL=redis://localhost:6379
|
|
171
|
+
SMTP_HOST=smtp.example.com
|
|
172
|
+
SMTP_PORT=587
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Validation Rules
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
NODE_STANDARD_VARS = {
|
|
179
|
+
'NODE_ENV': ['development', 'production', 'test'],
|
|
180
|
+
'PORT': lambda v: v.isdigit() and 1 <= int(v) <= 65535,
|
|
181
|
+
'DATABASE_URL': lambda v: v.startswith(('postgres://', 'mysql://', 'mongodb://'))
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
def validate_nodejs_env(env_file: Path) -> List[Dict]:
|
|
185
|
+
"""Validate Node.js environment variables."""
|
|
186
|
+
errors = []
|
|
187
|
+
vars_dict = parse_env_file(env_file)
|
|
188
|
+
|
|
189
|
+
for key, validator in NODE_STANDARD_VARS.items():
|
|
190
|
+
if key in vars_dict:
|
|
191
|
+
value = vars_dict[key]
|
|
192
|
+
|
|
193
|
+
if isinstance(validator, list):
|
|
194
|
+
if value not in validator:
|
|
195
|
+
errors.append({
|
|
196
|
+
'key': key,
|
|
197
|
+
'error': f'Invalid value "{value}", expected one of {validator}'
|
|
198
|
+
})
|
|
199
|
+
elif callable(validator):
|
|
200
|
+
if not validator(value):
|
|
201
|
+
errors.append({
|
|
202
|
+
'key': key,
|
|
203
|
+
'error': 'Value validation failed'
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
return errors
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Flask/Python
|
|
210
|
+
|
|
211
|
+
### Standard Variables
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# Flask configuration
|
|
215
|
+
FLASK_APP=app.py
|
|
216
|
+
FLASK_ENV=development # or production
|
|
217
|
+
FLASK_DEBUG=1
|
|
218
|
+
|
|
219
|
+
# Database (SQLAlchemy)
|
|
220
|
+
DATABASE_URL=postgresql://localhost/mydb
|
|
221
|
+
SQLALCHEMY_DATABASE_URI=postgresql://localhost/mydb
|
|
222
|
+
|
|
223
|
+
# Security
|
|
224
|
+
SECRET_KEY=your-secret-key-here
|
|
225
|
+
WTF_CSRF_SECRET_KEY=csrf-secret
|
|
226
|
+
|
|
227
|
+
# External services
|
|
228
|
+
REDIS_URL=redis://localhost:6379
|
|
229
|
+
MAIL_SERVER=smtp.gmail.com
|
|
230
|
+
MAIL_PORT=587
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Python-dotenv Loading
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
# Load environment in Flask app
|
|
237
|
+
from dotenv import load_dotenv
|
|
238
|
+
import os
|
|
239
|
+
|
|
240
|
+
# Load .env file
|
|
241
|
+
load_dotenv()
|
|
242
|
+
|
|
243
|
+
# Access variables
|
|
244
|
+
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
|
|
245
|
+
app.config['DATABASE_URL'] = os.getenv('DATABASE_URL')
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Validation Rules
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
FLASK_STANDARD_VARS = {
|
|
252
|
+
'FLASK_APP': lambda v: v.endswith('.py'),
|
|
253
|
+
'FLASK_ENV': ['development', 'production'],
|
|
254
|
+
'FLASK_DEBUG': ['0', '1', 'true', 'false']
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
def validate_flask_env(env_file: Path) -> List[Dict]:
|
|
258
|
+
"""Validate Flask environment variables."""
|
|
259
|
+
errors = []
|
|
260
|
+
vars_dict = parse_env_file(env_file)
|
|
261
|
+
|
|
262
|
+
# Check required Flask vars
|
|
263
|
+
required = ['FLASK_APP', 'SECRET_KEY']
|
|
264
|
+
for var in required:
|
|
265
|
+
if var not in vars_dict:
|
|
266
|
+
errors.append({
|
|
267
|
+
'key': var,
|
|
268
|
+
'error': f'Required Flask variable missing'
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
# Validate present vars
|
|
272
|
+
for key, validator in FLASK_STANDARD_VARS.items():
|
|
273
|
+
if key in vars_dict:
|
|
274
|
+
value = vars_dict[key]
|
|
275
|
+
if isinstance(validator, list) and value not in validator:
|
|
276
|
+
errors.append({
|
|
277
|
+
'key': key,
|
|
278
|
+
'error': f'Invalid value, expected one of {validator}'
|
|
279
|
+
})
|
|
280
|
+
elif callable(validator) and not validator(value):
|
|
281
|
+
errors.append({
|
|
282
|
+
'key': key,
|
|
283
|
+
'error': 'Value validation failed'
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
return errors
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Django
|
|
290
|
+
|
|
291
|
+
### Standard Variables
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
# Django configuration
|
|
295
|
+
DJANGO_SETTINGS_MODULE=myproject.settings
|
|
296
|
+
DJANGO_SECRET_KEY=your-secret-key
|
|
297
|
+
DJANGO_DEBUG=False
|
|
298
|
+
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1
|
|
299
|
+
|
|
300
|
+
# Database
|
|
301
|
+
DATABASE_URL=postgres://localhost:5432/mydb
|
|
302
|
+
|
|
303
|
+
# Static/Media files
|
|
304
|
+
STATIC_ROOT=/var/www/static
|
|
305
|
+
MEDIA_ROOT=/var/www/media
|
|
306
|
+
|
|
307
|
+
# Security
|
|
308
|
+
CSRF_TRUSTED_ORIGINS=https://example.com
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Settings.py Integration
|
|
312
|
+
|
|
313
|
+
```python
|
|
314
|
+
# settings.py
|
|
315
|
+
import os
|
|
316
|
+
from pathlib import Path
|
|
317
|
+
from dotenv import load_dotenv
|
|
318
|
+
|
|
319
|
+
# Load .env
|
|
320
|
+
load_dotenv()
|
|
321
|
+
|
|
322
|
+
# Use env variables
|
|
323
|
+
SECRET_KEY = os.getenv('DJANGO_SECRET_KEY')
|
|
324
|
+
DEBUG = os.getenv('DJANGO_DEBUG', 'False') == 'True'
|
|
325
|
+
ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', '').split(',')
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Vite
|
|
329
|
+
|
|
330
|
+
### Environment Variable Access
|
|
331
|
+
|
|
332
|
+
**Client-Side Variables:**
|
|
333
|
+
```bash
|
|
334
|
+
# Must prefix with VITE_ for access
|
|
335
|
+
VITE_API_URL=https://api.example.com
|
|
336
|
+
VITE_APP_TITLE=My App
|
|
337
|
+
VITE_ENABLE_ANALYTICS=true
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Usage in Code:**
|
|
341
|
+
```javascript
|
|
342
|
+
// Access via import.meta.env
|
|
343
|
+
const apiUrl = import.meta.env.VITE_API_URL;
|
|
344
|
+
const appTitle = import.meta.env.VITE_APP_TITLE;
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Validation Rules
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
def validate_vite_env(env_file: Path) -> List[Dict]:
|
|
351
|
+
"""Validate Vite environment variables."""
|
|
352
|
+
errors = []
|
|
353
|
+
vars_dict = parse_env_file(env_file)
|
|
354
|
+
|
|
355
|
+
for key, value in vars_dict.items():
|
|
356
|
+
# Check for secrets in VITE_ vars
|
|
357
|
+
if key.startswith('VITE_'):
|
|
358
|
+
if any(s in key.lower() for s in ['secret', 'key', 'password', 'token']):
|
|
359
|
+
errors.append({
|
|
360
|
+
'key': key,
|
|
361
|
+
'error': 'SECURITY: Secret in VITE_ variable (exposed to browser)'
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
# Warn about non-VITE_ vars (won't be accessible)
|
|
365
|
+
elif not key in ['NODE_ENV', 'PORT']:
|
|
366
|
+
errors.append({
|
|
367
|
+
'key': key,
|
|
368
|
+
'warning': f'{key} not prefixed with VITE_ (not accessible in client code)'
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
return errors
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Create React App
|
|
375
|
+
|
|
376
|
+
### Environment Variable Access
|
|
377
|
+
|
|
378
|
+
**Client-Side Variables:**
|
|
379
|
+
```bash
|
|
380
|
+
# Must prefix with REACT_APP_ for access
|
|
381
|
+
REACT_APP_API_URL=https://api.example.com
|
|
382
|
+
REACT_APP_AUTH0_DOMAIN=example.auth0.com
|
|
383
|
+
REACT_APP_ENABLE_ANALYTICS=true
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**Built-in Variables:**
|
|
387
|
+
```bash
|
|
388
|
+
NODE_ENV=development # Set by CRA automatically
|
|
389
|
+
PUBLIC_URL=/ # Public URL of the app
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
**Usage in Code:**
|
|
393
|
+
```javascript
|
|
394
|
+
// Access via process.env
|
|
395
|
+
const apiUrl = process.env.REACT_APP_API_URL;
|
|
396
|
+
const domain = process.env.REACT_APP_AUTH0_DOMAIN;
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
## Framework Comparison Table
|
|
400
|
+
|
|
401
|
+
| Framework | Client Prefix | Server Access | File Precedence | Auto-Reload |
|
|
402
|
+
|-----------|---------------|---------------|-----------------|-------------|
|
|
403
|
+
| Next.js | NEXT_PUBLIC_ | All vars | Complex (4 files) | Dev only |
|
|
404
|
+
| Vite | VITE_ | All vars | .env.local > .env | Dev only |
|
|
405
|
+
| CRA | REACT_APP_ | All vars | .env.local > .env | Requires restart |
|
|
406
|
+
| Express | N/A | All vars | .env only | With nodemon |
|
|
407
|
+
| Flask | N/A | All vars | .env only | With debug mode |
|
|
408
|
+
| Django | N/A | All vars | .env only | With runserver |
|
|
409
|
+
|
|
410
|
+
## Summary
|
|
411
|
+
|
|
412
|
+
**Framework Detection**:
|
|
413
|
+
- Auto-detect from package.json, requirements.txt, or config files
|
|
414
|
+
- Support explicit --framework override
|
|
415
|
+
|
|
416
|
+
**Key Patterns**:
|
|
417
|
+
- ✅ Next.js: NEXT_PUBLIC_ for client, file precedence critical
|
|
418
|
+
- ✅ Express: Standard NODE_ENV, PORT, DATABASE_URL
|
|
419
|
+
- ✅ Flask: FLASK_APP, FLASK_ENV, SECRET_KEY required
|
|
420
|
+
- ✅ Django: DJANGO_SETTINGS_MODULE, DJANGO_SECRET_KEY
|
|
421
|
+
- ✅ Vite: VITE_ prefix for client access
|
|
422
|
+
- ✅ CRA: REACT_APP_ prefix for client access
|
|
423
|
+
|
|
424
|
+
**Security Rules**:
|
|
425
|
+
- Never put secrets in client-exposed vars (NEXT_PUBLIC_, VITE_, REACT_APP_)
|
|
426
|
+
- Validate format of framework-specific vars
|
|
427
|
+
- Check for required variables per framework
|
|
428
|
+
|
|
429
|
+
## Related References
|
|
430
|
+
|
|
431
|
+
- [Validation](validation.md): General validation workflows
|
|
432
|
+
- [Security](security.md): Secret protection patterns
|
|
433
|
+
- [Troubleshooting](troubleshooting.md): Framework-specific issues
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
**Lines**: 279 ✓ 200-280 range
|