Project Tour
10/30/24About 2 min
Project Tour
This page will help you quickly understand the backend and frontend directory structures, key entry points, and common development paths (new modules/routes/permissions/frontend menus).
Backend Structure
qiluo/
├── 📁 config/ # Configuration files
├── 📁 data/ # Data storage directory
│ ├── 📁 img/ # Image resources
│ ├── 📁 log/ # Log files
│ ├── 📁 static/ # Static resources
│ ├── 📁 upload/ # Uploaded files
│ └── 📁 web/ # Frontend files
├── 📁 migration/ # Database migrations
├── 📁 src/ # Source code
│ ├── 📁 api/ # API controllers
│ │ ├── 📁 sys_controll/ # System management APIs
│ │ └── 📁 wechat/ # WeChat APIs
│ ├── 📁 cache/ # Cache management
│ ├── 📁 common/ # Common modules
│ ├── 📁 config/ # Configuration module
│ ├── 📁 midle_ware/ # Middleware
│ ├── 📁 model/ # Data models
│ ├── 📁 service/ # Business services
│ └── 📁 worker/ # Background tasks
└── 📄 Cargo.toml # Project configuration- Entry main.rs: App::run().await initializes configuration, logging, database connection, AppState, starts Axum service
- app.rs: Registers routes, mounts middleware, versioning
- middleware: Request ID, Trace logging, CORS, JWT auth, RBAC permissions, rate limiting, etc.
- system: Unified logging, scheduled tasks, Snowflake ID
lib.rs module organization (snippet)
pub mod api;
pub mod service;
mod db;
pub mod model;
pub mod cache;
pub mod config;
pub mod common;
pub mod app;
pub mod midle_ware;
pub mod worker;
pub use db::db as DB;
pub use db::generator_id as GID;
pub mod banner;Unified Response & Error (snippet)
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
Message(String),
WithStatus(StatusCode, String)
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ApiResponse<T> {
pub message: String,
pub data: T
}Route & Middleware (snippet)
fn configure_middlewares(&self, mut app: Router) -> Router {
let serverconfig = APPCOFIG.server.clone();
// CORS configuration
app = app.layer(self.configure_cors(&serverconfig));
// Payload limit
if let Some(limit) = serverconfig.middlewares.limit_payload.clone() {
if limit.enable {
if let Ok(size) = byte_unit::Byte::parse_str(&limit.body_limit, true) {
app = app.layer(axum::extract::DefaultBodyLimit::max(size.as_u64() as usize));
tracing::info!(data = &limit.body_limit, "[Middleware] Adding limit payload");
}
}
}
// Panic handling
if let Some(catch_panic) = serverconfig.middlewares.catch_panic {
if catch_panic.enable {
app = app.layer(CatchPanicLayer::custom(Self::handle_panic));
}
}
// Compression
if let Some(compression) = serverconfig.middlewares.compression.clone() {
if compression.enable {
let predicate = DefaultPredicate::new().and(NotForContentType::new("text/event-stream"));
app = app.layer(CompressionLayer::new().compress_when(predicate));
tracing::info!("[Middleware] Adding compression layer");
}
}
// Timeout
if let Some(timeout_request) = serverconfig.middlewares.timeout_request {
if timeout_request.enable {
app = app.layer(TimeoutLayer::new(Duration::from_millis(timeout_request.timeout)));
tracing::info!("[Middleware] Adding timeout layer");
}
}
app
}
impl WebApi {
pub fn routers() -> Router {
let mut webpath = WebPath::new();
webpath = webpath.merge(sys_controll::router_sys());
webpath = webpath.final_to_path();
let expand_path = webpath.get_last_level_paths();
let invfun = InvokeFunctionMsg {
job_id: None,
callfun: "updateapi".to_owned(),
parmets: serde_json::to_string(&expand_path).unwrap(),
};
tokio::spawn(async move {
let _ = InvokeFunctionWorker::execute_async(invfun).await;
});
let mut router = Router::new();
for p in expand_path {
if let Some(method_router) = p.method_router.clone() {
router = router.route(&p.final_path, method_router);
}
}
Router::new().merge(router)
}
pub fn white_routers() -> Router {
Router::new().merge(sys_controll::white_sys())
}
}Frontend Structure (Example)
qiluo_vue/
├── 📁 public/ # Static resources directory
├── 📁 src/ # Source code directory
│ ├── 📁 api/ # API interface definitions
│ ├── 📁 assets/ # Project resource files
│ ├── 📁 axios/ # Axios request configuration
│ ├── 📁 components/ # Common components
│ ├── 📁 constants/ # Constant definitions
│ ├── 📁 directives/ # Custom directives
│ ├── 📁 hooks/ # Custom Hooks
│ ├── 📁 layout/ # Layout components
│ ├── 📁 locales/ # Internationalization resources
│ ├── 📁 plugins/ # Plugin configurations
│ ├── 📁 router/ # Routing configuration
│ ├── 📁 store/ # State management
│ ├── 📁 styles/ # Style files
│ ├── 📁 utils/ # Utility functions
│ ├── 📁 views/ # Page views
│ ├── 📄 App.vue # Root component
│ ├── 📄 main.ts # Application entry file
│ └── 📄 permission.ts # Permission control
├── 📁 types/ # TypeScript type definitions
├── 📄 index.html # HTML template
├── 📄 package.json # Project dependencies
└── 📄 vite.config.ts # Vite configuration- Dynamic menus: Menu tree fetched from backend after login, used to generate routes
- Button permissions: permission_code + v-permission controls visibility
- API interception: Automatically injects Authorization Bearer Token, unified error messages
Standard Flow for Adding a Business Module (Example: Article)
- Database & Entity
sea-orm-cli migrate generate create_article
# Define fields in migration (id/title/content/status/created_at...)
sea-orm-cli migrate up
sea-orm-cli generate entity -o src/db/entities- Service
pub struct ArticleService { pub db: sea_orm::DatabaseConnection }
impl ArticleService {
pub async fn list(&self) -> anyhow::Result<Vec<ArticleVO>> { /* ... */ Ok(vec![]) }
pub async fn create(&self, req: CreateArticleReq) -> anyhow::Result<ArticleVO> { /* ... */ Ok(/*...*/) }
}- Route & Permission Code
// app.rs (snippet)
.nest("/content",
axum::Router::new()
.route("/articles", get(article_handler::list).post(article_handler::create))
.route_layer(axum::middleware::from_fn(mw::auth::require_auth))
)
// Register in permission system: content:article:list, content:article:createConfiguration & Environment
- Based on config/development.yaml
Next Steps
- Go to "Basics → Routes / Middleware / Controllers / Request & Response" for quick CRUD
- Go to "Sea-ORM → Introduction / Model Queries / Relationships" for deep database access
- Go to "Digging Deeper → Tasks/Queues/Cache/File Storage" to enhance system capabilities