// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. syntax = "proto3"; package mattermost.pluginapi.v1; option go_package = "github.com/mattermost/mattermost/server/public/pluginapi/grpc/generated/go/pluginapiv1"; import "google/protobuf/struct.proto"; // ============================================================================== // RPC ENVELOPE CONVENTIONS // ============================================================================== // // This file defines the common types and conventions used across all Plugin API // and Hook RPCs. All service definitions in Phase 2 (API) and Phase 3 (Hooks) // MUST follow these conventions for consistency. // // ERROR HANDLING STRATEGY: // ------------------------ // We use Response-embedded AppError (Option B) rather than gRPC status codes. // - Business errors are encoded in the response message's `error` field // - gRPC status codes are reserved for transport-level failures only // (timeouts, connection errors, unavailable plugin, etc.) // - This preserves full AppError semantics (id, message, detailed_error, // request_id, status_code, where, params) across language boundaries // // REQUEST CONVENTIONS: // -------------------- // Every RPC request message MUST: // - Be named `{MethodName}Request` (e.g., GetUserRequest, CreatePostRequest) // - Include `RequestContext context = 1;` as the first field (reserved tag 1) // - Include method-specific parameters as subsequent fields // // Example: // message GetUserRequest { // RequestContext context = 1; // Required: request metadata // string user_id = 2; // Method-specific parameter // } // // RESPONSE CONVENTIONS: // --------------------- // Every RPC response message MUST: // - Be named `{MethodName}Response` (e.g., GetUserResponse, CreatePostResponse) // - Include `AppError error = 1;` as the first field (reserved tag 1) // - If error is set (non-null), the operation failed // - If error is null/empty, the operation succeeded // - Include the result value(s) as subsequent fields // // Example: // message GetUserResponse { // AppError error = 1; // Null on success, populated on failure // User user = 2; // Result value (only valid if error is null) // } // // For methods returning multiple values or complex results, use additional fields: // message ListUsersResponse { // AppError error = 1; // repeated User users = 2; // int32 total_count = 3; // } // // For methods returning bool + error (like KVCompareAndSet): // message KVCompareAndSetResponse { // AppError error = 1; // bool success = 2; // } // // ============================================================================== // Empty is a placeholder message used for methods with no request/response data. message Empty {} // StringMap represents a map of string to string values. // Used for User.Props, User.NotifyProps, User.Timezone, etc. message StringMap { map values = 1; } // RequestContext contains metadata for every RPC request. // This MUST be embedded as the first field (tag 1) in every request message. // Provides correlation IDs for logging, tracing, and debugging across // the Go server and Python plugin boundary. message RequestContext { // plugin_id is the logical plugin identifier (from manifest.id). // Used for routing, logging, and permission checks. string plugin_id = 1; // request_id is a unique identifier for this request. // Used to correlate logs across Go server and Python plugin. // Should be generated by the caller and propagated through the call chain. string request_id = 2; // session_id is the optional session identifier for the user making the request. // May be empty for plugin-initiated requests not tied to a user session. string session_id = 3; // user_id is the optional user identifier for auditing purposes. // May be empty for system-level operations. string user_id = 4; } // AppError represents an error returned by the Mattermost server. // Maps to model.AppError in Go. // // This is embedded in every response message as field 1 to indicate // operation failure. A null/empty AppError indicates success. message AppError { // A unique error identifier (e.g., "api.user.create.email_taken.app_error") // Used for error categorization and i18n lookup. string id = 1; // Human-readable error message (may be translated) // This is the user-facing message. string message = 2; // Internal error details for debugging // Contains technical details not shown to end users. string detailed_error = 3; // The request ID for tracing // Matches RequestContext.request_id for correlation. string request_id = 4; // HTTP status code (maps to standard HTTP codes) // Examples: 400 (Bad Request), 404 (Not Found), 500 (Internal Server Error) int32 status_code = 5; // The function/method where the error originated (e.g., "UserStore.Get") // Useful for debugging and error reporting. string where = 6; // Optional parameters for error message interpolation. // Used when the error message is a template requiring variable substitution. // Example: {"field": "email", "value": "invalid@"} for validation errors. // Uses google.protobuf.Struct for flexible map[string]any representation. google.protobuf.Struct params = 7; } // ViewUsersRestrictions restricts which users can be viewed. // Maps to model.ViewUsersRestrictions in Go. message ViewUsersRestrictions { repeated string teams = 1; repeated string channels = 2; }