File Organization and Project Structure
A consistent directory layout across projects helps developers find code faster, reduces onboarding time, and simplifies build automation. The conventions below apply to all microservice and frontend repositories.
9.1 Repository-Level Layout
Every repository must follow a shallow hierarchy, grouping source code, tests, and infrastructure assets at the top level:
src/ contains the actual application logic, separated by framework conventions.
test/ mirrors the structure of
src/and contains test projects/files. Test namespaces and folders align with the source they test.build/ (or deploy/) holds everything needed to build Docker images and deploy: Dockerfile, Kubernetes manifests, Helm charts, environment-specific config scripts. Infrastructure code may be linted in a later phase; for now it must be kept organized and safe.
9.2 C# Project Structure (.NET Solution)
Each .NET microservice or class library follows this solution layout:
Key rules:
One project per layer: separate host, core logic, and infrastructure.
Folder-to‑namespace mapping: folders under
srcmust mirror namespaces. Nested folders create nested namespaces.No circular dependencies:
Coremust not referenceInfrastructureorApi;ApireferencesCoreandInfrastructure;InfrastructurereferencesCore.Test projects live under
/test, named[ProjectUnderTest].UnitTestsand[ProjectUnderTest].IntegrationTests.Solution items:
.editorconfig,Directory.Build.props, stylecop/analyzer configuration files are placed at the solution root so all projects inherit them.
9.3 Angular / TypeScript Project Structure
Angular applications (and shared libraries) follow the core/shared/features pattern, with a flat arrangement of modules/components inside each feature.
Key rules:
Feature isolation: every feature module encapsulates its own components, services, and models. Cross-feature dependencies are minimised; shared code goes to
shared/.Keep components small: if a component’s template grows beyond ~200 lines, extract sub-components inside the same feature folder.
Lazy loading: feature modules intended for lazy loading must be imported only via routing; do not import them eagerly.
Testing files (specs): co-located with the component/service they test (e.g.,
orders/list/list.component.spec.ts). Thetest/folder at the root is only for global test helpers or e2e tests if needed.Barrel exports: every folder that is imported by other modules should contain an
index.tsre‑exporting its public API. This avoids deep import paths and simplifies refactoring.// shared/components/index.ts export * from './chart/chart.component'; export * from './data-table/data-table.component';Shared npm libraries (our internal packages) live in their own repositories and follow a similar structure, but must expose their public API via a well‑defined
index.tsin thesrc/root.
9.4 Shared Libraries (npm)
For internal Angular libraries published to our private npm registry:
Every library must declare all public symbols in
public-api.ts. Consumers should never deep-import from/src/lib/...paths.Libraries must be versioned according to SemVer, and their
peerDependenciesmust list Angular and other framework packages.
9.5 Configuration Files and Environment Variables
C#:
appsettings.jsonholds non‑sensitive base configuration. Environment-specific overrides useappsettings.{Environment}.json. Secrets must come from environment variables, Azure Key Vault, or HashiCorp Vault and never be committed.Angular:
environment.ts(dev) andenvironment.prod.ts(prod) provide build‑time configuration. Any sensitive keys (API keys) must be injected at runtime via an endpoint or server‑side rendering; never commit them to the repository.All configuration files (
.editorconfig,.prettierrc,.eslintrc,stylelint.config) must be present at the root of every repository and reference the shared team rule packages.