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