Skip to content

Shopkeeper Micro-capability

Jumpmind Commerce's Shopkeeper Micro-capability supports the following functions:

  • Remote Manager Overrides
  • Real-time Sales Data Display
  • Real-time Device Transaction View

Architecture

Shopkeeper consists of a Java server and Angular typescript client like most JMC services. However, unlike most JMC services, Shopkeeper's state management is done via an NGXS integration on the client side, NOT via a Java state manager. These states are populated with data via REST calls to remote (or local) JMC service endpoints.

Additionally, to support real-time data, Shopkeeper's server supports a two-way gRPC connection to JMC's State Relay. The server makes the gRPC connection, while the client is notified of / allowed to pass updates to this stream via a websocket connection to the server. Both the websocket and gRPC connection are established when the Shopkeeper client application is initialized.

The State Relay

The JMC State Relay application is necessary to facilitate bi-directional realtime communication between the POS and Shopkeeper.

The State Relay is REQUIRED to access the full breadth of Shopkeeper functionality.

The State Relay is typically run centrally with Shopkeeper running either centrally, or in the store. Shopkeeper and the POS are designed to auto-connect to the State Relay, provided the configurations in the "Technical Configuration" section are setup correctly.

Enablement as a Microcap (Integrated)

The Integrated Microcap mode will enable bidirectional access between the Commerce application and the Shopkeeper module. Tapping the button on Commerce's Home screen will take you to Shopkeeper's dashboard.

Enabling Integrated (Microcap) Mode

Integrated mode can be enabled by exposing a "Shopkeeper" button on the Commerce home screen.

Integration Checklist

  • [ ] Add a row to ctx_button configured as follows:
button_group_id button_id button_name button_type button_value enabled
home LaunchShopkeeper key:home:home.shopkeeper action LaunchShopkeeper 1

Configuration

The Shopkeeper micro-cap's functionality is driven by a combination of database data and Spring context configuration, the latter of which supplies both technical and business rule parameters.

Technical Configuration

The following application-*.yml parameters govern technical behavior for the Shopkeeper module:

Key Purpose App Customization Required?
openpos.micro-caps.configs.shopkeeper.server-url names the URL of the server hosting Shopkeeper services when running in Integrated mode POS Y
openpos.micro-caps.configs.shopkeeper.remote-entry names and locates the script invoked to serve the Shopkeeper micro-cap when accessed from another application POS Y
openpos.state-relay.enabled enable the state relay to transmit data POS, Shopkeeper Y (Default is false for POS)
openpos.state-relay.target the remote host and port of the state relay for the POS and Shopkeeper to connect to POS, Shopkeeper Y

Checklist

  • [ ] Configure the URL of the server hosting Shopkeeper services
  • [ ] Configure the host and port at which the remoteEntry.js script serving the Shopkeeper micro-cap is invokable
  • [ ] Ensure the state relay is enabled on all valid registers and Shopkeeper
  • [ ] Ensure the POS and Shopkeeper are targeting the correct address of the state relay

Data

The following database tables must, at a minimum, be populated as described in order to enable all front- and back-end features exposed by the Shopkeeper micro-cap. These may be populated directly (via data scripts) or through integrations with external providers (via e.g. SymmetricDS).

Table Qualifier Features Requiring Purpose
dev_device Shopkeeper real-time device state display Provides Shopkeeper a list of devices to monitor. An devices in this table matching Shopkeeper's business unit ID will be flagged to be monitored.
sk_sales_ticker Sales Tickers Provides definitions for Shopkeeper's Sales tickers on its Sales widget.
sk_sales_timeline Sales Timelines Provides definitions for lines on Shopkeeper's timeline graph on its Sales widget.

Checklist

  • [ ] Populate requisite tables with customer-specific data

Data Model

Additional info regarding Data models can be seen in our Swagger output or the DataModel.md file. Swagger provides detailed descriptions of tables and columns that may be of assistance to gain a good conceptual understanding of the models used here.

erDiagram
    sk_sales_ticker {
        string ticker_id
        string title
        string subtitle
        int polling_interval
    }

    sk_sales_timeline {
        string timeline_id
        string title
        boolean bind_to_right_axis
    }

    sk_notification {
        string id
        string notification_type
        boolean resolved
        string sent_by_username
        string resolved_by_username
        date sent_time
        date resolved_time
        string device_id
        string message
    }

