Developer guide
Code structure, patterns, and testing for the Palmyra ERP application. Designed to be manageable by a single developer.
Code structure
Single solution: Palmyra ERP.Web (MVC + API + Vue) and Palmyra ERP.Tests. Controllers under Api/ and Pages/; business logic in Services/; data access in Data/ (DbService, CrudService) with raw SQL in Schema/. No ORM; data flows as Dictionary<string, object?>.
Key patterns
- CrudService — Auto-adds
WHERE tenant_id = @tenant_idto every query. - DbService — Npgsql wrapper: QueryAsync, ExecuteAsync, ScalarAsync, QueryPagedAsync.
- Generic base controller — Handles GET/POST/PUT/DELETE, pagination, 304, tenant isolation, permission check.
- Configuration over code — Business rules, workflows, features in DB (TenantConfig, WorkflowConfigs); not in code.
Testing
C# tests use seeded database (schema + seed SQL). Tests hit APIs directly; validate CRUD, workflow stages, permissions, and integration (e.g. GRN posting to inventory). See API Testing module for test harness and output log.
Schema migrations
Numbered SQL files in Schema/ (e.g. 001_tenants.sql). SchemaRunner runs them on startup and records applied migrations in _schema_migrations. No separate migration framework.