2026-01-28 10:58:15 +08:00
|
|
|
# PROJECT KNOWLEDGE BASE - EmailBill
|
2026-01-27 15:29:25 +08:00
|
|
|
|
2026-02-10 17:49:19 +08:00
|
|
|
**Generated:** 2026-02-10
|
|
|
|
|
**Commit:** 3e18283
|
2026-01-28 10:58:15 +08:00
|
|
|
**Branch:** main
|
|
|
|
|
|
|
|
|
|
## OVERVIEW
|
2026-01-27 15:29:25 +08:00
|
|
|
Full-stack budget tracking app with .NET 10 backend and Vue 3 frontend.
|
|
|
|
|
|
|
|
|
|
## Project Structure
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
EmailBill/
|
|
|
|
|
├── Common/ # Shared utilities and abstractions
|
|
|
|
|
├── Entity/ # Database entities (FreeSql ORM)
|
|
|
|
|
├── Repository/ # Data access layer
|
|
|
|
|
├── Service/ # Business logic layer
|
2026-02-10 17:49:19 +08:00
|
|
|
├── Application/ # Application layer (业务编排、DTO转换)
|
2026-01-27 15:29:25 +08:00
|
|
|
├── WebApi/ # ASP.NET Core Web API
|
|
|
|
|
├── WebApi.Test/ # Backend tests (xUnit)
|
2026-02-10 17:49:19 +08:00
|
|
|
├── Web/ # Vue 3 frontend (Vite + Vant UI)
|
|
|
|
|
└── .doc/ # Project documentation archive
|
2026-01-27 15:29:25 +08:00
|
|
|
```
|
|
|
|
|
|
2026-01-28 10:58:15 +08:00
|
|
|
## WHERE TO LOOK
|
|
|
|
|
| Task | Location | Notes |
|
|
|
|
|
|------|----------|-------|
|
|
|
|
|
| Entity definitions | Entity/ | BaseEntity pattern, FreeSql attributes |
|
|
|
|
|
| Data access | Repository/ | BaseRepository, GlobalUsings |
|
|
|
|
|
| Business logic | Service/ | Jobs, Email services, App settings |
|
2026-02-10 17:49:19 +08:00
|
|
|
| Application orchestration | Application/ | DTO 转换、业务编排、接口门面 |
|
2026-01-28 10:58:15 +08:00
|
|
|
| API endpoints | WebApi/Controllers/ | DTO patterns, REST controllers |
|
|
|
|
|
| Frontend views | Web/src/views/ | Vue composition API |
|
|
|
|
|
| API clients | Web/src/api/ | Axios-based HTTP clients |
|
|
|
|
|
| Tests | WebApi.Test/ | xUnit + NSubstitute + FluentAssertions |
|
2026-02-10 17:49:19 +08:00
|
|
|
| Documentation archive | .doc/ | Technical docs, migration guides |
|
2026-01-28 10:58:15 +08:00
|
|
|
|
2026-01-27 15:29:25 +08:00
|
|
|
## Build & Test Commands
|
|
|
|
|
|
|
|
|
|
### Backend (.NET 10)
|
|
|
|
|
```bash
|
|
|
|
|
# Build and run
|
|
|
|
|
dotnet build EmailBill.sln
|
|
|
|
|
dotnet run --project WebApi/WebApi.csproj
|
|
|
|
|
|
|
|
|
|
# Run all tests
|
|
|
|
|
dotnet test WebApi.Test/WebApi.Test.csproj
|
|
|
|
|
|
|
|
|
|
# Run single test class
|
|
|
|
|
dotnet test --filter "FullyQualifiedName~BudgetStatsTest"
|
|
|
|
|
|
|
|
|
|
# Run single test method
|
|
|
|
|
dotnet test --filter "FullyQualifiedName~BudgetStatsTest.GetCategoryStats_月度_Test"
|
|
|
|
|
|
|
|
|
|
# Clean
|
|
|
|
|
dotnet clean EmailBill.sln
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Frontend (Vue 3)
|
|
|
|
|
```bash
|
|
|
|
|
cd Web
|
|
|
|
|
|
|
|
|
|
# Setup and dev
|
|
|
|
|
pnpm install
|
|
|
|
|
pnpm dev
|
|
|
|
|
|
|
|
|
|
# Build and preview
|
|
|
|
|
pnpm build
|
|
|
|
|
pnpm preview
|
|
|
|
|
|
|
|
|
|
# Lint and format
|
|
|
|
|
pnpm lint # ESLint with auto-fix
|
|
|
|
|
pnpm format # Prettier formatting
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## C# Code Style
|
|
|
|
|
|
|
|
|
|
**Namespaces & Imports:**
|
|
|
|
|
- File-scoped namespaces: `namespace Entity;`
|
|
|
|
|
- Global usings in `Common/GlobalUsings.cs`
|
|
|
|
|
- Sort using statements alphabetically
|
|
|
|
|
|
|
|
|
|
**Naming:**
|
|
|
|
|
- Classes/Methods: `PascalCase`
|
|
|
|
|
- Interfaces: `IPascalCase`
|
|
|
|
|
- Private fields: `_camelCase`
|
|
|
|
|
- Parameters/locals: `camelCase`
|
|
|
|
|
|
|
|
|
|
**Entities:**
|
|
|
|
|
- Inherit from `BaseEntity`
|
|
|
|
|
- Use `[Column]` attributes for FreeSql ORM
|
|
|
|
|
- IDs via Snowflake: `YitIdHelper.NextId()`
|
|
|
|
|
- Use XML docs (`///`) for public APIs
|
|
|
|
|
- **Chinese comments for business logic** (per `.github/csharpe.prompt.md`)
|
|
|
|
|
|
|
|
|
|
**Best Practices:**
|
|
|
|
|
- Use modern C# syntax (records, pattern matching, nullable types)
|
|
|
|
|
- Use `IDateTimeProvider` instead of `DateTime.Now` for testability
|
|
|
|
|
- Avoid deep nesting, keep code flat and readable
|
|
|
|
|
- Reuse utilities from `Common` project
|
|
|
|
|
|
|
|
|
|
**Example:**
|
|
|
|
|
```csharp
|
|
|
|
|
namespace Entity;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 实体基类
|
|
|
|
|
/// </summary>
|
|
|
|
|
public abstract class BaseEntity
|
|
|
|
|
{
|
|
|
|
|
[Column(IsPrimary = true)]
|
|
|
|
|
public long Id { get; set; } = YitIdHelper.NextId();
|
|
|
|
|
|
|
|
|
|
public DateTime CreateTime { get; set; } = DateTime.Now;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Vue/TypeScript Style
|
|
|
|
|
|
|
|
|
|
**Component Structure:**
|
|
|
|
|
```vue
|
|
|
|
|
<template>
|
|
|
|
|
<van-config-provider :theme="theme">
|
|
|
|
|
<div class="component-name">
|
|
|
|
|
<!-- Content -->
|
|
|
|
|
</div>
|
|
|
|
|
</van-config-provider>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { ref } from 'vue'
|
|
|
|
|
import { useMessageStore } from '@/stores/message'
|
|
|
|
|
|
|
|
|
|
const messageStore = useMessageStore()
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
.component-name {
|
|
|
|
|
padding: 16px;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Rules:**
|
|
|
|
|
- Composition API with `<script setup lang="ts">`
|
|
|
|
|
- Import order: Vue APIs → external libs → internal modules
|
|
|
|
|
- Use `@/` alias for absolute imports, avoid `../../../`
|
|
|
|
|
- Vant UI components: `<van-*>`
|
|
|
|
|
- Pinia for state, Vue Router for navigation
|
|
|
|
|
- SCSS with BEM naming, mobile-first design
|
|
|
|
|
|
|
|
|
|
**ESLint Rules (see `Web/eslint.config.js`):**
|
|
|
|
|
- 2-space indentation
|
|
|
|
|
- Single quotes, no semicolons
|
|
|
|
|
- `const` over `let`, no `var`
|
|
|
|
|
- Always use `===` (strict equality)
|
|
|
|
|
- `space-before-function-paren: 'always'`
|
|
|
|
|
- Max 1 empty line between blocks
|
|
|
|
|
- Vue: multi-word component names disabled
|
|
|
|
|
|
|
|
|
|
**Prettier Rules (see `Web/.prettierrc.json`):**
|
|
|
|
|
- Single quotes, no semicolons
|
|
|
|
|
- Trailing commas: none
|
|
|
|
|
- Print width: 100 chars
|
|
|
|
|
|
|
|
|
|
## Testing
|
|
|
|
|
|
|
|
|
|
**Backend (xUnit + NSubstitute + FluentAssertions):**
|
|
|
|
|
```csharp
|
|
|
|
|
public class BudgetStatsTest : BaseTest
|
|
|
|
|
{
|
|
|
|
|
private readonly IBudgetRepository _repo = Substitute.For<IBudgetRepository>();
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task GetCategoryStats_月度_Test()
|
|
|
|
|
{
|
|
|
|
|
// Arrange
|
|
|
|
|
_repo.GetAllAsync().Returns(testData);
|
|
|
|
|
|
|
|
|
|
// Act
|
|
|
|
|
var result = await _service.GetCategoryStatsAsync(category, date);
|
|
|
|
|
|
|
|
|
|
// Assert
|
|
|
|
|
result.Month.Limit.Should().Be(2500);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
- Arrange-Act-Assert pattern
|
|
|
|
|
- Constructor injection for dependencies
|
|
|
|
|
- Use Chinese test method names for domain clarity
|
|
|
|
|
|
|
|
|
|
**Frontend:**
|
|
|
|
|
- Vue Test Utils for components
|
|
|
|
|
- axios-mock-adapter for API mocking
|
|
|
|
|
|
|
|
|
|
## Development Workflow
|
|
|
|
|
|
|
|
|
|
1. **Before committing backend:** `dotnet test`
|
|
|
|
|
2. **Before committing frontend:** `pnpm lint && pnpm build`
|
|
|
|
|
3. **Database migrations:** Use FreeSql (check `Repository/`)
|
|
|
|
|
4. **API docs:** Scalar OpenAPI viewer
|
|
|
|
|
|
|
|
|
|
## Environment
|
|
|
|
|
|
|
|
|
|
**Required:**
|
|
|
|
|
- .NET 10 SDK
|
|
|
|
|
- Node.js 20.19+ or 22.12+
|
|
|
|
|
- pnpm
|
|
|
|
|
|
|
|
|
|
**Database:** SQLite (embedded)
|
|
|
|
|
|
|
|
|
|
**Config:**
|
|
|
|
|
- Backend: `appsettings.json`
|
|
|
|
|
- Frontend: `.env.development` / `.env.production`
|
|
|
|
|
|
|
|
|
|
## Critical Guidelines (from `.github/csharpe.prompt.md`)
|
|
|
|
|
|
|
|
|
|
- 优先使用新C#语法 (Use modern C# syntax)
|
|
|
|
|
- 优先使用中文注释 (Prefer Chinese comments for business logic)
|
|
|
|
|
- 优先复用已有方法 (Reuse existing methods)
|
|
|
|
|
- 不要深嵌套代码 (Avoid deep nesting)
|
|
|
|
|
- 保持代码简洁易读 (Keep code clean and readable)
|