@malamute/ai-rules 1.0.0 → 1.3.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.
Files changed (145) hide show
  1. package/README.md +272 -121
  2. package/bin/cli.js +5 -2
  3. package/configs/_shared/CLAUDE.md +52 -149
  4. package/configs/_shared/rules/conventions/documentation.md +324 -0
  5. package/configs/_shared/rules/conventions/git.md +265 -0
  6. package/configs/_shared/rules/conventions/npm.md +80 -0
  7. package/configs/_shared/{.claude/rules → rules/conventions}/performance.md +1 -1
  8. package/configs/_shared/rules/conventions/principles.md +334 -0
  9. package/configs/_shared/rules/devops/ci-cd.md +262 -0
  10. package/configs/_shared/rules/devops/docker.md +275 -0
  11. package/configs/_shared/rules/devops/nx.md +194 -0
  12. package/configs/_shared/rules/domain/backend/api-design.md +203 -0
  13. package/configs/_shared/rules/lang/csharp/async.md +220 -0
  14. package/configs/_shared/rules/lang/csharp/csharp.md +314 -0
  15. package/configs/_shared/rules/lang/csharp/linq.md +210 -0
  16. package/configs/_shared/rules/lang/python/async.md +337 -0
  17. package/configs/_shared/rules/lang/python/celery.md +476 -0
  18. package/configs/_shared/rules/lang/python/config.md +339 -0
  19. package/configs/{python/.claude/rules → _shared/rules/lang/python}/database/sqlalchemy.md +6 -1
  20. package/configs/_shared/rules/lang/python/deployment.md +523 -0
  21. package/configs/_shared/rules/lang/python/error-handling.md +330 -0
  22. package/configs/_shared/rules/lang/python/migrations.md +421 -0
  23. package/configs/_shared/rules/lang/python/python.md +172 -0
  24. package/configs/_shared/rules/lang/python/repository.md +383 -0
  25. package/configs/{python/.claude/rules → _shared/rules/lang/python}/testing.md +2 -69
  26. package/configs/_shared/rules/lang/typescript/async.md +447 -0
  27. package/configs/_shared/rules/lang/typescript/generics.md +356 -0
  28. package/configs/_shared/rules/lang/typescript/typescript.md +212 -0
  29. package/configs/_shared/rules/quality/error-handling.md +48 -0
  30. package/configs/_shared/rules/quality/logging.md +45 -0
  31. package/configs/_shared/rules/quality/observability.md +240 -0
  32. package/configs/_shared/rules/quality/testing-patterns.md +65 -0
  33. package/configs/_shared/rules/security/secrets-management.md +222 -0
  34. package/configs/_shared/skills/analysis/explore/SKILL.md +257 -0
  35. package/configs/_shared/skills/analysis/security-audit/SKILL.md +184 -0
  36. package/configs/_shared/skills/dev/api-endpoint/SKILL.md +126 -0
  37. package/configs/_shared/{.claude/commands/generate-tests.md → skills/dev/generate-tests/SKILL.md} +6 -0
  38. package/configs/_shared/{.claude/commands/fix-issue.md → skills/git/fix-issue/SKILL.md} +6 -0
  39. package/configs/_shared/{.claude/commands/review-pr.md → skills/git/review-pr/SKILL.md} +6 -0
  40. package/configs/_shared/skills/infra/deploy/SKILL.md +139 -0
  41. package/configs/_shared/skills/infra/docker/SKILL.md +95 -0
  42. package/configs/_shared/skills/infra/migration/SKILL.md +158 -0
  43. package/configs/_shared/skills/nx/nx-affected/SKILL.md +72 -0
  44. package/configs/_shared/skills/nx/nx-lib/SKILL.md +375 -0
  45. package/configs/angular/CLAUDE.md +24 -216
  46. package/configs/angular/{.claude/rules → rules/core}/components.md +69 -15
  47. package/configs/angular/rules/core/resource.md +285 -0
  48. package/configs/angular/rules/core/signals.md +323 -0
  49. package/configs/angular/rules/http.md +338 -0
  50. package/configs/angular/rules/routing.md +291 -0
  51. package/configs/angular/rules/ssr.md +312 -0
  52. package/configs/angular/rules/state/signal-store.md +408 -0
  53. package/configs/angular/{.claude/rules → rules/state}/state.md +2 -2
  54. package/configs/angular/{.claude/rules → rules}/testing.md +7 -7
  55. package/configs/angular/rules/ui/aria.md +422 -0
  56. package/configs/angular/rules/ui/forms.md +424 -0
  57. package/configs/angular/rules/ui/pipes-directives.md +335 -0
  58. package/configs/angular/{.claude/settings.json → settings.json} +3 -0
  59. package/configs/dotnet/CLAUDE.md +53 -286
  60. package/configs/dotnet/rules/background-services.md +552 -0
  61. package/configs/dotnet/rules/configuration.md +426 -0
  62. package/configs/dotnet/rules/ddd.md +447 -0
  63. package/configs/dotnet/rules/dependency-injection.md +343 -0
  64. package/configs/dotnet/rules/mediatr.md +320 -0
  65. package/configs/dotnet/rules/middleware.md +489 -0
  66. package/configs/dotnet/rules/result-pattern.md +363 -0
  67. package/configs/dotnet/rules/validation.md +388 -0
  68. package/configs/dotnet/settings.json +29 -0
  69. package/configs/fastapi/CLAUDE.md +144 -0
  70. package/configs/fastapi/rules/background-tasks.md +254 -0
  71. package/configs/fastapi/rules/dependencies.md +170 -0
  72. package/configs/{python/.claude → fastapi}/rules/fastapi.md +61 -1
  73. package/configs/fastapi/rules/lifespan.md +274 -0
  74. package/configs/fastapi/rules/middleware.md +229 -0
  75. package/configs/fastapi/rules/pydantic.md +433 -0
  76. package/configs/fastapi/rules/responses.md +251 -0
  77. package/configs/fastapi/rules/routers.md +202 -0
  78. package/configs/fastapi/rules/security.md +222 -0
  79. package/configs/fastapi/rules/testing.md +251 -0
  80. package/configs/fastapi/rules/websockets.md +298 -0
  81. package/configs/fastapi/settings.json +35 -0
  82. package/configs/flask/CLAUDE.md +166 -0
  83. package/configs/flask/rules/blueprints.md +208 -0
  84. package/configs/flask/rules/cli.md +285 -0
  85. package/configs/flask/rules/configuration.md +281 -0
  86. package/configs/flask/rules/context.md +238 -0
  87. package/configs/flask/rules/error-handlers.md +278 -0
  88. package/configs/flask/rules/extensions.md +278 -0
  89. package/configs/flask/rules/flask.md +171 -0
  90. package/configs/flask/rules/marshmallow.md +206 -0
  91. package/configs/flask/rules/security.md +267 -0
  92. package/configs/flask/rules/testing.md +284 -0
  93. package/configs/flask/settings.json +35 -0
  94. package/configs/nestjs/CLAUDE.md +57 -215
  95. package/configs/nestjs/rules/common-patterns.md +300 -0
  96. package/configs/nestjs/rules/filters.md +376 -0
  97. package/configs/nestjs/rules/interceptors.md +317 -0
  98. package/configs/nestjs/rules/middleware.md +321 -0
  99. package/configs/nestjs/{.claude/rules → rules}/modules.md +26 -0
  100. package/configs/nestjs/rules/pipes.md +351 -0
  101. package/configs/nestjs/rules/websockets.md +451 -0
  102. package/configs/nestjs/settings.json +31 -0
  103. package/configs/nextjs/CLAUDE.md +69 -331
  104. package/configs/nextjs/rules/api-routes.md +358 -0
  105. package/configs/nextjs/rules/authentication.md +355 -0
  106. package/configs/nextjs/{.claude/rules → rules}/components.md +52 -0
  107. package/configs/nextjs/rules/data-fetching.md +249 -0
  108. package/configs/nextjs/rules/database.md +400 -0
  109. package/configs/nextjs/rules/middleware.md +303 -0
  110. package/configs/nextjs/rules/routing.md +324 -0
  111. package/configs/nextjs/rules/seo.md +350 -0
  112. package/configs/nextjs/rules/server-actions.md +353 -0
  113. package/configs/nextjs/{.claude/rules → rules}/state/zustand.md +6 -6
  114. package/configs/nextjs/{.claude/settings.json → settings.json} +7 -0
  115. package/package.json +24 -9
  116. package/src/cli.js +218 -0
  117. package/src/config.js +63 -0
  118. package/src/index.js +4 -0
  119. package/src/installer.js +414 -0
  120. package/src/merge.js +109 -0
  121. package/src/tech-config.json +45 -0
  122. package/src/utils.js +88 -0
  123. package/configs/dotnet/.claude/settings.json +0 -9
  124. package/configs/nestjs/.claude/settings.json +0 -15
  125. package/configs/python/.claude/rules/flask.md +0 -332
  126. package/configs/python/.claude/settings.json +0 -18
  127. package/configs/python/CLAUDE.md +0 -273
  128. package/src/install.js +0 -315
  129. /package/configs/_shared/{.claude/rules → rules/domain/frontend}/accessibility.md +0 -0
  130. /package/configs/_shared/{.claude/rules → rules/security}/security.md +0 -0
  131. /package/configs/_shared/{.claude/skills → skills/dev}/debug/SKILL.md +0 -0
  132. /package/configs/_shared/{.claude/skills → skills/dev}/learning/SKILL.md +0 -0
  133. /package/configs/_shared/{.claude/skills → skills/dev}/spec/SKILL.md +0 -0
  134. /package/configs/_shared/{.claude/skills → skills/git}/review/SKILL.md +0 -0
  135. /package/configs/dotnet/{.claude/rules → rules}/api.md +0 -0
  136. /package/configs/dotnet/{.claude/rules → rules}/architecture.md +0 -0
  137. /package/configs/dotnet/{.claude/rules → rules}/database/efcore.md +0 -0
  138. /package/configs/dotnet/{.claude/rules → rules}/testing.md +0 -0
  139. /package/configs/nestjs/{.claude/rules → rules}/auth.md +0 -0
  140. /package/configs/nestjs/{.claude/rules → rules}/database/prisma.md +0 -0
  141. /package/configs/nestjs/{.claude/rules → rules}/database/typeorm.md +0 -0
  142. /package/configs/nestjs/{.claude/rules → rules}/testing.md +0 -0
  143. /package/configs/nestjs/{.claude/rules → rules}/validation.md +0 -0
  144. /package/configs/nextjs/{.claude/rules → rules}/state/redux-toolkit.md +0 -0
  145. /package/configs/nextjs/{.claude/rules → rules}/testing.md +0 -0
