BeMart

Migration Status — EC-CUBE 4.3 → BEAR.Sunday + Be Framework

Migration Status — EC-CUBE 4.3 → BEAR.Sunday + Be Framework

Living document. Update the relevant row/cell whenever a layer’s status changes. Updated 2026-06-09 JST against 1.x commit f4d77609, alps.json, be/src, src/Resource, var/templates, var/sql, docs/api/openapi.json, and the Web E2E evidence set.

The migration runs through 5 layers. ALPS is the source of truth; the lower layers implement it. “Done / partial / pending” is judged against the ALPS spec, route-gate coverage, and the explicit residual boundary, not optimistically.


1. Summary

Layer Done State
1. ALPS spec (alps.json) 534 descriptors, 207 transition descriptors Complete as current contract. 207 transitions = 97 safe + 46 unsafe + 64 idempotent descriptors. Route connection / safety-retreat decisions are explicit instead of implicit controller behavior.
2. Be domain (be/src) 147 Input / 148 Final / 157 Semantic / 14 Being / 39 Reason Entity Complete for the migrated behavioral contract and connected hard-route surfaces. Remaining work is not unknown domain coverage; it is named compatibility residuals (target-engine SQL verification, product CSV import, plugin lifecycle, export fidelity).
3. BEAR Resource 146 Page resource files Aura route extras map EC-CUBE route name ↔ URL path ↔ resource URI. Resource files include storefront, admin, fallback/action, and support-style page resources, so this metric is broader than older “139 page resource” snapshots.
4. SQL persistence (var/sql + Ray.MediaQuery) 54 query interfaces, 150 #[DbQuery], 150 SQL files Phase 2 has been cut over from concrete Sql* adapter classes to Ray.MediaQuery direct proxies. Prod SQL binding is SqlModule → MediaQueryRuntimeModule; reproducible prod DB seed script exists.
5. HTML presentation (var/templates) 133 Twig templates Phase 3 complete for the in-scope migration. Current inventory: 43 storefront/non-admin page templates, 72 admin page/partial templates, 15 shared Block templates, 3 frames. Storefront is covered; admin in-scope editor waves are covered; Store/Plugin install/search subtree remains out of scope.

Test baseline: after the PR closeout and API doc refresh, GitHub Actions on 1.x passes composer psalm and composer test; PHPUnit reports 1734 tests, 26059 assertions. The latest Web E2E evidence set (20260608-canonical-resource-routes-web-e2e) runs html-prod-hal-api-app against an actual DB and records 181 pass / 2 fail / 3 out-of-scope across 186 features with 140 retained screenshots. Target-engine SQL portability still needs explicit MariaDB 10.11 verification where noted in §4.


2. Feature matrix

Rows = flow-* feature areas (see docs/tag.md for the tag taxonomy). Columns = the 5 layers. Counts are ALPS transitions per flow. ✓ done · ~ partial · ✗ pending.

Feature area (flow) ALPS Be domain BEAR Resource (JSON) SQL HTML
flow-browse (catalog browse) ✓ 5 ✓ ✓ ✓ ✓ storefront
flow-purchase (cart→checkout) ✓ 19 ✓ (doCreateOrder + doCheckout both: PurchaseFlow + dtb_order_item snapshot) ✓ ~ (order-item snapshot SQL caveat in §4) ✓ storefront
flow-register (customer signup) ✓ 3 ✓ ✓ ✓ ✓ storefront
flow-account (mypage / address) ✓ 15 ✓ ✓ ✓ ✓ storefront
flow-favorite ✓ 3 ✓ ✓ ✓ ✓ storefront
flow-inquiry (contact form) ✓ 2 ✓ ✓ ✓ (Contact has no table) ✓ storefront
flow-admin-auth ✓ 1 ✓ ✓ ✓ ✓ admin
flow-manage-product ✓ 26 ~ (no Be transition for product CSV import — ProductCsv::onPost parses inline; category/class CSV paths go through Be) ✓ ✓ ✓ admin (list/tag/class + product/category/csv editors + product-class register done)
flow-manage-order ✓ 14 ~ (PDF fidelity residual; shipping CSV persistence connected) ✓ ✓ ✓ admin (list + edit/shipping/mail/mail_confirm/pdf/csv-shipping done)
flow-manage-customer ✓ 11 ✓ ✓ ✓ ~ admin (list + customer edit done; customer-delivery-edit creates new addresses only — update/delete are unreachable from the UI, see CustomerDeliveryEdit.php docblock)
flow-manage-shop ✓ 15 ✓ ✓ ✓ ✓ admin (payment/delivery/tax list + calendar/csv/order-status/tradelaw + payment/delivery edits + shop-master editors done)
flow-manage-content ✓ 9 ✓ ✓ ✓ ~ admin (news/page/css/js/cache/maintenance done; content/file-manager renders POST forms with no write handler — see §2.1)
flow-manage-cms (layout/block) ✓ 8 ✓ ~ (Template list/add only) ✓ ✓ admin (layout/block/template list + template_add done)
flow-manage-system ✓ 8 ✓ ✓ ✓ ~ admin (member/login-history + system/log/security/masterdata/authority done; two-factor-auth-edit renders a POST form with no write handler — see §2.1)
flow-manage-mail ✓ 2 ✓ ✓ ✓ ✓ admin (mail-template editor done)
flow-manage-plugin (out of scope) ✓ 6 ~ (doInstallPlugin stub) ✓ ✓ ~ admin (plugin list done; install/search out of scope)
route-gate transitions ✓ 60 ~ (connected surfaces; some fidelity residuals) ✓ n/a n/a
non-flow behavioral transitions ✓ 9 ✓ n/a n/a n/a

