claude-code-templates 1.16.1 → 1.17.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 +7 -7
- package/bin/create-claude-config.js +17 -8
- package/package.json +2 -3
- package/src/analytics/core/AgentAnalyzer.js +17 -3
- package/src/analytics/core/ProcessDetector.js +23 -7
- package/src/analytics/core/StateCalculator.js +102 -33
- package/src/analytics/data/DataCache.js +7 -7
- package/src/analytics-web/chats_mobile.html +2590 -0
- package/src/analytics-web/components/App.js +10 -10
- package/src/analytics-web/components/SessionTimer.js +1 -1
- package/src/analytics-web/components/Sidebar.js +5 -14
- package/src/analytics-web/index.html +932 -78
- package/src/analytics.js +263 -5
- package/src/chats-mobile.js +682 -0
- package/src/claude-api-proxy.js +460 -0
- package/src/file-operations.js +239 -36
- package/src/health-check.js +310 -0
- package/src/index.js +1245 -36
- package/src/tracking-service.js +31 -34
- package/components/agents/api-security-audit.md +0 -92
- package/components/agents/database-optimization.md +0 -94
- package/components/agents/react-performance-optimization.md +0 -64
- package/components/commands/check-file.md +0 -53
- package/components/commands/generate-tests.md +0 -68
- package/components/mcps/deepgraph-nextjs.json +0 -12
- package/components/mcps/deepgraph-react.json +0 -12
- package/components/mcps/deepgraph-typescript.json +0 -12
- package/components/mcps/deepgraph-vue.json +0 -12
- package/components/mcps/filesystem-access.json +0 -12
- package/components/mcps/github-integration.json +0 -11
- package/components/mcps/memory-integration.json +0 -8
- package/components/mcps/mysql-integration.json +0 -11
- package/components/mcps/postgresql-integration.json +0 -11
- package/components/mcps/web-fetch.json +0 -8
- package/src/analytics-web/components/AgentsPage.js +0 -4761
- package/templates/common/.claude/commands/git-workflow.md +0 -239
- package/templates/common/.claude/commands/project-setup.md +0 -316
- package/templates/common/.mcp.json +0 -41
- package/templates/common/CLAUDE.md +0 -109
- package/templates/common/README.md +0 -96
- package/templates/go/.mcp.json +0 -78
- package/templates/go/README.md +0 -25
- package/templates/javascript-typescript/.claude/commands/api-endpoint.md +0 -51
- package/templates/javascript-typescript/.claude/commands/debug.md +0 -52
- package/templates/javascript-typescript/.claude/commands/lint.md +0 -48
- package/templates/javascript-typescript/.claude/commands/npm-scripts.md +0 -48
- package/templates/javascript-typescript/.claude/commands/refactor.md +0 -55
- package/templates/javascript-typescript/.claude/commands/test.md +0 -61
- package/templates/javascript-typescript/.claude/commands/typescript-migrate.md +0 -51
- package/templates/javascript-typescript/.claude/settings.json +0 -142
- package/templates/javascript-typescript/.mcp.json +0 -80
- package/templates/javascript-typescript/CLAUDE.md +0 -185
- package/templates/javascript-typescript/README.md +0 -259
- package/templates/javascript-typescript/examples/angular-app/.claude/commands/components.md +0 -63
- package/templates/javascript-typescript/examples/angular-app/.claude/commands/services.md +0 -62
- package/templates/javascript-typescript/examples/node-api/.claude/commands/api-endpoint.md +0 -46
- package/templates/javascript-typescript/examples/node-api/.claude/commands/database.md +0 -56
- package/templates/javascript-typescript/examples/node-api/.claude/commands/middleware.md +0 -61
- package/templates/javascript-typescript/examples/node-api/.claude/commands/route.md +0 -57
- package/templates/javascript-typescript/examples/node-api/CLAUDE.md +0 -102
- package/templates/javascript-typescript/examples/react-app/.claude/commands/component.md +0 -29
- package/templates/javascript-typescript/examples/react-app/.claude/commands/hooks.md +0 -44
- package/templates/javascript-typescript/examples/react-app/.claude/commands/state-management.md +0 -45
- package/templates/javascript-typescript/examples/react-app/CLAUDE.md +0 -81
- package/templates/javascript-typescript/examples/react-app/agents/react-performance-optimization.md +0 -530
- package/templates/javascript-typescript/examples/react-app/agents/react-state-management.md +0 -295
- package/templates/javascript-typescript/examples/vue-app/.claude/commands/components.md +0 -46
- package/templates/javascript-typescript/examples/vue-app/.claude/commands/composables.md +0 -51
- package/templates/python/.claude/commands/lint.md +0 -111
- package/templates/python/.claude/commands/test.md +0 -73
- package/templates/python/.claude/settings.json +0 -153
- package/templates/python/.mcp.json +0 -78
- package/templates/python/CLAUDE.md +0 -276
- package/templates/python/examples/django-app/.claude/commands/admin.md +0 -264
- package/templates/python/examples/django-app/.claude/commands/django-model.md +0 -124
- package/templates/python/examples/django-app/.claude/commands/views.md +0 -222
- package/templates/python/examples/django-app/CLAUDE.md +0 -313
- package/templates/python/examples/django-app/agents/django-api-security.md +0 -642
- package/templates/python/examples/django-app/agents/django-database-optimization.md +0 -752
- package/templates/python/examples/fastapi-app/.claude/commands/api-endpoints.md +0 -513
- package/templates/python/examples/fastapi-app/.claude/commands/auth.md +0 -775
- package/templates/python/examples/fastapi-app/.claude/commands/database.md +0 -657
- package/templates/python/examples/fastapi-app/.claude/commands/deployment.md +0 -160
- package/templates/python/examples/fastapi-app/.claude/commands/testing.md +0 -927
- package/templates/python/examples/fastapi-app/CLAUDE.md +0 -229
- package/templates/python/examples/flask-app/.claude/commands/app-factory.md +0 -384
- package/templates/python/examples/flask-app/.claude/commands/blueprint.md +0 -243
- package/templates/python/examples/flask-app/.claude/commands/database.md +0 -410
- package/templates/python/examples/flask-app/.claude/commands/deployment.md +0 -620
- package/templates/python/examples/flask-app/.claude/commands/flask-route.md +0 -217
- package/templates/python/examples/flask-app/.claude/commands/testing.md +0 -559
- package/templates/python/examples/flask-app/CLAUDE.md +0 -391
- package/templates/ruby/.claude/commands/model.md +0 -360
- package/templates/ruby/.claude/commands/test.md +0 -480
- package/templates/ruby/.claude/settings.json +0 -146
- package/templates/ruby/.mcp.json +0 -83
- package/templates/ruby/CLAUDE.md +0 -284
- package/templates/ruby/examples/rails-app/.claude/commands/authentication.md +0 -490
- package/templates/ruby/examples/rails-app/CLAUDE.md +0 -376
- package/templates/rust/.mcp.json +0 -78
- package/templates/rust/README.md +0 -26
|
@@ -1,620 +0,0 @@
|
|
|
1
|
-
# Flask Deployment Configuration
|
|
2
|
-
|
|
3
|
-
Complete production deployment setup for Flask applications.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
# Build Docker image
|
|
9
|
-
docker build -t myapp .
|
|
10
|
-
|
|
11
|
-
# Run with Docker Compose
|
|
12
|
-
docker-compose up -d
|
|
13
|
-
|
|
14
|
-
# Deploy to cloud
|
|
15
|
-
gunicorn --bind 0.0.0.0:8000 app:app
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Production Configuration
|
|
19
|
-
|
|
20
|
-
```python
|
|
21
|
-
# config.py
|
|
22
|
-
import os
|
|
23
|
-
from urllib.parse import quote_plus
|
|
24
|
-
|
|
25
|
-
class ProductionConfig:
|
|
26
|
-
"""Production configuration."""
|
|
27
|
-
|
|
28
|
-
# Security
|
|
29
|
-
SECRET_KEY = os.environ.get('SECRET_KEY')
|
|
30
|
-
DEBUG = False
|
|
31
|
-
TESTING = False
|
|
32
|
-
|
|
33
|
-
# Database
|
|
34
|
-
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
|
|
35
|
-
f"postgresql://{os.environ.get('DB_USER')}:{quote_plus(os.environ.get('DB_PASSWORD'))}@" \
|
|
36
|
-
f"{os.environ.get('DB_HOST')}:{os.environ.get('DB_PORT', '5432')}/{os.environ.get('DB_NAME')}"
|
|
37
|
-
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
|
38
|
-
SQLALCHEMY_ENGINE_OPTIONS = {
|
|
39
|
-
'pool_size': 10,
|
|
40
|
-
'max_overflow': 20,
|
|
41
|
-
'pool_recycle': 3600,
|
|
42
|
-
'pool_pre_ping': True
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
# Security Headers
|
|
46
|
-
SECURITY_HEADERS = {
|
|
47
|
-
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
|
|
48
|
-
'X-Content-Type-Options': 'nosniff',
|
|
49
|
-
'X-Frame-Options': 'DENY',
|
|
50
|
-
'X-XSS-Protection': '1; mode=block',
|
|
51
|
-
'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
# Session
|
|
55
|
-
SESSION_COOKIE_SECURE = True
|
|
56
|
-
SESSION_COOKIE_HTTPONLY = True
|
|
57
|
-
SESSION_COOKIE_SAMESITE = 'Lax'
|
|
58
|
-
PERMANENT_SESSION_LIFETIME = 3600 # 1 hour
|
|
59
|
-
|
|
60
|
-
# Cache
|
|
61
|
-
CACHE_TYPE = 'redis'
|
|
62
|
-
CACHE_REDIS_URL = os.environ.get('REDIS_URL', 'redis://localhost:6379/0')
|
|
63
|
-
CACHE_DEFAULT_TIMEOUT = 300
|
|
64
|
-
|
|
65
|
-
# Rate Limiting
|
|
66
|
-
RATELIMIT_STORAGE_URL = os.environ.get('REDIS_URL', 'redis://localhost:6379/1')
|
|
67
|
-
RATELIMIT_DEFAULT = '100/hour'
|
|
68
|
-
|
|
69
|
-
# Logging
|
|
70
|
-
LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO')
|
|
71
|
-
LOG_FILE = os.environ.get('LOG_FILE', '/var/log/app/app.log')
|
|
72
|
-
|
|
73
|
-
# File Upload
|
|
74
|
-
MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB
|
|
75
|
-
UPLOAD_FOLDER = os.environ.get('UPLOAD_FOLDER', '/var/uploads')
|
|
76
|
-
|
|
77
|
-
# Email
|
|
78
|
-
MAIL_SERVER = os.environ.get('MAIL_SERVER')
|
|
79
|
-
MAIL_PORT = int(os.environ.get('MAIL_PORT', 587))
|
|
80
|
-
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS', 'true').lower() in ['true', 'on', '1']
|
|
81
|
-
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
|
|
82
|
-
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
|
|
83
|
-
MAIL_DEFAULT_SENDER = os.environ.get('MAIL_DEFAULT_SENDER')
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## WSGI Configuration
|
|
87
|
-
|
|
88
|
-
```python
|
|
89
|
-
# wsgi.py
|
|
90
|
-
import os
|
|
91
|
-
from app import create_app
|
|
92
|
-
|
|
93
|
-
# Get environment
|
|
94
|
-
config_name = os.environ.get('FLASK_ENV', 'production')
|
|
95
|
-
app = create_app(config_name)
|
|
96
|
-
|
|
97
|
-
if __name__ == "__main__":
|
|
98
|
-
app.run()
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## Gunicorn Configuration
|
|
102
|
-
|
|
103
|
-
```python
|
|
104
|
-
# gunicorn.conf.py
|
|
105
|
-
import multiprocessing
|
|
106
|
-
import os
|
|
107
|
-
|
|
108
|
-
# Server socket
|
|
109
|
-
bind = f"0.0.0.0:{os.environ.get('PORT', 8000)}"
|
|
110
|
-
backlog = 2048
|
|
111
|
-
|
|
112
|
-
# Worker processes
|
|
113
|
-
workers = multiprocessing.cpu_count() * 2 + 1
|
|
114
|
-
worker_class = 'sync'
|
|
115
|
-
worker_connections = 1000
|
|
116
|
-
timeout = 30
|
|
117
|
-
keepalive = 60
|
|
118
|
-
max_requests = 1000
|
|
119
|
-
max_requests_jitter = 100
|
|
120
|
-
|
|
121
|
-
# Security
|
|
122
|
-
limit_request_line = 4094
|
|
123
|
-
limit_request_fields = 100
|
|
124
|
-
limit_request_field_size = 8190
|
|
125
|
-
|
|
126
|
-
# Logging
|
|
127
|
-
accesslog = '-'
|
|
128
|
-
errorlog = '-'
|
|
129
|
-
loglevel = os.environ.get('LOG_LEVEL', 'info').lower()
|
|
130
|
-
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
|
|
131
|
-
|
|
132
|
-
# Process naming
|
|
133
|
-
proc_name = 'flask_app'
|
|
134
|
-
|
|
135
|
-
# Server mechanics
|
|
136
|
-
daemon = False
|
|
137
|
-
pidfile = '/tmp/gunicorn.pid'
|
|
138
|
-
user = os.environ.get('USER', 'www-data')
|
|
139
|
-
group = os.environ.get('GROUP', 'www-data')
|
|
140
|
-
tmp_upload_dir = None
|
|
141
|
-
|
|
142
|
-
# SSL
|
|
143
|
-
keyfile = os.environ.get('SSL_KEYFILE')
|
|
144
|
-
certfile = os.environ.get('SSL_CERTFILE')
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Docker Configuration
|
|
148
|
-
|
|
149
|
-
```dockerfile
|
|
150
|
-
# Dockerfile
|
|
151
|
-
FROM python:3.11-slim
|
|
152
|
-
|
|
153
|
-
# Set environment variables
|
|
154
|
-
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
155
|
-
PYTHONUNBUFFERED=1 \
|
|
156
|
-
PIP_NO_CACHE_DIR=1 \
|
|
157
|
-
PIP_DISABLE_PIP_VERSION_CHECK=1
|
|
158
|
-
|
|
159
|
-
# Install system dependencies
|
|
160
|
-
RUN apt-get update && apt-get install -y \
|
|
161
|
-
build-essential \
|
|
162
|
-
libpq-dev \
|
|
163
|
-
curl \
|
|
164
|
-
&& rm -rf /var/lib/apt/lists/*
|
|
165
|
-
|
|
166
|
-
# Create app user
|
|
167
|
-
RUN groupadd -r appuser && useradd -r -g appuser appuser
|
|
168
|
-
|
|
169
|
-
# Set work directory
|
|
170
|
-
WORKDIR /app
|
|
171
|
-
|
|
172
|
-
# Install Python dependencies
|
|
173
|
-
COPY requirements/production.txt ./requirements.txt
|
|
174
|
-
RUN pip install --no-cache-dir -r requirements.txt
|
|
175
|
-
|
|
176
|
-
# Copy application code
|
|
177
|
-
COPY . .
|
|
178
|
-
|
|
179
|
-
# Create necessary directories
|
|
180
|
-
RUN mkdir -p /var/log/app /var/uploads && \
|
|
181
|
-
chown -R appuser:appuser /app /var/log/app /var/uploads
|
|
182
|
-
|
|
183
|
-
# Switch to non-root user
|
|
184
|
-
USER appuser
|
|
185
|
-
|
|
186
|
-
# Expose port
|
|
187
|
-
EXPOSE 8000
|
|
188
|
-
|
|
189
|
-
# Health check
|
|
190
|
-
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
|
|
191
|
-
CMD curl -f http://localhost:8000/health || exit 1
|
|
192
|
-
|
|
193
|
-
# Run application
|
|
194
|
-
CMD ["gunicorn", "--config", "gunicorn.conf.py", "wsgi:app"]
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
## Docker Compose
|
|
198
|
-
|
|
199
|
-
```yaml
|
|
200
|
-
# docker-compose.yml
|
|
201
|
-
version: '3.8'
|
|
202
|
-
|
|
203
|
-
services:
|
|
204
|
-
web:
|
|
205
|
-
build: .
|
|
206
|
-
ports:
|
|
207
|
-
- "8000:8000"
|
|
208
|
-
environment:
|
|
209
|
-
- FLASK_ENV=production
|
|
210
|
-
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
|
|
211
|
-
- REDIS_URL=redis://redis:6379/0
|
|
212
|
-
- SECRET_KEY=${SECRET_KEY}
|
|
213
|
-
depends_on:
|
|
214
|
-
- db
|
|
215
|
-
- redis
|
|
216
|
-
volumes:
|
|
217
|
-
- uploads:/var/uploads
|
|
218
|
-
- logs:/var/log/app
|
|
219
|
-
restart: unless-stopped
|
|
220
|
-
healthcheck:
|
|
221
|
-
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
|
222
|
-
interval: 30s
|
|
223
|
-
timeout: 10s
|
|
224
|
-
retries: 3
|
|
225
|
-
|
|
226
|
-
db:
|
|
227
|
-
image: postgres:15
|
|
228
|
-
environment:
|
|
229
|
-
- POSTGRES_DB=myapp
|
|
230
|
-
- POSTGRES_USER=postgres
|
|
231
|
-
- POSTGRES_PASSWORD=password
|
|
232
|
-
volumes:
|
|
233
|
-
- postgres_data:/var/lib/postgresql/data
|
|
234
|
-
restart: unless-stopped
|
|
235
|
-
healthcheck:
|
|
236
|
-
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
237
|
-
interval: 30s
|
|
238
|
-
timeout: 10s
|
|
239
|
-
retries: 3
|
|
240
|
-
|
|
241
|
-
redis:
|
|
242
|
-
image: redis:7-alpine
|
|
243
|
-
command: redis-server --appendonly yes
|
|
244
|
-
volumes:
|
|
245
|
-
- redis_data:/data
|
|
246
|
-
restart: unless-stopped
|
|
247
|
-
healthcheck:
|
|
248
|
-
test: ["CMD", "redis-cli", "ping"]
|
|
249
|
-
interval: 30s
|
|
250
|
-
timeout: 10s
|
|
251
|
-
retries: 3
|
|
252
|
-
|
|
253
|
-
nginx:
|
|
254
|
-
image: nginx:alpine
|
|
255
|
-
ports:
|
|
256
|
-
- "80:80"
|
|
257
|
-
- "443:443"
|
|
258
|
-
volumes:
|
|
259
|
-
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
|
260
|
-
- ./ssl:/etc/nginx/ssl:ro
|
|
261
|
-
- uploads:/var/uploads:ro
|
|
262
|
-
depends_on:
|
|
263
|
-
- web
|
|
264
|
-
restart: unless-stopped
|
|
265
|
-
|
|
266
|
-
volumes:
|
|
267
|
-
postgres_data:
|
|
268
|
-
redis_data:
|
|
269
|
-
uploads:
|
|
270
|
-
logs:
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
## Nginx Configuration
|
|
274
|
-
|
|
275
|
-
```nginx
|
|
276
|
-
# nginx.conf
|
|
277
|
-
events {
|
|
278
|
-
worker_connections 1024;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
http {
|
|
282
|
-
upstream app {
|
|
283
|
-
server web:8000;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
# Rate limiting
|
|
287
|
-
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
|
288
|
-
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
|
|
289
|
-
|
|
290
|
-
# SSL configuration
|
|
291
|
-
ssl_protocols TLSv1.2 TLSv1.3;
|
|
292
|
-
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
|
|
293
|
-
ssl_prefer_server_ciphers off;
|
|
294
|
-
|
|
295
|
-
# Security headers
|
|
296
|
-
add_header X-Frame-Options DENY;
|
|
297
|
-
add_header X-Content-Type-Options nosniff;
|
|
298
|
-
add_header X-XSS-Protection "1; mode=block";
|
|
299
|
-
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
300
|
-
|
|
301
|
-
server {
|
|
302
|
-
listen 80;
|
|
303
|
-
server_name example.com www.example.com;
|
|
304
|
-
return 301 https://$server_name$request_uri;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
server {
|
|
308
|
-
listen 443 ssl http2;
|
|
309
|
-
server_name example.com www.example.com;
|
|
310
|
-
|
|
311
|
-
ssl_certificate /etc/nginx/ssl/cert.pem;
|
|
312
|
-
ssl_certificate_key /etc/nginx/ssl/key.pem;
|
|
313
|
-
|
|
314
|
-
# File upload size
|
|
315
|
-
client_max_body_size 16M;
|
|
316
|
-
|
|
317
|
-
# Static files
|
|
318
|
-
location /static/ {
|
|
319
|
-
alias /var/uploads/static/;
|
|
320
|
-
expires 1y;
|
|
321
|
-
add_header Cache-Control "public, immutable";
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
location /uploads/ {
|
|
325
|
-
alias /var/uploads/;
|
|
326
|
-
expires 1h;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
# API rate limiting
|
|
330
|
-
location /api/ {
|
|
331
|
-
limit_req zone=api burst=20 nodelay;
|
|
332
|
-
proxy_pass http://app;
|
|
333
|
-
proxy_set_header Host $host;
|
|
334
|
-
proxy_set_header X-Real-IP $remote_addr;
|
|
335
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
336
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
# Login rate limiting
|
|
340
|
-
location /auth/login {
|
|
341
|
-
limit_req zone=login burst=5 nodelay;
|
|
342
|
-
proxy_pass http://app;
|
|
343
|
-
proxy_set_header Host $host;
|
|
344
|
-
proxy_set_header X-Real-IP $remote_addr;
|
|
345
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
346
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
# Main application
|
|
350
|
-
location / {
|
|
351
|
-
proxy_pass http://app;
|
|
352
|
-
proxy_set_header Host $host;
|
|
353
|
-
proxy_set_header X-Real-IP $remote_addr;
|
|
354
|
-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
355
|
-
proxy_set_header X-Forwarded-Proto $scheme;
|
|
356
|
-
|
|
357
|
-
# Timeout settings
|
|
358
|
-
proxy_connect_timeout 60s;
|
|
359
|
-
proxy_send_timeout 60s;
|
|
360
|
-
proxy_read_timeout 60s;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
## Environment Variables
|
|
367
|
-
|
|
368
|
-
```bash
|
|
369
|
-
# .env.production
|
|
370
|
-
# Application
|
|
371
|
-
FLASK_ENV=production
|
|
372
|
-
SECRET_KEY=your-super-secret-key-here
|
|
373
|
-
|
|
374
|
-
# Database
|
|
375
|
-
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
|
|
376
|
-
DB_HOST=localhost
|
|
377
|
-
DB_PORT=5432
|
|
378
|
-
DB_NAME=myapp
|
|
379
|
-
DB_USER=user
|
|
380
|
-
DB_PASSWORD=password
|
|
381
|
-
|
|
382
|
-
# Redis
|
|
383
|
-
REDIS_URL=redis://localhost:6379/0
|
|
384
|
-
|
|
385
|
-
# Email
|
|
386
|
-
MAIL_SERVER=smtp.gmail.com
|
|
387
|
-
MAIL_PORT=587
|
|
388
|
-
MAIL_USE_TLS=true
|
|
389
|
-
MAIL_USERNAME=your-email@gmail.com
|
|
390
|
-
MAIL_PASSWORD=your-app-password
|
|
391
|
-
MAIL_DEFAULT_SENDER=your-email@gmail.com
|
|
392
|
-
|
|
393
|
-
# Logging
|
|
394
|
-
LOG_LEVEL=INFO
|
|
395
|
-
LOG_FILE=/var/log/app/app.log
|
|
396
|
-
|
|
397
|
-
# File Upload
|
|
398
|
-
UPLOAD_FOLDER=/var/uploads
|
|
399
|
-
|
|
400
|
-
# SSL (if using)
|
|
401
|
-
SSL_KEYFILE=/path/to/private.key
|
|
402
|
-
SSL_CERTFILE=/path/to/certificate.crt
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
## Health Check Endpoint
|
|
406
|
-
|
|
407
|
-
```python
|
|
408
|
-
# app/health.py
|
|
409
|
-
from flask import Blueprint, jsonify
|
|
410
|
-
from app.extensions import db
|
|
411
|
-
from sqlalchemy import text
|
|
412
|
-
import redis
|
|
413
|
-
import os
|
|
414
|
-
|
|
415
|
-
health_bp = Blueprint('health', __name__)
|
|
416
|
-
|
|
417
|
-
@health_bp.route('/health')
|
|
418
|
-
def health_check():
|
|
419
|
-
"""Application health check."""
|
|
420
|
-
checks = {
|
|
421
|
-
'status': 'healthy',
|
|
422
|
-
'database': check_database(),
|
|
423
|
-
'redis': check_redis(),
|
|
424
|
-
'disk_space': check_disk_space()
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
# Determine overall status
|
|
428
|
-
if all(check['status'] == 'ok' for check in checks.values() if isinstance(check, dict)):
|
|
429
|
-
status_code = 200
|
|
430
|
-
else:
|
|
431
|
-
status_code = 503
|
|
432
|
-
checks['status'] = 'unhealthy'
|
|
433
|
-
|
|
434
|
-
return jsonify(checks), status_code
|
|
435
|
-
|
|
436
|
-
def check_database():
|
|
437
|
-
"""Check database connectivity."""
|
|
438
|
-
try:
|
|
439
|
-
db.session.execute(text('SELECT 1'))
|
|
440
|
-
return {'status': 'ok', 'message': 'Database connection successful'}
|
|
441
|
-
except Exception as e:
|
|
442
|
-
return {'status': 'error', 'message': str(e)}
|
|
443
|
-
|
|
444
|
-
def check_redis():
|
|
445
|
-
"""Check Redis connectivity."""
|
|
446
|
-
try:
|
|
447
|
-
redis_url = os.environ.get('REDIS_URL', 'redis://localhost:6379/0')
|
|
448
|
-
r = redis.from_url(redis_url)
|
|
449
|
-
r.ping()
|
|
450
|
-
return {'status': 'ok', 'message': 'Redis connection successful'}
|
|
451
|
-
except Exception as e:
|
|
452
|
-
return {'status': 'error', 'message': str(e)}
|
|
453
|
-
|
|
454
|
-
def check_disk_space():
|
|
455
|
-
"""Check available disk space."""
|
|
456
|
-
try:
|
|
457
|
-
import shutil
|
|
458
|
-
total, used, free = shutil.disk_usage('/')
|
|
459
|
-
free_percent = (free / total) * 100
|
|
460
|
-
|
|
461
|
-
if free_percent > 10:
|
|
462
|
-
status = 'ok'
|
|
463
|
-
elif free_percent > 5:
|
|
464
|
-
status = 'warning'
|
|
465
|
-
else:
|
|
466
|
-
status = 'critical'
|
|
467
|
-
|
|
468
|
-
return {
|
|
469
|
-
'status': status,
|
|
470
|
-
'free_space_percent': round(free_percent, 2),
|
|
471
|
-
'free_space_gb': round(free / (1024**3), 2)
|
|
472
|
-
}
|
|
473
|
-
except Exception as e:
|
|
474
|
-
return {'status': 'error', 'message': str(e)}
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
## Monitoring and Logging
|
|
478
|
-
|
|
479
|
-
```python
|
|
480
|
-
# app/logging.py
|
|
481
|
-
import logging
|
|
482
|
-
import logging.handlers
|
|
483
|
-
import os
|
|
484
|
-
from flask import request, g
|
|
485
|
-
import time
|
|
486
|
-
|
|
487
|
-
def setup_logging(app):
|
|
488
|
-
"""Setup application logging."""
|
|
489
|
-
if not app.debug and not app.testing:
|
|
490
|
-
# File logging
|
|
491
|
-
if app.config.get('LOG_FILE'):
|
|
492
|
-
file_handler = logging.handlers.RotatingFileHandler(
|
|
493
|
-
app.config['LOG_FILE'],
|
|
494
|
-
maxBytes=10240000, # 10MB
|
|
495
|
-
backupCount=10
|
|
496
|
-
)
|
|
497
|
-
file_handler.setFormatter(logging.Formatter(
|
|
498
|
-
'%(asctime)s %(levelname)s: %(message)s '
|
|
499
|
-
'[in %(pathname)s:%(lineno)d]'
|
|
500
|
-
))
|
|
501
|
-
file_handler.setLevel(getattr(logging, app.config.get('LOG_LEVEL', 'INFO')))
|
|
502
|
-
app.logger.addHandler(file_handler)
|
|
503
|
-
|
|
504
|
-
# Console logging
|
|
505
|
-
if not app.logger.handlers:
|
|
506
|
-
stream_handler = logging.StreamHandler()
|
|
507
|
-
stream_handler.setFormatter(logging.Formatter(
|
|
508
|
-
'%(asctime)s %(levelname)s: %(message)s'
|
|
509
|
-
))
|
|
510
|
-
stream_handler.setLevel(logging.INFO)
|
|
511
|
-
app.logger.addHandler(stream_handler)
|
|
512
|
-
|
|
513
|
-
app.logger.setLevel(logging.INFO)
|
|
514
|
-
app.logger.info('Application startup')
|
|
515
|
-
|
|
516
|
-
# Request timing middleware
|
|
517
|
-
@app.before_request
|
|
518
|
-
def before_request():
|
|
519
|
-
g.start_time = time.time()
|
|
520
|
-
|
|
521
|
-
@app.after_request
|
|
522
|
-
def after_request(response):
|
|
523
|
-
if hasattr(g, 'start_time'):
|
|
524
|
-
duration = time.time() - g.start_time
|
|
525
|
-
app.logger.info(
|
|
526
|
-
f'{request.method} {request.path} - '
|
|
527
|
-
f'{response.status_code} - {duration:.3f}s'
|
|
528
|
-
)
|
|
529
|
-
return response
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
## Database Backup Script
|
|
533
|
-
|
|
534
|
-
```bash
|
|
535
|
-
#!/bin/bash
|
|
536
|
-
# backup.sh
|
|
537
|
-
|
|
538
|
-
set -e
|
|
539
|
-
|
|
540
|
-
# Configuration
|
|
541
|
-
BACKUP_DIR="/var/backups/db"
|
|
542
|
-
DATABASE_URL="$DATABASE_URL"
|
|
543
|
-
DATE=$(date +%Y%m%d_%H%M%S)
|
|
544
|
-
BACKUP_FILE="$BACKUP_DIR/backup_$DATE.sql"
|
|
545
|
-
RETENTION_DAYS=7
|
|
546
|
-
|
|
547
|
-
# Create backup directory
|
|
548
|
-
mkdir -p "$BACKUP_DIR"
|
|
549
|
-
|
|
550
|
-
# Create backup
|
|
551
|
-
echo "Creating database backup..."
|
|
552
|
-
pg_dump "$DATABASE_URL" > "$BACKUP_FILE"
|
|
553
|
-
|
|
554
|
-
# Compress backup
|
|
555
|
-
gzip "$BACKUP_FILE"
|
|
556
|
-
|
|
557
|
-
# Remove old backups
|
|
558
|
-
echo "Cleaning up old backups..."
|
|
559
|
-
find "$BACKUP_DIR" -name "backup_*.sql.gz" -mtime +$RETENTION_DAYS -delete
|
|
560
|
-
|
|
561
|
-
echo "Backup completed: $BACKUP_FILE.gz"
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
## Deployment Scripts
|
|
565
|
-
|
|
566
|
-
```bash
|
|
567
|
-
#!/bin/bash
|
|
568
|
-
# deploy.sh
|
|
569
|
-
|
|
570
|
-
set -e
|
|
571
|
-
|
|
572
|
-
echo "Starting deployment..."
|
|
573
|
-
|
|
574
|
-
# Pull latest code
|
|
575
|
-
git pull origin main
|
|
576
|
-
|
|
577
|
-
# Build new Docker image
|
|
578
|
-
docker-compose build web
|
|
579
|
-
|
|
580
|
-
# Run database migrations
|
|
581
|
-
docker-compose run --rm web flask db upgrade
|
|
582
|
-
|
|
583
|
-
# Update services
|
|
584
|
-
docker-compose up -d
|
|
585
|
-
|
|
586
|
-
# Health check
|
|
587
|
-
echo "Waiting for application to be ready..."
|
|
588
|
-
sleep 10
|
|
589
|
-
|
|
590
|
-
if curl -f http://localhost:8000/health; then
|
|
591
|
-
echo "Deployment successful!"
|
|
592
|
-
else
|
|
593
|
-
echo "Deployment failed - health check failed"
|
|
594
|
-
exit 1
|
|
595
|
-
fi
|
|
596
|
-
```
|
|
597
|
-
|
|
598
|
-
## Monitoring with Prometheus
|
|
599
|
-
|
|
600
|
-
```python
|
|
601
|
-
# app/metrics.py
|
|
602
|
-
from prometheus_flask_exporter import PrometheusMetrics
|
|
603
|
-
from flask import request
|
|
604
|
-
import time
|
|
605
|
-
|
|
606
|
-
def setup_metrics(app):
|
|
607
|
-
"""Setup Prometheus metrics."""
|
|
608
|
-
metrics = PrometheusMetrics(app)
|
|
609
|
-
|
|
610
|
-
# Custom metrics
|
|
611
|
-
metrics.info('app_info', 'Application info', version='1.0.0')
|
|
612
|
-
|
|
613
|
-
# Database connection pool metrics
|
|
614
|
-
@metrics.gauge('db_pool_size', 'Database connection pool size')
|
|
615
|
-
def db_pool_size():
|
|
616
|
-
from app.extensions import db
|
|
617
|
-
return db.engine.pool.size()
|
|
618
|
-
|
|
619
|
-
return metrics
|
|
620
|
-
```
|