Aman-Mittal opened a new pull request, #189:
URL: https://github.com/apache/fineract-consumer-facing/pull/189

   Closes #186 (the enforcement part). Burn-down of the frozen violations: 
#187, #188.
   
   `AGENTS.md` ("Backend conventions") defines the BFF's CQRS and module 
layout. Until now only Spring Modulith's `verify()` and a no-cross-side-imports 
rule checked it. This PR adds 32 ArchUnit rules covering the rest of what can 
be checked from bytecode. There is no production code change: only tests, test 
resources, one `test`-task block in `build.gradle`, and docs.
   
   ## Rules
   
   Every rule cites its `AGENTS.md` section in `because(...)`.
   
   **`CqrsArchitectureTest`**
   - The existing no-cross-side rules.
   - The query side declares only `@Transactional(readOnly = true)`.
   - Query `@Entity` classes are `@Immutable`.
   - The query side never calls a repository's `save*`, `delete*` or `flush*`, 
and declares no `@Modifying`.
   - Public command-service methods never return `domain` types.
   
   **`LayeringArchitectureTest`**
   - Controllers depend on no `domain`, `repository` or `*Impl`.
   - Every `*Impl` implements its same-package interface.
   - `data/` does not depend on `domain`.
   - Service interfaces expose no `domain` or `repository` types.
   - `api/` and `data/` never reference generated Fineract models.
   - No `EntityManager` or criteria API in services.
   - `@Query` methods live in `repository/`.
   - Controller advice lives in `infrastructure.exception`.
   - *Frozen:* features do not use the generated Feign clients directly (see 
below).
   
   **`NamingArchitectureTest`**
   - Query `data/` suffixes.
   - No `*Dto`, `*Result`, `*Summary`, `*Info` or `*View`.
   - No `*Manager`, `*Util` or `*Context` in `infrastructure`.
   - Side-specific names for controllers, repositories and query entities.
   - Advice classes are `*Handler`.
   - *Frozen:* command `data/` suffixes.
   - Enums, `*Constants` holders and `@ConfigurationProperties` classes are 
exempt from the `data/` suffix rules, because they carry no request or response 
data.
   
   **`CodingConventionsArchitectureTest`**
   - No `@Repository` on Spring Data interfaces.
   - No records.
   - `data/` classes are `final` with `private final` fields.
   - Feature exceptions extend `AbstractConsumerException` and declare `CODE`.
   - No `@NamedInterface` or `@ApplicationModule` (detection is central).
   
   **`TestTierArchitectureTest`**
   - No `@SpringBootTest` or `@DataJpaTest`, matched by name and through 
meta-annotations.
   - No Testcontainers.
   - No exemption was needed: the Cucumber glue calls the running BFF over HTTP 
and starts no Spring context.
   
   Rules dropped as not reliably checkable stay review items:
   - transactions on commands depending on whether they touch BFF tables;
   - the exact Lombok annotation set;
   - "tests assert against production constants".
   
   ## Frozen violations: a store that can only shrink
   
   Two rules have existing violations. They are wrapped in `FreezingArchRule`, 
and their current violations are recorded under 
`consumer/src/test/resources/archunit_store/`.
   - **The store:** `ShrinkOnlyViolationStore` replaces ArchUnit's default 
store, which uses random file names and writes a timestamp.
     - It writes one deterministic, sorted file per rule, carrying the ASF 
header, so RAT needs no exclusion.
     - Adding a line to an existing file throws.
   - **Configuration:** `archunit.properties` sets `allowStoreCreation=false`.
     - A new frozen rule without a store file fails the build.
     - `./gradlew test -ParchunitFreezeNewRules` records a new rule once.
   - **Checked by hand:**
     - a new violation fails;
     - a fixed violation is removed from its file on the next run;
     - a fake extra line is dropped, leaving the file byte-identical to the 
original.
   
   This works the same way as the frontend's `eslint-suppressions.json` (#172).
   
   | Frozen rule | Violations | Issue |
   |---|---|---|
   | Command `data/` classes end in `Command`, `CommandData`, `CommandRequest` 
or `CommandResponse` | 3 classes | #187 (good first issue) |
   | Feature packages do not depend on 
`infrastructure.fineractclient.generated.api` | 89 dependencies in 9 service 
Impls | #188 |
   
   **Please weigh in on #188.** `AGENTS.md` says feature services depend on 
narrow interfaces, not on the Feign clients directly. 
`docs/consumer/architecture/modules.adoc` describes services calling the 
generated `*Api` classes, and the code does exactly that.
   - **As it stands:** the rule follows `AGENTS.md` and is frozen, so it only 
stops new direct uses, and the docs note this.
   - **If the project prefers the documented flow:** dropping commit `test: 
freeze direct use of the Fineract Feign clients in features` and its doc 
sentence removes the rule entirely.
   
   ## Docs
   
   - `docs/consumer/architecture/modules.adoc` has a new "Architecture rules" 
section: a table of rules with hard or frozen mode, and how to fix a frozen 
violation and watch the store shrink.
   - A short "Enforcement" paragraph in `AGENTS.md`.
   - One-line pointers in `CONTRIBUTING.md` and `build-and-test.adoc`.
   
   ## Verification (local)
   
   - `./gradlew test --tests '*Architecture*'` passes 36 tests (4 existing, 
plus 32).
   - `./gradlew test spotbugsTest` passes 522 tests (490 + 32), with 0 failures 
and no SpotBugs findings on tests. Error Prone is clean on the new files.
   - I checked that the write-call and meta-annotation checks detect 
violations, using a throwaway probe: the write-call rule flagged 17 
`save`/`delete` calls when pointed at the command side.
   - RAT and the docs build are left to CI.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to