fast-clean-architecture 1.0.0__py3-none-any.whl → 1.1.2__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.
- fast_clean_architecture/__init__.py +5 -6
- fast_clean_architecture/analytics.py +260 -0
- fast_clean_architecture/cli.py +563 -46
- fast_clean_architecture/config.py +47 -23
- fast_clean_architecture/error_tracking.py +201 -0
- fast_clean_architecture/exceptions.py +432 -12
- fast_clean_architecture/generators/__init__.py +11 -1
- fast_clean_architecture/generators/component_generator.py +407 -103
- fast_clean_architecture/generators/config_updater.py +186 -38
- fast_clean_architecture/generators/generator_factory.py +223 -0
- fast_clean_architecture/generators/package_generator.py +9 -7
- fast_clean_architecture/generators/template_validator.py +109 -9
- fast_clean_architecture/generators/validation_config.py +5 -3
- fast_clean_architecture/generators/validation_metrics.py +10 -6
- fast_clean_architecture/health.py +169 -0
- fast_clean_architecture/logging_config.py +52 -0
- fast_clean_architecture/metrics.py +108 -0
- fast_clean_architecture/protocols.py +406 -0
- fast_clean_architecture/templates/external.py.j2 +109 -32
- fast_clean_architecture/utils.py +50 -31
- fast_clean_architecture/validation.py +302 -0
- {fast_clean_architecture-1.0.0.dist-info → fast_clean_architecture-1.1.2.dist-info}/METADATA +131 -64
- fast_clean_architecture-1.1.2.dist-info/RECORD +38 -0
- fast_clean_architecture-1.0.0.dist-info/RECORD +0 -30
- {fast_clean_architecture-1.0.0.dist-info → fast_clean_architecture-1.1.2.dist-info}/WHEEL +0 -0
- {fast_clean_architecture-1.0.0.dist-info → fast_clean_architecture-1.1.2.dist-info}/entry_points.txt +0 -0
- {fast_clean_architecture-1.0.0.dist-info → fast_clean_architecture-1.1.2.dist-info}/licenses/LICENSE +0 -0
fast_clean_architecture/cli.py
CHANGED
@@ -1,31 +1,98 @@
|
|
1
1
|
"""Command-line interface for fast-clean-architecture."""
|
2
2
|
|
3
|
+
import os
|
3
4
|
import sys
|
4
5
|
from pathlib import Path
|
5
|
-
from typing import Optional
|
6
|
+
from typing import List, NoReturn, Optional, Union, cast
|
6
7
|
|
7
8
|
import typer
|
8
9
|
from rich.console import Console
|
9
|
-
from rich.table import Table
|
10
10
|
from rich.panel import Panel
|
11
|
-
from rich.
|
11
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
12
|
+
from rich.prompt import Confirm, Prompt
|
12
13
|
from rich.syntax import Syntax
|
14
|
+
from rich.table import Table
|
15
|
+
from rich.text import Text
|
13
16
|
|
17
|
+
from .analytics import log_usage_summary, track_command_usage, track_component_creation
|
14
18
|
from .config import Config
|
15
|
-
from .
|
16
|
-
from .
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
from .
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
from .error_tracking import log_error_summary, track_error
|
20
|
+
from .exceptions import FastCleanArchitectureError, ValidationError
|
21
|
+
from .generators import ConfigUpdater, PackageGenerator
|
22
|
+
from .generators.generator_factory import create_generator_factory
|
23
|
+
from .health import log_startup_health
|
24
|
+
from .logging_config import configure_logging, get_logger
|
25
|
+
from .utils import sanitize_name, validate_name, validate_python_identifier
|
26
|
+
|
27
|
+
# Configure structured logging
|
28
|
+
configure_logging()
|
29
|
+
logger = get_logger(__name__)
|
30
|
+
|
31
|
+
# Log startup health
|
32
|
+
log_startup_health()
|
24
33
|
|
25
34
|
# Create the main Typer app
|
26
35
|
app = typer.Typer(
|
27
36
|
name="fca-scaffold",
|
28
|
-
help="Fast Clean Architecture scaffolding tool for FastAPI projects
|
37
|
+
help="""[bold blue]Fast Clean Architecture[/bold blue] is a scaffolding tool for FastAPI projects.
|
38
|
+
|
39
|
+
[bold]Quick Start:[/bold]
|
40
|
+
1. Initialize a new project
|
41
|
+
[cyan]fca-scaffold init[/cyan]
|
42
|
+
|
43
|
+
2. Create a system context
|
44
|
+
[cyan]fca-scaffold create-system-context admin[/cyan]
|
45
|
+
|
46
|
+
3. Create a module in the admin system
|
47
|
+
[cyan]fca-scaffold create-module admin auth[/cyan]
|
48
|
+
|
49
|
+
4. Create a component (e.g., entities, services, repositories)
|
50
|
+
[cyan]fca-scaffold create-component admin/auth/domain/entities Admin[/cyan]
|
51
|
+
|
52
|
+
[bold]Definitions:[/bold]
|
53
|
+
[yellow]System:[/yellow]
|
54
|
+
A bounded context representing a major business domain.
|
55
|
+
Examples: user_management, payment_processing
|
56
|
+
|
57
|
+
[yellow]Module:[/yellow]
|
58
|
+
A functional area within a system that groups related components.
|
59
|
+
Examples: auth, billing, notifications
|
60
|
+
|
61
|
+
[yellow]Component:[/yellow]
|
62
|
+
Individual code artifacts within Clean Architecture layers:
|
63
|
+
|
64
|
+
[dim]Domain:[/dim]
|
65
|
+
- entities
|
66
|
+
- repositories
|
67
|
+
- value_objects
|
68
|
+
|
69
|
+
[dim]Application:[/dim]
|
70
|
+
- services
|
71
|
+
- commands
|
72
|
+
- queries
|
73
|
+
|
74
|
+
[dim]Infrastructure:[/dim]
|
75
|
+
- models
|
76
|
+
- repositories
|
77
|
+
- external
|
78
|
+
|
79
|
+
[dim]Presentation:[/dim]
|
80
|
+
- api
|
81
|
+
- schemas
|
82
|
+
|
83
|
+
[bold]Get help for any command:[/bold]
|
84
|
+
[cyan]fca-scaffold [COMMAND] --help[/cyan]
|
85
|
+
|
86
|
+
[bold]Examples:[/bold]
|
87
|
+
Initialize a project with a description:
|
88
|
+
[dim]fca-scaffold init my-project --description "My FastAPI project"[/dim]
|
89
|
+
|
90
|
+
Check scaffold status:
|
91
|
+
[dim]fca-scaffold status[/dim]
|
92
|
+
|
93
|
+
Show current config:
|
94
|
+
[dim]fca-scaffold config show[/dim]
|
95
|
+
""",
|
29
96
|
rich_markup_mode="rich",
|
30
97
|
)
|
31
98
|
|
@@ -44,7 +111,7 @@ FORCE_OPTION = typer.Option(
|
|
44
111
|
)
|
45
112
|
VERBOSE_OPTION = typer.Option(False, "--verbose", "-v", help="Enable verbose output")
|
46
113
|
CONFIG_PATH_OPTION = typer.Option(
|
47
|
-
"
|
114
|
+
"fca_config.yaml", "--config", "-c", help="Path to configuration file"
|
48
115
|
)
|
49
116
|
|
50
117
|
|
@@ -61,7 +128,7 @@ def get_config_path(config_file: str) -> Path:
|
|
61
128
|
return config_path
|
62
129
|
|
63
130
|
|
64
|
-
def handle_error(error: Exception, verbose: bool = False) ->
|
131
|
+
def handle_error(error: Exception, verbose: bool = False) -> NoReturn:
|
65
132
|
"""Handle and display errors consistently."""
|
66
133
|
if isinstance(error, FastCleanArchitectureError):
|
67
134
|
console.print(f"[red]Error:[/red] {error}")
|
@@ -76,16 +143,34 @@ def handle_error(error: Exception, verbose: bool = False) -> None:
|
|
76
143
|
|
77
144
|
@app.command()
|
78
145
|
def init(
|
79
|
-
name: Optional[str] = typer.Argument(
|
146
|
+
name: Optional[str] = typer.Argument(
|
147
|
+
None, help="Project name (will be sanitized for Python compatibility)"
|
148
|
+
),
|
80
149
|
description: Optional[str] = typer.Option(
|
81
|
-
None, "--description", "--desc", help="Project description"
|
150
|
+
None, "--description", "--desc", help="Project description for documentation"
|
151
|
+
),
|
152
|
+
version: Optional[str] = typer.Option(
|
153
|
+
"0.1.0", "--version", help="Initial project version (semantic versioning)"
|
82
154
|
),
|
83
|
-
version: Optional[str] = typer.Option("0.1.0", "--version", help="Project version"),
|
84
155
|
config_file: str = CONFIG_PATH_OPTION,
|
85
156
|
force: bool = FORCE_OPTION,
|
86
157
|
verbose: bool = VERBOSE_OPTION,
|
87
158
|
) -> None:
|
88
|
-
"""Initialize a new Fast Clean Architecture project.
|
159
|
+
"""Initialize a new Fast Clean Architecture project.
|
160
|
+
|
161
|
+
Creates a new FCA project with configuration file and basic directory structure.
|
162
|
+
If no name is provided, you'll be prompted to enter one.
|
163
|
+
|
164
|
+
[bold]Examples:[/bold]
|
165
|
+
[cyan]fca-scaffold init[/cyan] # Interactive mode
|
166
|
+
[cyan]fca-scaffold init my-api[/cyan] # With project name
|
167
|
+
[cyan]fca-scaffold init my-api --desc "User management API"[/cyan] # With description
|
168
|
+
[cyan]fca-scaffold init my-api --version 1.0.0 --force[/cyan] # Overwrite existing
|
169
|
+
|
170
|
+
[bold]What it creates:[/bold]
|
171
|
+
• [dim]fca_config.yaml[/dim] - Project configuration file
|
172
|
+
• [dim]systems/[/dim] - Directory for system contexts
|
173
|
+
"""
|
89
174
|
try:
|
90
175
|
project_root = get_project_root()
|
91
176
|
config_path = get_config_path(config_file)
|
@@ -139,16 +224,35 @@ def init(
|
|
139
224
|
|
140
225
|
@app.command()
|
141
226
|
def create_system_context(
|
142
|
-
name: str = typer.Argument(
|
227
|
+
name: str = typer.Argument(
|
228
|
+
..., help="System context name (e.g., admin, customer, settings)"
|
229
|
+
),
|
143
230
|
description: Optional[str] = typer.Option(
|
144
|
-
None, "--description", "--desc", help="
|
231
|
+
None, "--description", "--desc", help="Description of what this system handles"
|
145
232
|
),
|
146
233
|
config_file: str = CONFIG_PATH_OPTION,
|
147
234
|
dry_run: bool = DRY_RUN_OPTION,
|
148
235
|
force: bool = FORCE_OPTION,
|
149
236
|
verbose: bool = VERBOSE_OPTION,
|
150
237
|
) -> None:
|
151
|
-
"""Create a new system context.
|
238
|
+
"""Create a new system context.
|
239
|
+
|
240
|
+
A system context represents a bounded context in your domain, containing related
|
241
|
+
business functionality or aimed at different operational context such as admin, customer, settings. Each system can contain multiple modules.
|
242
|
+
|
243
|
+
[bold]Examples:[/bold]
|
244
|
+
[cyan]fca-scaffold create-system-context admin[/cyan]
|
245
|
+
[cyan]fca-scaffold create-system-context customer --desc "Customer System"[/cyan]
|
246
|
+
[cyan]fca-scaffold create-system-context settings --dry-run[/cyan] # Preview only
|
247
|
+
|
248
|
+
[bold]What it creates:[/bold]
|
249
|
+
• [dim]systems/[SYSTEM_NAME]/[/dim] - System directory
|
250
|
+
• [dim]systems/[SYSTEM_NAME]/__init__.py[/dim] - Python package file
|
251
|
+
• Updates [dim]fca_config.yaml[/dim] with system information
|
252
|
+
|
253
|
+
[bold]Next steps:[/bold]
|
254
|
+
Create modules with: [cyan]fca-scaffold create-module [SYSTEM_NAME] [MODULE_NAME][/cyan]
|
255
|
+
"""
|
152
256
|
try:
|
153
257
|
project_root = get_project_root()
|
154
258
|
config_path = get_config_path(config_file)
|
@@ -183,17 +287,41 @@ def create_system_context(
|
|
183
287
|
|
184
288
|
@app.command()
|
185
289
|
def create_module(
|
186
|
-
system_name: str = typer.Argument(..., help="
|
187
|
-
module_name: str = typer.Argument(
|
290
|
+
system_name: str = typer.Argument(..., help="Existing system context name"),
|
291
|
+
module_name: str = typer.Argument(
|
292
|
+
..., help="Module name (e.g., authentication, user_profile)"
|
293
|
+
),
|
188
294
|
description: Optional[str] = typer.Option(
|
189
|
-
None, "--description", "--desc", help="
|
295
|
+
None, "--description", "--desc", help="Description of module functionality"
|
190
296
|
),
|
191
297
|
config_file: str = CONFIG_PATH_OPTION,
|
192
298
|
dry_run: bool = DRY_RUN_OPTION,
|
193
299
|
force: bool = FORCE_OPTION,
|
194
300
|
verbose: bool = VERBOSE_OPTION,
|
195
301
|
) -> None:
|
196
|
-
"""Create a new module within a system context.
|
302
|
+
"""Create a new module within a system context.
|
303
|
+
|
304
|
+
Modules organize related functionality within a system context, following
|
305
|
+
Clean Architecture layers (domain, application, infrastructure, presentation).
|
306
|
+
|
307
|
+
[bold]Examples:[/bold]
|
308
|
+
[cyan]fca-scaffold create-module admin authentication[/cyan]
|
309
|
+
[cyan]fca-scaffold create-module customer payment_processing --desc "Payment processing logic"[/cyan]
|
310
|
+
[cyan]fca-scaffold create-module settings notification_settings --dry-run[/cyan] # Preview only
|
311
|
+
|
312
|
+
[bold]What it creates:[/bold]
|
313
|
+
• [dim]systems/[SYSTEM_NAME]/modules/[MODULE_NAME]/[/dim] - Module directory
|
314
|
+
• [dim]systems/[SYSTEM_NAME]/modules/[MODULE_NAME]/__init__.py[/dim] - Package file
|
315
|
+
• [dim]systems/[SYSTEM_NAME]/modules/[MODULE_NAME]/[MODULE_NAME]_module_api.py[/dim] - Module API file
|
316
|
+
• [dim]systems/[SYSTEM_NAME]/modules/[MODULE_NAME]/domain/[/dim] - Domain layer
|
317
|
+
• [dim]systems/[SYSTEM_NAME]/modules/[MODULE_NAME]/application/[/dim] - Application layer
|
318
|
+
• [dim]systems/[SYSTEM_NAME]/modules/[MODULE_NAME]/infrastructure/[/dim] - Infrastructure layer
|
319
|
+
• [dim]systems/[SYSTEM_NAME]/modules/[MODULE_NAME]/presentation/[/dim] - Presentation layer
|
320
|
+
• Updates [dim]fca_config.yaml[/dim] with module information
|
321
|
+
|
322
|
+
[bold]Next steps:[/bold]
|
323
|
+
Create components with: [cyan]fca-scaffold create-component [SYSTEM_NAME]/[MODULE_NAME]/[LAYER]/[TYPE] [COMPONENT_NAME][/cyan]
|
324
|
+
"""
|
197
325
|
try:
|
198
326
|
project_root = get_project_root()
|
199
327
|
config_path = get_config_path(config_file)
|
@@ -207,11 +335,23 @@ def create_module(
|
|
207
335
|
if not validate_python_identifier(sanitized_module):
|
208
336
|
raise ValidationError(f"Invalid module name: {module_name}")
|
209
337
|
|
210
|
-
# Initialize
|
338
|
+
# Initialize config updater for validation
|
211
339
|
config_updater = ConfigUpdater(config_path, console)
|
340
|
+
|
341
|
+
# Validate system exists BEFORE creating any directory structure
|
342
|
+
if sanitized_system not in config_updater.config.project.systems:
|
343
|
+
raise ValidationError(
|
344
|
+
f"System '{sanitized_system}' not found.\n\n"
|
345
|
+
f"To create the module, first create the system:\n"
|
346
|
+
f' fca-scaffold create-system-context {sanitized_system} --description "[SYSTEM_DESCRIPTION]"\n\n'
|
347
|
+
f"Then create your module:\n"
|
348
|
+
f" fca-scaffold create-module {sanitized_system} {sanitized_module}"
|
349
|
+
)
|
350
|
+
|
351
|
+
# Initialize package generator
|
212
352
|
package_generator = PackageGenerator(console)
|
213
353
|
|
214
|
-
# Create module structure
|
354
|
+
# Create module structure (only after validation passes)
|
215
355
|
package_generator.create_module_structure(
|
216
356
|
base_path=project_root,
|
217
357
|
system_name=sanitized_system,
|
@@ -220,7 +360,7 @@ def create_module(
|
|
220
360
|
)
|
221
361
|
|
222
362
|
if not dry_run:
|
223
|
-
# Update configuration
|
363
|
+
# Update configuration (system existence already validated)
|
224
364
|
config_updater.add_module(sanitized_system, sanitized_module, description)
|
225
365
|
|
226
366
|
console.print(
|
@@ -234,9 +374,12 @@ def create_module(
|
|
234
374
|
@app.command()
|
235
375
|
def create_component(
|
236
376
|
location: str = typer.Argument(
|
237
|
-
...,
|
377
|
+
...,
|
378
|
+
help="Component location: system/module/layer/type (e.g., user_management/auth/domain/entities)",
|
379
|
+
),
|
380
|
+
name: str = typer.Argument(
|
381
|
+
..., help="Component name (e.g., User, AuthService, UserRepository)"
|
238
382
|
),
|
239
|
-
name: str = typer.Argument(..., help="Component name"),
|
240
383
|
config_file: str = CONFIG_PATH_OPTION,
|
241
384
|
dry_run: bool = DRY_RUN_OPTION,
|
242
385
|
force: bool = FORCE_OPTION,
|
@@ -244,10 +387,54 @@ def create_component(
|
|
244
387
|
) -> None:
|
245
388
|
"""Create a new component.
|
246
389
|
|
247
|
-
|
248
|
-
|
390
|
+
Creates components following Clean Architecture patterns. Components are generated
|
391
|
+
from templates and placed in the appropriate layer directory.
|
392
|
+
|
393
|
+
[bold]Location format:[/bold] [cyan]system_name/module_name/layer/component_type[/cyan]
|
394
|
+
|
395
|
+
[bold]Available layers and component types:[/bold]
|
396
|
+
[yellow]domain/[/yellow]
|
397
|
+
• [cyan]entities[/cyan] - Domain entities (business objects)
|
398
|
+
• [cyan]value_objects[/cyan] - Value objects (immutable data)
|
399
|
+
• [cyan]repositories[/cyan] - Repository interfaces
|
400
|
+
• [cyan]services[/cyan] - Domain services
|
401
|
+
|
402
|
+
[yellow]application/[/yellow]
|
403
|
+
• [cyan]commands[/cyan] - Command handlers (CQRS)
|
404
|
+
• [cyan]queries[/cyan] - Query handlers (CQRS)
|
405
|
+
• [cyan]services[/cyan] - Application services
|
406
|
+
|
407
|
+
[yellow]infrastructure/[/yellow]
|
408
|
+
• [cyan]models[/cyan] - Database models and schemas
|
409
|
+
• [cyan]repositories[/cyan] - Repository implementations
|
410
|
+
• [cyan]external[/cyan] - External service adapters
|
411
|
+
|
412
|
+
[yellow]presentation/[/yellow]
|
413
|
+
• [cyan]api[/cyan] - API endpoints/controllers
|
414
|
+
• [cyan]schemas[/cyan] - Request/response schemas
|
415
|
+
|
416
|
+
[bold]Examples:[/bold]
|
417
|
+
[cyan]fca-scaffold create-component admin/auth/domain/entities User[/cyan]
|
418
|
+
[cyan]fca-scaffold create-component admin/auth/application/commands CreateUser[/cyan]
|
419
|
+
[cyan]fca-scaffold create-component customer/payment_processing/infrastructure/repositories PaymentProcessingRepository[/cyan]
|
420
|
+
[cyan]fca-scaffold create-component settings/notification_settings/presentation/api NotificationSettingsAPI[/cyan]
|
421
|
+
|
422
|
+
[bold]What it creates:[/bold]
|
423
|
+
• Python file with component implementation
|
424
|
+
• Imports and dependencies based on component type
|
425
|
+
• Updates [dim]fca_config.yaml[/dim] with component information
|
249
426
|
"""
|
250
427
|
try:
|
428
|
+
# Log CLI command start
|
429
|
+
logger.info(
|
430
|
+
"CLI create_component command started",
|
431
|
+
operation="cli_create_component",
|
432
|
+
location=location,
|
433
|
+
name=name,
|
434
|
+
dry_run=dry_run,
|
435
|
+
force=force,
|
436
|
+
)
|
437
|
+
|
251
438
|
project_root = get_project_root()
|
252
439
|
config_path = get_config_path(config_file)
|
253
440
|
|
@@ -274,12 +461,18 @@ def create_component(
|
|
274
461
|
):
|
275
462
|
raise ValidationError("Invalid names provided")
|
276
463
|
|
277
|
-
# Initialize generators
|
464
|
+
# Initialize generators using factory pattern
|
278
465
|
config_updater = ConfigUpdater(config_path, console)
|
279
|
-
|
466
|
+
generator_factory = create_generator_factory(config_updater.config, console)
|
467
|
+
component_generator = generator_factory.create_generator("component")
|
468
|
+
|
469
|
+
# Cast to ComponentGeneratorProtocol for type safety
|
470
|
+
from .generators import ComponentGeneratorProtocol
|
471
|
+
|
472
|
+
component_gen = cast(ComponentGeneratorProtocol, component_generator)
|
280
473
|
|
281
474
|
# Create component
|
282
|
-
file_path =
|
475
|
+
file_path = component_gen.create_component(
|
283
476
|
base_path=project_root,
|
284
477
|
system_name=sanitized_system,
|
285
478
|
module_name=sanitized_module,
|
@@ -305,19 +498,87 @@ def create_component(
|
|
305
498
|
f"[green]✅ Component '{sanitized_name}' created at {location}![/green]"
|
306
499
|
)
|
307
500
|
|
501
|
+
# Log successful completion
|
502
|
+
logger.info(
|
503
|
+
"CLI create_component command completed successfully",
|
504
|
+
operation="cli_create_component",
|
505
|
+
component_name=sanitized_name,
|
506
|
+
location=location,
|
507
|
+
file_path=str(file_path) if not dry_run else None,
|
508
|
+
)
|
509
|
+
|
510
|
+
# Track component creation for analytics
|
511
|
+
if not dry_run:
|
512
|
+
track_component_creation(
|
513
|
+
system_name=sanitized_system,
|
514
|
+
module_name=sanitized_module,
|
515
|
+
layer=layer,
|
516
|
+
component_type=component_type,
|
517
|
+
component_name=sanitized_name,
|
518
|
+
)
|
519
|
+
|
308
520
|
except Exception as e:
|
521
|
+
# Log CLI error and track it
|
522
|
+
logger.error(
|
523
|
+
"CLI create_component command failed",
|
524
|
+
operation="cli_create_component",
|
525
|
+
error=str(e),
|
526
|
+
error_type=type(e).__name__,
|
527
|
+
location=location,
|
528
|
+
name=name,
|
529
|
+
)
|
530
|
+
|
531
|
+
# Track the error for analytics
|
532
|
+
track_error(
|
533
|
+
error=e,
|
534
|
+
context={
|
535
|
+
"command": "create_component",
|
536
|
+
"location": location,
|
537
|
+
"name": name,
|
538
|
+
"dry_run": dry_run,
|
539
|
+
"force": force,
|
540
|
+
},
|
541
|
+
operation="cli_create_component",
|
542
|
+
)
|
543
|
+
|
309
544
|
handle_error(e, verbose)
|
310
545
|
|
311
546
|
|
312
547
|
@app.command()
|
313
548
|
def batch_create(
|
314
|
-
spec_file: str = typer.Argument(
|
549
|
+
spec_file: str = typer.Argument(
|
550
|
+
..., help="Path to YAML specification file (see examples/components_spec.yaml)"
|
551
|
+
),
|
315
552
|
config_file: str = CONFIG_PATH_OPTION,
|
316
553
|
dry_run: bool = DRY_RUN_OPTION,
|
317
554
|
force: bool = FORCE_OPTION,
|
318
555
|
verbose: bool = VERBOSE_OPTION,
|
319
556
|
) -> None:
|
320
|
-
"""Create multiple components from a YAML specification file.
|
557
|
+
"""Create multiple components from a YAML specification file.
|
558
|
+
|
559
|
+
Batch creation allows you to define multiple systems, modules, and components
|
560
|
+
in a single YAML file and create them all at once.
|
561
|
+
|
562
|
+
[bold]Examples:[/bold]
|
563
|
+
[cyan]fca-scaffold batch-create components_spec.yaml[/cyan]
|
564
|
+
[cyan]fca-scaffold batch-create my-spec.yaml --dry-run[/cyan] # Preview only
|
565
|
+
|
566
|
+
[bold]Specification file format:[/bold]
|
567
|
+
[dim]systems:[/dim]
|
568
|
+
[dim] - name: admin[/dim]
|
569
|
+
[dim] modules:[/dim]
|
570
|
+
[dim] - name: authentication[/dim]
|
571
|
+
[dim] components:[/dim]
|
572
|
+
[dim] domain:[/dim]
|
573
|
+
[dim] entities: [AdminUser, AdminRole][/dim]
|
574
|
+
[dim] value_objects: [AdminEmail, AdminPassword][/dim]
|
575
|
+
[dim] repositories: [AdminUserRepository][/dim]
|
576
|
+
[dim] application:[/dim]
|
577
|
+
[dim] commands: [CreateAdminUser, UpdateAdminUser][/dim]
|
578
|
+
|
579
|
+
[bold]See also:[/bold]
|
580
|
+
Check [cyan]examples/components_spec.yaml[/cyan] for a complete example
|
581
|
+
"""
|
321
582
|
try:
|
322
583
|
import yaml
|
323
584
|
|
@@ -332,9 +593,10 @@ def batch_create(
|
|
332
593
|
with open(spec_path, "r", encoding="utf-8") as f:
|
333
594
|
spec = yaml.safe_load(f)
|
334
595
|
|
335
|
-
# Initialize generators
|
596
|
+
# Initialize generators using factory pattern
|
336
597
|
config_updater = ConfigUpdater(config_path, console)
|
337
|
-
|
598
|
+
generator_factory = create_generator_factory(config_updater.config, console)
|
599
|
+
component_generator = generator_factory.create_generator("component")
|
338
600
|
|
339
601
|
# Process specification
|
340
602
|
for system_spec in spec.get("systems", []):
|
@@ -344,8 +606,13 @@ def batch_create(
|
|
344
606
|
module_name = module_spec["name"]
|
345
607
|
components_spec = module_spec.get("components", {})
|
346
608
|
|
609
|
+
# Cast to ComponentGeneratorProtocol for type safety
|
610
|
+
from .protocols import ComponentGeneratorProtocol
|
611
|
+
|
612
|
+
component_gen = cast(ComponentGeneratorProtocol, component_generator)
|
613
|
+
|
347
614
|
# Create components
|
348
|
-
|
615
|
+
component_gen.create_multiple_components(
|
349
616
|
base_path=project_root,
|
350
617
|
system_name=system_name,
|
351
618
|
module_name=module_name,
|
@@ -365,7 +632,22 @@ def status(
|
|
365
632
|
config_file: str = CONFIG_PATH_OPTION,
|
366
633
|
verbose: bool = VERBOSE_OPTION,
|
367
634
|
) -> None:
|
368
|
-
"""Show project status and configuration summary.
|
635
|
+
"""Show project status and configuration summary.
|
636
|
+
|
637
|
+
Displays an overview of your FCA project including systems, modules,
|
638
|
+
and recent activity. Useful for understanding project structure.
|
639
|
+
|
640
|
+
[bold]Examples:[/bold]
|
641
|
+
[cyan]fca-scaffold status[/cyan] # Show project overview
|
642
|
+
[cyan]fca-scaffold status --verbose[/cyan] # Detailed information
|
643
|
+
[cyan]fca-scaffold status -c my-config.yaml[/cyan] # Custom config file
|
644
|
+
|
645
|
+
[bold]Information shown:[/bold]
|
646
|
+
• Project name, version, and timestamps
|
647
|
+
• Systems and module counts
|
648
|
+
• Recent creation/update dates
|
649
|
+
• Configuration file location
|
650
|
+
"""
|
369
651
|
try:
|
370
652
|
config_path = get_config_path(config_file)
|
371
653
|
|
@@ -417,11 +699,31 @@ def status(
|
|
417
699
|
|
418
700
|
@app.command()
|
419
701
|
def config(
|
420
|
-
action: str = typer.Argument(..., help="Action: show, edit, validate"),
|
702
|
+
action: str = typer.Argument(..., help="Action to perform: show, edit, validate"),
|
421
703
|
config_file: str = CONFIG_PATH_OPTION,
|
422
704
|
verbose: bool = VERBOSE_OPTION,
|
423
705
|
) -> None:
|
424
|
-
"""Manage project configuration.
|
706
|
+
"""Manage project configuration.
|
707
|
+
|
708
|
+
Provides tools to view, edit, and validate your FCA project configuration.
|
709
|
+
The configuration file tracks all systems, modules, and components.
|
710
|
+
|
711
|
+
[bold]Available actions:[/bold]
|
712
|
+
[cyan]show[/cyan] - Display configuration file contents with syntax highlighting
|
713
|
+
[cyan]edit[/cyan] - Get instructions for editing the configuration
|
714
|
+
[cyan]validate[/cyan] - Check if configuration file is valid YAML and structure
|
715
|
+
|
716
|
+
[bold]Examples:[/bold]
|
717
|
+
[cyan]fca-scaffold config show[/cyan] # View current config
|
718
|
+
[cyan]fca-scaffold config validate[/cyan] # Check config validity
|
719
|
+
[cyan]fca-scaffold config show -c my-config.yaml[/cyan] # Custom config file
|
720
|
+
|
721
|
+
[bold]Configuration structure:[/bold]
|
722
|
+
• [dim]project[/dim] - Project metadata (name, version, description)
|
723
|
+
• [dim]systems[/dim] - System contexts and their modules
|
724
|
+
• [dim]components[/dim] - Generated components and their locations
|
725
|
+
• [dim]timestamps[/dim] - Creation and modification dates
|
726
|
+
"""
|
425
727
|
try:
|
426
728
|
config_path = get_config_path(config_file)
|
427
729
|
|
@@ -461,10 +763,100 @@ def config(
|
|
461
763
|
handle_error(e, verbose)
|
462
764
|
|
463
765
|
|
766
|
+
@app.command()
|
767
|
+
def help_guide() -> None:
|
768
|
+
"""Show comprehensive help and quick reference guide.
|
769
|
+
|
770
|
+
Displays a detailed guide covering all commands, common workflows,
|
771
|
+
and best practices for using Fast Clean Architecture.
|
772
|
+
|
773
|
+
[bold]Example:[/bold]
|
774
|
+
[cyan]fca-scaffold help-guide[/cyan]
|
775
|
+
|
776
|
+
[bold]Covers:[/bold]
|
777
|
+
• Complete workflow from project init to component creation
|
778
|
+
• Command reference with examples
|
779
|
+
• Clean Architecture layer explanations
|
780
|
+
• Best practices and tips
|
781
|
+
"""
|
782
|
+
console.print(
|
783
|
+
Panel.fit(
|
784
|
+
"[bold blue]Fast Clean Architecture - Complete Guide[/bold blue]\n\n"
|
785
|
+
"[bold yellow]📖 Key Definitions:[/bold yellow]\n\n"
|
786
|
+
"[yellow]System:[/yellow]\n"
|
787
|
+
" A bounded context representing a major business domain.\n"
|
788
|
+
" Examples: admin, customer, settings\n\n"
|
789
|
+
"[yellow]Module:[/yellow]\n"
|
790
|
+
" A functional area within a system that groups related components.\n"
|
791
|
+
" Examples: auth, billing, notifications, reporting\n\n"
|
792
|
+
"[yellow]Component:[/yellow]\n"
|
793
|
+
" Individual code artifacts within Clean Architecture layers:\n\n"
|
794
|
+
" [dim]Domain:[/dim]\n"
|
795
|
+
" - entities\n"
|
796
|
+
" - repositories\n"
|
797
|
+
" - value_objects\n\n"
|
798
|
+
" [dim]Application:[/dim]\n"
|
799
|
+
" - services\n"
|
800
|
+
" - commands\n"
|
801
|
+
" - queries\n\n"
|
802
|
+
" [dim]Infrastructure:[/dim]\n"
|
803
|
+
" - models\n"
|
804
|
+
" - repositories\n"
|
805
|
+
" - external\n\n"
|
806
|
+
" [dim]Presentation:[/dim]\n"
|
807
|
+
" - api\n"
|
808
|
+
" - schemas\n\n"
|
809
|
+
"[bold yellow]🚀 Quick Start Workflow:[/bold yellow]\n"
|
810
|
+
"1. [cyan]fca-scaffold init my-project[/cyan] - Initialize project\n"
|
811
|
+
"2. [cyan]fca-scaffold create-system-context admin[/cyan] - Create system\n"
|
812
|
+
"3. [cyan]fca-scaffold create-module admin auth[/cyan] - Create module\n"
|
813
|
+
"4. [cyan]fca-scaffold create-component admin/auth/domain/entities AdminUser[/cyan] - Create any component type\n\n"
|
814
|
+
"[bold yellow]📋 Available Commands:[/bold yellow]\n"
|
815
|
+
"• [cyan]init[/cyan] - Initialize new project\n"
|
816
|
+
"• [cyan]create-system-context[/cyan] - Create system (bounded context)\n"
|
817
|
+
"• [cyan]create-module[/cyan] - Create module within system\n"
|
818
|
+
"• [cyan]create-component[/cyan] - Create individual components (entities, services, repositories, etc.)\n"
|
819
|
+
"• [cyan]batch-create[/cyan] - Create multiple components from YAML\n"
|
820
|
+
"• [cyan]status[/cyan] - Show project overview\n"
|
821
|
+
"• [cyan]config[/cyan] - Manage configuration\n"
|
822
|
+
"• [cyan]version[/cyan] - Show version info\n\n"
|
823
|
+
"[bold yellow]🏗️ Clean Architecture Layers & Components:[/bold yellow]\n"
|
824
|
+
"• [yellow]domain/[/yellow] - Business logic\n"
|
825
|
+
" ◦ entities, repositories, value_objects\n"
|
826
|
+
"• [yellow]application/[/yellow] - Use cases\n"
|
827
|
+
" ◦ services, commands, queries\n"
|
828
|
+
"• [yellow]infrastructure/[/yellow] - External concerns\n"
|
829
|
+
" ◦ models, repositories, external\n"
|
830
|
+
"• [yellow]presentation/[/yellow] - User interface\n"
|
831
|
+
" ◦ api, schemas\n\n"
|
832
|
+
"[bold yellow]💡 Pro Tips:[/bold yellow]\n"
|
833
|
+
"• Use [cyan]--dry-run[/cyan] to preview changes\n"
|
834
|
+
"• Use [cyan]--help[/cyan] with any command for detailed info\n"
|
835
|
+
"• Check [cyan]fca-scaffold status[/cyan] to see project structure\n"
|
836
|
+
"• Validate config with [cyan]fca-scaffold config validate[/cyan]\n\n"
|
837
|
+
"[bold yellow]📖 For detailed help on any command:[/bold yellow]\n"
|
838
|
+
"[cyan]fca-scaffold [COMMAND] --help[/cyan]",
|
839
|
+
title="📚 Fast Clean Architecture - Help Guide",
|
840
|
+
)
|
841
|
+
)
|
842
|
+
|
843
|
+
|
464
844
|
@app.command()
|
465
845
|
def version() -> None:
|
466
|
-
"""Show version information.
|
467
|
-
|
846
|
+
"""Show version information.
|
847
|
+
|
848
|
+
Displays the current version of Fast Clean Architecture scaffolding tool
|
849
|
+
along with author information.
|
850
|
+
|
851
|
+
[bold]Example:[/bold]
|
852
|
+
[cyan]fca-scaffold version[/cyan]
|
853
|
+
|
854
|
+
[bold]Useful for:[/bold]
|
855
|
+
• Checking which version you're running
|
856
|
+
• Bug reports and support requests
|
857
|
+
• Ensuring compatibility with documentation
|
858
|
+
"""
|
859
|
+
from . import __author__, __version__
|
468
860
|
|
469
861
|
console.print(
|
470
862
|
Panel.fit(
|
@@ -476,5 +868,130 @@ def version() -> None:
|
|
476
868
|
)
|
477
869
|
|
478
870
|
|
871
|
+
@app.command()
|
872
|
+
def system_status(
|
873
|
+
verbose: bool = VERBOSE_OPTION,
|
874
|
+
) -> None:
|
875
|
+
"""Show system status, health, and usage analytics.
|
876
|
+
|
877
|
+
Displays comprehensive information about:
|
878
|
+
- System health and resource usage
|
879
|
+
- Error tracking summary
|
880
|
+
- Usage analytics and productivity metrics
|
881
|
+
|
882
|
+
[bold]Examples:[/bold]
|
883
|
+
[cyan]fca-scaffold system-status[/cyan]
|
884
|
+
[cyan]fca-scaffold system-status --verbose[/cyan]
|
885
|
+
"""
|
886
|
+
try:
|
887
|
+
from .analytics import get_analytics
|
888
|
+
from .error_tracking import get_error_tracker
|
889
|
+
from .health import get_health_monitor
|
890
|
+
|
891
|
+
console.print("\n[bold blue]📊 Fast Clean Architecture Status[/bold blue]\n")
|
892
|
+
|
893
|
+
# FCA System Health
|
894
|
+
console.print("[bold yellow]🏥 FCA System Health[/bold yellow]")
|
895
|
+
health_monitor = get_health_monitor()
|
896
|
+
health_data = health_monitor.get_system_health()
|
897
|
+
|
898
|
+
if "error" in health_data:
|
899
|
+
console.print(f"[red]❌ Health check failed: {health_data['error']}[/red]")
|
900
|
+
else:
|
901
|
+
process_data = health_data.get("process", {})
|
902
|
+
|
903
|
+
console.print(
|
904
|
+
f" • Memory Usage: {process_data.get('memory_rss_mb', 0):.1f} MB ({process_data.get('memory_percent', 0):.1f}%)"
|
905
|
+
)
|
906
|
+
console.print(f" • CPU Usage: {process_data.get('cpu_percent', 0):.1f}%")
|
907
|
+
console.print(
|
908
|
+
f" • Session Duration: {health_data.get('uptime_seconds', 0):.1f} seconds"
|
909
|
+
)
|
910
|
+
|
911
|
+
# Error Tracking
|
912
|
+
console.print("\n[bold yellow]🐛 Error Tracking[/bold yellow]")
|
913
|
+
error_tracker = get_error_tracker()
|
914
|
+
error_summary = error_tracker.get_error_summary()
|
915
|
+
|
916
|
+
console.print(f" • Total Errors: {error_summary.get('total_errors', 0)}")
|
917
|
+
console.print(f" • Unique Errors: {error_summary.get('unique_errors', 0)}")
|
918
|
+
|
919
|
+
if error_summary.get("most_common_errors"):
|
920
|
+
console.print(" • Most Common Errors:")
|
921
|
+
for error_info in error_summary["most_common_errors"][:3]:
|
922
|
+
console.print(
|
923
|
+
f" - {error_info['signature']}: {error_info['count']} times"
|
924
|
+
)
|
925
|
+
|
926
|
+
# Usage Analytics
|
927
|
+
console.print("\n[bold yellow]📈 Usage Analytics[/bold yellow]")
|
928
|
+
analytics = get_analytics()
|
929
|
+
usage_summary = analytics.get_usage_summary()
|
930
|
+
productivity = analytics.get_productivity_metrics()
|
931
|
+
|
932
|
+
session_data = usage_summary.get("session", {})
|
933
|
+
console.print(
|
934
|
+
f" • Session Duration: {session_data.get('duration_seconds', 0):.1f} seconds"
|
935
|
+
)
|
936
|
+
console.print(f" • Total Commands: {session_data.get('total_commands', 0)}")
|
937
|
+
console.print(
|
938
|
+
f" • Components Created: {productivity.get('components_created', 0)}"
|
939
|
+
)
|
940
|
+
console.print(
|
941
|
+
f" • Components/Hour: {productivity.get('components_per_hour', 0):.1f}"
|
942
|
+
)
|
943
|
+
|
944
|
+
if usage_summary.get("commands"):
|
945
|
+
console.print(" • Command Usage:")
|
946
|
+
for command, count in list(usage_summary["commands"].items())[:3]:
|
947
|
+
console.print(f" - {command}: {count} times")
|
948
|
+
|
949
|
+
if usage_summary.get("component_types"):
|
950
|
+
console.print(" • Popular Component Types:")
|
951
|
+
for comp_type, count in list(usage_summary["component_types"].items())[:3]:
|
952
|
+
console.print(f" - {comp_type}: {count} times")
|
953
|
+
|
954
|
+
if verbose:
|
955
|
+
# Show detailed information
|
956
|
+
console.print("\n[bold yellow]🔍 Detailed Information[/bold yellow]")
|
957
|
+
|
958
|
+
if usage_summary.get("layers"):
|
959
|
+
console.print(" • Layer Usage:")
|
960
|
+
for layer, count in usage_summary["layers"].items():
|
961
|
+
console.print(f" - {layer}: {count} times")
|
962
|
+
|
963
|
+
if usage_summary.get("systems"):
|
964
|
+
console.print(" • System Usage:")
|
965
|
+
for system, count in usage_summary["systems"].items():
|
966
|
+
console.print(f" - {system}: {count} times")
|
967
|
+
|
968
|
+
if usage_summary.get("performance"):
|
969
|
+
console.print(" • Performance Metrics:")
|
970
|
+
for command, perf in usage_summary["performance"].items():
|
971
|
+
console.print(
|
972
|
+
f" - {command}: avg {perf['average_ms']}ms (min: {perf['min_ms']}ms, max: {perf['max_ms']}ms)"
|
973
|
+
)
|
974
|
+
|
975
|
+
console.print("\n[green]✅ Status check completed[/green]")
|
976
|
+
|
977
|
+
# Log the status check
|
978
|
+
logger.info(
|
979
|
+
"System status command executed",
|
980
|
+
operation="cli_system_status",
|
981
|
+
verbose=verbose,
|
982
|
+
)
|
983
|
+
|
984
|
+
except Exception as e:
|
985
|
+
logger.error(
|
986
|
+
"System status command failed",
|
987
|
+
operation="cli_system_status",
|
988
|
+
error=str(e),
|
989
|
+
error_type=type(e).__name__,
|
990
|
+
)
|
991
|
+
handle_error(e, verbose)
|
992
|
+
|
993
|
+
|
479
994
|
if __name__ == "__main__":
|
995
|
+
# Ensure logging is configured
|
996
|
+
configure_logging()
|
480
997
|
app()
|