@peabody-soft/mbs-protos 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Attachment.proto CHANGED
@@ -7,33 +7,19 @@ import "AttachmentType.proto";
7
7
  import "Entity.proto";
8
8
 
9
9
  // A file (a photo of a business, product or package, for example) attached to an entity.
10
- // Excluded: isPublic, isReadyForSync and isProcessingComplete.
11
- // Not included because it is derived: storageFileName, the name the file is stored under. A client
12
- // needs it to fetch the file, so here is exactly how Attachment.getStorageFileName builds it, from
13
- // the createdAt of this entity, its id, its fileHash and its fileExtension:
14
- //
15
- // "%04d-%02d-%02d-%016X-%s.%s" (Java Attachment.ATTACHMENT_FILE_NAME_FORMAT)
16
- //
17
- // year, month and day the createdAt of this entity, read in UTC. The month is the one
18
- // java.util.Calendar gives and is therefore zero based: January is 00 and
19
- // December is 11, so a file created in September 2026 is stored under
20
- // "2026-08-...". Both ends of the protocol do this, so a client must too.
21
- // id Entity.id, 16 upper case hex digits, zero padded, with no 0x prefix
22
- // fileHash the 16 bytes of fileHash as 32 upper case hex digits
23
- // fileExtension appended after a dot, as it is
24
- //
25
- // The case matters: a blob name is case sensitive. The whole name is one flat name, not a path -
26
- // see UrlAndToken for how a url is built from it.
10
+ // Excluded: isPublic, isReadyForSync, isProcessingComplete.
11
+ // Not included because it is derived: storageFileName, built as "%04d-%02d-%02d-%016X-%s.%s" from
12
+ // this entity's createdAt (UTC, zero based month - September is 08), id (16 upper case hex digits),
13
+ // fileHash (32 upper case hex digits) and fileExtension. Case sensitive; see UrlAndToken for the url.
27
14
  message Attachment {
28
15
 
29
16
  Entity entity = 1;
30
17
 
31
- // Exposed instead of the raw type id held in the category of this attachment
18
+ // The type id, exposed instead of the raw value packed into this attachment's category.
32
19
  AttachmentType attachmentType = 2;
33
20
 
34
- // Id of the entity this file is attached to - a business, a product or a package in this
35
- // protocol. Nothing nests here, so this is how a client finds the photos of an entity. The
36
- // entity type of the owner is the most significant byte of this id (see Constants).
21
+ // Id of the entity this file is attached to - a business, product or package. The most
22
+ // significant byte of this id is the owner's entity type (see Constants).
37
23
  int64 owningEntityId = 3;
38
24
 
39
25
  // MD5 hash of the attached file, exactly Constants.ATTACHMENT_FILE_HASH_SIZE_BYTES bytes long.
package/AuthTokens.proto CHANGED
@@ -5,47 +5,25 @@ option java_package = "com.merabills.server.core.generated";
5
5
 
6
6
  import "AuthenticationMethod.proto";
7
7
 
8
- // The tokens that prove who is making a request. This is serialized into the authorization header
9
- // of every request, the way ServiceProxy.setAuthorizationHeader serializes the Java AuthTokens, so
10
- // it is a credential envelope rather than part of the entity model and never appears in a body.
11
- //
12
- // The three tokens answer different questions: authenticationToken says which person is calling,
13
- // userToken says which MeraBills user that person is, and linkToken says which business they may
14
- // act against. They are parsed in that order and the first is a prerequisite for the second, so a
15
- // userToken is never trusted on its own (Authority.parseUserToken parses the authentication token
16
- // first). A storefront acquires them in that order too - it signs in with an identity provider,
17
- // exchanges that for a user token by calling the profile sync out, and gets a link token per
18
- // business from the BusinessLinks that call returns.
19
- //
20
- // Not included because the server derives it: the subject id, and the phone number, which
21
- // Authority.parseAuthenticationToken reads out of authenticationToken rather than trusting a field.
22
- // A client that knows its own subject id has no reason to send it, and no way to be believed if it
23
- // did.
24
- //
25
- // Every value here is a bearer credential: never log one, never put one in a url, and hold them
26
- // only for as long as the session lasts.
8
+ // The tokens that prove who is making a request. Serialized into the authorization header of every
9
+ // request, never into a body; every value is a bearer credential - never log or url-encode one.
10
+ // Not included because the server derives it: the subject id and phone number, parsed by the server
11
+ // out of authenticationToken rather than trusted from a field.
27
12
  message AuthTokens {
28
13
 
29
14
  // Which identity provider issued authenticationToken, and so how the server parses it. Always
30
- // set - it selects the parser, and a request whose method has none is refused. There is no
31
- // unspecified value, because zero is FIREBASE.
15
+ // set; there is no unspecified value because zero is FIREBASE.
32
16
  AuthenticationMethod authenticationMethod = 1;
33
17
 
34
18
  // The credential from that identity provider - a Firebase id token when the method is FIREBASE.
35
- // Always set: every request is parsed for a subject, so there is no anonymous form of this
36
- // message. This is not issued by this server, and this server does not renew it; a client
37
- // refreshes it with its identity provider.
19
+ // Always set. Not issued or renewed by this server; refreshed with the identity provider.
38
20
  string authenticationToken = 2;
39
21
 
40
- // Token proving which MeraBills user the subject is, issued and signed by this server, carrying
41
- // the user id and the rights of the caller. Absent until a client has called the profile sync out
42
- // once, and again once it expires, at which point a client calls that again to be given another
43
- // rather than deriving one.
22
+ // Token proving which MeraBills user the subject is, issued and signed by this server. Absent
23
+ // until the profile sync out has been called once, and again once it expires.
44
24
  optional string userToken = 3;
45
25
 
46
- // Token authorizing the caller to act against one business - the BusinessLink.linkToken of that
47
- // business, which a ProfileSyncOutResponse carries. Absent for a request that names no business,
48
- // required for one that does. It is per business, so a client that shows two businesses holds one
49
- // of these for each and sends the one that matches the request.
26
+ // Token authorizing the caller against one business - the BusinessLink.linkToken of that
27
+ // business. Absent for a request that names no business, required for one that does.
50
28
  optional string linkToken = 4;
51
29
  }
@@ -10,10 +10,8 @@ option java_package = "com.merabills.server.core.generated";
10
10
  // always set, so a client never needs one.
11
11
  enum AuthenticationMethod {
12
12
 
13
- // The authentication token is a Firebase id token, and the subject id the server reads out of it
14
- // is a Firebase uid, which is not the same thing as the MeraBills User.entity.id. The userToken
15
- // of an AuthTokens is not a Firebase token - it is issued by this server, whatever method
16
- // authenticated the subject.
13
+ // The authentication token is a Firebase id token; the subject id parsed from it is a Firebase
14
+ // uid, not the same thing as User.entity.id.
17
15
  FIREBASE = 0;
18
16
 
19
17
  // Reserved for internal administrative callers. A storefront never uses this method.
package/Business.proto CHANGED
@@ -5,15 +5,11 @@ option java_package = "com.merabills.server.core.generated";
5
5
 
6
6
  import "Entity.proto";
7
7
 
8
- // A business that a customer can buy from.
9
- // A business contains no other entity: its settings arrive as a Configuration, its photos as
10
- // Attachments whose owningEntityId is this business, and its catalog as the item entities of a
11
- // BusinessSyncOutResponse.
12
- // This is a profile database entity, so it is carried by a ProfileSyncOutResponse - one per business
13
- // the caller is linked to. A BusinessSyncOutResponse carries it as well, for the one business it is
14
- // about, because a client that has not signed in has no profile sync out to read it from.
15
- // Excluded: category (and the BusinessType derived from it), displayNameOld,
16
- // allowJoinWithoutInvitation, forTraining and all Translations fields.
8
+ // A business that a customer can buy from. Contains no other entity: settings arrive as a
9
+ // Configuration, photos as Attachments whose owningEntityId is this business, and the catalog as
10
+ // the item entities of a BusinessSyncOutResponse.
11
+ // Excluded: category (and the derived BusinessType), displayNameOld, allowJoinWithoutInvitation,
12
+ // forTraining, all Translations fields.
17
13
  message Business {
18
14
 
19
15
  Entity entity = 1;
@@ -6,32 +6,21 @@ option java_package = "com.merabills.server.core.generated";
6
6
  import "Entity.proto";
7
7
  import "Role.proto";
8
8
 
9
- // Associates an entity - a user or a business - with a business, in a particular role. This is what
10
- // tells a signed in customer which businesses they are a customer of, and it carries the token that
11
- // lets them act against each one.
12
- //
13
- // A business link lives in a profile database, alongside the User and the Business entities it names,
14
- // so it is carried by a ProfileSyncOutResponse and never by a BusinessSyncOutResponse.
15
- //
16
- // Excluded: invitationDetails - the name of the inviter, the note they wrote and the rest of it are
17
- // about accepting an invitation, which is not part of a storefront.
18
- // Not included because they are derived from expiry: isExpirySet and hasExpired.
9
+ // Associates an entity - a user or a business - with a business, in a role, and carries the token
10
+ // that lets it act against that business. Lives in a profile database; carried by a
11
+ // ProfileSyncOutResponse, never by a BusinessSyncOutResponse.
12
+ // Excluded: invitationDetails.
13
+ // Not included because it is derived from expiry: isExpirySet, hasExpired.
19
14
  message BusinessLink {
20
15
 
21
16
  Entity entity = 1;
22
17
 
23
- // Id of the entity this link is for: a user or a business, and nothing else. The entity type is
24
- // the most significant byte of this id (Constants.USER_ENTITY_TYPE_ID or
25
- // Constants.BUSINESS_ENTITY_TYPE_ID), which is how a client tells the two apart. For a storefront
26
- // this is the User of the caller.
18
+ // Id of the entity this link is for - a user or a business. The most significant byte of this id
19
+ // (Constants.USER_ENTITY_TYPE_ID or Constants.BUSINESS_ENTITY_TYPE_ID) says which.
27
20
  int64 linkedEntityId = 2;
28
21
 
29
- // Id of the business this link is to.
30
- //
31
- // This is an entity id, so it matches Business.entity.id - not Business.businessId, which is the
32
- // lower case url friendly string a storefront is reached by. The Java accessors are both called
33
- // getBusinessId and return different things (a long here, a String on Business), so this is easy to
34
- // get wrong.
22
+ // Id of the business this link is to - an entity id, matching Business.entity.id, not
23
+ // Business.businessId (the url friendly string).
35
24
  int64 businessId = 3;
36
25
 
37
26
  // What the linked entity may do with the business. A storefront customer is normally
@@ -39,21 +28,14 @@ message BusinessLink {
39
28
  Role role = 4;
40
29
 
41
30
  // Id of the party record of the linked entity within that business, or Constants.ENTITY_ID_NULL
42
- // when there is none. A Party is not generated by this protocol, so this id cannot be resolved by
43
- // a storefront; it is here because it is a field of the Java class and because the server needs it.
44
- // Every role outside the partner group has one.
31
+ // when there is none. Not resolvable by a storefront - Party is not generated by this protocol.
45
32
  int64 partyId = 5;
46
33
 
47
- // Token proving that the linked entity may act against this business. This is what goes into
48
- // AuthTokens.linkToken of every later request that names the business.
49
- //
50
- // It is a bearer credential: never log it, never put it in a URL, and never show it to anyone but
51
- // the entity it was issued to. It is not one of the stored attributes of the entity - the server
52
- // issues it - so a link that arrives without one cannot be used to reach the business.
34
+ // Bearer credential proving the linked entity may act against this business - goes into
35
+ // AuthTokens.linkToken of every later request naming it. Never log it or put it in a url.
53
36
  optional string linkToken = 6;
54
37
 
55
- // Time after which this link is no longer valid, in milliseconds since Jan 1, 1970 00:00:00 UTC.
56
- // BusinessLink.NO_EXPIRY (0) means it does not expire. A client must compare this against its own
57
- // clock, so allow for Constants.MAX_CLOCK_SKEW before deciding a link has expired.
38
+ // Time this link stops being valid, in milliseconds since Jan 1, 1970 00:00:00 UTC.
39
+ // 0 (BusinessLink.NO_EXPIRY) means it never expires; allow for Constants.MAX_CLOCK_SKEW.
58
40
  int64 expiry = 7;
59
41
  }
@@ -5,38 +5,18 @@ option java_package = "com.merabills.server.core.generated";
5
5
 
6
6
  import "Message.proto";
7
7
 
8
- // A request to sync in the entities a customer has changed: their shopping cart, and the orders
9
- // they place from it. This is the counterpart of BusinessSyncOutRequest and mirrors the Java sync in
10
- // (Service.businessSyncIn, which takes the Entity[][] that BusinessDb.syncInToMaster authorizes a
11
- // table at a time): entities travel flat, one array per entity type, and nothing is nested.
12
- //
13
- // This writes one business database, which is what it is named after. A message is a business entity
14
- // even though the customer sent it, so the cart and the orders belong here; the profile of the
15
- // customer does not, and is written by a sync in of its own.
16
- //
17
- // Who is asking is not part of this message: it is in the AuthTokens of the authorization header. The
18
- // server authorizes each array against the rights of that caller - messages against
19
- // Right.MESSAGES_MODIFY - so a client cannot push an entity type it has no right to, and a
20
- // storefront customer may push only their own messages.
21
- //
22
- // An entity being synced in carries the id it already has, or Constants.ENTITY_ID_NULL when the
23
- // client is creating it and the server is to assign one. The update numbers of the incoming
24
- // entities are the client's own and are not comparable with the server's: the server assigns new
25
- // ones and returns them in the BusinessSyncInResponse.
8
+ // Pushes the business entities a customer has changed - their shopping cart and the orders placed
9
+ // from it - to one business database, named the same way a BusinessSyncOutRequest names it.
10
+ // An entity being synced in carries the id it already has, or Constants.ENTITY_ID_NULL if the
11
+ // caller is creating it and the server is to assign one; incoming update numbers are the caller's
12
+ // own and are replaced by the server, which returns the new ones in the BusinessSyncInResponse.
26
13
  message BusinessSyncInRequest {
27
14
 
28
- // The business these entities belong to, named by its unique, lower case, url friendly id - the
29
- // same Business.businessId that BusinessSyncOutRequest names
30
- // (Constants.BUSINESS_ID_MIN_LENGTH to Constants.BUSINESS_ID_MAX_LENGTH)
15
+ // The business these entities belong to - its unique, lower case, url friendly id
16
+ // (Constants.BUSINESS_ID_MIN_LENGTH to Constants.BUSINESS_ID_MAX_LENGTH).
31
17
  string businessId = 1;
32
18
 
33
- // The shopping cart of the customer (a message whose payload is a PartyPreferencesPayload) and
34
- // the orders they place (a payload of SalesOrderPayload) - entity type
35
- // Constants.MESSAGE_ENTITY_TYPE_ID.
36
- //
37
- // This is the only entity type a storefront may push. A customer does not edit the business, its
38
- // settings, its catalog or its photos, and their own User lives in a profile database that this
39
- // call does not touch - so there is deliberately no field for any of those types here, rather
40
- // than a field the server would reject.
19
+ // The shopping cart (a PartyPreferencesPayload) and orders (a SalesOrderPayload) of the customer -
20
+ // entity type Constants.MESSAGE_ENTITY_TYPE_ID, the only entity type a customer may push.
41
21
  repeated Message messages = 2;
42
22
  }
@@ -3,21 +3,19 @@ package com.merabills.storefront;
3
3
  option java_multiple_files = true;
4
4
  option java_package = "com.merabills.server.core.generated";
5
5
 
6
- // The answer to a BusinessSyncInRequest: the update number the server assigned to the entities that
7
- // were pushed, one per entity type, the way Java sync in returns the long[] of max incoming update
8
- // numbers that BusinessDb.syncIn produces, indexed by table entity type id.
9
- //
10
- // A client raises its cursor for that entity type to the number below, so that the next
11
- // BusinessSyncOutRequest does not fetch back what it has just sent. Zero means nothing of that type
12
- // was accepted, which is what a request that carried none of them gets back.
13
- //
14
- // This response carries no entities. A client that needs the server's view of what it pushed - the
15
- // id assigned to an entity the server created, or the authoritative totals of a shopping list,
16
- // which are computed with the rounding rules of PriceCalculation - syncs out again afterwards.
6
+ import "AuthTokens.proto";
7
+
8
+ // The answer to a BusinessSyncInRequest: the update number the server assigned to the pushed
9
+ // entities, one per entity type. Raise the matching cursor to this value so the next sync out does
10
+ // not fetch back what was just sent; 0 means nothing of that type was accepted. Carries no entities
11
+ // - sync out again to see the server's view of what was pushed.
17
12
  message BusinessSyncInResponse {
18
13
 
19
- // The highest update number the server assigned to the messages of the request - entity type
20
- // Constants.MESSAGE_ENTITY_TYPE_ID. There is one field per entity type that
21
- // BusinessSyncInRequest can carry, and messages are the only one.
22
- int64 messageUpdateNumber = 1;
14
+ // The tokens to send with the next request, when the server has renewed one of them. Absent means
15
+ // what the client already holds still works - never a signal to drop the tokens it has.
16
+ optional AuthTokens authTokens = 1;
17
+
18
+ // Highest update number assigned to the messages of the request - entity type
19
+ // Constants.MESSAGE_ENTITY_TYPE_ID, the only entity field this response carries.
20
+ int64 messageUpdateNumber = 2;
23
21
  }
@@ -3,98 +3,40 @@ package com.merabills.storefront;
3
3
  option java_multiple_files = true;
4
4
  option java_package = "com.merabills.server.core.generated";
5
5
 
6
- // A request to sync out everything a storefront needs of one business: the Business, its settings, its
7
- // catalog and the messages of the customer. This is an incremental sync, so the request carries a
8
- // cursor per entity type and the BusinessSyncOutResponse carries only what has changed since, flat,
9
- // for the client to reassemble.
10
- //
11
- // This reads one business database, which is why there is no cursor for the User of the caller and no
12
- // User in the response: a user lives in a profile database and is read by a ProfileSyncOutRequest, the
13
- // way Java splits Service.businessSyncOut from Service.profileSyncOut.
14
- //
15
- // A Business is a profile database entity too, but it is carried here as well, because a client that
16
- // has not signed in has no profile sync out to read it from and would otherwise not know the name or
17
- // the country of the business it is showing. So businessUpdateNumber below and
18
- // ProfileSyncOutRequest.businessUpdateNumber are cursors over the same entity type kept by two
19
- // different calls: a client keeps one per call and must not carry a number from one over to the other.
20
- //
21
- // Who is asking is not part of this message: it is in the AuthTokens of the authorization header,
22
- // whose linkToken is the BusinessLink.linkToken of the business named below.
23
- //
24
- // The store it is asking on behalf of is, in clientDatabaseId below. A storefront keeps a
25
- // persistent store, so it is a database in the sync topology and has an id of its own, and the
26
- // server needs that id to know which changes not to send back. This is the requestingDbId argument
27
- // of Service.businessSyncOut, which the Java clients pass as the db-id query parameter
28
- // (HttpQueryParameters.DATABASE_ID) rather than in the body; a storefront carries it here instead,
29
- // so that one protobuf message says everything a sync out needs.
30
- //
31
- // Each cursor below is the highest Entity.updateNumber of that entity type that this client has
32
- // already synced out. The server sends back the entities of that type whose updateNumber is
33
- // greater, so a client stores the highest updateNumber it receives per type and sends it back on
34
- // the next call. Zero, the default, means this client has nothing yet and asks for everything -
35
- // a first sync therefore leaves every cursor unset.
36
- //
37
- // One field below is not a cursor: attachmentBaseUrlExpiry is a time, and it asks for a value rather
38
- // than for entities. It is here because the files of the attachments of a business are read from a
39
- // url that expires, and renewing it in this call costs nothing, where a call of its own would cost a
40
- // round trip on every sync.
41
- //
42
- // Sync out is bounded: one call returns at most Constants.SYNC_OUT_LIMIT entities across all types
43
- // together. On receiving that many, a client must call again with its updated cursors until it
44
- // receives fewer.
45
- //
46
- // There is one cursor per entity type that has a table of its own, which is how updateNumbers are
47
- // kept, and not one per class: the product categories, products, packages, price lists and prices
48
- // of a catalog are all item entities and all share itemUpdateNumber. Update numbers are only
49
- // comparable within one entity type, and only against the same server.
6
+ // Reads everything a storefront needs of one business: the Business, its settings, catalog and
7
+ // messages, flat for the client to reassemble. Incremental and bounded: each cursor is the highest
8
+ // Entity.updateNumber of that type already synced (0 asks for everything), and a response of
9
+ // Constants.SYNC_OUT_LIMIT entities means call again with the updated cursors. The caller and the
10
+ // business's link token are in the AuthTokens of the authorization header, not in this message.
50
11
  message BusinessSyncOutRequest {
51
12
 
52
- // The business to sync out, named by its unique, lower case, url friendly id - the same
53
- // Business.businessId that the storefront was reached by
54
- // (Constants.BUSINESS_ID_MIN_LENGTH to Constants.BUSINESS_ID_MAX_LENGTH)
13
+ // The business to sync out, by its unique, lower case, url friendly id (Constants.BUSINESS_ID_MIN_LENGTH
14
+ // to Constants.BUSINESS_ID_MAX_LENGTH).
55
15
  string businessId = 1;
56
16
 
57
- // Id of the store this client keeps, which is what makes an incremental sync out incremental in
58
- // both directions: the server compares it against the Entity.updateInfo of every candidate
59
- // entity and leaves out the ones this client wrote itself, because it already has them.
60
- //
61
- // A client generates this once and keeps it for the life of its store. It is never
62
- // Constants.MASTER_DB_ID, which is the server, and never a reserved id, so a client that sends
63
- // zero is claiming to be the server and will be sent its own writes back on every sync.
64
- //
65
- // The same value goes into the Entity.updateInfo of everything this client pushes in a
66
- // BusinessSyncInRequest. There is no such field on that request, because there the id arrives on
67
- // each entity instead.
17
+ // Id of the store this client keeps; never Constants.MASTER_DB_ID or another reserved id. The
18
+ // server leaves out entities whose Entity.updateInfo matches this, so a client does not get its
19
+ // own writes back, and this same id goes into every entity a client pushes in a BusinessSyncInRequest.
68
20
  int64 clientDatabaseId = 2;
69
21
 
70
- // The business - entity type Constants.BUSINESS_ENTITY_TYPE_ID
22
+ // Cursor for the Business entity (Constants.BUSINESS_ENTITY_TYPE_ID). Separate from, and never
23
+ // mixed with, ProfileSyncOutRequest.businessUpdateNumber.
71
24
  int64 businessUpdateNumber = 3;
72
25
 
73
- // The photos of the business, its products and its packages - entity type
74
- // Constants.ATTACHMENT_ENTITY_TYPE_ID
26
+ // Cursor for photos of the business, its products and its packages (Constants.ATTACHMENT_ENTITY_TYPE_ID).
75
27
  int64 attachmentUpdateNumber = 4;
76
28
 
77
- // The expiry of the attachment base url and token this client is holding - the UrlAndToken.expiry
78
- // of the last BusinessSyncOutResponse.attachmentBaseUrl it received, sent back unchanged. Zero,
79
- // the default, means this client holds none and is asking for one, which is what a first sync
80
- // does.
81
- //
82
- // The server answers with a new attachmentBaseUrl when this is zero, or within
83
- // Constants.ATTACHMENT_BASE_URL_EXPIRY_MARGIN of the time it reads the request, and leaves it
84
- // absent otherwise. This is a time and not an update number: it is not comparable with the cursors
85
- // around it, it does not rise monotonically, and a client must never derive it from anything but
86
- // the UrlAndToken it holds.
29
+ // The UrlAndToken.expiry of the attachment base url this client is holding, sent back unchanged;
30
+ // 0 means it holds none. A time, not a cursor - it does not rise monotonically.
87
31
  int64 attachmentBaseUrlExpiry = 5;
88
32
 
89
- // The settings of the business, which are held in a configuration entity - entity type
90
- // Constants.CONFIGURATION_ENTITY_TYPE_ID
33
+ // Cursor for the business's settings (Constants.CONFIGURATION_ENTITY_TYPE_ID).
91
34
  int64 configurationUpdateNumber = 6;
92
35
 
93
- // The orders of the customer and their shopping cart - entity type
94
- // Constants.MESSAGE_ENTITY_TYPE_ID
36
+ // Cursor for the customer's orders and shopping cart (Constants.MESSAGE_ENTITY_TYPE_ID).
95
37
  int64 messageUpdateNumber = 7;
96
38
 
97
- // The whole catalog: product categories, products, packages, price lists and prices, which are
98
- // all item entities and share this one cursor - entity type Constants.ITEM_ENTITY_TYPE_ID
39
+ // Cursor for the whole catalog - product categories, products, packages, price lists and prices,
40
+ // which all share this one cursor (Constants.ITEM_ENTITY_TYPE_ID).
99
41
  int64 itemUpdateNumber = 8;
100
42
  }
@@ -4,6 +4,7 @@ option java_multiple_files = true;
4
4
  option java_package = "com.merabills.server.core.generated";
5
5
 
6
6
  import "Attachment.proto";
7
+ import "AuthTokens.proto";
7
8
  import "Business.proto";
8
9
  import "Configuration.proto";
9
10
  import "Message.proto";
@@ -14,96 +15,44 @@ import "Product.proto";
14
15
  import "ProductCategory.proto";
15
16
  import "UrlAndToken.proto";
16
17
 
17
- // The answer to a BusinessSyncOutRequest: the entities of one business that have changed since the
18
- // update numbers the request carried, one field per entity type, the way Database.syncOut returns its
19
- // two dimensional array of entities. Nothing is nested, and no entity contains another, because an
20
- // incremental sync sends only what changed - a tree could not say which of its collections are
21
- // complete, where a deleted entity belongs, or that a product has moved to another category.
22
- //
23
- // The five repeated item types, the attachments, the configurations and the messages are what Java
24
- // keeps in a business database (EntityType with DbType.BUSINESS). The Business below is not: like the
25
- // User and the BusinessLink, it is a profile database entity. It is carried here anyway, because a
26
- // client that has not signed in has no profile sync out to read it from and would otherwise not know
27
- // the name or the country of the business it is showing. The User and the BusinessLink are not, because
28
- // an anonymous client has neither.
29
- //
30
- // A type of which there can only ever be one is a single message rather than an array, so that its
31
- // presence carries the same "changed or not" information an array carries by being empty: the
32
- // request names one business.
33
- //
34
- // Every field below is an entity of that business except one: attachmentBaseUrl is a value, and the
35
- // only thing here that a client does not put in its cache and does not count against
36
- // Constants.SYNC_OUT_LIMIT. It answers BusinessSyncOutRequest.attachmentBaseUrlExpiry rather than an
37
- // update number, it can never be a tombstone, and it says where the files of the attachments are
38
- // rather than what has changed.
39
- //
40
- // A client reconstructs the hierarchy itself, from the ids the entities carry:
41
- // Business the business the request named
42
- // Configuration its settings, by Entity.id
43
- // Attachment its owner is owningEntityId - a business, a product or a package. Its
44
- // file is under attachmentBaseUrl, under the storage file name that
45
- // Attachment says how to build.
46
- // Message its sender is senderId, which names a User of the profile database
47
- // ProductCategory a category of the catalog
48
- // Product its category is Item.parentItemId, or none when that is 0
49
- // Package its product is Item.parentItemId
50
- // PriceList the price list the business sells from. It has no parent, and there is
51
- // only ever one of it in a response.
52
- // Price its package is packageId; its price list is Item.parentItemId
53
- // Process the arrays in the order they are declared below: a parent always arrives in an earlier
54
- // array than its children, so nothing has to be resolved twice.
55
- //
56
- // An entity may be a tombstone rather than a value: when
57
- // (updateNumber & Constants.UPDATE_TYPE_MASK) == Constants.UPDATE_TYPE_DELETED the entity has been
58
- // deleted and the client must drop it and everything it owned. Only the Entity of a tombstone is
59
- // meaningful.
60
- //
61
- // An entity type that has not changed is simply absent - an empty array, or an unset business.
62
- // Absence says nothing about the entities of that type a client already holds; only an entity that
63
- // arrives, or a tombstone, changes anything. So a client keeps its previous update number for an
64
- // absent type.
65
- //
66
- // One response carries at most Constants.SYNC_OUT_LIMIT entities across all arrays together. On
67
- // receiving that many, a client raises each update number to the highest it has seen for that type
68
- // and requests again, until it receives fewer.
69
- //
70
- // Java keys its array of arrays by table entity type id. The five item types below share the item
71
- // table, and therefore BusinessSyncOutRequest.itemUpdateNumber, but are separate arrays here because a
72
- // protobuf repeated field cannot hold a mixture of types.
18
+ // The answer to a BusinessSyncOutRequest: the entities of one business that changed since the
19
+ // request's update numbers, one field per entity type, flat - a client rebuilds the hierarchy from
20
+ // Item.parentItemId, Attachment.owningEntityId and Price.packageId, processing the arrays below in
21
+ // order (parent before child). An absent/empty field means that type has not changed; a tombstone
22
+ // (updateNumber's update-type bits = Constants.UPDATE_TYPE_DELETED) means the entity, and what it
23
+ // owned, was deleted. At most Constants.SYNC_OUT_LIMIT entities arrive together - that many means
24
+ // call again with the raised cursors.
73
25
  message BusinessSyncOutResponse {
74
26
 
75
- // The business named by the request. Absent unless it has changed. Also carried, along with the
76
- // links to it, by a ProfileSyncOutResponse - the same entity from two calls, each with its own
77
- // cursor.
78
- Business business = 1;
27
+ // The tokens to send with the next request, when the server has renewed one of them. Absent means
28
+ // what the client already holds still works - never a signal to drop the tokens it has.
29
+ optional AuthTokens authTokens = 1;
79
30
 
80
- // Photos of the business, its products and its packages
81
- repeated Attachment attachments = 2;
31
+ // The business named by the request. Absent unless it has changed. Also carried by a
32
+ // ProfileSyncOutResponse, with its own separate cursor - keep the two update numbers apart.
33
+ Business business = 2;
82
34
 
83
- // Where the files of those photos are, and the token that authorizes reading them.
84
- //
85
- // Absent when the expiry in BusinessSyncOutRequest.attachmentBaseUrlExpiry is still further away
86
- // than Constants.ATTACHMENT_BASE_URL_EXPIRY_MARGIN, which means the one the client holds is good
87
- // and is to be kept. So, unlike an absent entity array, absence here is not "nothing changed" but
88
- // "what you have still works". A client that holds none sends zero and always gets one back.
89
- //
90
- // This is not per attachment: one container holds the files of every attachment of the business,
91
- // so one of these serves the whole response and every attachment already cached. A client
92
- // therefore stores it once, against the business, and not against a photo.
93
- UrlAndToken attachmentBaseUrl = 3;
35
+ // Photos of the business, its products and its packages.
36
+ repeated Attachment attachments = 3;
37
+
38
+ // Where the files of every attachment of the business are, and the token that authorizes reading
39
+ // them - one value for the whole business, not per photo. Absent means what the client already
40
+ // holds still works; a client holding none sends 0 and always gets one back. Never a tombstone and
41
+ // never counted against Constants.SYNC_OUT_LIMIT.
42
+ UrlAndToken attachmentBaseUrl = 4;
94
43
 
95
44
  // The settings of the business. An array because a business can have more than one public
96
45
  // configuration, even though only the general settings are typed today.
97
- repeated Configuration configurations = 4;
46
+ repeated Configuration configurations = 5;
98
47
 
99
48
  // The orders of the customer, and their shopping cart
100
- repeated Message messages = 5;
49
+ repeated Message messages = 6;
101
50
 
102
51
  // Item entities, in the order a client needs them: a category before its products, a product
103
52
  // before its packages, and both a package and a price list before the prices that name them
104
- repeated ProductCategory productCategories = 6;
105
- repeated Product products = 7;
106
- repeated Package packages = 8;
107
- repeated PriceList priceLists = 9;
108
- repeated Price prices = 10;
53
+ repeated ProductCategory productCategories = 7;
54
+ repeated Product products = 8;
55
+ repeated Package packages = 9;
56
+ repeated PriceList priceLists = 10;
57
+ repeated Price prices = 11;
109
58
  }
@@ -6,13 +6,10 @@ option java_package = "com.merabills.server.core.generated";
6
6
  import "Entity.proto";
7
7
  import "GeneralSettings.proto";
8
8
 
9
- // A setting of a business, and its value. In Java the value is a serialized string whose meaning is
10
- // determined by the id of the configuration; it is typed here, the same way a Message payload is.
11
- //
12
- // Which configuration this is is its Entity.id. Only public configurations - those with an id at or
13
- // above Configuration.MIN_PUBLIC_CONFIGURATION_ID - are ever sent to a storefront, and of those
14
- // only the general settings, whose id is 0x0D10000000000000 (941252322120433664). A client does not
15
- // need that id: it switches on which member of data is set.
9
+ // A setting of a business, identified by Entity.id, with its value typed here rather than left as
10
+ // the serialized string Java stores. Only public configurations (id at or above
11
+ // Configuration.MIN_PUBLIC_CONFIGURATION_ID) are ever sent; a client switches on which member of
12
+ // data is set rather than checking the id.
16
13
  message Configuration {
17
14
 
18
15
  Entity entity = 1;