chore: initial commit for asepharyana-hub-scraper
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
# Clean-Modular Architecture Refactor Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Refactor the codebase into a rigid Clean-Modular architecture to improve maintainability and strictly enforce separation of concerns.
|
||||
|
||||
**Architecture:** A three-tier modular approach consisting of Presentation (API Handlers/DTOs), Core (Domain Models/Traits/Use Cases), and Infrastructure (Adapters/Repositories/Scrapers).
|
||||
|
||||
**Tech Stack:** Rust, Axum, SeaORM, Redis, reqwest.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Initialize Core Domain Models & Shared Errors
|
||||
|
||||
**Files:**
|
||||
- Create: `src/shared/errors/mod.rs`
|
||||
- Create: `src/core/models/image.rs`
|
||||
- Create: `src/core/models/mod.rs`
|
||||
- Create: `src/shared/mod.rs`
|
||||
|
||||
- [ ] **Step 1: Define shared application errors**
|
||||
- [ ] **Step 2: Define pure domain models for ImageCache**
|
||||
- [ ] **Step 3: Setup core and shared modules in `lib.rs`**
|
||||
|
||||
```rust
|
||||
// src/shared/errors/mod.rs
|
||||
use axum::{response::{IntoResponse, Response}, Json, http::StatusCode};
|
||||
use serde_json::json;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum AppError {
|
||||
#[error("Not found: {0}")]
|
||||
NotFound(String),
|
||||
#[error("Internal error: {0}")]
|
||||
Internal(String),
|
||||
#[error("Validation error: {0}")]
|
||||
Validation(String),
|
||||
}
|
||||
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> Response {
|
||||
let (status, message) = match self {
|
||||
AppError::NotFound(m) => (StatusCode::NOT_FOUND, m),
|
||||
AppError::Internal(m) => (StatusCode::INTERNAL_SERVER_ERROR, m),
|
||||
AppError::Validation(m) => (StatusCode::BAD_REQUEST, m),
|
||||
};
|
||||
(status, Json(json!({ "error": message }))).into_response()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Commit changes**
|
||||
```bash
|
||||
git add src/shared/errors/mod.rs src/core/models/image.rs
|
||||
git commit -m "feat: init core models and shared errors"
|
||||
```
|
||||
|
||||
### Task 2: Define Core Repository Traits
|
||||
|
||||
**Files:**
|
||||
- Create: `src/core/repositories/image_repository.rs`
|
||||
- Create: `src/core/repositories/mod.rs`
|
||||
|
||||
- [ ] **Step 1: Define ImageRepository trait in `core`**
|
||||
|
||||
```rust
|
||||
// src/core/repositories/image_repository.rs
|
||||
use async_trait::async_trait;
|
||||
use crate::core::models::image::ImageCache;
|
||||
use crate::shared::errors::AppError;
|
||||
|
||||
#[async_trait]
|
||||
pub trait ImageRepository: Send + Sync {
|
||||
async fn find_by_original_url(&self, url: &str) -> Result<Option<ImageCache>, AppError>;
|
||||
async fn save(&self, image: ImageCache) -> Result<(), AppError>;
|
||||
async fn delete_by_original_url(&self, url: &str) -> Result<(), AppError>;
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Commit changes**
|
||||
```bash
|
||||
git add src/core/repositories/
|
||||
git commit -m "feat: define core repository traits"
|
||||
```
|
||||
|
||||
### Task 3: Migrate SeaORM Entities to Infrastructure
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/infra/mod.rs`
|
||||
- Create: `src/infra/repositories/mysql_image_repository.rs`
|
||||
|
||||
- [ ] **Step 1: Implement ImageRepository for MySQL using SeaORM**
|
||||
- [ ] **Step 2: Move `src/entities/image_cache.rs` logic into the new repository implementation**
|
||||
- [ ] **Step 3: Update `src/infra/mod.rs` to expose repositories**
|
||||
|
||||
- [ ] **Step 4: Commit changes**
|
||||
```bash
|
||||
git add src/infra/repositories/
|
||||
git commit -m "feat: implement mysql image repository in infra"
|
||||
```
|
||||
|
||||
### Task 4: Implement Core Use Cases (Image Caching)
|
||||
|
||||
**Files:**
|
||||
- Create: `src/core/use_cases/cache_image.rs`
|
||||
- Create: `src/core/use_cases/mod.rs`
|
||||
|
||||
- [ ] **Step 1: Implement `CacheImageUseCase`**
|
||||
- [ ] **Step 2: Orchestrate logic between repository, redis, and scraper/uploader**
|
||||
|
||||
- [ ] **Step 3: Commit changes**
|
||||
```bash
|
||||
git add src/core/use_cases/
|
||||
git commit -m "feat: implement image caching use cases"
|
||||
```
|
||||
|
||||
### Task 5: Refactor Scrapers into Infrastructure
|
||||
|
||||
**Files:**
|
||||
- Create: `src/core/repositories/scraping_repository.rs`
|
||||
- Create: `src/infra/scrapers/otakudesu.rs`
|
||||
|
||||
- [ ] **Step 1: Define Scraping traits in `core`**
|
||||
- [ ] **Step 2: Implement site-specific scrapers in `infra`**
|
||||
- [ ] **Step 3: Migrate existing logic from `src/scraping/`**
|
||||
|
||||
- [ ] **Step 4: Commit changes**
|
||||
```bash
|
||||
git add src/infra/scrapers/
|
||||
git commit -m "feat: migrate scrapers to infra adapters"
|
||||
```
|
||||
|
||||
### Task 6: Refactor Presentation Layer (API Handlers)
|
||||
|
||||
**Files:**
|
||||
- Create: `src/presentation/api/anime_handler.rs`
|
||||
- Create: `src/presentation/api/mod.rs`
|
||||
- Create: `src/presentation/mod.rs`
|
||||
|
||||
- [ ] **Step 1: Migrate handlers from `src/routes/` to `presentation/api/`**
|
||||
- [ ] **Step 2: Update handlers to use Use Cases instead of direct service/helper calls**
|
||||
- [ ] **Step 3: Update global router in `src/main.rs` or `src/lib.rs`**
|
||||
|
||||
- [ ] **Step 4: Commit changes**
|
||||
```bash
|
||||
git add src/presentation/api/
|
||||
git commit -m "feat: refactor presentation layer api handlers"
|
||||
```
|
||||
|
||||
### Task 7: Global Cleanup & Verification
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/lib.rs`
|
||||
- Delete: `src/helpers/` (partially merged into shared/infra)
|
||||
- Delete: `src/services/` (merged into core/use_cases)
|
||||
- Delete: `src/routes/` (merged into presentation)
|
||||
|
||||
- [ ] **Step 1: Update `lib.rs` to reflect new module structure**
|
||||
- [ ] **Step 2: Remove old redundant directories**
|
||||
- [ ] **Step 3: Run full test suite**
|
||||
- [ ] **Step 4: Verify metrics endpoint**
|
||||
|
||||
- [ ] **Step 5: Final Commit**
|
||||
```bash
|
||||
git commit -m "refactor: complete clean-modular architecture overhaul"
|
||||
```
|
||||
@@ -0,0 +1,49 @@
|
||||
# Design Spec: Clean-Modular Architecture Refactor
|
||||
|
||||
**Date**: 2026-05-08
|
||||
**Topic**: Refactor `apps/rust` from Hybrid to Clean-Modular Architecture.
|
||||
|
||||
## 1. Purpose
|
||||
Standardize codebase structure for rigidity, maintainability, and clear separation of concerns (SOC) without violating the **Zero-Bloat Policy**.
|
||||
|
||||
## 2. Target Architecture
|
||||
Moving from current structure to a three-tier modular design:
|
||||
|
||||
### A. Presentation Layer (`src/presentation/`)
|
||||
- **API Handlers**: Pure Axum handlers.
|
||||
- **DTOs**: Request/Response models for external communication.
|
||||
- **Middleware**: Cross-cutting concerns (CORS, Metrics, Logging).
|
||||
|
||||
### B. Core Layer (`src/core/`) - The Domain
|
||||
- **Models**: Pure data structures (Plain Rust Objects).
|
||||
- **Repository Traits**: Abstract interfaces for data persistence.
|
||||
- **Use Cases**: Orchestration of business logic (e.g., `ScrapeAnime`, `ProcessImage`).
|
||||
- **Dependencies**: None (or minimal shared utils).
|
||||
|
||||
### C. Infrastructure Layer (`src/infra/`) - The Adapters
|
||||
- **Repositories**: SeaORM & Redis implementations of Core traits.
|
||||
- **Scrapers**: Site-specific parsing logic implementing Core scraping traits.
|
||||
- **External Clients**: HTTP Client (reqwest), Browser Pool.
|
||||
|
||||
### D. Shared Layer (`src/shared/`)
|
||||
- **Utils**: Low-level helpers (Date, JSON, String).
|
||||
- **Config**: Application configuration.
|
||||
- **Errors**: Centralized error handling.
|
||||
|
||||
## 3. Implementation Strategy
|
||||
1. **Phase 1**: Scaffold new directory structure.
|
||||
2. **Phase 2**: Migrate `models` and `entities` to `core/models` and `infra/repositories`.
|
||||
3. **Phase 3**: Refactor `scraping` logic into `infra/scrapers` and define traits in `core`.
|
||||
4. **Phase 4**: Move Axum handlers to `presentation/api` and update routing.
|
||||
5. **Phase 5**: Cleanup `helpers` into `shared/utils`.
|
||||
|
||||
## 4. Constraints
|
||||
- **Zero-Bloat**: No new heavy dependencies for the sake of abstraction.
|
||||
- **Performance**: Maintain latency metrics as defined in `docs/development.md`.
|
||||
- **SeaORM**: Entities stay in `infra/` to keep `core/` pure.
|
||||
|
||||
## 5. Success Criteria
|
||||
- All tests pass.
|
||||
- `/metrics` show no latency regression.
|
||||
- Circular dependencies are eliminated.
|
||||
- Folder structure matches this spec.
|
||||
Reference in New Issue
Block a user