# 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