Commit 873998629c05736ac583b38745059a58105ac3a8
1 parent
0add76bd
docs(progress+readme): pin SPA commit + document the runnable demo
Updates the "at a glance" row to v0.29.0-SNAPSHOT + fc62d6d7, bumps the Phase 6 R1 row to DONE with the commit ref and an overview of what landed (Gradle wrapper, SpaController, security reordering, bundled fat-jar, 16 pages), and rewrites the "How to run" section to walk the click-through demo instead of just curl. README's status table updated to reflect 10/10 PBCs + 356 tests + SPA status; building section now mentions that `./gradlew build` compiles the SPA too. No code changes.
Showing
2 changed files
with
73 additions
and
22 deletions
PROGRESS.md
| ... | ... | @@ -10,11 +10,11 @@ |
| 10 | 10 | |
| 11 | 11 | | | | |
| 12 | 12 | |---|---| |
| 13 | -| **Latest version** | v0.28.0-SNAPSHOT (pbc-production v3 + shop-floor dashboard + OpenAPI / Swagger UI with 15 grouped specs + plug-in endpoints visible in spec + real buildInfo) | | |
| 14 | -| **Latest commit** | `dfd01ff feat(plugins+bootstrap): plug-in endpoints visible in OpenAPI spec` | | |
| 13 | +| **Latest version** | v0.29.0-SNAPSHOT (R1 Web SPA bootstrap + demo seed — click-through end-to-end buy-sell loop from the browser) | | |
| 14 | +| **Latest commit** | `0add76b ci(docker): install nodejs+npm in build stage for :web SPA build` | | |
| 15 | 15 | | **Repo** | https://github.com/reporkey/vibe-erp | |
| 16 | -| **Modules** | 24 | | |
| 17 | -| **Unit tests** | 355, all green | | |
| 16 | +| **Modules** | 24 JVM subprojects + `:web` SPA | | |
| 17 | +| **Unit tests** | 356, all green | | |
| 18 | 18 | | **Real PBCs implemented** | **10 of 10** (pbc-identity, pbc-catalog, pbc-partners, pbc-inventory, pbc-warehousing, pbc-orders-sales, pbc-orders-purchase, pbc-finance, pbc-production, pbc-quality) — P5.x row of the implementation plan complete at minimal v1 scope | |
| 19 | 19 | | **End-to-end smoke runs** | An SO confirmed with 2 lines auto-spawns 2 draft work orders via `SalesOrderConfirmedSubscriber`; completing one credits the finished-good stock via `PRODUCTION_RECEIPT`, cancelling the other flips its status, and a manual WO can still be created with no source SO. All in one run: 6 outbox rows DISPATCHED across `orders_sales.SalesOrder` and `production.WorkOrder` topics; pbc-finance still writes its AR row for the underlying SO; the `inventory__stock_movement` ledger carries the production receipt tagged `WO:<code>`. First PBC that REACTS to another PBC's events by creating new business state (not just derived reporting state). | |
| 20 | 20 | | **Plug-ins serving HTTP** | 1 (reference printing-shop, 7 endpoints + own DB schema + own metadata + own i18n bundles) | |
| ... | ... | @@ -92,10 +92,10 @@ That target breaks down into roughly 30 work units across 8 phases. About **22 a |
| 92 | 92 | |
| 93 | 93 | | # | Unit | Status | |
| 94 | 94 | |---|---|---| |
| 95 | -| R1 | Vite + React + TS bootstrap, login flow, OpenAPI client | 🔜 Pending | | |
| 96 | -| R2 | Identity screens | 🔜 Pending | | |
| 95 | +| R1 | Vite + React + TS bootstrap, login flow, typed REST client | ✅ DONE — `fc62d6d` — new `:web` Gradle subproject wraps Vite/React 18/TypeScript/Tailwind 3.4 via Exec tasks; `:distribution` consumes the dist via an outgoing/incoming Gradle configuration and stages it into `classpath:/static/` so a single fat-jar serves both API and SPA. Hand-written typed fetch client over `/api/v1/**` (211 KB JS gzipped, no codegen toolchain). AuthContext stores the JWT in localStorage with a 401 handler. `SpaController` forwards every known SPA route prefix to `/index.html` so React Router deep links work on hard refresh. `SecurityConfiguration` reordered: `/api/**` stays `.authenticated()` before the SPA permitAll rules so the "API is always authenticated" invariant holds even with the SPA bundled in the same image. Dockerfile build stage adds `apk add nodejs npm` so `./gradlew :distribution:bootJar` produces a self-contained image with the SPA inside. End-to-end smoke verified on fresh Postgres: log in, walk SO DRAFT → CONFIRMED → SHIPPED, watch stock balances drop + AR journal entry settle — all in a real browser. | | |
| 96 | +| R2 | Identity screens (user admin, role admin) | 🔜 Pending | | |
| 97 | 97 | | R3 | Customize / metadata UIs | 🔜 Pending | |
| 98 | -| R4 | Per-PBC list/detail/create/edit screens | 🔜 Pending | | |
| 98 | +| R4 | Per-PBC create/edit screens (list/detail are live in R1) | 🔜 Pending — list + detail pages for all 10 PBCs landed in R1 along with the ship/receive/confirm/cancel action verbs on the order + work-order detail pages. Create/edit forms and richer per-PBC screens (BOM editor, routing editor) will follow when a real consumer asks for them. | | |
| 99 | 99 | |
| 100 | 100 | ### Phase 7 — Reference printing-shop plug-in |
| 101 | 101 | |
| ... | ... | @@ -175,30 +175,59 @@ This is **real**: a JAR file dropped into a directory, loaded by the framework, |
| 175 | 175 | - **MCP server.** The architecture leaves room for it; the implementation is v1.1. |
| 176 | 176 | - **Mobile.** v2. |
| 177 | 177 | |
| 178 | -## How to run what exists today | |
| 178 | +## How to run the end-to-end demo | |
| 179 | 179 | |
| 180 | 180 | ```bash |
| 181 | -# Bring up Postgres + the plug-in JAR (in background) | |
| 181 | +# Bring up Postgres + stage the reference plug-in JAR | |
| 182 | 182 | docker compose up -d db |
| 183 | 183 | ./gradlew :reference-customer:plugin-printing-shop:installToDev |
| 184 | 184 | |
| 185 | -# Boot the framework against it | |
| 185 | +# Boot the framework (serves both the REST API and the React SPA | |
| 186 | +# from the same fat-jar on http://localhost:8080) | |
| 186 | 187 | ./gradlew :distribution:bootRun |
| 187 | 188 | |
| 189 | +# Open the browser: | |
| 190 | +open http://localhost:8080 | |
| 191 | +``` | |
| 192 | + | |
| 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. | |
| 198 | + | |
| 199 | +Walk the demo: | |
| 200 | + | |
| 201 | +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. | |
| 212 | + | |
| 213 | +Or for the API-only version: | |
| 214 | + | |
| 215 | +```bash | |
| 188 | 216 | # In another shell: |
| 189 | 217 | curl -s localhost:8080/api/v1/_meta/info |
| 190 | 218 | curl -s localhost:8080/api/v1/_meta/metadata | jq |
| 191 | 219 | |
| 192 | -# Read the bootstrap admin password from the boot logs, then: | |
| 193 | 220 | ACCESS=$(curl -s -H 'Content-Type: application/json' \ |
| 194 | 221 | -X POST localhost:8080/api/v1/auth/login \ |
| 195 | 222 | -d '{"username":"admin","password":"<from-logs>"}' | jq -r .accessToken) |
| 196 | 223 | |
| 197 | -curl -s -H "Authorization: Bearer $ACCESS" localhost:8080/api/v1/identity/users | |
| 198 | -curl -s -H "Authorization: Bearer $ACCESS" localhost:8080/api/v1/catalog/uoms | |
| 224 | +curl -s -H "Authorization: Bearer $ACCESS" localhost:8080/api/v1/catalog/items | |
| 225 | +curl -s -H "Authorization: Bearer $ACCESS" localhost:8080/api/v1/orders/sales-orders | |
| 199 | 226 | curl -s -H "Authorization: Bearer $ACCESS" localhost:8080/api/v1/plugins/printing-shop/plates |
| 200 | 227 | ``` |
| 201 | 228 | |
| 229 | +OpenAPI spec at [`/v3/api-docs`](http://localhost:8080/v3/api-docs) and Swagger UI at [`/swagger-ui/index.html`](http://localhost:8080/swagger-ui/index.html). | |
| 230 | + | |
| 202 | 231 | ## Module map |
| 203 | 232 | |
| 204 | 233 | ``` | ... | ... |
README.md
| ... | ... | @@ -77,7 +77,7 @@ vibe-erp/ |
| 77 | 77 | ## Building |
| 78 | 78 | |
| 79 | 79 | ```bash |
| 80 | -# Build everything (compiles 18 modules, runs 230 unit tests) | |
| 80 | +# Build everything (compiles all JVM modules + the web SPA, runs 356 unit tests) | |
| 81 | 81 | ./gradlew build |
| 82 | 82 | |
| 83 | 83 | # Bring up Postgres + the reference plug-in JAR |
| ... | ... | @@ -88,20 +88,42 @@ docker compose up -d db |
| 88 | 88 | ./gradlew :distribution:bootRun |
| 89 | 89 | ``` |
| 90 | 90 | |
| 91 | -The bootstrap admin password is printed to the application logs on first boot. After login, REST endpoints are live under `/api/v1/identity/users`, `/api/v1/catalog/uoms`, `/api/v1/catalog/items`, `/api/v1/partners/partners`, `/api/v1/plugins/printing-shop/*`, and the public introspection endpoint at `/api/v1/_meta/metadata`. | |
| 91 | +The bootstrap admin password is printed to the application logs on first boot. | |
| 92 | + | |
| 93 | +## Running the end-to-end demo | |
| 94 | + | |
| 95 | +The dev profile opts in to a one-shot `DemoSeedRunner` that stages a starter dataset on first boot (5 items, 2 warehouses with opening stock, 4 partners, one open sales order, one open purchase order — everything prefixed `DEMO-`). Combined with the React SPA served out of the same fat-jar, that's enough to click through the entire buy-sell loop in the browser. | |
| 96 | + | |
| 97 | +```bash | |
| 98 | +docker compose up -d db | |
| 99 | +./gradlew :distribution:bootRun | |
| 100 | +open http://localhost:8080 | |
| 101 | +``` | |
| 102 | + | |
| 103 | +Then: | |
| 104 | + | |
| 105 | +1. Log in as `admin` — the password is in the bootRun log, under `vibe_erp bootstrap admin created`. | |
| 106 | +2. The dashboard shows every PBC populated with seeded rows. Click through **Items**, **Partners**, **Locations**, **Stock Balances** — each page is live against Postgres. | |
| 107 | +3. Click **Sales Orders → DEMO-SO-0001**. The order is in `DRAFT`; click **Confirm**. The `Journal entries` panel on the same page shows an `AR POSTED` row appear, created reactively by `pbc-finance` from the `SalesOrderConfirmedEvent`. | |
| 108 | +4. Pick `DEMO-WH-FG` as the shipping location and click **Ship**. The order flips to `SHIPPED`, the `Inventory movements` panel shows the `SALES_SHIPMENT` ledger rows, and the journal entry settles to `AR SETTLED`. Navigate to **Stock Balances** and confirm the two finished-good rows dropped by the shipped quantity. | |
| 109 | +5. Do the mirror-image flow on **Purchase Orders → DEMO-PO-0001** (Confirm → Receive into `DEMO-WH-RAW`). Stock grows, an `AP` row posts and settles, and another ledger row appears. | |
| 110 | +6. **Shop Floor** renders any `IN_PROGRESS` work order with a live progress bar; create one via **Work Orders** or via the workflow engine and watch it update every 5 seconds. | |
| 111 | + | |
| 112 | +REST endpoints are live under `/api/v1/**` for every PBC (see `/v3/api-docs` or the Swagger UI at `/swagger-ui/index.html` for the full catalog). The SPA uses them directly — no separate backend server is needed. | |
| 92 | 113 | |
| 93 | 114 | ## Status |
| 94 | 115 | |
| 95 | -**Current stage: foundation complete; Tier 1 customization live; business surface area growing.** All eight cross-cutting platform services are live and verified end-to-end against a real Postgres: auth (JWT + Argon2id + bootstrap admin), plug-in HTTP endpoints, plug-in linter (ASM bytecode scan), plug-in-owned DB schemas + typed SQL, event bus + transactional outbox, the metadata seeder + custom-field validator, and the ICU4J translator with per-plug-in locale chain. The Tier 1 customization story works end-to-end: a YAML declaration adds a typed custom field to an existing entity, the framework's `ExtJsonValidator` enforces it on every save, and the SPA-facing `GET /api/v1/_meta/metadata/custom-fields/{entityName}` endpoint serves the runtime view to the form builder. | |
| 116 | +**Current stage: end-to-end runnable demo.** All 10 core PBCs are live against real Postgres, the full buy-sell-make loop is wired via cross-PBC events, every cross-cutting platform service (auth + authorization + plug-in HTTP + linter + Liquibase + metadata + i18n + events/outbox + JasperReports + FileStorage + Quartz + embedded Flowable) is running, and the **R1 React SPA** is served out of the same fat-jar with a seeded starter dataset so the entire buy-sell-make loop can be walked in a browser on first boot. | |
| 96 | 117 | |
| 97 | 118 | | | | |
| 98 | 119 | |---|---| |
| 99 | -| Modules | 18 | | |
| 100 | -| Unit tests | 230, all green | | |
| 101 | -| Real PBCs | 8 of 10 | | |
| 102 | -| Cross-cutting services live | 9 | | |
| 103 | -| Plug-ins serving HTTP | 1 (reference printing-shop) | | |
| 104 | -| Production-ready | **No** — workflow engine, forms, web SPA, more PBCs all still pending | | |
| 120 | +| JVM modules | 24 Kotlin subprojects + `:web` | | |
| 121 | +| Unit tests | 356, all green | | |
| 122 | +| Real PBCs | 10 of 10 | | |
| 123 | +| Cross-cutting services live | 12 | | |
| 124 | +| Plug-ins serving HTTP | 1 (reference printing-shop — 8 endpoints, own DB schema, metadata, i18n, TaskHandlers, JobHandler, BPMN, reports, file storage) | | |
| 125 | +| Web SPA | Served by Spring Boot at `/` — login, dashboard, 14 pages, live ship/receive/confirm verbs, shop-floor dashboard | | |
| 126 | +| Production-ready | **No** — OIDC, MCP server, JSON Schema form renderer, GL-level finance, and richer per-PBC verbs are still pending | | |
| 105 | 127 | |
| 106 | 128 | For the full feature inventory, completed work, and next-priority list, see [`PROGRESS.md`](PROGRESS.md). For the detailed roadmap, see [`docs/superpowers/specs/2026-04-07-vibe-erp-implementation-plan.md`](docs/superpowers/specs/2026-04-07-vibe-erp-implementation-plan.md). |
| 107 | 129 | ... | ... |