Table of Contents
- Project Architecture & Development Specification Document
Project Architecture & Development Specification Document
1. Project Overview & Design Philosophy
This project is a modern blog system built upon the core design philosophies of backend-frontend separation and separation of concerns.
- Frontend: Developed using the SvelteKit framework, it is solely responsible for rendering the user interface (UI) and handling user interactions.
- Backend: Built with the Rust language and the Actix-web framework, it serves as a pure API server, handling core business logic and data persistence.
This architectural choice not only allows the frontend and backend teams to develop, test, and deploy independently but, more importantly, lays a solid foundation for the project's long-term maintainability and scalability.
2. In-depth Analysis of Clean Architecture
The project's core architecture adheres to the principles of Clean Architecture, aiming to build a system that is stable, highly cohesive, loosely coupled, and easily testable. The central idea of this architecture is the Dependency Inversion Principle, which dictates that all dependencies must point inwards toward the core of the system.
2.1. Architectural Layers and Responsibilities
Both the frontend and backend codebases follow a concentric layered structure:
-
Domain/Entity Layer:
- Responsibility: This is the heart of the system, defining the most core, pure business objects (Entities) and universal business rules. It should not depend on any outer layer and has the lowest frequency of change.
- Implementation:
- Backend: The
backend/feature/post/src/domain/entity/
directory contains the structural definitions of core business models likePost
andLabel
. - Frontend: The
frontend/src/lib/post/domain/entity/
directory contains corresponding business model classes, ensuring that the frontend's business logic also operates on stable domain models.
- Backend: The
-
Application/Use Case Layer:
- Responsibility: This layer encapsulates and implements all application-specific business logic. It orchestrates the domain objects to accomplish specific use cases, such as "retrieve all posts" or "load a single post's content."
- Implementation:
- Backend: The
backend/feature/post/src/application/use_case/
directory defines interfaces (trait
) and their concrete implementations (Impl
) for various services, likeGetAllPostInfoUseCase
. - Frontend: The
frontend/src/lib/post/application/useCase/
directory defines corresponding Use Case classes that drive the frontend's business flows.
- Backend: The
-
Adapter Layer:
- Responsibility: This layer acts as a bridge between the inner application layer and the outer world. It contains various "adapters" that convert data from external formats into a format that the inner layers can understand, and vice versa. This includes API controllers, implementations of database repositories, and frontend state managers (Presenters/BLoCs).
- Implementation:
- Backend: Within the
adapter
directory, thedelivery
subdirectory handles incoming API requests, while thegateway
subdirectory implements the repository interfaces defined in the application layer to interact with the database. - Frontend: In the
adapter
directory, thegateway
is responsible for communicating with the backend API, while thepresenter
uses the BLoC (Business Logic Component) pattern to manage state, transforming business logic results into ViewModels that the UI can render.
- Backend: Within the
-
Framework Layer:
- Responsibility: This is the outermost layer of the system, containing all specific external tools and technical details, such as web frameworks (Actix-web, SvelteKit), database drivers (
sqlx
), UI component libraries, etc. This layer changes most frequently, but thanks to dependency inversion, these changes do not affect the inner core logic. - Implementation:
- Backend: In the
framework
directory, theweb
subdirectory defines Actix-web routes, and thedb
subdirectory implements the actual interaction logic with the PostgreSQL database usingsqlx
. - Frontend: In the
framework
directory, theapi
subdirectory usesfetch
for API calls, and theui
subdirectory contains all Svelte UI components.
- Backend: In the
- Responsibility: This is the outermost layer of the system, containing all specific external tools and technical details, such as web frameworks (Actix-web, SvelteKit), database drivers (
2.2. Data Flow and Object Conversion
To maintain decoupling between layers, data is converted as it crosses layer boundaries:
- DTO (Data Transfer Object): Used for transferring data over the network or between processes. For instance, the backend's
PostResponseDto
and the frontend'sPostResponseDto
are used for API serialization and deserialization. - Mapper/Record: The backend uses Mapper and Record objects to convert database query results into domain-layer Entities.
- ViewModel: The frontend's Presenter layer converts domain objects received from the application layer into
PostViewModel
orPostInfoViewModel
. These ViewModels are designed specifically for UI display and contain presentation logic, such as date formatting.
2.3. Dependency Injection
The backend establishes a dependency injection container in server/src/container.rs
. On application startup, this container is responsible for instantiating all services and "injecting" their dependencies, such as injecting PostRepositoryImpl
into GetAllPostInfoUseCaseImpl
. This practice significantly enhances the code's testability and modularity.
3. Development and Deployment Practices
3.1. Database Management
- Migration Tooling: The project uses
sqlx-cli
for database schema version control and migration. All migration scripts are stored in thebackend/migrations
directory. - Automatic Timestamps: A database trigger is employed to automatically update the
updated_time
column in tables, ensuring accurate tracking of the last modification time for records.
3.2. CI/CD Automation Flow
The project has a robust CI/CD pipeline configured with Gitea Workflows to ensure code quality and automate deployment.
- PR Title Convention: Pull Request titles are enforced to follow a specific format. This practice is beneficial for auto-generating changelogs or integrating with project management tools.
- Containerized Deployment: Both frontend and backend applications are containerized (
Dockerfile
) and are automatically built and pushed to a container registry upon a new release, greatly simplifying the deployment process.
4. Coding Convention
4.1. General Principles
- Naming: File and class names clearly reflect their role in the architecture (e.g.,
*UseCase
,*Repository
,*Controller
,*Dto
,*ViewModel
). This consistency allows developers to quickly understand the code's structure and responsibilities. - Asynchronicity: The entire project leverages asynchronous programming (
async/await
) to handle I/O-bound operations, ensuring high performance and responsiveness of the system.
4.2. Frontend-Specific Conventions
- Code Quality: The use of
ESLint
andPrettier
is enforced to unify code style and prevent potential errors. - Type Safety: The project fully embraces TypeScript with strict mode enabled, providing a safety net for long-term maintenance of a large-scale project.
- Server-Side Rendering (SSR): By using
dehydrate
andrehydrate
methods/+page.server.ts], data is pre-fetched on the server, serialized, and passed to the client. This technique improves initial page load times and enhances SEO performance.
4.3. Backend-Specific Conventions
- Modularity: The backend code is structured into a Cargo Workspace with two primary crates:
feature
andserver
. This effectively separates the core business logic from the web server's bootstrapping logic. - Interface Abstraction:
trait
is extensively used to define interfaces (e.g.,PostRepository
,PostController
), combined with theasync-trait
crate for asynchronous interfaces. This makes components easily replaceable and mockable in tests.