-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
Canonical reference: docs/architecture.md, docs/libraries.md, docs/coding-standards.md.
| Layer | Technology | Container |
|---|---|---|
| Frontend | Angular + Angular Material — zoneless, signals, standalone components; served by nginx | forge-ui |
| Backend | .NET Web API — MediatR/CQRS, FluentValidation, Mapperly, Serilog, Hangfire, SignalR | forge-api |
| Database | PostgreSQL + pgvector; schema owned by forge-db | forge |
| Object storage | MinIO (S3-compatible) | forge-storage |
| Backups | Scheduled pg_dump sidecar |
forge-backup |
| Optional | Ollama (AI), Coqui (TTS), DocuSeal (signing), Seq (logs), GlitchTip (crash reports) | profile-gated |
Also in the mix: OpenAPI + Scalar for API docs, Three.js for inline STL rendering, Playwright and Vitest for tests.
forge-api is layered with a genuinely pure core — forge.core has zero project references and holds only entities, enums, interfaces, models and settings.
forge.core entities / enums / interfaces / models / settings (no project refs)
forge.data EF Core DbContext + persistence → core
forge.integrations external providers (accounting, shipping, AI, …) → core
forge.api features, controllers, capability gates → the bulk of the code
forge.tests unit + integration + architecture tests
Features are MediatR request/handler pairs under Features/; controllers are thin. Mapping is source-generated with Mapperly — no runtime reflection mappers. Background work runs on Hangfire with the PostgreSQL storage provider.
This is the single most important architectural fact to know before touching the database.
There are no EF Core migrations. The desired-state schema is a tree of one-object-per-file SQL scripts in forge-db, reconciled onto a live database with stripe/pg-schema-diff. EF Core is present purely as the query-mapping layer.
- Schema changes = edit the
forge-dbschema tree, then regenerate the SQL the API embeds. - The API's
SchemaBootstrapperprovisions a fresh database from that assembled schema and is a no-op on an existing one — it does not reconcile drift. - Upgrades of a populated install go through the
forge-deployschema reconcile step. - Consequence for developers: a stale local database volume will not self-heal. Reconcile it with the forge-db harness rather than expecting startup to fix it.
The reason for the split is that some of the schema cannot be expressed by an ORM migration generator at all — the vector-search extension behind document search, and the database triggers that make posted accounting entries immutable.
Time is injected, never read from the ambient clock. IClock (forge.core/Interfaces/IClock.cs) has a SystemClock for production and a SimulationClock for end-to-end tests, which is what makes deterministic multi-week simulation runs possible. It is injected into AppDbContext's timestamp stamping and into time-dependent handlers. New code calling DateTime.UtcNow directly is a standards violation.
ASP.NET Identity with JWT bearer tokens for the SPA and refresh-token rotation. Roles are additive — a user can hold several.
Authentication is tiered, because a shop floor and an office need different things:
| Tier | Method | Where |
|---|---|---|
| 1 | RFID/NFC scan + PIN | Kiosk (primary) |
| 2 | Barcode scan + PIN | Kiosk (fallback) |
| 3 | Username + password | Desktop / mobile |
| 4 | Enterprise SSO — Google, Microsoft, generic OIDC | Optional |
Admins create accounts and issue a setup token; the employee completes their own password, PIN and profile. An admin never views or sets a password or PIN — a reset issues a new setup token instead.
OAuth tokens for the accounting provider are held on a single company-level connection and encrypted via the ASP.NET Data Protection API, with keys in Postgres.
SignalR carries the live surface — board sync, notifications, timers and chat run over dedicated hubs, with reconnection handling and a connection banner in the UI. Hangfire runs the scheduled and deferred work.
IAccountingService is a common interface over customers, invoices, estimates, POs, payments, time activities, employees, vendors and items. AccountingServiceFactory resolves the active provider from settings. Each provider owns its auth flow, API client and DTO mapping; the sync queue, caching and orphan detection are provider-agnostic. See Accounting Modes — the behavioural consequences are large enough to deserve their own page.
Forge's coding standards are backed by tests and lint rules rather than prose alone, using a consistent pattern: hard rules fail the build; legacy debt is held by a per-file ratchet. New files must be clean, already-baselined files may not get worse, and improving a file fails the check until you regenerate and commit the baseline in the same commit. Baselines are never hand-edited upward.
-
forge-api— architecture tests underforge.tests/Architecture/cover capability gating on controllers and source standards (clock usage, try/catch in controllers, file size). -
forge-ui—npm run lint:standardscovers console logging, hardcoded colours, unjustified!important, inline templates and raw form controls.
Before pushing UI work, run the local gates: npm run lint && npm run lint:i18n && npm run test -- --watch=false. Translations live only at public/assets/i18n/{en,es}.json with enforced 1:1 parity between locales.
Forge · Apache 2.0 · built by Armory Works — this wiki maps the docs; the authoritative detail lives in docs/.
Evaluating
Running it
- Installation
- First Week
- Configuration and Integrations
- Hardening a Production Install
- Backup and Restore
- Upgrades and Rollback
- Accounting Modes
Using it
- App Surfaces
- Shop Floor Kiosk
- Mobile and Offline
- Access and Roles
- Customizing an Install
- Feature Reference
- UI Flows
Building on it
- API Access
- Architecture
- Capability Gating
- Workflow, Gates and Approvals
- Data Ownership and Export
- Glossary
Contributing
Repo wikis