diff --git a/README.md b/README.md index 531cafb..30a220a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## Usage -### Generate clients with [buf](https://buf.build/): +### Generate clients with [buf](https://buf.build/) Ensure [buf](https://buf.build/docs/installation) and [protoc](https://grpc.io/docs/protoc-installation/) are installed on your system. @@ -10,9 +10,9 @@ Ensure [buf](https://buf.build/docs/installation) and [protoc](https://grpc.io/d buf dep update ./proto ``` -#### Rust (tonic): +#### Rust (tonic) -##### Dependencies: +##### Dependencies Install "protoc-gen-\*" with cargo. @@ -22,7 +22,7 @@ cargo install protoc-gen-prost-crate cargo install protoc-gen-tonic ``` -##### Generate: +##### Generate ```sh buf generate proto --template proto/buf.gen.rust.yaml @@ -32,9 +32,9 @@ buf generate proto --template proto/buf.gen.rust.yaml Outputs will be in out/ directory. -#### Typescript in Browser: +#### Typescript in Browser -##### Dependencies: +##### Dependencies Install "protoc-gen-\*" with npm. @@ -42,7 +42,7 @@ Install "protoc-gen-\*" with npm. npm install -g ts-proto ``` -##### Generate: +##### Generate ```sh buf generate proto --template proto/buf.gen.ts.yaml @@ -54,7 +54,7 @@ Outputs will be in services/ directory. ### Proto linter -#### Dependencies: +#### Dependencies Install protolint with npx. @@ -62,7 +62,7 @@ Install protolint with npx. npx protolint ``` -#### Lint: +#### Lint ```sh protolint lint proto @@ -79,8 +79,11 @@ When using "vscode-proto3" extention in VS Code, add the following to the '.vsco } } ``` + ## Optionals + how to select only specific proto, use `--path` args + ```sh buf generate proto --template service-apis/proto/buf.gen.py.yaml -o gen --path service-apis/proto/digitalkin/kin --path service-apis/proto/google -``` \ No newline at end of file +``` diff --git a/proto/digitalkin/cost/v1/cost.proto b/proto/digitalkin/cost/v1/cost.proto index 1c8f8db..cdd6f57 100644 --- a/proto/digitalkin/cost/v1/cost.proto +++ b/proto/digitalkin/cost/v1/cost.proto @@ -40,12 +40,18 @@ message Cost { double cost = 1 [(buf.validate.field).required = true]; // mission_id: Mission ID linked to the cost string mission_id = 2 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // name: Name of the cost (unique by mission_id) + // name: Name of the cost string name = 3 [(buf.validate.field).required = true]; - // type: Type of the cost - CostType type = 4 [(buf.validate.field).required = true]; + // cost_type: Type of the cost + CostType cost_type = 4 [(buf.validate.field).required = true]; // unit: Unit of the cost string unit = 5 [(buf.validate.field).required = true]; + // rate: Rate of the cost + double rate = 6 [(buf.validate.field).required = true]; + // setup_version_id: Setup version ID linked to the cost + string setup_version_id = 7 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "setup_versions:"]; + // quantity: Quantity of the cost + double quantity = 8 [(buf.validate.field).required = true]; } // AddCostRequest: Request to add a cost @@ -54,56 +60,58 @@ message AddCostRequest { double cost = 1 [(buf.validate.field).required = true]; // mission_id: Mission ID linked to the cost string mission_id = 2 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // name: Name of the cost (unique by mission_id) + // name: Name of the cost string name = 3 [(buf.validate.field).required = true]; - // type: Type of the cost - CostType type = 4 [(buf.validate.field).required = true]; + // cost_type: Type of the cost + CostType cost_type = 4 [(buf.validate.field).required = true]; // unit: Unit of the cost string unit = 5 [(buf.validate.field).required = true]; + // rate: Rate of the cost + double rate = 6 [(buf.validate.field).required = true]; + // setup_version_id: Setup version ID linked to the cost + string setup_version_id = 7 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "setup_versions:"]; + // quantity: Quantity of the cost + double quantity = 8 [(buf.validate.field).required = true]; } // AddCostResponse: Response to added cost message AddCostResponse { - // success: Success of the operation - bool success = 1 [(buf.validate.field).required = true]; } -// GetCostsByMissionRequest: Request to get costs by mission -message GetCostsByMissionRequest { - // mission_id: Mission ID linked to the cost - string mission_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; -} -// GetCostsByMissionResponse: Response to get costs by mission -message GetCostsByMissionResponse { - // costs: Costs - repeated Cost costs = 1 [(buf.validate.field).required = true]; +// CostFilter: Filter criteria for costs +message CostFilter { + // names: Filter costs by one or more names + repeated string names = 1; + + // cost_types: Filter costs by cost types + repeated CostType cost_types = 2; } -// GetCostsByNameRequest: Request to get costs by name -message GetCostsByNameRequest { +// GetCostsRequest: Request to get multiple costs +message GetCostsRequest { // mission_id: Mission ID linked to the cost string mission_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // name: Name of the cost (unique by mission_id) - string name = 2 [(buf.validate.field).required = true]; + // filter: Filter criteria for costs + CostFilter filter = 2; } -// GetCostsByNameResponse: Response to get costs by name -message GetCostsByNameResponse { - // costs: Costs - repeated Cost costs = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; +// GetCostsResponse: Response to get multiple costs +message GetCostsResponse { + // costs: List of cost + repeated Cost costs = 1 [(buf.validate.field).required = true]; } -// GetCostsByTypeRequest: Request to get costs by type -message GetCostsByTypeRequest { +// GetCostRequest: Request to get cost by name +message GetCostRequest { // mission_id: Mission ID linked to the cost string mission_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // type: Type of the cost - CostType type = 2 [(buf.validate.field).required = true]; + // name: Name of the cost + string name = 2 [(buf.validate.field).required = true]; } -// GetCostsByTypeResponse: Response to get costs by type -message GetCostsByTypeResponse { - // costs: Costs +// GetCostResponse: Response to get cost by name +message GetCostResponse { + // costs: List of cost repeated Cost costs = 1 [(buf.validate.field).required = true]; -} \ No newline at end of file +} diff --git a/proto/digitalkin/cost/v1/cost_service.proto b/proto/digitalkin/cost/v1/cost_service.proto index aa27d03..84321ca 100644 --- a/proto/digitalkin/cost/v1/cost_service.proto +++ b/proto/digitalkin/cost/v1/cost_service.proto @@ -23,12 +23,9 @@ service CostService { // AddCost: Add a cost rpc AddCost (AddCostRequest) returns (AddCostResponse); - // GetCostsByMission: Get a cost by Mission ID - rpc GetCostsByMission (GetCostsByMissionRequest) returns (GetCostsByMissionResponse); + // GetCost: Get a cost + rpc GetCost (GetCostRequest) returns (GetCostResponse); - // GetCostsByName: Get costs by name - rpc GetCostsByName (GetCostsByNameRequest) returns (GetCostsByNameResponse); - - // GetCostsByType: Get costs by type - rpc GetCostsByType (GetCostsByTypeRequest) returns (GetCostsByTypeResponse); + // GetCosts: Get all costs with filters + rpc GetCosts (GetCostsRequest) returns (GetCostsResponse); } \ No newline at end of file diff --git a/proto/digitalkin/filesystem/v1/data.proto b/proto/digitalkin/filesystem/v1/data.proto deleted file mode 100644 index 815cba4..0000000 --- a/proto/digitalkin/filesystem/v1/data.proto +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2025 DigitalKin Inc. -// -// Licensed under the GNU General Public License, Version 3.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.gnu.org/licenses/gpl-3.0.html -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package digitalkin.filesystem.v1; - -import "buf/validate/validate.proto"; - -// FileType: Enum to file type -enum FileType { - // DOCUMENT: Document file - DOCUMENT = 0; - // IMAGE: Image file - IMAGE = 1; - // VIDEO: Video file - VIDEO = 2; - // AUDIO: Audio file - AUDIO = 3; - // OTHER: Other file - OTHER = 4; -} - -// File: Message to represent stored files -message File { - // mission_id: Mission ID linked to the file - string mission_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // name: Name of the file (unique by mission_id) - string name = 2 [(buf.validate.field).required = true]; - // type: Type of the file - FileType type = 3 [(buf.validate.field).required = true]; - // url: URL to access the file - string url = 4 [(buf.validate.field).required = true]; -} - -// UploadFileRequest: Request to upload a file -message UploadFileRequest { - // mission_id: Mission ID linked to the file - string mission_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // name: Name of the file (unique by mission_id) - string name = 2 [(buf.validate.field).required = true]; - // type: Type of the file - FileType type = 3 [(buf.validate.field).required = true]; - // content: Content of the file - bytes content = 4 [(buf.validate.field).required = true]; -} - -// UploadFileResponse: Response to uploaded file -message UploadFileResponse { - // success: Success of the operation - bool success = 1 [(buf.validate.field).required = true]; - // file: Uploaded file - File file = 2 [(buf.validate.field).required = true]; -} - -// GetFileRequest: Request to get a file by ID -message GetFileRequest { - // mission_id: Mission ID linked to the file - string mission_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // name: Name of the file (unique by mission_id) - string name = 2 [(buf.validate.field).required = true]; -} - -// GetFileResponse: Response to get a file by ID -message GetFileResponse { - // file: Retrieved file - File file = 1 [(buf.validate.field).required = true]; - // content: Content of the file - bytes content = 2 [(buf.validate.field).required = true]; -} - -// GetFilesByMissionRequest: Request to get files by mission -message GetFilesByMissionRequest { - // mission_id: Mission ID linked to the files - string mission_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; -} - -// GetFilesByMissionResponse: Response to get files by mission -message GetFilesByMissionResponse { - // files: Retrieved files - repeated File files = 1; -} - -// GetFilesByNameRequest: Request to get files by name -message GetFilesByNameRequest { - // mission_id: Mission ID linked to the files - string mission_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // name: Name of the files - string name = 2 [(buf.validate.field).required = true]; -} - -// GetFilesByNameResponse: Response to get files by name -message GetFilesByNameResponse { - // success: Success of the operation - bool success = 1 [(buf.validate.field).required = true]; - // file: Retrieved file - File file = 2 [(buf.validate.field).required = true]; -} - -// DeleteFileRequest: Request to delete a file -message DeleteFileRequest { - // mission_id: Mission ID linked to the file - string mission_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // name: Name of the file (unique by mission_id) - string name = 2; -} - -// DeleteFileResponse: Response to delete a file -message DeleteFileResponse { - // success: Success of the operation - bool success = 1 [(buf.validate.field).required = true]; -} \ No newline at end of file diff --git a/proto/digitalkin/filesystem/v1/filesystem.proto b/proto/digitalkin/filesystem/v1/filesystem.proto new file mode 100644 index 0000000..77ae0c0 --- /dev/null +++ b/proto/digitalkin/filesystem/v1/filesystem.proto @@ -0,0 +1,307 @@ +// Copyright 2025 DigitalKin Inc. +// +// Licensed under the GNU General Public License, Version 3.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.gnu.org/licenses/gpl-3.0.html +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package digitalkin.filesystem.v1; + +import "buf/validate/validate.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; + +// FileType: Enum for file type classification +enum FileType { + // FILE_TYPE_UNSPECIFIED: Default value, should not be used + FILE_TYPE_UNSPECIFIED = 0; + // FILE_TYPE_DOCUMENT: Document files (PDF, DOC, TXT, etc.) + FILE_TYPE_DOCUMENT = 1; + // FILE_TYPE_IMAGE: Image files (PNG, JPG, GIF, etc.) + FILE_TYPE_IMAGE = 2; + // FILE_TYPE_VIDEO: Video files (MP4, AVI, MOV, etc.) + FILE_TYPE_VIDEO = 3; + // FILE_TYPE_AUDIO: Audio files (MP3, WAV, etc.) + FILE_TYPE_AUDIO = 4; + // FILE_TYPE_ARCHIVE: Archive files (ZIP, TAR, etc.) + FILE_TYPE_ARCHIVE = 5; + // FILE_TYPE_CODE: Source code files + FILE_TYPE_CODE = 6; + // FILE_TYPE_OTHER: Other file types + FILE_TYPE_OTHER = 7; +} + +// FileStatus: Enum for file status in the system +enum FileStatus { + // FILE_STATUS_UNSPECIFIED: Default value, should not be used + FILE_STATUS_UNSPECIFIED = 0; + // FILE_STATUS_UPLOADING: File is being uploaded + FILE_STATUS_UPLOADING = 1; + // FILE_STATUS_ACTIVE: File is active and available + FILE_STATUS_ACTIVE = 2; + // FILE_STATUS_PROCESSING: File is being processed + FILE_STATUS_PROCESSING = 3; + // FILE_STATUS_ARCHIVED: File is archived + FILE_STATUS_ARCHIVED = 4; + // FILE_STATUS_DELETED: File is marked for deletion + FILE_STATUS_DELETED = 5; +} + +// File: Message to represent stored files with comprehensive metadata +message File { + // file_id: Unique identifier for the file (UUID) + string file_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.uuid = true]; + + // context: Context ID linked to the file + string context = 2 [(buf.validate.field).required = true, (buf.validate.field).string.pattern = "^(missions:|setups:).*$"]; + + // name: Name of the file (unique within context) + string name = 3 [(buf.validate.field).required = true, (buf.validate.field).string.min_len = 1]; + + // file_type: Type classification of the file + FileType file_type = 4 [(buf.validate.field).required = true, (buf.validate.field).enum.not_in = 0]; + + // content_type: MIME type of the file + string content_type = 5 [(buf.validate.field).required = true]; + + // size_bytes: Size of the file in bytes + int64 size_bytes = 6 [(buf.validate.field).required = true, (buf.validate.field).int64.gte = 0]; + + // checksum: SHA-256 checksum of the file content + string checksum = 7 [(buf.validate.field).required = true]; + + // metadata: Flexible metadata for additional file properties + google.protobuf.Struct metadata = 8; + + // storage_uri: Internal URI for accessing the file content + string storage_uri = 9 [(buf.validate.field).required = true]; + + // file_url: External URL for accessing the file content + string file_url = 10 [(buf.validate.field).required = true]; + + // status: Current status of the file + FileStatus status = 11 [(buf.validate.field).required = true, (buf.validate.field).enum.not_in = 0]; + + // content: The content of the file + bytes content = 12; +} + +// FileFilter: Filter criteria for querying files +message FileFilter { + // names: Filter by file names (exact matches) + repeated string names = 1; + + // file_ids: Filter by file IDs + repeated string file_ids = 2 [(buf.validate.field).repeated.items.string.uuid = true]; + + // file_types: Filter by file types + repeated FileType file_types = 3 [(buf.validate.field).repeated.items.enum.not_in = 0]; + + // context: Filter by context (required for scoping) + string context = 4 [(buf.validate.field).required = true, (buf.validate.field).string.pattern = "^(missions:|setups:).*$"]; + + // created_after: Filter files created after this timestamp + google.protobuf.Timestamp created_after = 5; + + // created_before: Filter files created before this timestamp + google.protobuf.Timestamp created_before = 6; + + // updated_after: Filter files updated after this timestamp + google.protobuf.Timestamp updated_after = 7; + + // updated_before: Filter files updated before this timestamp + google.protobuf.Timestamp updated_before = 8; + + // status: Filter by file status + FileStatus status = 9; + + // content_type_prefix: Filter by content type prefix (e.g., "image/") + string content_type_prefix = 10; + + // min_size_bytes: Filter files with minimum size + int64 min_size_bytes = 11 [(buf.validate.field).int64.gte = 0]; + + // max_size_bytes: Filter files with maximum size + int64 max_size_bytes = 12 [(buf.validate.field).int64.gte = 0]; + + // prefix: Filter by path prefix (e.g., "folder1/") + string prefix = 13 [(buf.validate.field).string.pattern = "^[^/]*/?[^/]*$"]; + + // content_type: Filter by content type + string content_type = 14; +} + +// FileResult: Wrapper for file operations that may succeed or fail +message FileResult { + oneof result { + // file: Successfully processed file + File file = 1; + // error: Error information if operation failed + string error = 2; + } +} + +// UploadFileData: Data for uploading a single file +message UploadFileData { + // context: Context ID for the file + string context = 1 [(buf.validate.field).required = true, (buf.validate.field).string.pattern = "^(missions:|setups:).*$"]; + + // name: Name of the file + string name = 2 [(buf.validate.field).required = true, (buf.validate.field).string.min_len = 1]; + + // file_type: Type classification of the file + FileType file_type = 3 [(buf.validate.field).required = true, (buf.validate.field).enum.not_in = 0]; + + // content_type: MIME type of the file + string content_type = 4 [(buf.validate.field).required = true]; + + // content: File content + bytes content = 5 [(buf.validate.field).required = true]; + + // metadata: Additional metadata for the file + google.protobuf.Struct metadata = 6; + + // status: Status of the file + FileStatus status = 7 [(buf.validate.field).required = true, (buf.validate.field).enum.not_in = 0]; + + // replace_if_exists: Whether to replace existing file with same name + bool replace_if_exists = 8; +} + +// UploadFilesRequest: Request to upload multiple files +message UploadFilesRequest { + // files: List of files to upload + repeated UploadFileData files = 1 [(buf.validate.field).required = true, (buf.validate.field).repeated.min_items = 1]; +} + +// UploadFilesResponse: Response for file upload operations +message UploadFilesResponse { + // results: Results for each uploaded file + repeated FileResult results = 1; + + // total_uploaded: Number of successfully uploaded files + int32 total_uploaded = 2; + + // total_failed: Number of failed uploads + int32 total_failed = 3; +} + +// GetFileRequest: Request to get a specific file +message GetFileRequest { + // context: Context ID for the file + string context = 1 [(buf.validate.field).required = true, (buf.validate.field).string.pattern = "^(missions:|setups:).*$"]; + + // file_id: File ID + string file_id = 2 [(buf.validate.field).required = true, (buf.validate.field).string.uuid = true]; + + // include_content: Whether to include file content in response + bool include_content = 3; +} + +// GetFileResponse: Response containing file information +message GetFileResponse { + // file: The requested file + File file = 1 [(buf.validate.field).required = true]; + + // content: File content (only if requested) + bytes content = 2; +} + +// UpdateFileRequest: Request to update a file +message UpdateFileRequest { + // context: Context ID for the file + string context = 1 [(buf.validate.field).required = true, (buf.validate.field).string.pattern = "^(missions:|setups:).*$"]; + + // file_id: Current id of the file + string file_id = 2 [(buf.validate.field).required = true, (buf.validate.field).string.uuid = true]; + + // new_name: New name for the file (optional) + string new_name = 3; + + // file_type: New file type (optional) + FileType file_type = 4; + + // content_type: New content type (optional) + string content_type = 5; + + // content: New file content (optional) + bytes content = 6; + + // status: New status of the file + FileStatus status = 7 [(buf.validate.field).required = true, (buf.validate.field).enum.not_in = 0]; + + // metadata: New metadata (optional, will merge with existing) + google.protobuf.Struct metadata = 8; +} + +// UpdateFileResponse: Response for file update +message UpdateFileResponse { + // result: Result of the file update operation + FileResult result = 1; +} + +// GetFilesRequest: Request to get multiple files by various criteria +message GetFilesRequest { + // context: Context ID for the files + string context = 1 [(buf.validate.field).required = true, (buf.validate.field).string.pattern = "^(missions:|setups:).*$"]; + + // filters: How to identify the files + FileFilter filters = 2 [(buf.validate.field).required = true]; + + // list_size: Number of files to return per page + int32 list_size = 3 [(buf.validate.field).int32.gte = 1, (buf.validate.field).int32.lte = 1000]; + + // offset: Offset of the first file in the list + int32 offset = 4 [(buf.validate.field).int32.gte = 0]; + + // order: Field to order results by + string order = 5; + + // include_content: Whether to include file content in response + bool include_content = 6; +} + +// GetFilesResponse: Response containing multiple files +message GetFilesResponse { + // files: List of files matching the criteria + repeated File files = 1 [(buf.validate.field).required = true, (buf.validate.field).repeated.min_items = 1]; + + // total_count: Total number of files matching the criteria + int32 total_count = 2; +} + +// DeleteFilesRequest: Request to delete multiple files +message DeleteFilesRequest { + // context: Context ID for the files + string context = 1 [(buf.validate.field).required = true, (buf.validate.field).string.pattern = "^(missions:|setups:).*$"]; + + // filters: How to identify the files + FileFilter filters = 2 [(buf.validate.field).required = true]; + + // force: Whether to force delete even if file is in use + bool force = 3; + + // permanent: Whether to permanently delete (vs mark as deleted) + bool permanent = 4; +} + +// DeleteFilesResponse: Response for file deletion +message DeleteFilesResponse { + // results: Results for each file deletion attempt + map results = 1; + + // total_deleted: Number of successfully deleted files + int32 total_deleted = 2; + + // total_failed: Number of failed deletions + int32 total_failed = 3; +} \ No newline at end of file diff --git a/proto/digitalkin/filesystem/v1/filesystem_service.proto b/proto/digitalkin/filesystem/v1/filesystem_service.proto index 8bdd739..4990bc3 100644 --- a/proto/digitalkin/filesystem/v1/filesystem_service.proto +++ b/proto/digitalkin/filesystem/v1/filesystem_service.proto @@ -16,22 +16,60 @@ syntax = "proto3"; package digitalkin.filesystem.v1; -import "digitalkin/filesystem/v1/data.proto"; +import "digitalkin/filesystem/v1/filesystem.proto"; -// FileSystemService: Service to store objects -service FileSystemService { - // UploadFile: Upload a file to the system - rpc UploadFile (UploadFileRequest) returns (UploadFileResponse); - - // GetFile: Get a file by ID - rpc GetFile (GetFileRequest) returns (GetFileResponse); - - // GetFilesByMission: Get files by mission - rpc GetFilesByMission (GetFilesByMissionRequest) returns (GetFilesByMissionResponse); - - // GetFilesByName: Get files by name and mission - rpc GetFilesByName (GetFilesByNameRequest) returns (GetFilesByNameResponse); +// FilesystemService: Service for managing files and file operations +// +// This service provides comprehensive file management capabilities including +// upload, retrieval, update, and deletion operations with rich metadata support, +// filtering, and pagination. +service FilesystemService { + // UploadFiles: Upload multiple files to the system + // + // This method allows batch uploading of files with validation and + // error handling for each individual file. Files are processed + // atomically - if one fails, others may still succeed. + // + rpc UploadFiles(UploadFilesRequest) returns (UploadFilesResponse); + + // GetFile: Retrieve a specific file by ID or name + // + // This method fetches detailed information about a single file, + // with optional content inclusion. Supports lookup by either + // unique ID or name within a kin_context. + // + rpc GetFile(GetFileRequest) returns (GetFileResponse); - // DeleteFile: Delete a file by name and mission - rpc DeleteFile (DeleteFileRequest) returns (DeleteFileResponse); + // GetFiles: Retrieve multiple files by various criteria + // + // This method provides efficient retrieval of multiple files using: + // - File IDs + // - File names + // - Path prefix + // With support for: + // - Pagination for large result sets + // - Optional content inclusion + // - Total count of matching files + // + rpc GetFiles(GetFilesRequest) returns (GetFilesResponse); + + // UpdateFile: Update file metadata, content, or both + // + // This method allows updating various aspects of a file: + // - Rename files + // - Update content and content type + // - Modify metadata + // - Create new versions + // + rpc UpdateFile(UpdateFileRequest) returns (UpdateFileResponse); + + // DeleteFiles: Delete multiple files + // + // This method supports batch deletion of files with options for: + // - Soft deletion (marking as deleted) + // - Permanent deletion + // - Force deletion of files in use + // - Individual error reporting per file + // + rpc DeleteFiles(DeleteFilesRequest) returns (DeleteFilesResponse); } \ No newline at end of file diff --git a/proto/digitalkin/module/v2/information.proto b/proto/digitalkin/module/v2/information.proto index d718047..cdf2f9b 100644 --- a/proto/digitalkin/module/v2/information.proto +++ b/proto/digitalkin/module/v2/information.proto @@ -122,4 +122,30 @@ message GetModuleSecretResponse { bool success = 1; // secret_schema: Secret schema of the Module google.protobuf.Struct secret_schema = 2 [(buf.validate.field).required = true]; +} + +// GetConfigSetupModuleRequest +// +// Fields: +// +// - module_id: Database ID of the Module to get config setup schema +// - llm_format: Define if the setup schema should be in LLM format or raw pydantic format +message GetConfigSetupModuleRequest { + // module_id: Database ID of the Module to get setup schema + string module_id = 1 [(buf.validate.field).string.min_len = 1, (buf.validate.field).string.prefix = "modules:", (buf.validate.field).required = true]; + // llm_format: Define if the setup schema should be in LLM format or raw pydantic format + bool llm_format = 2; +} + +// GetConfigSetupModuleResponse +// +// Returns: +// +// - success: Flag to indicate if the config setup schema request was successful +// - config_setup_schema: Config setup schema of the Module +message GetConfigSetupModuleResponse { + // success: Flag to indicate if the setup schema request was successful + bool success = 1; + // config_setup_schema: Setup schema of the Module + google.protobuf.Struct config_setup_schema = 2 [(buf.validate.field).required = true]; } \ No newline at end of file diff --git a/proto/digitalkin/module/v2/lifecycle.proto b/proto/digitalkin/module/v2/lifecycle.proto index a7d1d8e..db59bb9 100644 --- a/proto/digitalkin/module/v2/lifecycle.proto +++ b/proto/digitalkin/module/v2/lifecycle.proto @@ -17,11 +17,42 @@ syntax = "proto3"; package digitalkin.module.v2; +import "digitalkin/setup/v2/setup.proto"; + import "buf/validate/validate.proto"; import "google/api/field_behavior.proto"; import "google/protobuf/struct.proto"; +// ConfigSetupModuleRequest +// This request is used to configure an existing setup version. +// +// Fields: +// - setup_version: The setup version to configure. +// - content: The new content to compute and/or configure. +// - mission_id: Database ID of the Module to start +message ConfigSetupModuleRequest { + // setup_version: The setup version to configure. + digitalkin.setup.v2.SetupVersion setup_version = 1 [(buf.validate.field).required = true]; + // content: The new content to compute and/or configure. + google.protobuf.Struct content = 2 [(buf.validate.field).required = true]; + // mission_id: Database ID of the Module to start + string mission_id = 3 [(buf.validate.field).string.min_len = 1, (buf.validate.field).string.prefix = "missions:", (buf.validate.field).required = true]; +} + +// ConfigSetupModuleResponse +// Returns the configured setup version. +// +// Fields: +// - success: description flag of the operation. +// - setup_version: The updated setup version entity. +message ConfigSetupModuleResponse { + // success: description flag of the operation. + bool success = 1; + // setup_version: The updated setup version entity. + digitalkin.setup.v2.SetupVersion setup_version = 2; +} + // StartModuleRequest // TODO: do we have to add secret_id ? // diff --git a/proto/digitalkin/module/v2/module_service.proto b/proto/digitalkin/module/v2/module_service.proto index f2a2c11..1c1dcc4 100644 --- a/proto/digitalkin/module/v2/module_service.proto +++ b/proto/digitalkin/module/v2/module_service.proto @@ -45,5 +45,9 @@ service ModuleService { rpc GetModuleSetup (GetModuleSetupRequest) returns (GetModuleSetupResponse); // GetModuleSecret rpc GetModuleSecret (GetModuleSecretRequest) returns (GetModuleSecretResponse); + // GetConfigSetupModule + rpc GetConfigSetupModule (GetConfigSetupModuleRequest) returns (GetConfigSetupModuleResponse); + // ConfigSetupModule + rpc ConfigSetupModule(ConfigSetupModuleRequest) returns (ConfigSetupModuleResponse); } \ No newline at end of file diff --git a/proto/digitalkin/setup/v1/setup.proto b/proto/digitalkin/setup/v1/setup.proto index 7f7dab5..c76eddd 100644 --- a/proto/digitalkin/setup/v1/setup.proto +++ b/proto/digitalkin/setup/v1/setup.proto @@ -19,7 +19,6 @@ package digitalkin.setup.v1; import "digitalkin/setup/v1/assistant.proto"; import "google/api/field_behavior.proto"; -import "google/protobuf/any.proto"; // Data // diff --git a/proto/digitalkin/setup/v2/setup.proto b/proto/digitalkin/setup/v2/setup.proto index 3543628..ea39805 100644 --- a/proto/digitalkin/setup/v2/setup.proto +++ b/proto/digitalkin/setup/v2/setup.proto @@ -296,3 +296,35 @@ message DeleteSetupVersionResponse { // success: description flag of the operation. bool success = 1; } + +// ListSetupsRequest +// This request is used to retrieve a paginated list of setups, filtered by organisation or owner. +// +// Fields: +// - organisation_id: (Optional) Filter by the organisation identifier. +// - owner_id: (Optional) Filter by the owner identifier (e.g., from Clerk). +// - list_size: (Optional) Maximum number of setups to return. +// - offset: (Optional) Start index for pagination. +message ListSetupsRequest { + // organisation_id: The unique identifier of the organisation. + optional string organisation_id = 1 [(buf.validate.field).string.min_len = 1]; + // owner_id: The owner_id of the setup. + optional string owner_id = 2 [(buf.validate.field).string.min_len = 1]; + // list_size: Maximum number of setups to return. + optional int32 list_size = 3 [(buf.validate.field).int32.gte = 1]; + // offset: Start index for pagination. + optional int32 offset = 4 [(buf.validate.field).int32.gte = 0]; +} + +// ListSetupsResponse +// Returns a paginated list of setups matching the request criteria. +// +// Fields: +// - list_size: Number of setups returned. +// - setups: List of setups with their details and optional status. +message ListSetupsResponse { + // list_size: Number of setups returned. + int32 list_size = 1 [(buf.validate.field).int32.gte = 0]; + // setups: List of setups with their details. + repeated Setup setups = 2; +} \ No newline at end of file diff --git a/proto/digitalkin/setup/v2/setup_service.proto b/proto/digitalkin/setup/v2/setup_service.proto index 3608710..ccc9bc3 100644 --- a/proto/digitalkin/setup/v2/setup_service.proto +++ b/proto/digitalkin/setup/v2/setup_service.proto @@ -41,4 +41,6 @@ service SetupService { rpc UpdateSetupVersion(UpdateSetupVersionRequest) returns (UpdateSetupVersionResponse); // DeleteSetupVersion deletes a setup version. rpc DeleteSetupVersion(DeleteSetupVersionRequest) returns (DeleteSetupVersionResponse); + // ListSetups retrieves a paginated list of setups, filtered by organisation or owner. + rpc ListSetups(ListSetupsRequest) returns (ListSetupsResponse); } \ No newline at end of file diff --git a/proto/digitalkin/storage/v1/s3_storage.proto b/proto/digitalkin/storage/v1/s3_storage.proto index 74129da..ac48014 100644 --- a/proto/digitalkin/storage/v1/s3_storage.proto +++ b/proto/digitalkin/storage/v1/s3_storage.proto @@ -19,7 +19,6 @@ syntax = "proto3"; package digitalkin.storage.v1; -import "digitalkin/common/v1/common.proto"; import "google/api/annotations.proto"; // StorageService diff --git a/proto/digitalkin/storage/v2/data.proto b/proto/digitalkin/storage/v2/data.proto index ba09358..9ae60b8 100644 --- a/proto/digitalkin/storage/v2/data.proto +++ b/proto/digitalkin/storage/v2/data.proto @@ -38,14 +38,16 @@ message StorageRecord { google.protobuf.Struct data = 1 [(buf.validate.field).required = true]; // mission_id: Mission ID linked to the data string mission_id = 2 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // name: Name of the data (unique by mission_id) - string name = 3 [(buf.validate.field).required = true]; + // collection: Name of a group of records (unique by mission_id) + string collection = 3 [(buf.validate.field).required = true]; + // record_id: Name of a record (unique by mission_id and collection) to identify the data + string record_id = 4 [(buf.validate.field).required = true]; // creation_date: Creation date of the data - google.protobuf.Timestamp creation_date = 4 [(buf.validate.field).required = true]; + google.protobuf.Timestamp creation_date = 5 [(buf.validate.field).required = true]; // update_date: Update date of the data - google.protobuf.Timestamp update_date = 5 [(buf.validate.field).required = true]; + google.protobuf.Timestamp update_date = 6 [(buf.validate.field).required = true]; // data_type: Type of the data - DataType data_type = 6 [(buf.validate.field).required = true]; + DataType data_type = 7 [(buf.validate.field).required = true]; } // StoreRecordRequest: Request to store record @@ -54,10 +56,12 @@ message StoreRecordRequest { google.protobuf.Struct data = 1 [(buf.validate.field).required = true]; // mission_id: Mission ID linked to the data string mission_id = 2 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // name: Name of the data (unique by mission_id) - string name = 3 [(buf.validate.field).required = true]; + // collection: Name of a group of records (unique by mission_id) + string collection = 3 [(buf.validate.field).required = true]; + // record_id: Name of a record (unique by mission_id and collection) to identify the data + string record_id = 4 [(buf.validate.field).required = true]; // data_type: Type of the data - DataType data_type = 4 [(buf.validate.field).required = true]; + DataType data_type = 5 [(buf.validate.field).required = true]; } // StoreRecordResponse: Response to stored record @@ -72,8 +76,10 @@ message StoreRecordResponse { message ReadRecordRequest { // mission_id: Mission ID linked to the data string mission_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // name: Name of the data (unique by mission_id) - string name = 2 [(buf.validate.field).required = true]; + // collection: Name of a group of records (unique by mission_id) + string collection = 2 [(buf.validate.field).required = true]; + // record_id: Name of a record (unique by mission_id and collection) to identify the data + string record_id = 3 [(buf.validate.field).required = true]; } // ReadRecordResponse: Response after read a record @@ -84,19 +90,20 @@ message ReadRecordResponse { StorageRecord stored_data = 2 [(buf.validate.field).required = true]; } - -// ModifyRecordRequest: Request to modify record -message ModifyRecordRequest { +// UpdateRecordRequest: Request to modify record +message UpdateRecordRequest { // data: Data to store or to retrieve google.protobuf.Struct data = 1 [(buf.validate.field).required = true]; // mission_id: Mission ID linked to the data string mission_id = 2 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // name: Name of the data (unique by mission_id) - string name = 3 [(buf.validate.field).required = true]; + // collection: Name of a group of records (unique by mission_id) + string collection = 3 [(buf.validate.field).required = true]; + // record_id: Name of a record (unique by mission_id and collection) to identify the data + string record_id = 4 [(buf.validate.field).required = true]; } -// ModifyRecordResponse: Response to record modification -message ModifyRecordResponse { +// UpdateRecordResponse: Response to record modification +message UpdateRecordResponse { // success: Success of the operation bool success = 1 [(buf.validate.field).required = true]; // stored_data: Stored data @@ -107,12 +114,41 @@ message ModifyRecordResponse { message RemoveRecordRequest { // mission_id: Mission ID linked to the data string mission_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; - // name: Name of the data (unique by mission_id) - string name = 2 [(buf.validate.field).required = true]; + // collection: Name of a group of records (unique by mission_id) + string collection = 3 [(buf.validate.field).required = true]; + // record_id: Name of a record (unique by mission_id and collection) to identify the data + string record_id = 4 [(buf.validate.field).required = true]; } // RemoveRecordResponse: Response to removed record message RemoveRecordResponse { // success: Success of the operation bool success = 1 [(buf.validate.field).required = true]; +} + +// ListRecordsRequest: Request to list all records in a given collection +message ListRecordsRequest { + // mission_id: Mission ID linked to the data + string mission_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; + // collection: Name of a group of records (unique by mission_id) + string collection = 2 [(buf.validate.field).required = true]; +} + +// ListRecordsResponse: Response to list all records in a given collection +message ListRecordsResponse { + // records: List of records + repeated StorageRecord records = 1 [(buf.validate.field).required = true]; +} + +// RemoveCollectionRequest: Request to remove a collection +message RemoveCollectionRequest { + // mission_id: Mission ID linked to the data + string mission_id = 1 [(buf.validate.field).required = true, (buf.validate.field).string.prefix = "missions:"]; + // collection: Name of a group of records (unique by mission_id) + string collection = 2 [(buf.validate.field).required = true]; +} +// RemoveCollectionResponse: Response to removed collection +message RemoveCollectionResponse { + // success: Success of the operation + bool success = 1 [(buf.validate.field).required = true]; } \ No newline at end of file diff --git a/proto/digitalkin/storage/v2/storage_service.proto b/proto/digitalkin/storage/v2/storage_service.proto index dc3b7d4..a269191 100644 --- a/proto/digitalkin/storage/v2/storage_service.proto +++ b/proto/digitalkin/storage/v2/storage_service.proto @@ -26,9 +26,15 @@ service StorageService { // ReadRecord: Get data by mission and name rpc ReadRecord (ReadRecordRequest) returns (ReadRecordResponse); - // ModifyRecord: Update data record - rpc ModifyRecord (ModifyRecordRequest) returns (ModifyRecordResponse); + // UpdateRecord: Update data record + rpc UpdateRecord (UpdateRecordRequest) returns (UpdateRecordResponse); // RemoveRecord: Delete data rpc RemoveRecord (RemoveRecordRequest) returns (RemoveRecordResponse); + + // ListRecords: List all records in a given collection + rpc ListRecords(ListRecordsRequest) returns (ListRecordsResponse); + + // RemoveCollection: Delete all records in a given collection + rpc RemoveCollection(RemoveCollectionRequest) returns (RemoveCollectionResponse); } \ No newline at end of file