Commit 634c18fe40b8b8e77068154261c5a2812c694a4e

Authored by zichun
1 parent 8e0801e9

docs: align CLAUDE.md + PROGRESS.md with actual codebase state

CLAUDE.md "Repository state" was stale (18→25 subprojects,
246→356 tests, 8→10 PBCs, 9→12 platform services).
PROGRESS.md "What's not yet live" still listed Flowable,
JasperReports, file store, job scheduler, OIDC, and web SPA
as missing — all are live. "Current stage" paragraph updated
to reflect 10 PBCs and 12 services. "How to run" section
updated to remove DemoSeedRunner reference (moved to demo
branch).
Showing 2 changed files with 32 additions and 34 deletions
CLAUDE.md
... ... @@ -93,13 +93,13 @@ plugins (incl. ref) depend on: api/api-v1 only
93 93  
94 94 ## Repository state
95 95  
96   -**Foundation complete; first business surface in place.** As of the latest commit:
  96 +**Foundation complete; all platform services and core PBCs live.** As of the latest commit:
97 97  
98   -- **18 Gradle subprojects** built and tested. The dependency rule (PBCs never import each other; plug-ins only see `api.v1`) is enforced at configuration time by the root `build.gradle.kts`.
99   -- **246 unit tests across 18 modules**, all green. `./gradlew build` is the canonical full build.
100   -- **All 9 cross-cutting platform services live and smoke-tested end-to-end** against real Postgres: auth (P4.1), authorization with `@RequirePermission` + JWT roles claim + AOP enforcement (P4.3), plug-in HTTP endpoints (P1.3), plug-in linter (P1.2), plug-in-owned Liquibase + typed SQL (P1.4), event bus + transactional outbox (P1.7), metadata loader + custom-field validation (P1.5 + P3.4), ICU4J translator with per-plug-in locale chain (P1.6), plus the audit/principal context bridge.
101   -- **8 of 10 core PBCs implemented end-to-end** (`pbc-identity`, `pbc-catalog`, `pbc-partners`, `pbc-inventory`, `pbc-orders-sales`, `pbc-orders-purchase`, `pbc-finance`, `pbc-production`). **The full buy-sell-make loop works**: a purchase order receives stock via `PURCHASE_RECEIPT`, a sales order ships stock via `SALES_SHIPMENT`, and a work order with a bill of materials consumes raw materials via `MATERIAL_ISSUE` and produces finished goods via `PRODUCTION_RECEIPT`, all atomically in one transaction. All four write paths feed the same `inventory__stock_movement` ledger via the same `InventoryApi.recordMovement` facade.
102   -- **pbc-production v2** adds an IN_PROGRESS state between DRAFT and COMPLETED, a `WorkOrderInput` child entity carrying per-unit BOM consumption rates, and a scrap verb that writes a negative `ADJUSTMENT` ledger row for post-completion corrections without leaving the terminal COMPLETED state.
  98 +- **25 Gradle subprojects** built and tested (1 API + 11 platform + 10 PBC + 1 reference plug-in + web + distribution). The dependency rule (PBCs never import each other; plug-ins only see `api.v1`) is enforced at configuration time by the root `build.gradle.kts`.
  99 +- **356 unit tests across 25 modules**, all green. `./gradlew build` is the canonical full build.
  100 +- **All 12 cross-cutting platform services live and smoke-tested end-to-end** against real Postgres: auth (P4.1), OIDC federation (P4.2), authorization with `@RequirePermission` + JWT roles claim + AOP enforcement (P4.3), plug-in HTTP endpoints (P1.3), plug-in linter (P1.2), plug-in-owned Liquibase + typed SQL (P1.4), event bus + transactional outbox (P1.7), metadata loader + custom-field validation (P1.5 + P3.4), ICU4J translator with per-plug-in locale chain (P1.6), JasperReports renderer (P1.8), file store with local + S3 backends (P1.9), Quartz job scheduler (P1.10), plus the audit/principal context bridge.
  101 +- **10 of 10 core PBCs implemented** (6 feature-complete, 4 at minimal v1 scope): `pbc-identity`, `pbc-catalog`, `pbc-partners`, `pbc-inventory`, `pbc-warehousing`, `pbc-orders-sales`, `pbc-orders-purchase`, `pbc-finance`, `pbc-production`, `pbc-quality`. **The full buy-sell-make loop works**: a purchase order receives stock via `PURCHASE_RECEIPT`, a sales order ships stock via `SALES_SHIPMENT`, and a work order with a bill of materials consumes raw materials via `MATERIAL_ISSUE` and produces finished goods via `PRODUCTION_RECEIPT`, all atomically in one transaction. All four write paths feed the same `inventory__stock_movement` ledger via the same `InventoryApi.recordMovement` facade.
  102 +- **pbc-production v3** adds an IN_PROGRESS state between DRAFT and COMPLETED, a `WorkOrderInput` child entity carrying per-unit BOM consumption rates, a scrap verb, and `WorkOrderOperation` child entity with per-op sequential state machine and operator-entered actual minutes for variance reporting. Shop-floor dashboard projects IN_PROGRESS work orders with progress bars.
