199 lines
6.1 KiB
Markdown
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
|