Layer-specific notes:

2.1 Rendered forms without a write handler

Two admin resources still render a <form method="post"> that no method answers. The markup was ported ahead of the handler, so the button reaches BEAR\Resource and comes back 405. Reproduce any row with composer page -- post <path>.

Template POST target Resource Methods
Page/Admin/TwoFactorAuthEdit.html.twig:125 /admin/two-factor-auth-edit Admin/TwoFactorAuthEdit.php onGet
Page/Admin/Content/FileManager.html.twig:308,348,382 /admin/content/file-manager Admin/Content/FileManager.php onGet

Each of the remaining two needs a scope decision before a transition: file-manager needs a multipart file-I/O design, and two-factor-auth-edit needs the admin-editing-another-member 2FA semantics worked out (issue #143).

Page/Admin/Product/CsvProduct.html.twig was an earlier entry. Its upload posted to its own screen URL instead of /admin/product-csv, where ProductCsv::onPost already implements the import (the router turns an import_file upload into the csv parameter). Repointing the action was the whole fix — no new transition.

Admin/CustomerDeliveryEdit.php, Admin/Customer.php, and Admin/Product/ProductClass.php were three more entries, fixed for #143: each gained an admin-specific Be Input/Final (AdminCreateCustomerDeliveryAddressInput, AdminUpdateCustomerDeliveryAddressInput, AdminDeleteCustomerDeliveryAddressInput, AdminUpdateCustomerInput, AdminRegisterProductClassInput) distinct from the storefront transitions — UpdateCustomerAddressInput omits customerId on purpose and derives the owner from the customer session, which is the opposite of an administrator editing someone else’s row.

tests/Router/TemplateFormActionTest.php holds the same list and fails both ways: a third dead form breaks the build, and so does an entry that is no longer dead. The other 121 POST forms resolve to a resource that writes.

2.2 #[Alps] references the profile does not define

alps.json is the SSOT and #[Alps('id')] is a resource claiming to implement one of its transitions. Nothing checked that the id exists — asd --validate validates the profile, not the references into it — and 19 had drifted; 15 were resolved for #143. tests/Alps/AlpsReferenceTest.php now holds the remaining list and fails on a fifth as well as on an entry that has since been resolved.

Group Count What it needs
Screens and actions absent from the profile 4 A descriptor each

The four: doCreateMailTemplate, goAdminContentFileManager, goAdminTwoFactorAuthEdit, goShoppingShippingMultipleEdit.

goShoppingShippingMultipleEdit is not a rename — it is an editor screen distinct from the goShoppingShippingMultiple (list) transition it links to.

Two of the four are also the two remaining §2.1 dead forms (goAdminContentFileManager / goAdminTwoFactorAuthEdit), so for those the read descriptor, the write descriptor and the handler land together.

Resolved for #143: the route-gate/fallback ids (doActionRedirect, goUnsupportedRoute, +6) and the placeholder goAdminEmptyPage dropped #[Alps] — a client cannot discover a URL EC-CUBE has that BeMart deliberately does not model as an application transition. goAdminLog / goAdminOrderOrderPdf / goAdminOrderMailConfirm / goAdminTemplateTemplateAdd were renamed (the last two to existing profile ids goOrderMailConfirm / goTemplateInstall; the first two to new descriptors goLog / goOrderPdf, since goAdminOrderOrderPdf is not a rename of goExportOrderPdf — it is the distinct options-form screen that links to it). goAdminCustomerDeliveryEdit / goAdminProductProductClass became goCustomerDeliveryEdit / goProductClass alongside the §2.1 dead-form fixes above.


3. Phase log

Phase Scope Key commits
Phase A Be domain + BEAR JSON resources. Pilots 1–5 established the Be patterns, then parallel waves took the original behavioral transition set to completion. Later ALPS remediation and route-gate additions expanded the contract, but the original Phase-A figure remains historical. Phase B added Psalm taint setup, ProdModule, env-gated entry point. Recorded in docs/HANDOVER.md (historical log)
Phase 2 — SQL Fake → SQL, then SQL → Ray.MediaQuery boundary cleanup. The original storage-interface migration used G-23’s workflow/state-transition contract discipline, historically named hypermedia-test-as-contract; the current form is 54 MediaQuery interfaces and 150 SQL files with prod context bound through SqlModule / MediaQueryRuntimeModule. Reproducible prod DB seed (mtb_* masters + setup script) exists. 3a439a2, 0757f26, 051d235, fd96242 (2a); f6f22ee…9a9c89b (2b); f128ba6, 6ed334d (2c); later Ray.MediaQuery cutover
Phase 3 — HTML BEAR resources rendered as HTML; templates are faithful ports of EC-CUBE’s default and admin Twig themes (see var/templates/README.md). Storefront done in waves plus shared Block widgets. Ray.WebFormModule adopted for form pages. Enrichment re-derived thin resource bodies from EC-CUBE so HTML can be faithful (Cart, Mypage History, Shopping confirm/complete). Admin theme then ported through Tier-1 and in-scope Tier-2 editor waves; Store/Plugin install/search subtree remains out of scope. Current template inventory is 133 Twig files. 762a739/2525710/9d06ec3 (Cart pilot); 1507dc2 (wave 1) → 46b2a08 (wave 7); 5a95435 (WebFormModule); f91e10f (admin News pilot); 1e91e92 (per-section ja-split); da48413 (Customer); section-waves batches 1–2; 2f59bb3…a455281 (Order Tier-2); 4eb93f3…0296306 (Product Tier-2); 571dd5b (Store template_add); f3df0d4 (Block widgets); 1177e0d/2f8d17a (Shopping enrich); 5d9e6ba (fidelity-test fixes); f9c5580 (doResendActivationMail)
Phase B — security / production hardening Psalm taint setup, ProdModule, env-gated CLI entry point, EC-CUBE static-asset deployment (default + admin themes), and the HTTP router — Aura.Router maps EC-CUBE route name ↔ URL path ↔ resource URI through route extras; the BEAR.Sunday RouterInterface adapter returns RouterMatch, while BEAR\Resource owns missing resource 404 and method 405; BeMartTwigExtension::url()/path() resolve through Aura’s generator. a002097 (asset deploy); 53e587e/39f1117 (HTTP router); 16e8c9d (asset-package-aware render stubs)

ALPS remediation (f01e1ae, per docs/phases/alps-audit-phase3.md) happened during Phase 3: it re-tagged Favorite and added transitions that Phase A’s domain never saw. Later route-gate work made hard route/fallback decisions explicit in ALPS, so the current profile is larger than the Phase-A/Phase-3 snapshots.


4. Outstanding work

Punch-list, roughly highest-effort first:

  1. Admin HTML Tier-2 — rendered, two write handlers missing. Admin Tier-1 plus every in-scope Tier-2 editor wave is ported as markup: flow-manage-system, Customer delivery-edit, Setting/System, Setting/Shop, Order, Product, and Store template_add. Current admin inventory is 72 admin page/partial templates. Two of those screens post to a resource that cannot answer — §2.1 lists them, and until each gains a write handler the editor is display-only. The remaining Store/Plugin install/search subtree is out of scope because plug-ins are excluded from this migration. Per-section history: docs/phases/admin-fanout-plan.md and var/templates/README.md “Fan-out status”.
  2. HTML enrichment backlog. Phase 3 flagged data pages whose resource bodies are too thin for a faithful EC-CUBE port; each needs the Cart-style re-derive (ALPS → Entity/SQL/Fake enrich → template wiring). Done: Mypage History (a31f8d8/3c1b03d), Shopping confirm/complete (1177e0d/2f8d17a). Still open: Mypage dashboard, Favorite, Address, Contact.
  3. Block/* widget templates — done. ✓ Done. The logo and footer Block widgets are ported (var/templates/Block/, f3df0d4). The remaining Block regions (cart/login/search) stay EC-CUBE-runtime residuals; Block is intentionally not modelled in ALPS.
  4. Phase-3 remediation transitions — all implemented. ✓ Done. The named transitions the Phase-3 ALPS remediation added are implemented in be/src (doSortNoMove, doToggleVisible, doUpdateTrackingNumber, doSendShippingNotifyMail, doResendActivationMail — domain + storage/mailer + JSON resource + tests). Later route-gate descriptors are tracked separately from this remediation set.
  5. Phase-A stub / compatibility residuals. goExportOrderPdf is now the Issue #24 compatibility pilot: Resource reachability, download headers, and %PDF- body generation are implemented through an isolated EC-CUBE/TCPDF service, but full EC-CUBE fidelity (delivery-note layout parity, dtb_order_pdf saved settings, multi-shipping template reproduction) is intentionally left as a tracked residual. doImportCategoryCsv and doImportShippingCsv are real — CategoryCsvImported parses the 4-column EC-CUBE format and upserts/deletes via CategoryStorageInterface (+ CategoryIdQueryInterface for new ids); AdminShippingCsvImported resolves each row’s order and writes the tracking number through the same ShippingAddressStorageInterface::updateTrackingNumber surface as the inline doUpdateTrackingNumber (durable persistence covered by the SQL suite; Fake writes are no-ops). doUpdateCsv is consumed end-to-end — the export Finals overlay saved dtb_csv configuration on their default column vector via CsvColumnLayout::resolve, preserving default output when config is absent or enables no known columns. doCreateOrder and doCheckout now converge on PurchaseFlow + dtb_order_item snapshot writes — admin order creation and storefront checkout both freeze line items through OrderItemCommandInterface::register, with domain wiring pinned by AdminOrderCreatedTest / CheckoutCompletedSnapshotTest. ⚠ SQL verification caveat: the durable order-item SQL path still needs a green target-engine run of DATABASE_URL=... vendor/bin/phpunit --testsuite sql; order_item_register.sql uses JSON_TABLE while the target is documented as MariaDB 10.11, so portability must be confirmed or the INSERT rewritten without JSON_TABLE. The alps.json contract was synced to match (OrderItemInput, regenerated HTML/SVG artifacts). Still stubbed / intentionally-not-modelled: doImportProductCsv (intentionally not migrated — the route is export-only), doInstallPlugin (plugin scope, out of scope).
  6. #[Input]-vs-Form refactor. Noted from MyVendor.Cms issue #37 — reconcile Be Framework #[Input] with the Ray.WebFormModule AbstractForm. Unverified here — confirm against that issue before acting.
  7. Production DB bring-up. Phase 2c shipped the seed script and prod SqlModule binding; an actual production database bring-up / cutover is still pending.
  8. Hard ActionRedirect routes — connected. ✓ Done. The 22 Hard rows that Issue #24 parked on ActionRedirect (docs/eccube-feature-alps-status.html) are now wired to concrete Be/BEAR resources with the Be domain transition implemented: 認証/credential (doChangePassword / doVerifyTwoFactorAuth / doSetTwoFactorAuth / doUpdateSecurity), コンテンツ/file (doClearCache / doUpdateContentCss / doUpdateContentJs / doToggleMaintenance), マスタデータ (doSelectMasterData / doUpdateMasterData), 規格CSV (goExportClassName / goExportClassCategory / doImportClassNameCsv / doImportClassCategoryCsv), Store/template (doSelectTemplate / doDeleteTemplate / doDownloadTemplate / doInstallTemplate). Each side-effect (credential hash, TOTP, config/cache/asset files, CSV encode/parse, template zip/install) is isolated behind a be/src/Reason/Service/*Interface boundary with an src/Compatibility/Eccube/ default + a Fake — the Issue #24 PDF-pilot pattern. Full EC-CUBE fidelity for those side-effects (real file writes, byte-exact CSV, persisted TOTP secret) is the tracked production-cutover residual. Difficulty stays Hard; the routes are now 実装済み, so the Hard-ActionRedirect count is 0. ⚠ 2FA setup pre-auth residual (PR #28 review — TwoFactorAuthSet::onPut): the device-setup page is reached PRE-AUTH (anonymous login-context), so it currently takes loginId + the candidate TOTP secret from the request body, and TwoFactorAuthInterface::enable() overwrites the secret for that loginId with no ownership check — a caller who passes another admin’s loginId could replace that admin’s 2FA device. The production cutover must bind a server-generated secret + the pending login identity into a pre-auth session/challenge state at credential-verification time and consume it here instead of trusting the client values; until then the route relies on CSRF + the documented enable() contract. Do not widen this surface (e.g. expose it post-auth for an arbitrary loginId) before the challenge state lands.

5. Where things live

You want… Look at
The feature list (source of truth) alps.json · docs/alps.json.html · docs/alps.svg
Tag taxonomy (flow-*, src-*) docs/tag.md
Phase A detail (Be domain + JSON) docs/HANDOVER.md
Phase 2 detail (SQL) sql/diff/entity-vs-eccube.md · var/sql/ · src/Module/MediaQueryRuntimeModule.php
Phase 3 detail (HTML) docs/phases/alps-audit-phase3.md · var/templates/README.md
Route/function status + migration difficulty docs/eccube-feature-alps-status.html
Migration skills / lessons (G-14…G-25) docs/skills/
Docs map / index docs/README.md
Continuation guide docs/HOW_TO_CONTINUE.md
Stale older trackers (Phase A era, do not trust for current state) docs/archive/progress.md · docs/archive/task_plan.md