Commit 634c18fe40b8b8e77068154261c5a2812c694a4e
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 | ... | ... |