Skip to content

Core POS Extraction Map

This is the governed removal plan for the legacy POS implementation still embedded in emali2-core. It is based on a read-only source audit on 26 July 2026. It does not authorize deleting those files before the route, data, card-present, inventory, and rollback gates below are satisfied.

Decision

The standalone repositories are the target owners:

Capability Target owner Core after cutover
Terminals, shifts, catalog, inventory, sales, tenders, receipts, refunds, customers, engagement, reconciliation emali2-pos No executable retail implementation
Card-terminal estate, authorization, capture, reversal, settlement, underwriting, chargebacks, sponsor/acquirer adapters emali2-card-present No executable card-present implementation
Organizations, merchant stores, users/staff, wallet/ledger, customer approval, merchant collection Emali Core/platform Authoritative platform APIs and projections only
POS-to-Core payment integration Core merchant-collection contract Retained as a narrow store-scoped API; not a POS database or UI

Core Liquibase migration 536 and its merchant-collection binding tables remain in Core. They authorize the standalone POS service to request regulated wallet payments. They do not recreate POS sales, terminals, shifts, receipts, or inventory in Core.

Current dependency closure

The legacy POS package is not an isolated directory. The audit found 32 direct production files:

  • 17 files under domain/pos;
  • 10 files under repository/pos;
  • 4 files under service/pos;
  • 1 shared web/dto/pos/PosDtos.java.

Nine additional production files import those types directly:

  • integration/acquirer/AcquirerGateway.java;
  • integration/acquirer/SandboxAcquirerGateway.java;
  • integration/cardpresent/CardPresentSponsorGateway.java;
  • integration/cardpresent/SandboxCardPresentSponsorGateway.java;
  • service/cardpresent/CardPresentService.java;
  • service/inventory/RetailInventoryService.java;
  • web/MerchantOnboardingController.java;
  • web/PosController.java;
  • web/PosPaymentController.java.

web/OrgInventoryController.java depends on RetailInventoryService without directly importing a POS package, so it is also inside the compile and route closure. The card-present domain, repositories, controller, DTO, and their tests become part of the removal closure when CardPresentService moves.

Five tests outside service/pos also reference the legacy boundary:

  • integration/cardpresent/SandboxCardPresentSponsorGatewayTest;
  • service/cardpresent/CardPresentServiceUnitIsolationTest;
  • service/inventory/RetailInventoryServiceUnitIsolationTest;
  • web/LegacyPlatformAdminRoleIsolationContractTest;
  • web/PortalMethodSecurityCoverageTest.

Deleting only domain/pos, repository/pos, service/pos, the DTO, and the two POS controllers will therefore break Core compilation and its security coverage.

Route and code cutover sequence

1. Freeze and prove parity

  • Keep the Core POS implementation read-only as a rollback source.
  • Inventory every caller of /api/v1/pos/**, /api/v1/org-inventory/**, /api/v1/card-present/**, and /api/v1/merchant-onboarding/**.
  • Compare route contracts, authorization outcomes, row counts, totals, currencies, terminal assignments, sale/tender states, and receipt/refund results using sanitized identifiers.
  • Stop new POS writes to Core before the final data delta is copied.

2. Cut over retail routes

  • Route /api/v1/pos/** only to the standalone POS service.
  • Keep legacy terminal registration and direct platform payment endpoints as explicit 410 Gone tombstones in the standalone service.
  • Move all /api/v1/org-inventory/** consumers to the standalone POS-owned compatibility routes, then retire OrgInventoryController.
  • Remove Core PosController, PosPaymentController, PosService, PosCustomerService, and PosEngagementService only after gateway and direct-service probes prove no Core handler is reachable.

3. Cut over inventory

  • Treat the standalone catalog, price, stock, suppliers, receiving, transfers, counts, supervisor overrides, and sale stock ledger as authoritative.
  • Remove the Core sale callbacks from RetailInventoryService.
  • Retire the remaining Core inventory controller/service/domain/repository stack only after non-POS platform consumers are either migrated or an explicit platform-owned inventory use case is documented.
  • Never let POS read Core inventory tables directly during the transition.

4. Cut over card-present

  • Route /api/v1/card-present/** only to emali2-card-present.
  • Keep POS-to-card communication API-only, keyed by opaque POS terminal UUID; do not recreate a cross-database foreign key.
  • Remove Core CardPresentController, CardPresentService, card-present domain/repositories/DTO, and both card-present/acquirer sandbox gateways after authorization, reversal, settlement, chargeback, and rollback probes pass against the separate service.

5. Resolve merchant onboarding ownership

/api/v1/merchant-onboarding/** is currently a platform-owned direct call, not a POS-service proxy. Before removing the POS package, choose one governed owner:

  • keep merchant organization onboarding in Core, but move its models and service out of domain/pos, repository/pos, service/pos, and web/dto/pos; or
  • move acquiring-specific onboarding to emali2-card-present and leave only organization/store registration in Core.

Do not silently delete onboarding or leave acquirer credentials duplicated in two databases.

6. Remove the legacy implementation atomically

In one isolated Core branch:

  1. remove the now-unreachable POS controllers;
  2. remove the direct POS packages and their focused tests;
  3. remove or refactor inventory, onboarding, acquirer, and card-present dependents according to the preceding decisions;
  4. update method-security coverage to describe the retained controllers;
  5. run clean compile, focused security tests, the full Core suite, route inventory, and dependency search;
  6. deploy with an explicit rollback window and verify the standalone routes.

The acceptance search must find no executable Core imports of com.emali2.core.*.pos, while continuing to find the narrow merchant collection integration.

Database migration map

Historical Core changelogs must remain immutable. The relevant chain includes:

Core history Legacy data Standalone destination
292 onboarding, acquirer profiles, terminals, sessions, sales, lines, tenders, receipts POS Flyway V3, V6-V8; onboarding decision above
294 catalog, prices, stock, suppliers, receiving, transfers, overrides POS Flyway V4-V5, V14-V18
298 engagement configuration POS Flyway V9-V10
302-303 customers, sale customer/offer snapshots POS Flyway V7, V9-V10 and later sale migrations
304 card-present terminal/payment/settlement/underwriting/chargeback records emali2-card-present migrations
295-296 retail capability and test seed data Recreate only governed projections/configuration; never copy test fixtures blindly
375 migration coverage metadata Retain as historical Core evidence
536 POS-service client/store and merchant-collection request bindings Retain in Core permanently

After the application cutover, add a new governed Core migration that first revokes legacy runtime writes and records the archival state. Archive or drop legacy tables only after retention, reconciliation, rollback, and backup restore requirements are accepted. Never edit or delete migrations 292-304 to make a fresh database appear clean.

Acceptance gates

  • The gateway has exactly one owner for each public route.
  • Standalone POS and card-present databases restore independently from Core.
  • Final Core-to-standalone row counts and monetary/state checks reconcile.
  • A late write is either rejected at Core or copied through a rehearsed delta.
  • Full Core compile and tests pass without the removed classes.
  • Security tests prove no raw platform-admin role inherits POS operations.
  • POS create/status/cancel and customer-approved capture/refund pass through the adapter.
  • Card authorization/reversal/settlement and inventory/receipt/refund parity pass in TEST.
  • Rollback restores routing without accepting split-brain writes.
  • No raw customer, till, credential, token, or idempotency value appears in migration output or logs.

Until every applicable gate passes, the correct action is to leave the legacy Core source in place and prevent it from receiving traffic—not to delete a partial directory.