*Note: Shopkeeper models have no relation to each other.

APIs

Shopkeeper has two main API service implementations:

  • Shopkeeper Device Management
  • Shopkeeper Statistics

APIs are invoked via the rest/shopkeeper path.

If you'd like to see detailed request and response information, please take a look at our Swagger API page. The information below is designed to be a quick reference.

Overriding Endpoint Service Calls

Several endpoint service calls in Shopkeeper are implemented with base functionality, but are designed to be overridden based on your own specific data and display requirements.

The "Intended to be Overridden" column in the subsequent tables should clarify which service calls these correspond to:

  • "YES" implies the endpoint has some level of out-of-the-box functionality, but is ultimately intended to be customized.
  • "NO" implies the endpoint is NOT designed to be overridden.
  • "OPTIONAL" implies the endpoint can be overridden, but the base functionality is intended to be serviceable to most clients.

Device Management /device-management

The Device Management API is designed to save, recall, and handle information regarding devices, notifications, or other device-specific things relevant to Shopkeeper.

The service has the following service calls:

Service Call HTTP Path Purpose Intended to be overridden
getDeviceIds() GET rest/shopkeeper/device-management/deviceids/{businessUnitId}/{appId} Obtain a list of devices for Shopkeeper to monitor. OPTIONAL
getResolvedNotifications() POST rest/shopkeeper/device-management/notifications/getResolved Obtain a list of resolved notifications. NO
saveNotifications() PUT rest/shopkeeper/device-management/notifications/save Save a notification NO
respondToManagerOverrideRequest() POST rest/shopkeeper/device-management/{deviceId}/manager-override/{requestId} Respond to a manager override request NO*

*respondToManagerOverrideRequest() is not designed to be overridden except in the case that a client is not using JMC POS.

Statistics /statistics

The Statistics API is designed to provide models and data for the various Sales displays on Shopkeeper.

The service has the following service calls:

Service Call HTTP Path Purpose Intended to be overridden
getTickers() GET rest/shopkeeper/statistics/tickers/{businessUnitId} Obtain a list of sales tickers for Shopkeeper to display on its Sales widgets. Tickers are defined by SK_SALES_TICKER NO
getTickerValue() POST rest/shopkeeper/statistics/tickerData/{businessUnitId}/{tickerId} Obtain data for a particular ticker. Is called periodically based on pollingInterval supplied in ticker model YES
saveTimelines() PUT rest/shopkeeper/statistics/timelines/{businessUnitId} Obtain a list of timelines for the Shopkeeper timeline graph. There is no limit to timelines, but only two y-axes are available. Timelines are defined by SK_SALES_TICKER NO
getTimelineData() POST rest/shopkeeper/statistics/timelineValues/{businessUnitId}/{timelineId} Obtain a set of data points for the given timeline. This is called once at screen creation, and not periodically (unlike a polling Ticker). YES
getDailyGoalValue() POST rest/shopkeeper/statistics/dailyGoal/{businessUnitId}/current Obtain the current daily goal value.This is displayed on the Sales gauge. There is no requirement for this to be a "daily" goal. Any value will suffice. This is polled periodically by Shopkeeper. OPTIONAL (Default requires sls_trans_summary integration)
getDailyGoalTarget() POST rest/shopkeeper/statistics/dailyGoal/{businessUnitId}/target Obtain the current target goal value. This is displayed on the Sales gauge. This value is NOT polled, and will only be requested by Shopkeeper on screen creation. YES

Implementing Additional Manager Override Context

Shopkeeper supports additional context for several manager override operations right out of the box. Additional context can be provided by implementing additional IManagerOverrideParams and IManagerOverrideParamBuilder classes in the POS project. See manager_override_context.md for more information.

FAQ

This FAQ contains common questions that may come up during the implementation process of Shopkeeper. If you find you have a question that is not listed here, please add it in if you receive an answer - even if the question is answered somewhere in this document already. Others may have been confused or glossed over the same information.

Q: How do I set my own value for a Ticker, Timeline, or Gauge Data?

