Files
2026-03-09 08:54:42 +07:00

199 lines
6.1 KiB
Markdown

# PROJECT KNOWLEDGE BASE
**Generated:** 2026-02-09
**Commit:** 107722278e9274073236e8ee4cba21f832b2ed86
**Branch:** main
## OVERVIEW
.NET 10.0 console application for extracting employee tax data from PostgreSQL multi-schema databases. Uses static service classes with synchronous operations.
## PROJECT STRUCTURE
```
./
├── excel_pajak/ # Main application
│ ├── Models/ # Data models (EmployeeInfo)
│ ├── Services/ # Static services (DatabaseService, ConfigurationService)
│ ├── Examples/ # Code examples
│ ├── appsettings.json # Configuration
│ └── excel_pajak.csproj # Main project
├── excel_pajak_test/ # MSTest project
└── openspec/ # OpenSpec change management artifacts
```
## COMMANDS
### Build
```bash
# Build entire solution
dotnet build
# Build specific project
dotnet build excel_pajak
dotnet build excel_pajak_test
```
### Run Tests
```bash
# Run all tests
dotnet test
# Run single test class
dotnet test --filter "FullyQualifiedName~DatabaseServiceTests"
# Run single test method
dotnet test --filter "FullyQualifiedName~DatabaseServiceTests.ExecuteScalar_NullConnectionString_ThrowsArgumentException"
# Run tests with specific logger
dotnet test --logger "console;verbosity=detailed"
# Run tests without building
dotnet test --no-build
```
### Run Application
```bash
# Run with default project
dotnet run --project excel_pajak
# Run with arguments
dotnet run --project excel_pajak -- --schema=company_2024 --year=2024
```
### Clean and Rebuild
```bash
# Clean solution
dotnet clean
# Clean and rebuild
dotnet clean && dotnet build -c Release
```
## CODE STYLE GUIDELINES
### General Principles
- Target .NET 10.0 with latest C# features
- Enable `ImplicitUsings` and `Nullable` reference types
- No comments unless required for complex logic
### Imports
- Use file-scoped namespaces (`namespace excel_pajak.Services;`)
- Group imports: System namespaces first, then third-party
- Order: `System.*``Microsoft.*``ThirdParty.*``Project.*`
```csharp
using Microsoft.Extensions.Configuration;
using Npgsql;
namespace excel_pajak.Services;
```
### Naming Conventions
- **Classes**: PascalCase (`DatabaseService`, `EmployeeInfo`)
- **Methods**: PascalCase (`ExecuteScalar`, `Initialize`)
- **Properties**: PascalCase (`EmployeeNumber`, `ConnectionString`)
- **Local variables**: camelCase (`connectionString`, `result`)
- **Constants**: UPPER_SNAKE_CASE for values, PascalCase for statics
- **Private fields**: camelCase with underscore prefix (`_connectionString`)
- **Parameters**: camelCase (`schema`, `year`)
### Types
- Use nullable reference types (`string?`, `int?`)
- Prefer `var` when type is obvious from context
- Use explicit types for public APIs and method returns
- Use `string?` instead of `string` with null annotations for nullable properties
### Error Handling
- Validate arguments with `ArgumentException` for null/empty checks
- Wrap database exceptions with `InvalidOperationException`
- Use result tuples for recoverable errors: `(bool success, string? result, Exception? error)`
- Re-throw exceptions with context using `throw new ExceptionType("message", inner)`
```csharp
if (string.IsNullOrWhiteSpace(connectionString))
throw new ArgumentException("Connection string cannot be null or empty.", nameof(connectionString));
try { /* ... */ }
catch (NpgsqlException ex)
{
throw new InvalidOperationException($"Database error: {ex.Message}", ex);
}
```
### Static Service Pattern
- Services use static classes with `Initialize()` pattern
- Lazy initialization for dependencies
- No async database operations (intentional - see ANTI-PATTERNS)
```csharp
public static class DatabaseService
{
private static string? _connectionString;
public static void Initialize(string connectionString)
{
_connectionString = connectionString;
}
}
```
### JSON Serialization
- Use `System.Text.Json` with `[JsonPropertyName]` attributes
- Snake_case for JSON property names
```csharp
public class EmployeeInfo
{
[JsonPropertyName("employee_number")]
public string? EmployeeNumber { get; set; }
}
```
### Configuration
- Use `appsettings.json` for all configuration
- Access via `Microsoft.Extensions.Configuration`
- Bind options with `ConfigurationBinder.Bind()`
### Validation
- Schema names: `^[a-zA-Z0-9_-]+$`
- Years: `^\d{4}$`
```csharp
private static readonly Regex SchemaValidation = new(@"^[a-zA-Z0-9_-]+$", RegexOptions.Compiled);
```
### Database Operations
- Synchronous only using Npgsql
- Use `json_agg(row_to_json(t))` for PostgreSQL JSON aggregation
- Placeholder replacement: `query.Replace("{schema}", schema)`
- Dispose resources with `using` statements or `using var`
### Testing
- Use MSTest with `[TestClass]` and `[TestMethod]`
- Use Shouldly for assertions: `Should.Throw<>`, `ShouldBe()`, `ShouldBeNull()`
- Use Moq for mocking
- Mark integration tests with `[Ignore]` if they require database connection
- Use region blocks (`#region`) for grouping related tests
## WHERE TO LOOK
| Task | Location |
|------|----------|
| Database operations | `excel_pajak/Services/DatabaseService.cs` |
| Configuration handling | `excel_pajak/Services/ConfigurationService.cs` |
| Data models | `excel_pajak/Models/EmployeeInfo.cs` |
| Tests | `excel_pajak_test/DatabaseServiceTests.cs` |
| Configuration | `excel_pajak/appsettings.json` |
## ANTI-PATTERNS TO AVOID
- No async database operations (intentional design, may need future migration)
- No connection pooling or disposal tracking in services
- Static state requires explicit `Initialize()` before use
## KEY DEPENDENCIES
- **Npgsql**: PostgreSQL driver (sync operations)
- **NPOI**: Excel file manipulation
- **Microsoft.Extensions.Configuration**: Configuration management
- **Shouldly**: Test assertions
- **Moq**: Mocking framework
- **MSTest**: Test framework
## NOTES
- All tests use MSTest framework
- Configuration requires valid connection string in `appsettings.json`
- Schema and Year parameters drive query execution
- Connection strings validated with regex for security