@@ -0,0 +1,285 @@
1
+ ---
2
+ paths:
3
+ - "**/*.py"
4
+ ---
5
+
6
+ # Flask CLI Commands
7
+
8
+ ## Basic Commands
9
+
10
+ ```python
11
+ import click
12
+ from flask import Flask
13
+ from flask.cli import with_appcontext
14
+
15
+ app = Flask(__name__)
16
+
17
+ @app.cli.command("init-db")
18
+ @with_appcontext
19
+ def init_db_command():
20
+ """Initialize the database."""
21
+ db.create_all()
22
+ click.echo("Database initialized.")
23
+
24
+ @app.cli.command("seed")
25
+ @with_appcontext
26
+ def seed_command():
27
+ """Seed the database with sample data."""
28
+ from app.seeds import seed_all
29
+ seed_all()
30
+ click.echo("Database seeded.")
31
+
32
+ # Usage:
33
+ # flask init-db
34
+ # flask seed
35
+ ```
36
+
37
+ ## Commands with Arguments
38
+
39
+ ```python
40
+ @app.cli.command("create-user")
41
+ @click.argument("email")
42
+ @click.argument("name")
43
+ @click.option("--admin", is_flag=True, help="Make user an admin")
44
+ @with_appcontext
45
+ def create_user_command(email: str, name: str, admin: bool):
46
+ """Create a new user."""
47
+ user = User(email=email, name=name, is_admin=admin)
48
+ db.session.add(user)
49
+ db.session.commit()
50
+ click.echo(f"Created user: {user.email} (admin={admin})")
51
+
52
+ # Usage:
53
+ # flask create-user john@example.com "John Doe"
54
+ # flask create-user admin@example.com "Admin" --admin
55
+ ```
56
+
57
+ ## Commands with Options
58
+
59
+ ```python
60
+ @app.cli.command("export-users")
61
+ @click.option("--format", type=click.Choice(["json", "csv"]), default="json")
62
+ @click.option("--output", "-o", type=click.Path(), default="users.json")
63
+ @click.option("--active-only", is_flag=True, help="Export only active users")
64
+ @with_appcontext
65
+ def export_users_command(format: str, output: str, active_only: bool):
66
+ """Export users to a file."""
67
+ query = User.query
68
+ if active_only:
69
+ query = query.filter(User.is_active == True)
70
+
71
+ users = query.all()
72
+
73
+ if format == "json":
74
+ data = UserSchema(many=True).dump(users)
75
+ with open(output, "w") as f:
76
+ json.dump(data, f, indent=2)
77
+ elif format == "csv":
78
+ # CSV export logic
79
+ pass
80
+
81
+ click.echo(f"Exported {len(users)} users to {output}")
82
+
83
+ # Usage:
84
+ # flask export-users --format csv -o users.csv --active-only
85
+ ```
86
+
87
+ ## Command Groups
88
+
89
+ ```python
90
+ @app.cli.group()
91
+ def user():
92
+ """User management commands."""
93
+ pass
94
+
95
+ @user.command("create")
96
+ @click.argument("email")
97
+ @click.argument("name")
98
+ @with_appcontext
99
+ def user_create(email: str, name: str):
100
+ """Create a new user."""
101
+ user = User(email=email, name=name)
102
+ db.session.add(user)
103
+ db.session.commit()
104
+ click.echo(f"Created: {user.email}")
105
+
106
+ @user.command("delete")
107
+ @click.argument("email")
108
+ @click.confirmation_option(prompt="Are you sure?")
109
+ @with_appcontext
110
+ def user_delete(email: str):
111
+ """Delete a user."""
112
+ user = User.query.filter_by(email=email).first()
113
+ if not user:
114
+ click.echo(f"User not found: {email}", err=True)
115
+ return
116
+
117
+ db.session.delete(user)
118
+ db.session.commit()
119
+ click.echo(f"Deleted: {email}")
120
+
121
+ @user.command("list")
122
+ @click.option("--limit", default=10)
123
+ @with_appcontext
124
+ def user_list(limit: int):
125
+ """List users."""
126
+ users = User.query.limit(limit).all()
127
+ for user in users:
128
+ click.echo(f"{user.id}: {user.email} ({user.name})")
129
+
130
+ # Usage:
131
+ # flask user create john@example.com "John"
132
+ # flask user delete john@example.com
133
+ # flask user list --limit 20
134
+ ```
135
+
136
+ ## Blueprint Commands
137
+
138
+ ```python
139
+ # In blueprint
140
+ from flask import Blueprint
141
+
142
+ users_bp = Blueprint("users", __name__, cli_group="users")
143
+
144
+ @users_bp.cli.command("sync")
145
+ @with_appcontext
146
+ def sync_users():
147
+ """Sync users from external source."""
148
+ # Sync logic
149
+ click.echo("Users synced")
150
+
151
+ # Usage:
152
+ # flask users sync
153
+ ```
154
+
155
+ ## Progress Bars
156
+
157
+ ```python
158
+ @app.cli.command("migrate-data")
159
+ @with_appcontext
160
+ def migrate_data_command():
161
+ """Migrate data with progress bar."""
162
+ records = OldModel.query.all()
163
+
164
+ with click.progressbar(records, label="Migrating") as bar:
165
+ for record in bar:
166
+ new_record = migrate_record(record)
167
+ db.session.add(new_record)
168
+
169
+ db.session.commit()
170
+ click.echo("Migration complete!")
171
+ ```
172
+
173
+ ## Colored Output
174
+
175
+ ```python
176
+ @app.cli.command("check")
177
+ @with_appcontext
178
+ def check_command():
179
+ """Check application health."""
180
+ # Database
181
+ try:
182
+ db.session.execute("SELECT 1")
183
+ click.secho("✓ Database: OK", fg="green")
184
+ except Exception as e:
185
+ click.secho(f"✗ Database: {e}", fg="red")
186
+
187
+ # Redis
188
+ try:
189
+ redis_client.ping()
190
+ click.secho("✓ Redis: OK", fg="green")
191
+ except Exception as e:
192
+ click.secho(f"✗ Redis: {e}", fg="red")
193
+
194
+ # External API
195
+ try:
196
+ response = requests.get(f"{API_URL}/health", timeout=5)
197
+ response.raise_for_status()
198
+ click.secho("✓ External API: OK", fg="green")
199
+ except Exception as e:
200
+ click.secho(f"✗ External API: {e}", fg="yellow")
201
+ ```
202
+
203
+ ## Interactive Prompts
204
+
205
+ ```python
206
+ @app.cli.command("setup")
207
+ def setup_command():
208
+ """Interactive setup wizard."""
209
+ click.echo("Welcome to the setup wizard!")
210
+
211
+ # Text input
212
+ app_name = click.prompt("Application name", default="My App")
213
+
214
+ # Password input
215
+ secret = click.prompt("Secret key", hide_input=True)
216
+
217
+ # Choice
218
+ env = click.prompt(
219
+ "Environment",
220
+ type=click.Choice(["development", "staging", "production"]),
221
+ default="development",
222
+ )
223
+
224
+ # Confirmation
225
+ if click.confirm("Save configuration?"):
226
+ save_config(app_name=app_name, secret=secret, env=env)
227
+ click.echo("Configuration saved!")
228
+ else:
229
+ click.echo("Aborted.")
230
+ ```
231
+
232
+ ## Async Commands (Flask 2.0+)
233
+
234
+ ```python
235
+ import asyncio
236
+
237
+ @app.cli.command("async-task")
238
+ @with_appcontext
239
+ def async_task_command():
240
+ """Run async task."""
241
+ asyncio.run(run_async_task())
242
+
243
+ async def run_async_task():
244
+ async with aiohttp.ClientSession() as session:
245
+ async with session.get("https://api.example.com/data") as response:
246
+ data = await response.json()
247
+ click.echo(f"Fetched {len(data)} records")
248
+ ```
249
+
250
+ ## Custom CLI Script
251
+
252
+ ```python
253
+ # manage.py
254
+ import click
255
+ from app import create_app, db
256
+
257
+ app = create_app()
258
+
259
+ @click.group()
260
+ def cli():
261
+ """Management script."""
262
+ pass
263
+
264
+ @cli.command()
265
+ def runserver():
266
+ """Run development server."""
267
+ app.run(debug=True)
268
+
269
+ @cli.command()
270
+ @click.option("--drop", is_flag=True, help="Drop tables first")
271
+ def initdb(drop: bool):
272
+ """Initialize database."""
273
+ with app.app_context():
274
+ if drop:
275
+ db.drop_all()
276
+ db.create_all()
277
+ click.echo("Database initialized.")
278
+
279
+ if __name__ == "__main__":
280
+ cli()
281
+
282
+ # Usage:
283
+ # python manage.py runserver
284
+ # python manage.py initdb --drop
285
+ ```
@@ -0,0 +1,281 @@
1
+ ---
2
+ paths:
3
+ - "**/*.py"
4
+ ---
5
+
6
+ # Flask Configuration Patterns
7
+
8
+ ## Class-Based Configuration
9
+
10
+ ```python
11
+ # config.py
12
+ import os
13
+ from datetime import timedelta
14
+
15
+ class Config:
16
+ """Base configuration."""
17
+ SECRET_KEY = os.environ.get("SECRET_KEY", "dev-secret-key")
18
+ SQLALCHEMY_TRACK_MODIFICATIONS = False
19
+
20
+ # JWT
21
+ JWT_SECRET_KEY = os.environ.get("JWT_SECRET_KEY", SECRET_KEY)
22
+ JWT_ACCESS_TOKEN_EXPIRES = timedelta(hours=1)
23
+ JWT_REFRESH_TOKEN_EXPIRES = timedelta(days=30)
24
+
25
+ # Mail
26
+ MAIL_SERVER = os.environ.get("MAIL_SERVER", "localhost")
27
+ MAIL_PORT = int(os.environ.get("MAIL_PORT", 587))
28
+ MAIL_USE_TLS = True
29
+
30
+ class DevelopmentConfig(Config):
31
+ """Development configuration."""
32
+ DEBUG = True
33
+ SQLALCHEMY_DATABASE_URI = os.environ.get(
34
+ "DATABASE_URL",
35
+ "postgresql://localhost/app_dev"
36
+ )
37
+ SQLALCHEMY_ECHO = True # Log SQL queries
38
+
39
+ class TestingConfig(Config):
40
+ """Testing configuration."""
41
+ TESTING = True
42
+ SQLALCHEMY_DATABASE_URI = "sqlite:///:memory:"
43
+ WTF_CSRF_ENABLED = False
44
+
45
+ class ProductionConfig(Config):
46
+ """Production configuration."""
47
+ DEBUG = False
48
+ SQLALCHEMY_DATABASE_URI = os.environ["DATABASE_URL"]
49
+
50
+ # Security
51
+ SESSION_COOKIE_SECURE = True
52
+ SESSION_COOKIE_HTTPONLY = True
53
+ SESSION_COOKIE_SAMESITE = "Lax"
54
+
55
+ config = {
56
+ "development": DevelopmentConfig,
57
+ "testing": TestingConfig,
58
+ "production": ProductionConfig,
59
+ "default": DevelopmentConfig,
60
+ }
61
+ ```
62
+
63
+ ## Loading Configuration
64
+
65
+ ```python
66
+ # app/__init__.py
67
+ from flask import Flask
68
+ from config import config
69
+
70
+ def create_app(config_name: str = None) -> Flask:
71
+ if config_name is None:
72
+ config_name = os.environ.get("FLASK_CONFIG", "development")
73
+
74
+ app = Flask(__name__)
75
+ app.config.from_object(config[config_name])
76
+
77
+ # Load additional config from file
78
+ app.config.from_pyfile("config.py", silent=True)
79
+
80
+ # Load from environment variable pointing to file
81
+ app.config.from_envvar("APP_CONFIG_FILE", silent=True)
82
+
83
+ return app
84
+ ```
85
+
86
+ ## Environment Variables
87
+
88
+ ```python
89
+ # .env (development)
90
+ FLASK_APP=app
91
+ FLASK_CONFIG=development
92
+ SECRET_KEY=your-secret-key
93
+ DATABASE_URL=postgresql://user:pass@localhost/app_dev
94
+ REDIS_URL=redis://localhost:6379/0
95
+
96
+ # Load with python-dotenv
97
+ from dotenv import load_dotenv
98
+ load_dotenv()
99
+
100
+ # Or in create_app
101
+ def create_app(config_name: str = None) -> Flask:
102
+ load_dotenv()
103
+ ...
104
+ ```
105
+
106
+ ## Pydantic Settings (Recommended)
107
+
108
+ ```python
109
+ from pydantic_settings import BaseSettings
110
+ from functools import lru_cache
111
+
112
+ class Settings(BaseSettings):
113
+ # App
114
+ app_name: str = "My App"
115
+ debug: bool = False
116
+ secret_key: str
117
+
118
+ # Database
119
+ database_url: str
120
+
121
+ # Redis
122
+ redis_url: str = "redis://localhost:6379/0"
123
+
124
+ # JWT
125
+ jwt_secret_key: str | None = None
126
+ jwt_access_token_expires: int = 3600 # seconds
127
+
128
+ # Mail
129
+ mail_server: str = "localhost"
130
+ mail_port: int = 587
131
+ mail_username: str | None = None
132
+ mail_password: str | None = None
133
+
134
+ class Config:
135
+ env_file = ".env"
136
+ env_file_encoding = "utf-8"
137
+
138
+ @lru_cache
139
+ def get_settings() -> Settings:
140
+ return Settings()
141
+
142
+ settings = get_settings()
143
+
144
+ # Usage in app
145
+ def create_app() -> Flask:
146
+ app = Flask(__name__)
147
+
148
+ app.config["SECRET_KEY"] = settings.secret_key
149
+ app.config["SQLALCHEMY_DATABASE_URI"] = settings.database_url
150
+ app.config["DEBUG"] = settings.debug
151
+
152
+ return app
153
+ ```
154
+
155
+ ## Configuration Validation
156
+
157
+ ```python
158
+ def validate_config(app: Flask):
159
+ """Validate required configuration."""
160
+ required = [
161
+ "SECRET_KEY",
162
+ "SQLALCHEMY_DATABASE_URI",
163
+ ]
164
+
165
+ missing = [key for key in required if not app.config.get(key)]
166
+
167
+ if missing:
168
+ raise RuntimeError(f"Missing required config: {', '.join(missing)}")
169
+
170
+ # Validate SECRET_KEY strength in production
171
+ if not app.debug:
172
+ if len(app.config["SECRET_KEY"]) < 32:
173
+ raise RuntimeError("SECRET_KEY must be at least 32 characters in production")
174
+
175
+ def create_app(config_name: str = None) -> Flask:
176
+ app = Flask(__name__)
177
+ app.config.from_object(config[config_name])
178
+ validate_config(app)
179
+ return app
180
+ ```
181
+
182
+ ## Instance Configuration
183
+
184
+ ```python
185
+ # instance/config.py (not in version control)
186
+ SECRET_KEY = "your-production-secret"
187
+ SQLALCHEMY_DATABASE_URI = "postgresql://prod-db/app"
188
+
189
+ # Load instance config
190
+ app = Flask(__name__, instance_relative_config=True)
191
+ app.config.from_pyfile("config.py", silent=True)
192
+ ```
193
+
194
+ ## Configuration by Feature
195
+
196
+ ```python
197
+ class Config:
198
+ # Core
199
+ SECRET_KEY = os.environ["SECRET_KEY"]
200
+
201
+ # Database
202
+ SQLALCHEMY_DATABASE_URI = os.environ["DATABASE_URL"]
203
+ SQLALCHEMY_TRACK_MODIFICATIONS = False
204
+ SQLALCHEMY_ENGINE_OPTIONS = {
205
+ "pool_size": 10,
206
+ "pool_recycle": 3600,
207
+ "pool_pre_ping": True,
208
+ }
209
+
210
+ # Cache
211
+ CACHE_TYPE = "redis"
212
+ CACHE_REDIS_URL = os.environ.get("REDIS_URL")
213
+ CACHE_DEFAULT_TIMEOUT = 300
214
+
215
+ # Session
216
+ SESSION_TYPE = "redis"
217
+ SESSION_REDIS = redis.from_url(os.environ.get("REDIS_URL"))
218
+ PERMANENT_SESSION_LIFETIME = timedelta(days=7)
219
+
220
+ # Security
221
+ SESSION_COOKIE_SECURE = True
222
+ SESSION_COOKIE_HTTPONLY = True
223
+ SESSION_COOKIE_SAMESITE = "Lax"
224
+
225
+ # CORS
226
+ CORS_ORIGINS = os.environ.get("CORS_ORIGINS", "").split(",")
227
+
228
+ # Uploads
229
+ MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB
230
+ UPLOAD_FOLDER = os.environ.get("UPLOAD_FOLDER", "/tmp/uploads")
231
+
232
+ # Logging
233
+ LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO")
234
+ LOG_FORMAT = "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
235
+ ```
236
+
237
+ ## Runtime Configuration Access
238
+
239
+ ```python
240
+ from flask import current_app
241
+
242
+ @users_bp.route("/config-example")
243
+ def config_example():
244
+ # Access config in routes
245
+ debug = current_app.config["DEBUG"]
246
+ app_name = current_app.config.get("APP_NAME", "Default")
247
+
248
+ return jsonify({
249
+ "debug": debug,
250
+ "app_name": app_name,
251
+ })
252
+
253
+ # In services
254
+ class EmailService:
255
+ def __init__(self):
256
+ self.server = current_app.config["MAIL_SERVER"]
257
+ self.port = current_app.config["MAIL_PORT"]
258
+ ```
259
+
260
+ ## Configuration for Extensions
261
+
262
+ ```python
263
+ def configure_extensions(app: Flask):
264
+ """Configure Flask extensions."""
265
+ # SQLAlchemy
266
+ app.config.setdefault("SQLALCHEMY_TRACK_MODIFICATIONS", False)
267
+
268
+ # JWT
269
+ app.config.setdefault("JWT_TOKEN_LOCATION", ["headers"])
270
+ app.config.setdefault("JWT_HEADER_NAME", "Authorization")
271
+ app.config.setdefault("JWT_HEADER_TYPE", "Bearer")
272
+
273
+ # CORS
274
+ app.config.setdefault("CORS_SUPPORTS_CREDENTIALS", True)
275
+
276
+ def create_app(config_name: str = None) -> Flask:
277
+ app = Flask(__name__)
278
+ app.config.from_object(config[config_name])
279
+ configure_extensions(app)
280
+ return app
281
+ ```