103 103 - **Event-driven cross-PBC integration is live in BOTH directions and the consumer reacts to the full lifecycle.** Six typed events under `org.vibeerp.api.v1.event.orders.*` are published from `SalesOrderService` and `PurchaseOrderService` inside the same `@Transactional` method as their state changes. **pbc-finance** subscribes to ALL SIX of them via the api.v1 `EventBus.subscribe(eventType, listener)` typed-class overload: confirm events POST AR/AP rows; ship/receive events SETTLE them; cancel events REVERSE them. Each transition is idempotent under at-least-once delivery. pbc-finance has no source dependency on pbc-orders-*; it reaches them only through events.
104 104 - **Tier 1 customization is universal across every core entity with an ext column.** Partner, Location, SalesOrder, PurchaseOrder, WorkOrder, and Item all implement the `org.vibeerp.api.v1.entity.HasExt` marker interface. Their services go through one `ExtJsonValidator.applyTo(entity, map)` helper that validates, canonicalises, and serialises the JSON in one call. Response mappers use `parseExt(entity)` for the symmetric read. No PBC services duplicate ext handling code.
105 105 - **Clean Core extensibility is executable.** The reference printing-shop plug-in ships a `customFields:` section in its metadata YAML that extends four CORE entities (Partner, Item, SalesOrder, WorkOrder) with printing-specific fields (e.g. `printing_shop_color_count`, `printing_shop_paper_gsm`, `printing_shop_quote_number`, `printing_shop_press_id`). The MetadataLoader merges plug-in declarations with core ones; the validator enforces the merged set on every save. Uninstalling the plug-in makes the fields disappear from both the UI and the validation — no migration, no code change. This is the executable grade-A extension under the A/B/C/D scale.
... ...
PROGRESS.md
... ... @@ -22,9 +22,9 @@
22 22  
23 23 ## Current stage
24 24  
25   -**Foundation complete; Tier 1 customization live; authorization enforced; full buy-and-sell loop closed; event-driven cross-PBC integration live in BOTH directions; consumer PBC now reacts to the full order lifecycle.** All eight cross-cutting platform services are live plus the authorization layer. **The framework now has seven PBCs, both ends of the inventory loop work, every state transition emits a typed domain event, and the consumer PBC reacts to all six lifecycle events** (confirm + ship/receive + cancel for both sales and purchase). The pbc-finance `OrderEventSubscribers` bean registers six typed-class subscriptions at boot. JournalEntry rows carry a lifecycle status (POSTED → SETTLED on fulfilment, POSTED → REVERSED on cancellation) and all transitions are idempotent under at-least-once delivery. Cancel-from-DRAFT is a clean no-op because no `*ConfirmedEvent` was ever published to create a row.
  25 +**Foundation complete; all platform services and core PBCs live; React SPA serving CRUD for every entity; Tier 1 customization rendering in the browser.** All 12 cross-cutting platform services are live (9 Phase-1 + 3 auth/authz). All 10 core PBCs are implemented (6 feature-complete, 4 at minimal v1 scope). The full buy-sell-make loop works end-to-end: purchase receipt, sales shipment, production receipt, and material issue all feed the same `inventory__stock_movement` ledger. Event-driven cross-PBC integration is live in both directions — pbc-finance subscribes to all 6 order lifecycle events (confirm + ship/receive + cancel) and writes balanced double-entry journal entries with idempotent handling. The React SPA has create/edit/detail pages for every manageable entity, a dynamic custom-field renderer (P3.1), client-side i18n (en-US + zh-CN), and identity management screens.