The preferred way to pass data to a Ticker or Timeline is to create a new IShopkeeperTickerDataAggregator or IShopkeeperTimelineDataAggregator implementation. This will allow you to pass data to Shopkeeper in a way that is both efficient and easy to maintain: 1. Add a new row to the sk_sales_ticker or sk_sales_timeline table with a unique ticker_id or timeline_id 2. Create a new implementation of IShopkeeperTickerDataAggregator or IShopkeeperTimelineDataAggregator and add it to the Spring context (add it to your project) 3. Implement the getAggregatorKey() method to return the ticker_id or timeline_id you created in step 1 4. Implement the getTickerData() or getTimelineData() method to return the data you want to display. You may utilize the @RequiredArgsConstructor tag to pull in any necessary JMC Microservices, or reach out to external services at this point.

To override the gauges, you can override the following endpoints depending on which gauge you'd prefer to setup data for: - ShopkeeperGetAverageBasketSizeEndpoint for the average basket size graph - ShopkeeperGetConversionRateEndpoint for the conversion rate display - ShopkeeperGetDailyGoalValueEndpoint for the daily goal display (the current value) - ShopkeeperGetDailyGoalTargetEndpoint for the daily goal display (the target value) - ShopkeeperGetCoverageDataEndpoint for the coverage graph

To do this, you will need to override the endpoint:

  1. Create a new endpoint for your service method with a custom implementation value. See our "How to add new implementations of existing service methods" in our microservices.md file.
  2. Use the @Autowired tag to pull in any relevant JMC Microservices to your new endpoint
  3. Utilize the microservices to implement your own custom logic

As an alternative, your endpoint can also make a remote call to another service. The ticker data lookup happens asynchronously, so the app will not be held up by lengthy response times.

Q: Are there any restrictions on the data I provide via the "data" and "value" Statistics aggregators / endpoints?

There are no enforced limits on this data, but all data from "value" endpoints is displayed as currency on the application UI. Additionally, timeline data is expected to adhere to one x-axis scale and at most two y-axis scales.

Aside from hard restrictions, keep in mind the polling rate set on tickers. Expensive operations done frequently can become problematic quickly. The tickers will always request new data upon rendering as well, regardless of their polling rate.

Q: Shopkeeper does not show any devices?

Shopkeeper will look in the dev_device table to find all entries that match a pos app ID and the business unit ID Shopkeeper is running on (You should be able to see this on Shopkeeper's dashboard). Ensure there are valid devices in this table.

Q: Shopkeeper shows several devices it's monitoring, but the devices do not appear to be updating in Shopkeeper?

Shopkeeper handles device state updates and manager overrides via the JMC State Relay application. Ensure the openpos.state-relay.enabled and openpos.state-relay.target are set correctly on all registers and Shopkeeper instances. Additionally, ensure the device IDs shown on Shopkeeper match the device IDs you're trying to monitor, and that the monitored devices are set to the pos app ID.

Q: Shopkeeper was monitoring devices, but no longer appears to be?

Shopkeeper's client makes a websocket connection to its server to receive and pass updates to the gRPC protocol that the state relay listens / sends on. Restarting the Shopkeeper client application will attempt to reconnect to this websocket.

If this issue is persistent, consider filing a bug report on our Issue Tracker.

Q: The State Relay doesn't appear to be doing anything?

The state relay, by default, is turned off on JMC POS configurations. Ensure openpos.state-relay.enabled is set to true on all relevant devices

Q: Can I show a relative date on my tickers like you do in the default configuration?

Shopkeeper knows how to compute a relative date for several token values. You can set the subtitle data field in sk_sales_ticker to one of the following values to get the corresponding computed date:

  • %DATE% (Today)
  • %LASTWEEK% (Last Week)
  • %LASTYEAR% (Last Year)

Q: How do I decline a manager override on Shopkeeper?

You cannot currently decline a manager override on Shopkeeper. You can only dismiss it from view.

If you'd like to see this feature in a future release, consider making a Feature Request on our issue tracker.

Q: What are the relationships between Shopkeeper's data tables?

Shopkeeper's data tables are isolated from each other and have no X:X relationships with each other.

Q: I'd like to override one of the endpoint invocations you said not to override above. Can I do that?

It's strongly recommended that you refrain from overriding any service calls not recommended to be overridden. These calls are generally simple database lookups of visual models the UI will use to display information. Overriding them can cause unneeded complexity and obscure bugs.