allframe_forge/scaffolding.rs
1//! Project scaffolding utilities
2//!
3//! This module handles the creation of directories and files
4//! for new AllFrame projects following Clean Architecture principles.
5//!
6//! The scaffolding creates a complete project structure with:
7//! - Domain layer (business logic, no dependencies)
8//! - Application layer (use case orchestration)
9//! - Infrastructure layer (external implementations)
10//! - Presentation layer (HTTP/API handlers)
11//!
12//! ## Archetypes
13//!
14//! Different archetypes have different directory structures:
15//!
16//! ### Basic
17//! Simple Clean Architecture project with greeter example.
18//!
19//! ### Gateway
20//! API Gateway service with gRPC, including:
21//! - Protocol buffer definitions
22//! - HTTP client for external APIs
23//! - Rate limiting and caching
24//! - Authentication (HMAC, API Key, etc.)
25
26use std::{fs, path::Path};
27
28use anyhow::Result;
29
30use crate::{
31 config::ProjectConfig,
32 templates::{self, acl, bff, consumer, gateway, producer, saga, scheduled, websocket},
33};
34
35/// Create the Clean Architecture directory structure
36///
37/// Creates all necessary directories for a Clean Architecture project:
38/// - `src/` - Source code root
39/// - `src/domain/` - Domain layer (entities, repositories)
40/// - `src/application/` - Application layer (services)
41/// - `src/infrastructure/` - Infrastructure layer (repository implementations)
42/// - `src/presentation/` - Presentation layer (HTTP handlers)
43/// - `tests/` - Integration tests
44///
45/// # Arguments
46/// * `project_path` - Root path where the project directories will be created
47///
48/// # Errors
49/// Returns an error if any directory creation fails
50pub fn create_directory_structure(project_path: &Path) -> Result<()> {
51 let dirs = vec![
52 "src",
53 "src/domain",
54 "src/application",
55 "src/infrastructure",
56 "src/presentation",
57 "tests",
58 ];
59
60 for dir in dirs {
61 fs::create_dir_all(project_path.join(dir))?;
62 }
63
64 Ok(())
65}
66
67/// Generate all project files with Clean Architecture structure
68///
69/// Creates all necessary files for a complete AllFrame project:
70///
71/// ## Root Files
72/// - `Cargo.toml` - Project manifest with dependencies
73/// - `src/main.rs` - Application entry point with tokio runtime
74/// - `.gitignore` - Git ignore rules for Rust projects
75/// - `README.md` - Project documentation
76///
77/// ## Domain Layer
78/// - `src/domain/mod.rs` - Domain module exports
79/// - `src/domain/greeter.rs` - Greeter trait definition
80///
81/// ## Application Layer
82/// - `src/application/mod.rs` - Application module exports
83/// - `src/application/greeting_service.rs` - Greeting service
84///
85/// ## Infrastructure Layer
86/// - `src/infrastructure/mod.rs` - Infrastructure module exports
87/// - `src/infrastructure/console_greeter.rs` - Console greeter implementation
88///
89/// ## Presentation Layer
90/// - `src/presentation/mod.rs` - Presentation module (placeholder)
91///
92/// # Arguments
93/// * `project_path` - Root path where files will be created
94/// * `project_name` - Name of the project (used in Cargo.toml and README)
95///
96/// # Errors
97/// Returns an error if any file write operation fails
98pub fn generate_files(project_path: &Path, project_name: &str) -> Result<()> {
99 // Root files
100 fs::write(
101 project_path.join("Cargo.toml"),
102 templates::cargo_toml(project_name),
103 )?;
104 fs::write(project_path.join("src/main.rs"), templates::main_rs())?;
105 fs::write(project_path.join(".gitignore"), templates::gitignore())?;
106 fs::write(
107 project_path.join("README.md"),
108 templates::readme(project_name),
109 )?;
110
111 // Domain layer
112 fs::write(
113 project_path.join("src/domain/mod.rs"),
114 templates::domain_mod(),
115 )?;
116 fs::write(
117 project_path.join("src/domain/greeter.rs"),
118 templates::domain_greeter(),
119 )?;
120
121 // Application layer
122 fs::write(
123 project_path.join("src/application/mod.rs"),
124 templates::application_mod(),
125 )?;
126 fs::write(
127 project_path.join("src/application/greeting_service.rs"),
128 templates::application_greeting_service(),
129 )?;
130
131 // Infrastructure layer
132 fs::write(
133 project_path.join("src/infrastructure/mod.rs"),
134 templates::infrastructure_mod(),
135 )?;
136 fs::write(
137 project_path.join("src/infrastructure/console_greeter.rs"),
138 templates::infrastructure_console_greeter(),
139 )?;
140
141 // Presentation layer
142 fs::write(
143 project_path.join("src/presentation/mod.rs"),
144 templates::presentation_mod(),
145 )?;
146
147 Ok(())
148}
149
150/// Create the Gateway Architecture directory structure
151///
152/// Creates all necessary directories for a Gateway service:
153/// - `src/` - Source code root
154/// - `src/domain/` - Domain layer (entities, repository traits)
155/// - `src/application/` - Application layer (services, use cases)
156/// - `src/infrastructure/` - Infrastructure layer (HTTP client, cache, auth)
157/// - `src/presentation/` - Presentation layer (gRPC handlers)
158/// - `proto/` - Protocol buffer definitions
159/// - `tests/` - Integration tests
160///
161/// # Arguments
162/// * `project_path` - Root path where the project directories will be created
163///
164/// # Errors
165/// Returns an error if any directory creation fails
166pub fn create_gateway_structure(project_path: &Path) -> Result<()> {
167 let dirs = vec![
168 "src",
169 "src/domain",
170 "src/application",
171 "src/infrastructure",
172 "src/presentation",
173 "proto",
174 "tests",
175 ];
176
177 for dir in dirs {
178 fs::create_dir_all(project_path.join(dir))?;
179 }
180
181 Ok(())
182}
183
184/// Generate all gateway project files
185///
186/// Creates all necessary files for a complete Gateway service:
187///
188/// ## Root Files
189/// - `Cargo.toml` - Project manifest with gateway dependencies
190/// - `build.rs` - Proto compilation build script
191/// - `src/main.rs` - Application entry point with gRPC server
192/// - `README.md` - Project documentation
193/// - `Dockerfile` - Container build file
194/// - `.gitignore` - Git ignore rules
195///
196/// ## Protocol Buffers
197/// - `proto/{service}.proto` - gRPC service definition
198///
199/// ## Domain Layer
200/// - `src/domain/mod.rs` - Domain module exports
201/// - `src/domain/entities.rs` - Domain entities
202/// - `src/domain/repository.rs` - Repository trait
203///
204/// ## Application Layer
205/// - `src/application/mod.rs` - Application module exports
206/// - `src/application/service.rs` - Gateway service implementation
207///
208/// ## Infrastructure Layer
209/// - `src/infrastructure/mod.rs` - Infrastructure module exports
210/// - `src/infrastructure/http_client.rs` - External API HTTP client
211/// - `src/infrastructure/auth.rs` - Authentication implementations
212/// - `src/infrastructure/cache.rs` - Caching implementation
213/// - `src/infrastructure/rate_limiter.rs` - Rate limiting
214///
215/// ## Presentation Layer
216/// - `src/presentation/mod.rs` - Presentation module exports
217/// - `src/presentation/grpc.rs` - gRPC service handlers
218///
219/// ## Configuration
220/// - `src/config.rs` - Service configuration
221/// - `src/error.rs` - Error types
222///
223/// # Arguments
224/// * `project_path` - Root path where files will be created
225/// * `config` - Project configuration
226///
227/// # Errors
228/// Returns an error if any file write operation fails
229pub fn generate_gateway_files(project_path: &Path, config: &ProjectConfig) -> Result<()> {
230 // Root files
231 fs::write(project_path.join("Cargo.toml"), gateway::cargo_toml(config))?;
232 fs::write(project_path.join("build.rs"), gateway::build_rs(config))?;
233 fs::write(project_path.join("src/main.rs"), gateway::main_rs(config))?;
234 fs::write(project_path.join(".gitignore"), templates::gitignore())?;
235 fs::write(project_path.join("README.md"), gateway::readme(config))?;
236 fs::write(project_path.join("Dockerfile"), gateway::dockerfile(config))?;
237
238 // Protocol buffers
239 let gateway_config = config.gateway.as_ref().ok_or_else(|| {
240 anyhow::anyhow!("Gateway config required for gateway archetype")
241 })?;
242 fs::write(
243 project_path.join(format!("proto/{}.proto", gateway_config.service_name)),
244 gateway::proto_file(config),
245 )?;
246
247 // Configuration files
248 fs::write(
249 project_path.join("src/config.rs"),
250 gateway::config_rs(config),
251 )?;
252 fs::write(project_path.join("src/error.rs"), gateway::error_rs(config))?;
253
254 // Domain layer
255 fs::write(
256 project_path.join("src/domain/mod.rs"),
257 gateway::domain_mod(config),
258 )?;
259 fs::write(
260 project_path.join("src/domain/entities.rs"),
261 gateway::domain_entities(config),
262 )?;
263 fs::write(
264 project_path.join("src/domain/repository.rs"),
265 gateway::domain_repository(config),
266 )?;
267
268 // Application layer
269 fs::write(
270 project_path.join("src/application/mod.rs"),
271 gateway::application_mod(config),
272 )?;
273 fs::write(
274 project_path.join("src/application/service.rs"),
275 gateway::application_service(config),
276 )?;
277
278 // Infrastructure layer
279 fs::write(
280 project_path.join("src/infrastructure/mod.rs"),
281 gateway::infrastructure_mod(config),
282 )?;
283 fs::write(
284 project_path.join("src/infrastructure/http_client.rs"),
285 gateway::infrastructure_http_client(config),
286 )?;
287 fs::write(
288 project_path.join("src/infrastructure/auth.rs"),
289 gateway::infrastructure_auth(config),
290 )?;
291 fs::write(
292 project_path.join("src/infrastructure/cache.rs"),
293 gateway::infrastructure_cache(config),
294 )?;
295 fs::write(
296 project_path.join("src/infrastructure/rate_limiter.rs"),
297 gateway::infrastructure_rate_limiter(config),
298 )?;
299
300 // Presentation layer
301 fs::write(
302 project_path.join("src/presentation/mod.rs"),
303 gateway::presentation_mod(config),
304 )?;
305 fs::write(
306 project_path.join("src/presentation/grpc.rs"),
307 gateway::presentation_grpc(config),
308 )?;
309
310 Ok(())
311}
312
313/// Create the Consumer Architecture directory structure
314///
315/// Creates all necessary directories for a Consumer (event handler) service:
316/// - `src/` - Source code root
317/// - `src/domain/` - Domain layer (events, handlers)
318/// - `src/application/` - Application layer (consumer orchestration)
319/// - `src/infrastructure/` - Infrastructure layer (broker, idempotency, health)
320/// - `tests/` - Integration tests
321///
322/// # Arguments
323/// * `project_path` - Root path where the project directories will be created
324///
325/// # Errors
326/// Returns an error if any directory creation fails
327pub fn create_consumer_structure(project_path: &Path) -> Result<()> {
328 let dirs = vec![
329 "src",
330 "src/domain",
331 "src/application",
332 "src/infrastructure",
333 "tests",
334 ];
335
336 for dir in dirs {
337 fs::create_dir_all(project_path.join(dir))?;
338 }
339
340 Ok(())
341}
342
343/// Generate all consumer project files
344///
345/// Creates all necessary files for a complete Consumer service:
346///
347/// ## Root Files
348/// - `Cargo.toml` - Project manifest with consumer dependencies
349/// - `src/main.rs` - Application entry point with consumer setup
350/// - `README.md` - Project documentation
351/// - `Dockerfile` - Container build file
352/// - `.gitignore` - Git ignore rules
353///
354/// ## Domain Layer
355/// - `src/domain/mod.rs` - Domain module exports
356/// - `src/domain/events.rs` - Event definitions with envelope pattern
357/// - `src/domain/handlers.rs` - Event handler traits and registry
358///
359/// ## Application Layer
360/// - `src/application/mod.rs` - Application module exports
361/// - `src/application/consumer.rs` - Consumer orchestration with
362/// retry/idempotency
363///
364/// ## Infrastructure Layer
365/// - `src/infrastructure/mod.rs` - Infrastructure module exports
366/// - `src/infrastructure/broker.rs` - Message broker implementation (Kafka)
367/// - `src/infrastructure/idempotency.rs` - Idempotency store
368/// - `src/infrastructure/health.rs` - Health check server
369///
370/// ## Configuration
371/// - `src/config.rs` - Service configuration
372/// - `src/error.rs` - Error types
373///
374/// # Arguments
375/// * `project_path` - Root path where files will be created
376/// * `config` - Project configuration
377///
378/// # Errors
379/// Returns an error if any file write operation fails
380pub fn generate_consumer_files(project_path: &Path, config: &ProjectConfig) -> Result<()> {
381 // Root files
382 fs::write(
383 project_path.join("Cargo.toml"),
384 consumer::cargo_toml(config),
385 )?;
386 fs::write(project_path.join("src/main.rs"), consumer::main_rs(config))?;
387 fs::write(project_path.join(".gitignore"), templates::gitignore())?;
388 fs::write(project_path.join("README.md"), consumer::readme(config))?;
389 fs::write(
390 project_path.join("Dockerfile"),
391 consumer::dockerfile(config),
392 )?;
393
394 // Configuration files
395 fs::write(
396 project_path.join("src/config.rs"),
397 consumer::config_rs(config),
398 )?;
399 fs::write(
400 project_path.join("src/error.rs"),
401 consumer::error_rs(config),
402 )?;
403
404 // Domain layer
405 fs::write(
406 project_path.join("src/domain/mod.rs"),
407 consumer::domain_mod(config),
408 )?;
409 fs::write(
410 project_path.join("src/domain/events.rs"),
411 consumer::domain_events(config),
412 )?;
413 fs::write(
414 project_path.join("src/domain/handlers.rs"),
415 consumer::domain_handlers(config),
416 )?;
417
418 // Application layer
419 fs::write(
420 project_path.join("src/application/mod.rs"),
421 consumer::application_mod(config),
422 )?;
423 fs::write(
424 project_path.join("src/application/consumer.rs"),
425 consumer::application_consumer(config),
426 )?;
427
428 // Infrastructure layer
429 fs::write(
430 project_path.join("src/infrastructure/mod.rs"),
431 consumer::infrastructure_mod(config),
432 )?;
433 fs::write(
434 project_path.join("src/infrastructure/broker.rs"),
435 consumer::infrastructure_broker(config),
436 )?;
437 fs::write(
438 project_path.join("src/infrastructure/idempotency.rs"),
439 consumer::infrastructure_idempotency(config),
440 )?;
441 fs::write(
442 project_path.join("src/infrastructure/health.rs"),
443 consumer::infrastructure_health(config),
444 )?;
445
446 Ok(())
447}
448
449/// Create the Producer Architecture directory structure
450///
451/// Creates all necessary directories for a Producer (event publisher) service:
452/// - `src/` - Source code root
453/// - `src/domain/` - Domain layer (entities, events, repository)
454/// - `src/application/` - Application layer (service, outbox)
455/// - `src/infrastructure/` - Infrastructure layer (repository, outbox,
456/// publisher)
457/// - `src/presentation/` - Presentation layer (HTTP handlers)
458/// - `tests/` - Integration tests
459///
460/// # Arguments
461/// * `project_path` - Root path where the project directories will be created
462///
463/// # Errors
464/// Returns an error if any directory creation fails
465pub fn create_producer_structure(project_path: &Path) -> Result<()> {
466 let dirs = vec![
467 "src",
468 "src/domain",
469 "src/application",
470 "src/infrastructure",
471 "src/presentation",
472 "tests",
473 ];
474
475 for dir in dirs {
476 fs::create_dir_all(project_path.join(dir))?;
477 }
478
479 Ok(())
480}
481
482/// Generate all producer project files
483///
484/// Creates all necessary files for a complete Producer service:
485///
486/// ## Root Files
487/// - `Cargo.toml` - Project manifest with producer dependencies
488/// - `src/main.rs` - Application entry point with API server and outbox
489/// processor
490/// - `README.md` - Project documentation
491/// - `Dockerfile` - Container build file
492/// - `.gitignore` - Git ignore rules
493///
494/// ## Domain Layer
495/// - `src/domain/mod.rs` - Domain module exports
496/// - `src/domain/entities.rs` - Domain entities
497/// - `src/domain/events.rs` - Event definitions with envelope pattern
498/// - `src/domain/repository.rs` - Repository trait
499///
500/// ## Application Layer
501/// - `src/application/mod.rs` - Application module exports
502/// - `src/application/service.rs` - Application service with event publishing
503/// - `src/application/outbox.rs` - Outbox trait
504///
505/// ## Infrastructure Layer
506/// - `src/infrastructure/mod.rs` - Infrastructure module exports
507/// - `src/infrastructure/repository.rs` - PostgreSQL repository
508/// - `src/infrastructure/outbox.rs` - PostgreSQL outbox
509/// - `src/infrastructure/publisher.rs` - Kafka event publisher
510/// - `src/infrastructure/outbox_processor.rs` - Outbox processor
511/// - `src/infrastructure/health.rs` - Health check server
512///
513/// ## Presentation Layer
514/// - `src/presentation/mod.rs` - Presentation module exports
515/// - `src/presentation/handlers.rs` - HTTP API handlers
516///
517/// ## Configuration
518/// - `src/config.rs` - Service configuration
519/// - `src/error.rs` - Error types
520///
521/// # Arguments
522/// * `project_path` - Root path where files will be created
523/// * `config` - Project configuration
524///
525/// # Errors
526/// Returns an error if any file write operation fails
527pub fn generate_producer_files(project_path: &Path, config: &ProjectConfig) -> Result<()> {
528 // Root files
529 fs::write(
530 project_path.join("Cargo.toml"),
531 producer::cargo_toml(config),
532 )?;
533 fs::write(project_path.join("src/main.rs"), producer::main_rs(config))?;
534 fs::write(project_path.join(".gitignore"), templates::gitignore())?;
535 fs::write(project_path.join("README.md"), producer::readme(config))?;
536 fs::write(
537 project_path.join("Dockerfile"),
538 producer::dockerfile(config),
539 )?;
540
541 // Configuration files
542 fs::write(
543 project_path.join("src/config.rs"),
544 producer::config_rs(config),
545 )?;
546 fs::write(
547 project_path.join("src/error.rs"),
548 producer::error_rs(config),
549 )?;
550
551 // Domain layer
552 fs::write(
553 project_path.join("src/domain/mod.rs"),
554 producer::domain_mod(config),
555 )?;
556 fs::write(
557 project_path.join("src/domain/entities.rs"),
558 producer::domain_entities(config),
559 )?;
560 fs::write(
561 project_path.join("src/domain/events.rs"),
562 producer::domain_events(config),
563 )?;
564 fs::write(
565 project_path.join("src/domain/repository.rs"),
566 producer::domain_repository(config),
567 )?;
568
569 // Application layer
570 fs::write(
571 project_path.join("src/application/mod.rs"),
572 producer::application_mod(config),
573 )?;
574 fs::write(
575 project_path.join("src/application/service.rs"),
576 producer::application_service(config),
577 )?;
578 fs::write(
579 project_path.join("src/application/outbox.rs"),
580 producer::application_outbox(config),
581 )?;
582
583 // Infrastructure layer
584 fs::write(
585 project_path.join("src/infrastructure/mod.rs"),
586 producer::infrastructure_mod(config),
587 )?;
588 fs::write(
589 project_path.join("src/infrastructure/repository.rs"),
590 producer::infrastructure_repository(config),
591 )?;
592 fs::write(
593 project_path.join("src/infrastructure/outbox.rs"),
594 producer::infrastructure_outbox(config),
595 )?;
596 fs::write(
597 project_path.join("src/infrastructure/publisher.rs"),
598 producer::infrastructure_publisher(config),
599 )?;
600 fs::write(
601 project_path.join("src/infrastructure/outbox_processor.rs"),
602 producer::infrastructure_outbox_processor(config),
603 )?;
604 fs::write(
605 project_path.join("src/infrastructure/health.rs"),
606 producer::infrastructure_health(config),
607 )?;
608
609 // Presentation layer
610 fs::write(
611 project_path.join("src/presentation/mod.rs"),
612 producer::presentation_mod(config),
613 )?;
614 fs::write(
615 project_path.join("src/presentation/handlers.rs"),
616 producer::presentation_handlers(config),
617 )?;
618
619 Ok(())
620}
621
622/// Create the BFF (Backend for Frontend) Architecture directory structure
623///
624/// Creates all necessary directories for a BFF service:
625/// - `src/` - Source code root
626/// - `src/domain/` - Domain layer (models, aggregates)
627/// - `src/application/` - Application layer (aggregator service)
628/// - `src/infrastructure/` - Infrastructure layer (clients, cache, health)
629/// - `src/presentation/` - Presentation layer (REST handlers, GraphQL)
630/// - `tests/` - Integration tests
631///
632/// # Arguments
633/// * `project_path` - Root path where the project directories will be created
634///
635/// # Errors
636/// Returns an error if any directory creation fails
637pub fn create_bff_structure(project_path: &Path) -> Result<()> {
638 let dirs = vec![
639 "src",
640 "src/domain",
641 "src/application",
642 "src/infrastructure",
643 "src/presentation",
644 "tests",
645 ];
646
647 for dir in dirs {
648 fs::create_dir_all(project_path.join(dir))?;
649 }
650
651 Ok(())
652}
653
654/// Generate all BFF project files
655///
656/// Creates all necessary files for a complete BFF service:
657///
658/// ## Root Files
659/// - `Cargo.toml` - Project manifest with BFF dependencies
660/// - `src/main.rs` - Application entry point with API server
661/// - `README.md` - Project documentation
662/// - `Dockerfile` - Container build file
663/// - `.gitignore` - Git ignore rules
664///
665/// ## Domain Layer
666/// - `src/domain/mod.rs` - Domain module exports
667/// - `src/domain/models.rs` - Domain models
668/// - `src/domain/aggregates.rs` - Aggregate types for frontend views
669///
670/// ## Application Layer
671/// - `src/application/mod.rs` - Application module exports
672/// - `src/application/aggregator.rs` - Aggregator service
673///
674/// ## Infrastructure Layer
675/// - `src/infrastructure/mod.rs` - Infrastructure module exports
676/// - `src/infrastructure/clients.rs` - Backend HTTP clients
677/// - `src/infrastructure/cache.rs` - Cache service
678/// - `src/infrastructure/health.rs` - Health check server
679///
680/// ## Presentation Layer
681/// - `src/presentation/mod.rs` - Presentation module exports
682/// - `src/presentation/handlers.rs` - REST API handlers
683/// - `src/presentation/graphql.rs` - GraphQL API (if enabled)
684///
685/// ## Configuration
686/// - `src/config.rs` - Service configuration
687/// - `src/error.rs` - Error types
688///
689/// # Arguments
690/// * `project_path` - Root path where files will be created
691/// * `config` - Project configuration
692///
693/// # Errors
694/// Returns an error if any file write operation fails
695pub fn generate_bff_files(project_path: &Path, config: &ProjectConfig) -> Result<()> {
696 let bff_config = config.bff.as_ref().ok_or_else(|| {
697 anyhow::anyhow!("BFF config required for bff archetype")
698 })?;
699
700 // Root files
701 fs::write(project_path.join("Cargo.toml"), bff::cargo_toml(config))?;
702 fs::write(project_path.join("src/main.rs"), bff::main_rs(config))?;
703 fs::write(project_path.join(".gitignore"), templates::gitignore())?;
704 fs::write(project_path.join("README.md"), bff::readme(config))?;
705 fs::write(project_path.join("Dockerfile"), bff::dockerfile(config))?;
706
707 // Configuration files
708 fs::write(project_path.join("src/config.rs"), bff::config_rs(config))?;
709 fs::write(project_path.join("src/error.rs"), bff::error_rs(config))?;
710
711 // Domain layer
712 fs::write(
713 project_path.join("src/domain/mod.rs"),
714 bff::domain_mod(config),
715 )?;
716 fs::write(
717 project_path.join("src/domain/models.rs"),
718 bff::domain_models(config),
719 )?;
720 fs::write(
721 project_path.join("src/domain/aggregates.rs"),
722 bff::domain_aggregates(config),
723 )?;
724
725 // Application layer
726 fs::write(
727 project_path.join("src/application/mod.rs"),
728 bff::application_mod(config),
729 )?;
730 fs::write(
731 project_path.join("src/application/aggregator.rs"),
732 bff::application_aggregator(config),
733 )?;
734
735 // Infrastructure layer
736 fs::write(
737 project_path.join("src/infrastructure/mod.rs"),
738 bff::infrastructure_mod(config),
739 )?;
740 fs::write(
741 project_path.join("src/infrastructure/clients.rs"),
742 bff::infrastructure_clients(config),
743 )?;
744 fs::write(
745 project_path.join("src/infrastructure/cache.rs"),
746 bff::infrastructure_cache(config),
747 )?;
748 fs::write(
749 project_path.join("src/infrastructure/health.rs"),
750 bff::infrastructure_health(config),
751 )?;
752
753 // Presentation layer
754 fs::write(
755 project_path.join("src/presentation/mod.rs"),
756 bff::presentation_mod(config),
757 )?;
758 fs::write(
759 project_path.join("src/presentation/handlers.rs"),
760 bff::presentation_handlers(config),
761 )?;
762
763 // GraphQL (if enabled)
764 if bff_config.graphql_enabled {
765 fs::write(
766 project_path.join("src/presentation/graphql.rs"),
767 bff::presentation_graphql(config),
768 )?;
769 }
770
771 Ok(())
772}
773
774/// Create the Scheduled Jobs Architecture directory structure
775///
776/// Creates all necessary directories for a Scheduled Jobs service:
777/// - `src/` - Source code root
778/// - `src/domain/` - Domain layer (job definitions)
779/// - `src/application/` - Application layer (scheduler)
780/// - `src/infrastructure/` - Infrastructure layer (health checks)
781/// - `tests/` - Integration tests
782///
783/// # Arguments
784/// * `project_path` - Root path where the project directories will be created
785///
786/// # Errors
787/// Returns an error if any directory creation fails
788pub fn create_scheduled_structure(project_path: &Path) -> Result<()> {
789 let dirs = vec![
790 "src",
791 "src/domain",
792 "src/application",
793 "src/infrastructure",
794 "tests",
795 ];
796
797 for dir in dirs {
798 fs::create_dir_all(project_path.join(dir))?;
799 }
800
801 Ok(())
802}
803
804/// Generate all scheduled jobs project files
805///
806/// Creates all necessary files for a complete Scheduled Jobs service:
807///
808/// ## Root Files
809/// - `Cargo.toml` - Project manifest with scheduler dependencies
810/// - `src/main.rs` - Application entry point with scheduler setup
811/// - `README.md` - Project documentation
812/// - `Dockerfile` - Container build file
813/// - `.gitignore` - Git ignore rules
814///
815/// ## Domain Layer
816/// - `src/domain/mod.rs` - Domain module exports
817/// - `src/domain/jobs.rs` - Job trait and context definitions
818///
819/// ## Application Layer
820/// - `src/application/mod.rs` - Application module exports
821/// - `src/application/scheduler.rs` - Job scheduler and job implementations
822///
823/// ## Infrastructure Layer
824/// - `src/infrastructure/mod.rs` - Infrastructure module exports
825/// - `src/infrastructure/health.rs` - Health check server
826///
827/// ## Configuration
828/// - `src/config.rs` - Service configuration
829/// - `src/error.rs` - Error types
830///
831/// # Arguments
832/// * `project_path` - Root path where files will be created
833/// * `config` - Project configuration
834///
835/// # Errors
836/// Returns an error if any file write operation fails
837pub fn generate_scheduled_files(project_path: &Path, config: &ProjectConfig) -> Result<()> {
838 // Root files
839 fs::write(
840 project_path.join("Cargo.toml"),
841 scheduled::cargo_toml(config),
842 )?;
843 fs::write(project_path.join("src/main.rs"), scheduled::main_rs(config))?;
844 fs::write(project_path.join(".gitignore"), templates::gitignore())?;
845 fs::write(project_path.join("README.md"), scheduled::readme(config))?;
846 fs::write(
847 project_path.join("Dockerfile"),
848 scheduled::dockerfile(config),
849 )?;
850
851 // Configuration files
852 fs::write(
853 project_path.join("src/config.rs"),
854 scheduled::config_rs(config),
855 )?;
856 fs::write(
857 project_path.join("src/error.rs"),
858 scheduled::error_rs(config),
859 )?;
860
861 // Domain layer
862 fs::write(
863 project_path.join("src/domain/mod.rs"),
864 scheduled::domain_mod(config),
865 )?;
866 fs::write(
867 project_path.join("src/domain/jobs.rs"),
868 scheduled::domain_jobs(config),
869 )?;
870
871 // Application layer
872 fs::write(
873 project_path.join("src/application/mod.rs"),
874 scheduled::application_mod(config),
875 )?;
876 fs::write(
877 project_path.join("src/application/scheduler.rs"),
878 scheduled::application_scheduler(config),
879 )?;
880
881 // Infrastructure layer
882 fs::write(
883 project_path.join("src/infrastructure/mod.rs"),
884 scheduled::infrastructure_mod(config),
885 )?;
886 fs::write(
887 project_path.join("src/infrastructure/health.rs"),
888 scheduled::infrastructure_health(config),
889 )?;
890
891 Ok(())
892}
893
894/// Create the WebSocket Gateway Architecture directory structure
895///
896/// Creates all necessary directories for a WebSocket Gateway service:
897/// - `src/` - Source code root
898/// - `src/domain/` - Domain layer (messages, connections)
899/// - `src/application/` - Application layer (hub)
900/// - `src/infrastructure/` - Infrastructure layer (health checks)
901/// - `src/presentation/` - Presentation layer (WebSocket handlers)
902/// - `tests/` - Integration tests
903///
904/// # Arguments
905/// * `project_path` - Root path where the project directories will be created
906///
907/// # Errors
908/// Returns an error if any directory creation fails
909pub fn create_websocket_structure(project_path: &Path) -> Result<()> {
910 let dirs = vec![
911 "src",
912 "src/domain",
913 "src/application",
914 "src/infrastructure",
915 "src/presentation",
916 "tests",
917 ];
918
919 for dir in dirs {
920 fs::create_dir_all(project_path.join(dir))?;
921 }
922
923 Ok(())
924}
925
926/// Generate all WebSocket Gateway project files
927///
928/// Creates all necessary files for a complete WebSocket Gateway service:
929///
930/// ## Root Files
931/// - `Cargo.toml` - Project manifest with WebSocket dependencies
932/// - `src/main.rs` - Application entry point with WebSocket server
933/// - `README.md` - Project documentation
934/// - `Dockerfile` - Container build file
935/// - `.gitignore` - Git ignore rules
936///
937/// ## Domain Layer
938/// - `src/domain/mod.rs` - Domain module exports
939/// - `src/domain/messages.rs` - WebSocket message types
940/// - `src/domain/connection.rs` - Connection management
941///
942/// ## Application Layer
943/// - `src/application/mod.rs` - Application module exports
944/// - `src/application/hub.rs` - WebSocket hub
945///
946/// ## Infrastructure Layer
947/// - `src/infrastructure/mod.rs` - Infrastructure module exports
948/// - `src/infrastructure/health.rs` - Health check server
949///
950/// ## Presentation Layer
951/// - `src/presentation/mod.rs` - Presentation module exports
952/// - `src/presentation/handlers.rs` - WebSocket handlers
953///
954/// ## Configuration
955/// - `src/config.rs` - Service configuration
956/// - `src/error.rs` - Error types
957///
958/// # Arguments
959/// * `project_path` - Root path where files will be created
960/// * `config` - Project configuration
961///
962/// # Errors
963/// Returns an error if any file write operation fails
964pub fn generate_websocket_files(project_path: &Path, config: &ProjectConfig) -> Result<()> {
965 // Root files
966 fs::write(
967 project_path.join("Cargo.toml"),
968 websocket::cargo_toml(config),
969 )?;
970 fs::write(project_path.join("src/main.rs"), websocket::main_rs(config))?;
971 fs::write(project_path.join(".gitignore"), templates::gitignore())?;
972 fs::write(project_path.join("README.md"), websocket::readme(config))?;
973 fs::write(
974 project_path.join("Dockerfile"),
975 websocket::dockerfile(config),
976 )?;
977
978 // Configuration files
979 fs::write(
980 project_path.join("src/config.rs"),
981 websocket::config_rs(config),
982 )?;
983 fs::write(
984 project_path.join("src/error.rs"),
985 websocket::error_rs(config),
986 )?;
987
988 // Domain layer
989 fs::write(
990 project_path.join("src/domain/mod.rs"),
991 websocket::domain_mod(config),
992 )?;
993 fs::write(
994 project_path.join("src/domain/messages.rs"),
995 websocket::domain_messages(config),
996 )?;
997 fs::write(
998 project_path.join("src/domain/connection.rs"),
999 websocket::domain_connection(config),
1000 )?;
1001
1002 // Application layer
1003 fs::write(
1004 project_path.join("src/application/mod.rs"),
1005 websocket::application_mod(config),
1006 )?;
1007 fs::write(
1008 project_path.join("src/application/hub.rs"),
1009 websocket::application_hub(config),
1010 )?;
1011
1012 // Infrastructure layer
1013 fs::write(
1014 project_path.join("src/infrastructure/mod.rs"),
1015 websocket::infrastructure_mod(config),
1016 )?;
1017 fs::write(
1018 project_path.join("src/infrastructure/health.rs"),
1019 websocket::infrastructure_health(config),
1020 )?;
1021
1022 // Presentation layer
1023 fs::write(
1024 project_path.join("src/presentation/mod.rs"),
1025 websocket::presentation_mod(config),
1026 )?;
1027 fs::write(
1028 project_path.join("src/presentation/handlers.rs"),
1029 websocket::presentation_handlers(config),
1030 )?;
1031
1032 Ok(())
1033}
1034
1035/// Create the Saga Orchestrator Architecture directory structure
1036pub fn create_saga_structure(project_path: &Path) -> Result<()> {
1037 let dirs = vec![
1038 "src",
1039 "src/domain",
1040 "src/application",
1041 "src/infrastructure",
1042 "src/presentation",
1043 "tests",
1044 ];
1045
1046 for dir in dirs {
1047 fs::create_dir_all(project_path.join(dir))?;
1048 }
1049
1050 Ok(())
1051}
1052
1053/// Generate all Saga Orchestrator project files
1054pub fn generate_saga_files(project_path: &Path, config: &ProjectConfig) -> Result<()> {
1055 // Root files
1056 fs::write(project_path.join("Cargo.toml"), saga::cargo_toml(config))?;
1057 fs::write(project_path.join("src/main.rs"), saga::main_rs(config))?;
1058 fs::write(project_path.join(".gitignore"), templates::gitignore())?;
1059 fs::write(project_path.join("README.md"), saga::readme(config))?;
1060 fs::write(project_path.join("Dockerfile"), saga::dockerfile(config))?;
1061
1062 // Configuration files
1063 fs::write(project_path.join("src/config.rs"), saga::config_rs(config))?;
1064 fs::write(project_path.join("src/error.rs"), saga::error_rs(config))?;
1065
1066 // Domain layer
1067 fs::write(
1068 project_path.join("src/domain/mod.rs"),
1069 saga::domain_mod(config),
1070 )?;
1071 fs::write(
1072 project_path.join("src/domain/saga.rs"),
1073 saga::domain_saga(config),
1074 )?;
1075 fs::write(
1076 project_path.join("src/domain/step.rs"),
1077 saga::domain_step(config),
1078 )?;
1079
1080 // Application layer
1081 fs::write(
1082 project_path.join("src/application/mod.rs"),
1083 saga::application_mod(config),
1084 )?;
1085 fs::write(
1086 project_path.join("src/application/orchestrator.rs"),
1087 saga::application_orchestrator(config),
1088 )?;
1089 fs::write(
1090 project_path.join("src/application/steps.rs"),
1091 saga::application_steps(config),
1092 )?;
1093
1094 // Infrastructure layer
1095 fs::write(
1096 project_path.join("src/infrastructure/mod.rs"),
1097 saga::infrastructure_mod(config),
1098 )?;
1099 fs::write(
1100 project_path.join("src/infrastructure/health.rs"),
1101 saga::infrastructure_health(config),
1102 )?;
1103
1104 // Presentation layer
1105 fs::write(
1106 project_path.join("src/presentation/mod.rs"),
1107 saga::presentation_mod(config),
1108 )?;
1109 fs::write(
1110 project_path.join("src/presentation/handlers.rs"),
1111 saga::presentation_handlers(config),
1112 )?;
1113
1114 Ok(())
1115}
1116
1117/// Create the Anti-Corruption Layer Architecture directory structure
1118///
1119/// Creates all necessary directories for an ACL service:
1120/// - `src/` - Source code root
1121/// - `src/domain/` - Domain layer (legacy models, modern models, transformer
1122/// traits)
1123/// - `src/application/` - Application layer (translator service)
1124/// - `src/infrastructure/` - Infrastructure layer (legacy client, health
1125/// checks)
1126/// - `src/presentation/` - Presentation layer (HTTP handlers)
1127/// - `tests/` - Integration tests
1128///
1129/// # Arguments
1130/// * `project_path` - Root path where the project directories will be created
1131///
1132/// # Errors
1133/// Returns an error if any directory creation fails
1134pub fn create_acl_structure(project_path: &Path) -> Result<()> {
1135 let dirs = vec![
1136 "src",
1137 "src/domain",
1138 "src/application",
1139 "src/infrastructure",
1140 "src/presentation",
1141 "tests",
1142 ];
1143
1144 for dir in dirs {
1145 fs::create_dir_all(project_path.join(dir))?;
1146 }
1147
1148 Ok(())
1149}
1150
1151/// Generate all Anti-Corruption Layer project files
1152///
1153/// Creates all necessary files for a complete ACL service:
1154///
1155/// ## Root Files
1156/// - `Cargo.toml` - Project manifest with ACL dependencies
1157/// - `src/main.rs` - Application entry point with HTTP server
1158/// - `README.md` - Project documentation
1159/// - `Dockerfile` - Container build file
1160/// - `.gitignore` - Git ignore rules
1161///
1162/// ## Domain Layer
1163/// - `src/domain/mod.rs` - Domain module exports
1164/// - `src/domain/legacy.rs` - Legacy system models
1165/// - `src/domain/modern.rs` - Modern domain models
1166/// - `src/domain/transformer.rs` - Transformer trait for bidirectional
1167/// conversion
1168///
1169/// ## Application Layer
1170/// - `src/application/mod.rs` - Application module exports
1171/// - `src/application/translator.rs` - Translation service
1172///
1173/// ## Infrastructure Layer
1174/// - `src/infrastructure/mod.rs` - Infrastructure module exports
1175/// - `src/infrastructure/legacy_client.rs` - Legacy system HTTP client
1176/// - `src/infrastructure/health.rs` - Health check server
1177///
1178/// ## Presentation Layer
1179/// - `src/presentation/mod.rs` - Presentation module exports
1180/// - `src/presentation/handlers.rs` - HTTP API handlers
1181///
1182/// ## Configuration
1183/// - `src/config.rs` - Service configuration
1184/// - `src/error.rs` - Error types
1185///
1186/// # Arguments
1187/// * `project_path` - Root path where files will be created
1188/// * `config` - Project configuration
1189///
1190/// # Errors
1191/// Returns an error if any file write operation fails
1192pub fn generate_acl_files(project_path: &Path, config: &ProjectConfig) -> Result<()> {
1193 // Root files
1194 fs::write(project_path.join("Cargo.toml"), acl::cargo_toml(config))?;
1195 fs::write(project_path.join("src/main.rs"), acl::main_rs(config))?;
1196 fs::write(project_path.join(".gitignore"), templates::gitignore())?;
1197 fs::write(project_path.join("README.md"), acl::readme(config))?;
1198 fs::write(project_path.join("Dockerfile"), acl::dockerfile(config))?;
1199
1200 // Configuration files
1201 fs::write(project_path.join("src/config.rs"), acl::config_rs(config))?;
1202 fs::write(project_path.join("src/error.rs"), acl::error_rs(config))?;
1203
1204 // Domain layer
1205 fs::write(
1206 project_path.join("src/domain/mod.rs"),
1207 acl::domain_mod(config),
1208 )?;
1209 fs::write(
1210 project_path.join("src/domain/legacy.rs"),
1211 acl::domain_legacy(config),
1212 )?;
1213 fs::write(
1214 project_path.join("src/domain/modern.rs"),
1215 acl::domain_modern(config),
1216 )?;
1217 fs::write(
1218 project_path.join("src/domain/transformer.rs"),
1219 acl::domain_transformer(config),
1220 )?;
1221
1222 // Application layer
1223 fs::write(
1224 project_path.join("src/application/mod.rs"),
1225 acl::application_mod(config),
1226 )?;
1227 fs::write(
1228 project_path.join("src/application/translator.rs"),
1229 acl::application_translator(config),
1230 )?;
1231
1232 // Infrastructure layer
1233 fs::write(
1234 project_path.join("src/infrastructure/mod.rs"),
1235 acl::infrastructure_mod(config),
1236 )?;
1237 fs::write(
1238 project_path.join("src/infrastructure/legacy_client.rs"),
1239 acl::infrastructure_legacy_client(config),
1240 )?;
1241 fs::write(
1242 project_path.join("src/infrastructure/health.rs"),
1243 acl::infrastructure_health(config),
1244 )?;
1245
1246 // Presentation layer
1247 fs::write(
1248 project_path.join("src/presentation/mod.rs"),
1249 acl::presentation_mod(config),
1250 )?;
1251 fs::write(
1252 project_path.join("src/presentation/handlers.rs"),
1253 acl::presentation_handlers(config),
1254 )?;
1255
1256 Ok(())
1257}