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