# PROJECT KNOWLEDGE BASE - EmailBill

**Generated:** 2026-01-28
**Commit:** 5c9d7c5
**Branch:** main

## OVERVIEW
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
├── WebApi/           # ASP.NET Core Web API
├── WebApi.Test/      # Backend tests (xUnit)
└── Web/              # Vue 3 frontend (Vite + Vant UI)
```

## 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 |
| 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 |

## 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)