Summary
Define a simpler, developer_facing Android SDK interface around three concepts__
_ Project — identifies one app or product owned by the developer.
_ Collection — a logical searchable index inside that project.
_ Stream — a source or grouping inside the collection.
This interface should hide the backend's current two_level collection/sub_collection structure.
Motivation
Backend_oriented names such as tenant_id and end_userid are difficult to apply consistently across different mobile applications. Not every app has an end_user_specific index; some apps need one global index, while others need an isolated index per end user.
Developers should be able to organize VModal data according to their application's domain without needing to understand the backend storage layout.
Proposed public terminology
| SDK concept | Meaning | Examples |
| ___ | ___ | ___ |
| projectId | Developer_owned app or product | food_app, shopping_app |
| collectionName | Logical searchable index | global, user_123, product_catalog |
| streamName | Source/group within a collection | uploads, camera, favorites |
projectId is intentionally different from userId__ in a mobile SDK, userId normally means the app's end user. Authentication identity fields can remain internal/separate from this content_organization interface.
Proposed Kotlin interface
Illustrative developer_facing API__
VModal.configure(
projectId = "food_app",
apiKey = apiKey,
)
VModal.setCollection("user_123")
VModal.setStream("favorites")
The current selection is then used by upload, indexing, and search operations__
VModal.upload(video)
VModal.search("birthday dinner")
An equivalent immutable/scoped API is acceptable if it is safer for concurrent Android work, provided the developer_facing terminology and usage remain simple__
val vmodal = VModal.configure(
projectId = "food_app",
apiKey = apiKey,
)
val favorites = vmodal.scope(
collectionName = "user_123",
streamName = "favorites",
)
favorites.upload(video)
favorites.search("birthday dinner")
This avoids one process_wide mutable collection when multiple users, workers, or simultaneous operations are active.
Internal API mapping
Enforce rules inside the SDK
collection_name __ only a_z A_Z 0_9 `_` characters. and 80 characters max
stream_name __ only a_z A_Z 0_9 `_` characters. and 80 characters max
enforce those rules and raise error if developper input wrong ones.
The backend currently supports only two hierarchy levels. The SDK should synthesize the project level by prefixing the collection__
## SDK__
projectId = "food_app"
collectionName = "user_123"
streamName = "favorites"
## Backend/API__
## aggregate by 2 `_` __ `__` underscore ...
collection_name = "food_app__user_123"
stream_name = "favorites"
Conceptually__
projectId + "__" + collectionName _> backend collection
streamName _> backend sub_collection/stream
The encoding must be centralized inside the SDK so callers never construct the composite name themselves. The implementation should either reject the reserved separator in project/collection names or use an escaping scheme to prevent collisions.
Reference use cases
1. Global search index
A Google Search_style app has one central index containing all searchable videos/assets__
val search = VModal.configure(
projectId = "video_search",
apiKey = apiKey,
).scope(
collectionName = "global",
streamName = "uploads",
)
search.upload(video)
search.search("red bicycle near a bridge")
Backend collection__ video_search__global
2. Private index per end user
Each app user has an isolated searchable index__
val personal = VModal.configure(
projectId = "food_app",
apiKey = apiKey,
).scope(
collectionName = "user__$endUserId",
streamName = "personal_videos",
)
personal.upload(video)
personal.search("pasta recipe")
Backend collection example__ food_app__user_123
The end_user identifier is an application concern expressed through collectionName; it is not a mandatory SDK concept.
3. Multiple streams for one user
One user collection can separate assets by source or purpose__
val app = VModal.configure(
projectId = "food_app",
apiKey = apiKey,
)
val camera = app.scope("user_123", "camera")
val favorites = app.scope("user_123", "favorites")
val uploads = app.scope("user_123", "uploads")
All three use backend collection food_app__user_123, with different stream_name values.
4. Product catalog
A commerce app can organize indexes by business domain rather than by end user__
val catalog = VModal.configure(
projectId = "shopping_app",
apiKey = apiKey,
).scope(
collectionName = "product_catalog",
streamName = "merchant_uploads",
)
Backend collection__ shopping_app__product_catalog
5. Multiple developer projects
The same developer can use separate project IDs for different apps__
val foodApp = VModal.configure("food_app", foodAppApiKey)
val shoppingApp = VModal.configure("shopping_app", shoppingAppApiKey)
Their logical collection names may be identical without colliding because the project ID is included in the backend collection name.
Behavioral expectations
_ projectId is required when configuring the SDK.
_ collectionName is required for collection_bound upload, indexing, and search operations.
_ streamName has an explicitly documented default or is required; it must not silently vary between operations.
_ Values are trimmed and validated consistently.
_ The SDK constructs the backend collection name in one internal helper.
_ Upload, indexing, search, listing, and deletion use the same mapping.
_ Public errors and documentation use project/collection/stream terminology.
_ Authentication identity remains separate from project/content organization.
_ The design works safely when multiple scopes or users are active concurrently.
_ Existing APIs receive a documented migration/deprecation path.
Open implementation decisions
_ Choose the final class/facade name__ VModal versus the existing Client.
_ Choose a stateful setter interface versus an immutable scope(...) interface. The scoped form is preferable for thread safety, but both examples document the intended developer experience.
_ Define allowed characters and maximum lengths for all three names.
_ Decide whether streamName should default to a stable value such as "default".
_ Define how listing APIs remove the projectId__ prefix before returning collection names to SDK callers.
Acceptance criteria
_ [ ] Public API specification is agreed for project, collection, and stream selection.
_ [ ] projectId + collectionName maps deterministically to the backend collection_name.
_ [ ] streamName maps to the backend stream/sub_collection level.
_ [ ] Callers never need to build or parse projectId__collectionName.
_ [ ] Global_index, per_user_index, multi_stream, catalog, and multi_project use cases are covered.
_ [ ] Naming validation and separator collision behavior are documented.
_ [ ] Authentication identity and content organization are kept conceptually separate.
_ [ ] A backward_compatibility/deprecation plan is documented before implementation.
Summary
Define a simpler, developer_facing Android SDK interface around three concepts__
_ Project — identifies one app or product owned by the developer.
_ Collection — a logical searchable index inside that project.
_ Stream — a source or grouping inside the collection.
This interface should hide the backend's current two_level collection/sub_collection structure.
Motivation
Backend_oriented names such as
tenant_idandend_useridare difficult to apply consistently across different mobile applications. Not every app has an end_user_specific index; some apps need one global index, while others need an isolated index per end user.Developers should be able to organize VModal data according to their application's domain without needing to understand the backend storage layout.
Proposed public terminology
| SDK concept | Meaning | Examples |
| ___ | ___ | ___ |
|
projectId| Developer_owned app or product |food_app,shopping_app||
collectionName| Logical searchable index |global,user_123,product_catalog||
streamName| Source/group within a collection |uploads,camera,favorites|projectIdis intentionally different fromuserId__ in a mobile SDK,userIdnormally means the app's end user. Authentication identity fields can remain internal/separate from this content_organization interface.Proposed Kotlin interface
Illustrative developer_facing API__
The current selection is then used by upload, indexing, and search operations__
An equivalent immutable/scoped API is acceptable if it is safer for concurrent Android work, provided the developer_facing terminology and usage remain simple__
This avoids one process_wide mutable collection when multiple users, workers, or simultaneous operations are active.
Internal API mapping
Enforce rules inside the SDK
The backend currently supports only two hierarchy levels. The SDK should synthesize the project level by prefixing the collection__
Conceptually__
The encoding must be centralized inside the SDK so callers never construct the composite name themselves. The implementation should either reject the reserved separator in project/collection names or use an escaping scheme to prevent collisions.
Reference use cases
1. Global search index
A Google Search_style app has one central index containing all searchable videos/assets__
Backend collection__
video_search__global2. Private index per end user
Each app user has an isolated searchable index__
Backend collection example__
food_app__user_123The end_user identifier is an application concern expressed through
collectionName; it is not a mandatory SDK concept.3. Multiple streams for one user
One user collection can separate assets by source or purpose__
All three use backend collection
food_app__user_123, with differentstream_namevalues.4. Product catalog
A commerce app can organize indexes by business domain rather than by end user__
Backend collection__
shopping_app__product_catalog5. Multiple developer projects
The same developer can use separate project IDs for different apps__
Their logical collection names may be identical without colliding because the project ID is included in the backend collection name.
Behavioral expectations
_
projectIdis required when configuring the SDK._
collectionNameis required for collection_bound upload, indexing, and search operations._
streamNamehas an explicitly documented default or is required; it must not silently vary between operations._ Values are trimmed and validated consistently.
_ The SDK constructs the backend collection name in one internal helper.
_ Upload, indexing, search, listing, and deletion use the same mapping.
_ Public errors and documentation use project/collection/stream terminology.
_ Authentication identity remains separate from project/content organization.
_ The design works safely when multiple scopes or users are active concurrently.
_ Existing APIs receive a documented migration/deprecation path.
Open implementation decisions
_ Choose the final class/facade name__
VModalversus the existingClient._ Choose a stateful setter interface versus an immutable
scope(...)interface. The scoped form is preferable for thread safety, but both examples document the intended developer experience._ Define allowed characters and maximum lengths for all three names.
_ Decide whether
streamNameshould default to a stable value such as"default"._ Define how listing APIs remove the
projectId__prefix before returning collection names to SDK callers.Acceptance criteria
_ [ ] Public API specification is agreed for project, collection, and stream selection.
_ [ ]
projectId + collectionNamemaps deterministically to the backendcollection_name._ [ ]
streamNamemaps to the backend stream/sub_collection level._ [ ] Callers never need to build or parse
projectId__collectionName._ [ ] Global_index, per_user_index, multi_stream, catalog, and multi_project use cases are covered.
_ [ ] Naming validation and separator collision behavior are documented.
_ [ ] Authentication identity and content organization are kept conceptually separate.
_ [ ] A backward_compatibility/deprecation plan is documented before implementation.