26 26  
27   -The next phase continues **building business surface area**: pbc-production (the framework's first non-order/non-master-data PBC), the workflow engine (Flowable), and eventually the React SPA.
  27 +The next phase focuses on **Tier 1 designer UIs** (form renderer, form designer, list view designer, rules engine) and **workflow UIs** (BPMN designer, user-task form rendering).
28 28  
29 29 ## Total scope (the v1.0 cut line)
30 30  
... ... @@ -129,11 +129,11 @@ These are the cross-cutting platform services already wired into the running fra
129 129 | **Metadata loader** (P1.5) | `platform-metadata` | Walks the host classpath and each plug-in JAR for `META-INF/vibe-erp/metadata/*.yml`, upserts entities/permissions/menus into `metadata__*` tables tagged by source. Idempotent (delete-by-source then insert). User-edited metadata (`source='user'`) is never touched. Public `GET /api/v1/_meta/metadata` returns the full set for SPA + AI-agent + OpenAPI introspection. |
130 130 | **i18n / Translator** (P1.6) | `platform-i18n` | ICU4J-backed `Translator` with named placeholders, plurals, gender, locale-aware number/date formatting. Per-plug-in instance scoped via a `(classLoader, baseName)` chain — plug-in's `META-INF/vibe-erp/i18n/messages_<locale>.properties` resolves before the host's `messages_<locale>.properties` for shared keys. `RequestLocaleProvider` reads `Accept-Language` from the active HTTP request via the servlet container, falling back to `vibeerp.i18n.defaultLocale` outside an HTTP context. JVM-default locale fallback explicitly disabled to prevent silent locale leaks. |
131 131 | **Custom field application** (P3.4) | `platform-metadata.customfield` | `CustomFieldRegistry` reads `metadata__custom_field` rows into an in-memory index keyed by entity name, refreshed at boot and after every plug-in load. `ExtJsonValidator` validates the JSONB `ext` map of any entity against the declared `FieldType`s — String maxLength, Integer/Decimal numeric coercion with precision/scale enforcement, Boolean, Date/DateTime ISO-8601 parsing, Enum allowed values, UUID format. Unknown keys are rejected; required missing fields are rejected; ALL violations are returned in a single 400 so a form submitter fixes everything in one round-trip. `Partner` is the first PBC entity to wire ext through `PartnerService.create/update`; the public `GET /api/v1/_meta/metadata/custom-fields/{entityName}` endpoint serves the api.v1 runtime view of declarations to the SPA / OpenAPI / AI agent. |
132   -| **PBC pattern** (P5.x recipe) | `pbc-identity`, `pbc-catalog`, `pbc-partners`, `pbc-inventory`, `pbc-orders-sales`, `pbc-orders-purchase`, `pbc-finance` | Seven real PBCs prove the recipe. **pbc-orders-purchase** is the buying-side mirror of pbc-orders-sales: same recipe, same three cross-PBC seams (PartnersApi + CatalogApi + InventoryApi), same line-with-recompute pattern, but the partner role check is inverted (must be SUPPLIER or BOTH), the state machine ends in RECEIVED instead of SHIPPED, and the cross-PBC inventory write uses positive deltas with `reason="PURCHASE_RECEIPT"`. **pbc-finance** is the framework's first CONSUMER PBC — it has no service of its own (yet), no cross-PBC facade in `api.v1.ext.*`, and no write endpoint. It exists ONLY to react to `SalesOrderConfirmedEvent` and `PurchaseOrderConfirmedEvent` from the api.v1 event surface and produce derived AR/AP rows. This validates the consumer side of the cross-PBC seam: a brand-new PBC subscribes to existing PBCs' events through `EventBus.subscribe(eventType, listener)` without any source dependency on the producers. |
  132 +| **PBC pattern** (P5.x recipe) | all 10 `pbc-*` modules | Ten PBCs prove the recipe. All 10 follow the same DDD layering (domain/application/http/infrastructure). Cross-PBC interaction goes through api.v1 service interfaces (InventoryApi, CatalogApi, PartnersApi) or the event bus — never source dependencies. **pbc-finance** is the framework's first CONSUMER PBC: it subscribes to all 6 order lifecycle events and writes balanced double-entry journal entries with idempotent handling. **pbc-production** demonstrates child entities (WorkOrderInput, WorkOrderOperation) and event-driven routing from plug-in requests. **pbc-warehousing** demonstrates atomic transfer pairs (TRANSFER_OUT + TRANSFER_IN) via InventoryApi. **pbc-quality** demonstrates append-only inspection records. |
133 133  
134 134 ## What the reference plug-in proves end-to-end
135 135  
136   -The printing-shop reference plug-in is the framework's executable acceptance test. As of `1ead32d` it demonstrates **everything a real customer plug-in needs** except workflow handling:
  136 +The printing-shop reference plug-in is the framework's executable acceptance test. It demonstrates **everything a real customer plug-in needs**:
137 137  
138 138 ```
139 139 Plug-in JAR drop → host bootstrap:
... ... @@ -164,14 +164,12 @@ This is **real**: a JAR file dropped into a directory, loaded by the framework,
164 164  
165 165 ## What's not yet live (the deferred list)
166 166  
167   -- **Workflow engine.** No Flowable yet. The api.v1 `TaskHandler` interface exists; the runtime that calls it doesn't.
168   -- **Forms.** No JSON Schema form renderer (server or client). No form designer.
169   -- **Reports.** No JasperReports.
170   -- **File store.** No abstraction; no S3 backend.
171   -- **Job scheduler.** No Quartz. Periodic jobs don't have a home.
172   -- **OIDC.** Built-in JWT only. OIDC client (Keycloak-compatible) is P4.2.
173   -- **More PBCs.** Identity, catalog, partners, inventory, orders-sales and orders-purchase exist. Warehousing, production, quality, finance are all pending.
174   -- **Web SPA.** No React app. The framework is API-only today.
  167 +- **Form designer / renderer.** P3.2 (metadata-driven form layout renderer) and P3.3 (web UI for designing forms) are pending.
  168 +- **List view designer.** P3.6 (metadata-driven list view configuration) is pending.
  169 +- **Rules engine.** P3.5 (event-driven automation rules stored as metadata rows) is pending.
  170 +- **BPMN designer.** P2.2 (web UI for editing BPMN workflows) is pending.
  171 +- **User-task form rendering.** P2.3 (rendering Flowable user-task forms in the SPA) is pending.
  172 +- **Metadata admin UIs.** R3 (customize / metadata screens in the SPA) is pending.
175 173 - **MCP server.** The architecture leaves room for it; the implementation is v1.1.
176 174 - **Mobile.** v2.
177 175  
... ... @@ -190,25 +188,25 @@ docker compose up -d db
190 188 open http://localhost:8080
191 189 ```
192 190  
193   -The dev profile opts in to the one-shot `DemoSeedRunner` which
194   -populates a starter dataset on first boot (5 items, 2 warehouses
195   -with opening stock, 4 partners, one open sales order, one open
196   -purchase order, all prefixed `DEMO-`). The bootstrap admin
197   -password is printed to the boot log.
  191 +The bootstrap admin password is printed to the boot log on first start.
  192 +On a fresh database, create your own master data through the SPA or API.
198 193  
199   -Walk the demo:
  194 +Walk the framework:
200 195  
201 196 1. Log in as `admin` (password from the boot log).
202   -2. **Sales Orders → DEMO-SO-0001** → **Confirm** → watch the
203   - `AR POSTED` row appear in the on-page journal-entry panel.
204   -3. Pick `DEMO-WH-FG` → **Ship** → order flips to `SHIPPED`, stock
205   - balances drop, the journal entry settles to `AR SETTLED`, and
206   - the `SALES_SHIPMENT` rows appear in the inventory movements
207   - panel. All from one button click.
208   -4. **Purchase Orders → DEMO-PO-0001** → **Confirm** → **Receive**
209   - into `DEMO-WH-RAW` for the mirror-image flow.
210   -5. **Shop Floor** polls every 5 seconds; create or start a work
211   - order and watch it appear with a progress bar.
  197 +2. Create items, partners, and locations via the SPA create forms.
  198 +3. Create a sales order → **Confirm** → watch the AR journal entry
  199 + appear automatically (event-driven cross-PBC integration).
  200 +4. **Ship** the sales order → stock balances drop, the journal entry
  201 + settles to `AR SETTLED`, and `SALES_SHIPMENT` rows appear in
  202 + the inventory movements ledger.
  203 +5. Create a purchase order → **Confirm** → **Receive** for the
  204 + mirror-image flow.
  205 +6. Create a work order with BOM inputs → **Start** → complete
  206 + operations → **Complete** → raw materials consumed, finished
  207 + goods produced.
  208 +7. **Shop Floor** polls every 5 seconds; start a work order and
  209 + watch it appear with a progress bar.
212 210  
213 211 Or for the API-only version:
214 212  
... ...