Coffee Catalog


Allows a user to order coffee and related paraphernalia.

Key Behaviors


Data Types

type Item struct {
  Id    string // UUID
  Image BlobRef
  Desc  string
  Price float

type User struct {
  Id         string // UUID
  // In reality we might define structs for some of the values below.
  Name       string // full name of user
  Email      string
  Address    string
  CreditCard string // should instead use a more secure API (token per order?)

type OrderItem struct {
  ItemId string
  Count  int

type Order struct {
  Id           string // UUID
  CreatedTime  time.Time
  PlacedTime   time.Time // zero value if not yet placed
  ReceivedTime time.Time // zero value if not yet received
  // We’d probably have more fields here, e.g. to specify
  // gift-wrapping options, track order status, etc.


<app-blessing>-catalog Collection
  <Item.Id>: Item

<user-blessing>-user Collection
  <User.Id>: User
  // possibly also include per-user catalog metadata, e.g. favorites

<user-blessing>-draftOrders Collection
  <Order.Id>: Order
    <Item.Id>: OrderItem

<user-blessing>-placedOrders Collection - same layout as draftOrders
<user-blessing>-processedOrders Collection - same layout as draftOrders


We might keep user records in a "users" table and order records in an “orders” table in order to enforce schema, but this is orthogonal to collection layout.

When a user "places" an order, all data for the order is moved (copy + delete) atomically from the “draftOrders” to the “placedOrders” collection.

The app cloud backend (order processor) watches for changes to "placedOrders" and processes these orders. After processing an order, it sets Order.ReceivedTime and atomically moves the order record from the “placedOrders” to the “processedOrders” collection. Whenever watch stops for any reason, it is restarted including the initial state to prevent skipping any orders. Order processing must also be either atomic with the move to “processedOrders”, or idempotent to allow safely retrying without executing more than once in case commit fails. It might need to snapshot orders in processing to its own local storage as an extra safeguard (e.g. in case a malicious user changes an order after it’s accepted for processing).

The client app periodically queries "placedOrders" and notifies users of any orders that have not yet been received.

To aid in frontend development, the app would likely implement some ORM-like wrappers and helper functions, e.g. an "order" object that directly contains a list of items (to simplify view rendering) and functions to add, remove, or update items in a draft order (to simplify writing back to the store).

Syncing and permissions

Let "bluebottle" be the blessing for the administrator/owner of the store.

In all cases, both "bluebottle" and user can have syncgroup admin (sgA) permissions to make adding new devices more flexible.