Skip to content

Architecture ​

ArchForge is four sibling Git repositories. This page explains how the pieces fit together, how a request travels through the backend, and which CI gates keep implementations honest against contracts.

System context ​

Two Spring Boot apps are built from one backend codebase, each with its own sa-token realm and response style. The backend owns the contract: its generated OpenAPI file and enum registry (spec/) feed both frontends via generated TypeScript.

Key consequences of this layout:

  • No cross-calls between the two apps. server-web never imports server-admin code; an ArchUnit rule fails the build if that ever happens.
  • Frontends never hand-write API types. pnpm gen:api regenerates them from openapi.yaml, and CI fails when committed artifacts drift.
  • Deleted paths stay deleted. /system/menu and /system/role are gone from the contract and cannot reappear in a controller.

Request lifecycle (admin) ​

A typical authenticated admin request — token issuance, the refresh queue, and permission checks:

On the C-end the same job is done by StpWebUtil + WebAuthInterceptor; errors come back as RFC 9457 ProblemDetail with an ArchForge error code property instead of the admin envelope.

Backend module layering ​

One Gradle root, layered modules. Arrows point in the allowed dependency direction:

The layering is not a drawing — it is enforced by ArchitectureTest:

  • controllers must not touch repositories directly,
  • domain modules must not depend on server packages,
  • starters must stay business-free,
  • every rule fails when it matches zero classes (failOnEmptyShould=true), so a typo'd package filter cannot silently disable architecture checks.

Contract-first workflow ​

The backend is the source of the contract: spec/openapi.yaml is generated from the running code and committed with the change that caused it. Every arrow below ends in a CI gate:

To add or change an endpoint: implement it behind controllers/services, run ./gradlew generateOpenApi and commit the regenerated spec/openapi.yaml; CI fails if the file is stale and oasdiff proves nothing broke for existing consumers. The clients then regenerate their types (pnpm gen:api).

Deployment topology ​

Development and production both start from docker/ compose files:

Details per environment live in the deployment guides (Docker, observability, production).

Quality gates summary ​

ConcernEnforcement
Module boundariesSpring Modulith verification + ArchUnit
Coverageaggregated JaCoCo; changed-line coverage ≥ 60% on PRs
Test tiersJUnit @Tag: P0 / P1 / contract / slow (container tests)
Contract driftoasdiff + sdk-sync + enum-sync + error-code registry
StyleSpotless, JSpecify @NullMarked on every package

Released under the MIT License.