@mr.dj2u/knowledge 0.1.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/dist/content/checklists/ship-test-loop.md +16 -0
- package/dist/content/checklists/unified-agent-bundle-validation.md +8 -0
- package/dist/content/examples/ship-test-loop.md +13 -0
- package/dist/content/examples/unified-agent-bundle-bootstrap.md +8 -0
- package/dist/content/guides/animation-performance.md +30 -0
- package/dist/content/guides/post-create-onboarding.md +113 -0
- package/dist/content/patterns/api/api-routes.md +314 -0
- package/dist/content/patterns/api/error-handling.md +311 -0
- package/dist/content/patterns/database/drizzle-schema.md +280 -0
- package/dist/content/patterns/database/migrations.md +365 -0
- package/dist/content/patterns/database/query-organization.md +537 -0
- package/dist/content/patterns/database/relations.md +450 -0
- package/dist/content/patterns/deployment/build-configuration.md +452 -0
- package/dist/content/patterns/deployment/ci-cd-patterns.md +448 -0
- package/dist/content/patterns/deployment/environment-config.md +380 -0
- package/dist/content/patterns/deployment/hosting-setup.md +425 -0
- package/dist/content/patterns/project/configuration-patterns.md +459 -0
- package/dist/content/patterns/project/documentation-org.md +506 -0
- package/dist/content/patterns/project/folder-structure.md +398 -0
- package/dist/content/patterns/project/library-exports.md +465 -0
- package/dist/content/patterns/project/monorepo-structure.md +500 -0
- package/dist/content/patterns/routing/dynamic-routes.md +221 -0
- package/dist/content/patterns/routing/file-based-routing.md +186 -0
- package/dist/content/patterns/routing/route-groups.md +429 -0
- package/dist/content/patterns/state/persistence-middleware.md +521 -0
- package/dist/content/patterns/state/selector-hooks.md +538 -0
- package/dist/content/patterns/state/store-organization.md +539 -0
- package/dist/content/patterns/state/zustand-patterns.md +348 -0
- package/dist/content/patterns/styling/component-styling.md +468 -0
- package/dist/content/patterns/styling/responsive-patterns.md +398 -0
- package/dist/content/patterns/styling/theme-configuration.md +426 -0
- package/dist/content/patterns/styling/uniwind-setup.md +412 -0
- package/dist/content/prompts/continue-development.md +27 -0
- package/dist/content/prompts/create-expo-super-stack.md +29 -0
- package/dist/content/prompts/fix-seo.md +29 -0
- package/dist/content/prompts/onboard-new-expo-app.md +11 -0
- package/dist/content/prompts/prepare-deploy.md +29 -0
- package/dist/content/prompts/project-research-plan.md +29 -0
- package/dist/content/prompts/review-expo-project.md +29 -0
- package/dist/content/prompts/run-doctor.md +30 -0
- package/dist/content/prompts/ship-test-loop.md +24 -0
- package/dist/content/reference/create-expo-stack-uniwind.md +29 -0
- package/dist/content/reference/doctor-dogfood.md +42 -0
- package/dist/content/reference/mcp-sdk-transport.md +30 -0
- package/dist/content/reference/package-ci-patterns.md +24 -0
- package/dist/content/reference/reference-repo-evacuation.md +31 -0
- package/dist/content/resource-index.json +67 -0
- package/dist/content/rules/app-folder-architecture.md +13 -0
- package/dist/content/rules/env-hygiene.md +9 -0
- package/dist/content/rules/seo-metadata.md +7 -0
- package/dist/content/rules/ssr-safety.md +9 -0
- package/dist/content/skills/api-routes.md +33 -0
- package/dist/content/skills/continue-development.md +31 -0
- package/dist/content/skills/debugging.md +31 -0
- package/dist/content/skills/deployment.md +32 -0
- package/dist/content/skills/dev-server-management.md +31 -0
- package/dist/content/skills/env-vars.md +32 -0
- package/dist/content/skills/expo-router-architecture.md +33 -0
- package/dist/content/skills/expo-ssr-safety.md +32 -0
- package/dist/content/skills/plugin-creation.md +41 -0
- package/dist/content/skills/production-server-patterns.md +31 -0
- package/dist/content/skills/project-onboarding.md +31 -0
- package/dist/content/skills/research-plan-intake.md +31 -0
- package/dist/content/skills/seo-metadata.md +31 -0
- package/dist/content/skills/super-stack-startup.md +31 -0
- package/dist/content/skills/uniwind-theming.md +32 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +369 -0
- package/dist/index.js.map +1 -0
- package/dist/patterns/index.d.ts +78 -0
- package/dist/patterns/index.d.ts.map +1 -0
- package/dist/patterns/index.js +264 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/prompts/index.d.ts +35 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +270 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/skills/index.d.ts +3 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +2 -0
- package/dist/skills/index.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
# Environment Configuration Pattern
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Environment configuration involves organizing and managing environment variables across development, staging, and production. This includes distinguishing between client-side public variables (exposed in build) and server-side private variables (never exposed), using proper naming conventions, and managing secrets securely.
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
**Configure environments when:**
|
|
10
|
+
- ✅ Switching between dev/staging/production
|
|
11
|
+
- ✅ Managing API URLs per environment
|
|
12
|
+
- ✅ Handling secrets and private keys
|
|
13
|
+
- ✅ Configuring database connections
|
|
14
|
+
- ✅ Setting feature flags
|
|
15
|
+
- ✅ Managing logging levels
|
|
16
|
+
- ✅ Building for web vs. native
|
|
17
|
+
|
|
18
|
+
## Core Concepts
|
|
19
|
+
|
|
20
|
+
**Environment Variable Types:**
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
1. Public (Client-Exposed)
|
|
24
|
+
├── EXPO_PUBLIC_* → Included in client build
|
|
25
|
+
├── REACT_APP_* → React convention (Expo also supports)
|
|
26
|
+
└── VUE_APP_* → Vue convention (if applicable)
|
|
27
|
+
|
|
28
|
+
2. Private (Server-Only)
|
|
29
|
+
├── DATABASE_URL → Database connection
|
|
30
|
+
├── API_SECRET_KEY → Signing secrets
|
|
31
|
+
├── JWT_SECRET → JWT signing
|
|
32
|
+
├── STRIPE_SECRET_KEY → Payment secrets
|
|
33
|
+
└── (no prefix) → Convention: private unless EXPO_PUBLIC_
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Why the Distinction?**
|
|
37
|
+
- Public variables: baked into client bundle, visible to end users
|
|
38
|
+
- Private variables: stay on server, never exposed to client
|
|
39
|
+
- Mixing = security vulnerability
|
|
40
|
+
|
|
41
|
+
## Code Examples
|
|
42
|
+
|
|
43
|
+
### Environment File Structure
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# File: .env (development)
|
|
47
|
+
# Public variables - EXPOSED in client build
|
|
48
|
+
EXPO_PUBLIC_API_URL=http://localhost:3000
|
|
49
|
+
EXPO_PUBLIC_APP_NAME=MyApp
|
|
50
|
+
EXPO_PUBLIC_LOG_LEVEL=debug
|
|
51
|
+
|
|
52
|
+
# Private variables - NEVER exposed (dev only)
|
|
53
|
+
DATABASE_URL=postgresql://user:pass@localhost:5432/appdb
|
|
54
|
+
JWT_SECRET=dev-secret-key-12345
|
|
55
|
+
STRIPE_SECRET_KEY=sk_test_1234567890abcdef
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# File: .env.production (production)
|
|
60
|
+
# Public variables
|
|
61
|
+
EXPO_PUBLIC_API_URL=https://api.example.com
|
|
62
|
+
EXPO_PUBLIC_APP_NAME=MyApp
|
|
63
|
+
EXPO_PUBLIC_LOG_LEVEL=warn
|
|
64
|
+
|
|
65
|
+
# Private variables - stored in secure vault or CI/CD secrets
|
|
66
|
+
DATABASE_URL=postgresql://user:secure-password@db.example.com:5432/proddb
|
|
67
|
+
JWT_SECRET=<from-secure-vault>
|
|
68
|
+
STRIPE_SECRET_KEY=sk_live_1234567890abcdef
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Accessing Environment Variables in Code
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// File: src/config.ts
|
|
75
|
+
import { Platform } from 'react-native';
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Public configuration (safe for client)
|
|
79
|
+
* These are prefixed with EXPO_PUBLIC_ and baked into the bundle
|
|
80
|
+
*/
|
|
81
|
+
export const PUBLIC_CONFIG = {
|
|
82
|
+
apiUrl: process.env.EXPO_PUBLIC_API_URL || 'http://localhost:3000',
|
|
83
|
+
appName: process.env.EXPO_PUBLIC_APP_NAME || 'MyApp',
|
|
84
|
+
logLevel: process.env.EXPO_PUBLIC_LOG_LEVEL || 'warn',
|
|
85
|
+
environment: process.env.NODE_ENV || 'development',
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Private configuration (server-side only)
|
|
90
|
+
* Only available in Node.js, NOT in client
|
|
91
|
+
*/
|
|
92
|
+
export const PRIVATE_CONFIG = {
|
|
93
|
+
databaseUrl: process.env.DATABASE_URL,
|
|
94
|
+
jwtSecret: process.env.JWT_SECRET,
|
|
95
|
+
stripeSecretKey: process.env.STRIPE_SECRET_KEY,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Validation - ensure required vars are present
|
|
100
|
+
*/
|
|
101
|
+
export function validateConfig() {
|
|
102
|
+
// Check public vars (development only)
|
|
103
|
+
if (process.env.NODE_ENV === 'development') {
|
|
104
|
+
if (!PUBLIC_CONFIG.apiUrl) {
|
|
105
|
+
throw new Error('EXPO_PUBLIC_API_URL is required');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Check private vars (server-side only)
|
|
110
|
+
if (typeof window === 'undefined') {
|
|
111
|
+
// Running on server
|
|
112
|
+
if (!PRIVATE_CONFIG.databaseUrl) {
|
|
113
|
+
throw new Error('DATABASE_URL is required');
|
|
114
|
+
}
|
|
115
|
+
if (!PRIVATE_CONFIG.jwtSecret) {
|
|
116
|
+
throw new Error('JWT_SECRET is required');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Validate on startup
|
|
122
|
+
validateConfig();
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### API Configuration
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
// File: src/services/api.ts
|
|
129
|
+
import { PUBLIC_CONFIG } from '@/config';
|
|
130
|
+
|
|
131
|
+
const API_BASE_URL = PUBLIC_CONFIG.apiUrl;
|
|
132
|
+
|
|
133
|
+
export const api = {
|
|
134
|
+
// All requests use the configured API URL
|
|
135
|
+
get: (path: string) =>
|
|
136
|
+
fetch(`${API_BASE_URL}${path}`),
|
|
137
|
+
|
|
138
|
+
post: (path: string, data: any) =>
|
|
139
|
+
fetch(`${API_BASE_URL}${path}`, {
|
|
140
|
+
method: 'POST',
|
|
141
|
+
body: JSON.stringify(data),
|
|
142
|
+
headers: { 'Content-Type': 'application/json' },
|
|
143
|
+
}),
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Usage
|
|
147
|
+
const users = await api.get('/users');
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Server-Side Configuration
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// File: api-server/src/config.ts
|
|
154
|
+
import { PRIVATE_CONFIG, PUBLIC_CONFIG } from '@/config';
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Server can access both public and private config
|
|
158
|
+
*/
|
|
159
|
+
export const serverConfig = {
|
|
160
|
+
// Public (can be sent to clients if needed)
|
|
161
|
+
public: PUBLIC_CONFIG,
|
|
162
|
+
|
|
163
|
+
// Private (never send to clients)
|
|
164
|
+
private: PRIVATE_CONFIG,
|
|
165
|
+
|
|
166
|
+
// Database
|
|
167
|
+
database: {
|
|
168
|
+
connectionString: PRIVATE_CONFIG.databaseUrl,
|
|
169
|
+
ssl: process.env.NODE_ENV === 'production',
|
|
170
|
+
pool: {
|
|
171
|
+
max: parseInt(process.env.DB_POOL_MAX || '10'),
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
// Auth
|
|
176
|
+
auth: {
|
|
177
|
+
jwtSecret: PRIVATE_CONFIG.jwtSecret,
|
|
178
|
+
jwtExpiry: process.env.JWT_EXPIRY || '7d',
|
|
179
|
+
refreshExpiry: process.env.REFRESH_EXPIRY || '30d',
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
// Payment
|
|
183
|
+
stripe: {
|
|
184
|
+
secretKey: PRIVATE_CONFIG.stripeSecretKey,
|
|
185
|
+
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Build-Time Environment Configuration
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// File: babel.config.js - Support @env directives
|
|
194
|
+
module.exports = {
|
|
195
|
+
presets: ['babel-preset-expo'],
|
|
196
|
+
plugins: [
|
|
197
|
+
[
|
|
198
|
+
'module-resolver',
|
|
199
|
+
{
|
|
200
|
+
alias: {
|
|
201
|
+
'@': './src',
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
],
|
|
206
|
+
};
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
// File: src/constants/api.ts - Using @env syntax
|
|
211
|
+
const API_URL = process.env.EXPO_PUBLIC_API_URL || 'http://localhost:3000';
|
|
212
|
+
|
|
213
|
+
// Usage in code:
|
|
214
|
+
export const endpoints = {
|
|
215
|
+
users: `${API_URL}/api/users`,
|
|
216
|
+
posts: `${API_URL}/api/posts`,
|
|
217
|
+
// etc
|
|
218
|
+
};
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Environment-Specific Configuration
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// File: src/config/environments.ts
|
|
225
|
+
type Environment = 'development' | 'staging' | 'production';
|
|
226
|
+
|
|
227
|
+
const environments: Record<Environment, any> = {
|
|
228
|
+
development: {
|
|
229
|
+
apiUrl: 'http://localhost:3000',
|
|
230
|
+
logLevel: 'debug',
|
|
231
|
+
debugMode: true,
|
|
232
|
+
analytics: false,
|
|
233
|
+
},
|
|
234
|
+
staging: {
|
|
235
|
+
apiUrl: 'https://staging-api.example.com',
|
|
236
|
+
logLevel: 'info',
|
|
237
|
+
debugMode: false,
|
|
238
|
+
analytics: true,
|
|
239
|
+
},
|
|
240
|
+
production: {
|
|
241
|
+
apiUrl: 'https://api.example.com',
|
|
242
|
+
logLevel: 'warn',
|
|
243
|
+
debugMode: false,
|
|
244
|
+
analytics: true,
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const currentEnv = (process.env.NODE_ENV || 'development') as Environment;
|
|
249
|
+
|
|
250
|
+
export const config = environments[currentEnv];
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### CI/CD Environment Secrets
|
|
254
|
+
|
|
255
|
+
```yaml
|
|
256
|
+
# File: .github/workflows/deploy.yml
|
|
257
|
+
name: Deploy
|
|
258
|
+
|
|
259
|
+
on:
|
|
260
|
+
push:
|
|
261
|
+
branches: [main]
|
|
262
|
+
|
|
263
|
+
jobs:
|
|
264
|
+
deploy:
|
|
265
|
+
runs-on: ubuntu-latest
|
|
266
|
+
|
|
267
|
+
environment: production
|
|
268
|
+
|
|
269
|
+
steps:
|
|
270
|
+
- uses: actions/checkout@v4
|
|
271
|
+
|
|
272
|
+
- name: Build app
|
|
273
|
+
env:
|
|
274
|
+
# Public variables (can be in code)
|
|
275
|
+
EXPO_PUBLIC_API_URL: ${{ secrets.PROD_API_URL }}
|
|
276
|
+
EXPO_PUBLIC_LOG_LEVEL: warn
|
|
277
|
+
|
|
278
|
+
# Private variables (for build process only)
|
|
279
|
+
DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
|
|
280
|
+
JWT_SECRET: ${{ secrets.PROD_JWT_SECRET }}
|
|
281
|
+
STRIPE_SECRET_KEY: ${{ secrets.PROD_STRIPE_SECRET_KEY }}
|
|
282
|
+
run: npm run build
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### .env File Examples
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
# File: .env.example (commit to repo - no secrets)
|
|
289
|
+
# Copy to .env and fill in values
|
|
290
|
+
|
|
291
|
+
# Public (safe to commit, used in builds)
|
|
292
|
+
EXPO_PUBLIC_API_URL=http://localhost:3000
|
|
293
|
+
EXPO_PUBLIC_APP_NAME=MyApp
|
|
294
|
+
EXPO_PUBLIC_LOG_LEVEL=debug
|
|
295
|
+
|
|
296
|
+
# Private (DO NOT COMMIT)
|
|
297
|
+
# DATABASE_URL=postgresql://user:password@localhost:5432/app
|
|
298
|
+
# JWT_SECRET=your-secret-key-here
|
|
299
|
+
# STRIPE_SECRET_KEY=sk_test_...
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Environment Configuration Best Practices
|
|
303
|
+
|
|
304
|
+
### ✅ DO
|
|
305
|
+
|
|
306
|
+
1. **Use EXPO_PUBLIC_ prefix for client variables**
|
|
307
|
+
```typescript
|
|
308
|
+
// Baked into bundle
|
|
309
|
+
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
2. **Separate public from private variables**
|
|
313
|
+
```
|
|
314
|
+
Public: EXPO_PUBLIC_API_URL
|
|
315
|
+
Private: DATABASE_URL (no prefix)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
3. **Validate required variables on startup**
|
|
319
|
+
```typescript
|
|
320
|
+
if (!process.env.EXPO_PUBLIC_API_URL) {
|
|
321
|
+
throw new Error('EXPO_PUBLIC_API_URL required');
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
4. **Use .env.example as template**
|
|
326
|
+
```bash
|
|
327
|
+
# .env.example shows structure without secrets
|
|
328
|
+
EXPO_PUBLIC_API_URL=http://localhost:3000
|
|
329
|
+
# DATABASE_URL=postgresql://...
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### ❌ DON'T
|
|
333
|
+
|
|
334
|
+
1. **Don't expose secrets in client code**
|
|
335
|
+
```typescript
|
|
336
|
+
// ❌ WRONG - API key visible in app
|
|
337
|
+
const apiKey = 'sk_live_1234567890';
|
|
338
|
+
|
|
339
|
+
// ✅ RIGHT - Use server-side only
|
|
340
|
+
// Server handles auth, client doesn't need key
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
2. **Don't commit .env files**
|
|
344
|
+
```
|
|
345
|
+
# .gitignore
|
|
346
|
+
.env
|
|
347
|
+
.env.local
|
|
348
|
+
.env.*.local
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
3. **Don't mix public/private without prefixes**
|
|
352
|
+
```typescript
|
|
353
|
+
// ❌ WRONG - Unclear which is exposed
|
|
354
|
+
process.env.API_URL // Is this public?
|
|
355
|
+
process.env.SECRET_KEY // Exposed to client?
|
|
356
|
+
|
|
357
|
+
// ✅ RIGHT - Clear intent
|
|
358
|
+
process.env.EXPO_PUBLIC_API_URL // Definitely public
|
|
359
|
+
process.env.JWT_SECRET // Definitely private
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
4. **Don't hardcode values**
|
|
363
|
+
```typescript
|
|
364
|
+
// ❌ WRONG
|
|
365
|
+
const apiUrl = 'https://api.example.com';
|
|
366
|
+
|
|
367
|
+
// ✅ RIGHT
|
|
368
|
+
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## Related Patterns
|
|
372
|
+
|
|
373
|
+
- [Build Configuration](./build-configuration.md) — Build setup and optimization
|
|
374
|
+
- [CI/CD Patterns](./ci-cd-patterns.md) — Automated deployment
|
|
375
|
+
- [Hosting Setup](./hosting-setup.md) — Server configuration
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
*Pattern extracted from production repositories: time2pay, PokePages, core-monorepo*
|
|
380
|
+
*Files: .env.*, app.json, babel.config.js, GitHub Actions workflows*
|