6.1 KiB
6.1 KiB
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
# Build entire solution
dotnet build
# Build specific project
dotnet build excel_pajak
dotnet build excel_pajak_test
Run Tests
# 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
# 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
# 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
ImplicitUsingsandNullablereference 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.*
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
varwhen type is obvious from context - Use explicit types for public APIs and method returns
- Use
string?instead ofstringwith null annotations for nullable properties
Error Handling
- Validate arguments with
ArgumentExceptionfor 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)
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)
public static class DatabaseService
{
private static string? _connectionString;
public static void Initialize(string connectionString)
{
_connectionString = connectionString;
}
}
JSON Serialization
- Use
System.Text.Jsonwith[JsonPropertyName]attributes - Snake_case for JSON property names
public class EmployeeInfo
{
[JsonPropertyName("employee_number")]
public string? EmployeeNumber { get; set; }
}
Configuration
- Use
appsettings.jsonfor all configuration - Access via
Microsoft.Extensions.Configuration - Bind options with
ConfigurationBinder.Bind()
Validation
- Schema names:
^[a-zA-Z0-9_-]+$ - Years:
^\d{4}$
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
usingstatements orusing 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