syntax = "proto3"; package memos.api.v1; import "api/v1/common.proto"; import "google/api/annotations.proto"; import "google/api/client.proto"; import "google/api/field_behavior.proto"; import "google/api/resource.proto"; import "google/protobuf/empty.proto"; import "google/protobuf/field_mask.proto"; import "google/protobuf/timestamp.proto"; option go_package = "gen/api/v1"; service UserService { // ListUsers returns a list of users. rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) { option (google.api.http) = {get: "/api/v1/users"}; } // GetUser gets a user by ID or username. // Supports both numeric IDs and username strings: // - users/{id} (e.g., users/101) // - users/{username} (e.g., users/steven) rpc GetUser(GetUserRequest) returns (User) { option (google.api.http) = {get: "/api/v1/{name=users/*}"}; option (google.api.method_signature) = "name"; } // CreateUser creates a new user. rpc CreateUser(CreateUserRequest) returns (User) { option (google.api.http) = { post: "/api/v1/users" body: "user" }; option (google.api.method_signature) = "user"; } // UpdateUser updates a user. rpc UpdateUser(UpdateUserRequest) returns (User) { option (google.api.http) = { patch: "/api/v1/{user.name=users/*}" body: "user" }; option (google.api.method_signature) = "user,update_mask"; } // DeleteUser deletes a user. rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty) { option (google.api.http) = {delete: "/api/v1/{name=users/*}"}; option (google.api.method_signature) = "name"; } // ListAllUserStats returns statistics for all users. rpc ListAllUserStats(ListAllUserStatsRequest) returns (ListAllUserStatsResponse) { option (google.api.http) = {get: "/api/v1/users:stats"}; } // GetUserStats returns statistics for a specific user. rpc GetUserStats(GetUserStatsRequest) returns (UserStats) { option (google.api.http) = {get: "/api/v1/{name=users/*}:getStats"}; option (google.api.method_signature) = "name"; } // GetUserSetting returns the user setting. rpc GetUserSetting(GetUserSettingRequest) returns (UserSetting) { option (google.api.http) = {get: "/api/v1/{name=users/*/settings/*}"}; option (google.api.method_signature) = "name"; } // UpdateUserSetting updates the user setting. rpc UpdateUserSetting(UpdateUserSettingRequest) returns (UserSetting) { option (google.api.http) = { patch: "/api/v1/{setting.name=users/*/settings/*}" body: "setting" }; option (google.api.method_signature) = "setting,update_mask"; } // ListUserSettings returns a list of user settings. rpc ListUserSettings(ListUserSettingsRequest) returns (ListUserSettingsResponse) { option (google.api.http) = {get: "/api/v1/{parent=users/*}/settings"}; option (google.api.method_signature) = "parent"; } // ListPersonalAccessTokens returns a list of Personal Access Tokens (PATs) for a user. // PATs are long-lived tokens for API/script access, distinct from short-lived JWT access tokens. rpc ListPersonalAccessTokens(ListPersonalAccessTokensRequest) returns (ListPersonalAccessTokensResponse) { option (google.api.http) = {get: "/api/v1/{parent=users/*}/personalAccessTokens"}; option (google.api.method_signature) = "parent"; } // CreatePersonalAccessToken creates a new Personal Access Token for a user. // The token value is only returned once upon creation. rpc CreatePersonalAccessToken(CreatePersonalAccessTokenRequest) returns (CreatePersonalAccessTokenResponse) { option (google.api.http) = { post: "/api/v1/{parent=users/*}/personalAccessTokens" body: "*" }; } // DeletePersonalAccessToken deletes a Personal Access Token. rpc DeletePersonalAccessToken(DeletePersonalAccessTokenRequest) returns (google.protobuf.Empty) { option (google.api.http) = {delete: "/api/v1/{name=users/*/personalAccessTokens/*}"}; option (google.api.method_signature) = "name"; } // ListUserWebhooks returns a list of webhooks for a user. rpc ListUserWebhooks(ListUserWebhooksRequest) returns (ListUserWebhooksResponse) { option (google.api.http) = {get: "/api/v1/{parent=users/*}/webhooks"}; option (google.api.method_signature) = "parent"; } // CreateUserWebhook creates a new webhook for a user. rpc CreateUserWebhook(CreateUserWebhookRequest) returns (UserWebhook) { option (google.api.http) = { post: "/api/v1/{parent=users/*}/webhooks" body: "webhook" }; option (google.api.method_signature) = "parent,webhook"; } // UpdateUserWebhook updates an existing webhook for a user. rpc UpdateUserWebhook(UpdateUserWebhookRequest) returns (UserWebhook) { option (google.api.http) = { patch: "/api/v1/{webhook.name=users/*/webhooks/*}" body: "webhook" }; option (google.api.method_signature) = "webhook,update_mask"; } // DeleteUserWebhook deletes a webhook for a user. rpc DeleteUserWebhook(DeleteUserWebhookRequest) returns (google.protobuf.Empty) { option (google.api.http) = {delete: "/api/v1/{name=users/*/webhooks/*}"}; option (google.api.method_signature) = "name"; } // ListUserNotifications lists notifications for a user. rpc ListUserNotifications(ListUserNotificationsRequest) returns (ListUserNotificationsResponse) { option (google.api.http) = {get: "/api/v1/{parent=users/*}/notifications"}; option (google.api.method_signature) = "parent"; } // UpdateUserNotification updates a notification. rpc UpdateUserNotification(UpdateUserNotificationRequest) returns (UserNotification) { option (google.api.http) = { patch: "/api/v1/{notification.name=users/*/notifications/*}" body: "notification" }; option (google.api.method_signature) = "notification,update_mask"; } // DeleteUserNotification deletes a notification. rpc DeleteUserNotification(DeleteUserNotificationRequest) returns (google.protobuf.Empty) { option (google.api.http) = {delete: "/api/v1/{name=users/*/notifications/*}"}; option (google.api.method_signature) = "name"; } } message User { option (google.api.resource) = { type: "memos.api.v1/User" pattern: "users/{user}" name_field: "name" singular: "user" plural: "users" }; // The resource name of the user. // Format: users/{user} string name = 1 [(google.api.field_behavior) = IDENTIFIER]; // The role of the user. Role role = 2 [(google.api.field_behavior) = REQUIRED]; // Required. The unique username for login. string username = 3 [(google.api.field_behavior) = REQUIRED]; // Optional. The email address of the user. string email = 4 [(google.api.field_behavior) = OPTIONAL]; // Optional. The display name of the user. string display_name = 5 [(google.api.field_behavior) = OPTIONAL]; // Optional. The avatar URL of the user. string avatar_url = 6 [(google.api.field_behavior) = OPTIONAL]; // Optional. The description of the user. string description = 7 [(google.api.field_behavior) = OPTIONAL]; // Input only. The password for the user. string password = 8 [(google.api.field_behavior) = INPUT_ONLY]; // The state of the user. State state = 9 [(google.api.field_behavior) = REQUIRED]; // Output only. The creation timestamp. google.protobuf.Timestamp create_time = 10 [(google.api.field_behavior) = OUTPUT_ONLY]; // Output only. The last update timestamp. google.protobuf.Timestamp update_time = 11 [(google.api.field_behavior) = OUTPUT_ONLY]; // User role enumeration. enum Role { // Unspecified role. ROLE_UNSPECIFIED = 0; // Host role with full system access. HOST = 1; // Admin role with administrative privileges. ADMIN = 2; // Regular user role. USER = 3; } } message ListUsersRequest { // Optional. The maximum number of users to return. // The service may return fewer than this value. // If unspecified, at most 50 users will be returned. // The maximum value is 1000; values above 1000 will be coerced to 1000. int32 page_size = 1 [(google.api.field_behavior) = OPTIONAL]; // Optional. A page token, received from a previous `ListUsers` call. // Provide this to retrieve the subsequent page. string page_token = 2 [(google.api.field_behavior) = OPTIONAL]; // Optional. Filter to apply to the list results. // Example: "username == 'steven'" // Supported operators: == // Supported fields: username string filter = 3 [(google.api.field_behavior) = OPTIONAL]; // Optional. If true, show deleted users in the response. bool show_deleted = 4 [(google.api.field_behavior) = OPTIONAL]; } message ListUsersResponse { // The list of users. repeated User users = 1; // A token that can be sent as `page_token` to retrieve the next page. // If this field is omitted, there are no subsequent pages. string next_page_token = 2; // The total count of users (may be approximate). int32 total_size = 3; } message GetUserRequest { // Required. The resource name of the user. // Supports both numeric IDs and username strings: // - users/{id} (e.g., users/101) // - users/{username} (e.g., users/steven) // Format: users/{id_or_username} string name = 1 [ (google.api.field_behavior) = REQUIRED, (google.api.resource_reference) = {type: "memos.api.v1/User"} ]; // Optional. The fields to return in the response. // If not specified, all fields are returned. google.protobuf.FieldMask read_mask = 2 [(google.api.field_behavior) = OPTIONAL]; } message CreateUserRequest { // Required. The user to create. User user = 1 [ (google.api.field_behavior) = REQUIRED, (google.api.field_behavior) = INPUT_ONLY ]; // Optional. The user ID to use for this user. // If empty, a unique ID will be generated. // Must match the pattern [a-z0-9-]+ string user_id = 2 [(google.api.field_behavior) = OPTIONAL]; // Optional. If set, validate the request but don't actually create the user. bool validate_only = 3 [(google.api.field_behavior) = OPTIONAL]; // Optional. An idempotency token that can be used to ensure that multiple // requests to create a user have the same result. string request_id = 4 [(google.api.field_behavior) = OPTIONAL]; } message UpdateUserRequest { // Required. The user to update. User user = 1 [(google.api.field_behavior) = REQUIRED]; // Required. The list of fields to update. google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = REQUIRED]; // Optional. If set to true, allows updating sensitive fields. bool allow_missing = 3 [(google.api.field_behavior) = OPTIONAL]; } message DeleteUserRequest { // Required. The resource name of the user to delete. // Format: users/{user} string name = 1 [ (google.api.field_behavior) = REQUIRED, (google.api.resource_reference) = {type: "memos.api.v1/User"} ]; // Optional. If set to true, the user will be deleted even if they have associated data. bool force = 2 [(google.api.field_behavior) = OPTIONAL]; } // User statistics messages message UserStats { option (google.api.resource) = { type: "memos.api.v1/UserStats" pattern: "users/{user}" singular: "userStats" plural: "userStats" }; // The resource name of the user whose stats these are. // Format: users/{user} string name = 1 [(google.api.field_behavior) = IDENTIFIER]; // The timestamps when the memos were displayed. repeated google.protobuf.Timestamp memo_display_timestamps = 2; // The stats of memo types. MemoTypeStats memo_type_stats = 3; // The count of tags. map tag_count = 4; // The pinned memos of the user. repeated string pinned_memos = 5; // Total memo count. int32 total_memo_count = 6; // Memo type statistics. message MemoTypeStats { int32 link_count = 1; int32 code_count = 2; int32 todo_count = 3; int32 undo_count = 4; } } message GetUserStatsRequest { // Required. The resource name of the user. // Format: users/{user} string name = 1 [ (google.api.field_behavior) = REQUIRED, (google.api.resource_reference) = {type: "memos.api.v1/User"} ]; } message ListAllUserStatsRequest { // This endpoint doesn't take any parameters. } message ListAllUserStatsResponse { // The list of user statistics. repeated UserStats stats = 1; } // User settings message message UserSetting { option (google.api.resource) = { type: "memos.api.v1/UserSetting" pattern: "users/{user}/settings/{setting}" singular: "userSetting" plural: "userSettings" }; // The name of the user setting. // Format: users/{user}/settings/{setting}, {setting} is the key for the setting. // For example, "users/123/settings/GENERAL" for general settings. string name = 1 [(google.api.field_behavior) = IDENTIFIER]; oneof value { GeneralSetting general_setting = 2; WebhooksSetting webhooks_setting = 5; } // Enumeration of user setting keys. enum Key { KEY_UNSPECIFIED = 0; // GENERAL is the key for general user settings. GENERAL = 1; // WEBHOOKS is the key for user webhooks. WEBHOOKS = 4; } // General user settings configuration. message GeneralSetting { // The preferred locale of the user. string locale = 1 [(google.api.field_behavior) = OPTIONAL]; // The default visibility of the memo. string memo_visibility = 3 [(google.api.field_behavior) = OPTIONAL]; // The preferred theme of the user. // This references a CSS file in the web/public/themes/ directory. // If not set, the default theme will be used. string theme = 4 [(google.api.field_behavior) = OPTIONAL]; } // User webhooks configuration. message WebhooksSetting { // List of user webhooks. repeated UserWebhook webhooks = 1; } } message GetUserSettingRequest { // Required. The resource name of the user setting. // Format: users/{user}/settings/{setting} string name = 1 [ (google.api.field_behavior) = REQUIRED, (google.api.resource_reference) = {type: "memos.api.v1/UserSetting"} ]; } message UpdateUserSettingRequest { // Required. The user setting to update. UserSetting setting = 1 [(google.api.field_behavior) = REQUIRED]; // Required. The list of fields to update. google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = REQUIRED]; } // Request message for ListUserSettings method. message ListUserSettingsRequest { // Required. The parent resource whose settings will be listed. // Format: users/{user} string parent = 1 [ (google.api.field_behavior) = REQUIRED, (google.api.resource_reference) = {type: "memos.api.v1/User"} ]; // Optional. The maximum number of settings to return. // The service may return fewer than this value. // If unspecified, at most 50 settings will be returned. // The maximum value is 1000; values above 1000 will be coerced to 1000. int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL]; // Optional. A page token, received from a previous `ListUserSettings` call. // Provide this to retrieve the subsequent page. string page_token = 3 [(google.api.field_behavior) = OPTIONAL]; } // Response message for ListUserSettings method. message ListUserSettingsResponse { // The list of user settings. repeated UserSetting settings = 1; // A token that can be sent as `page_token` to retrieve the next page. // If this field is omitted, there are no subsequent pages. string next_page_token = 2; // The total count of settings (may be approximate). int32 total_size = 3; } // PersonalAccessToken represents a long-lived token for API/script access. // PATs are distinct from short-lived JWT access tokens used for session authentication. message PersonalAccessToken { option (google.api.resource) = { type: "memos.api.v1/PersonalAccessToken" pattern: "users/{user}/personalAccessTokens/{personal_access_token}" singular: "personalAccessToken" plural: "personalAccessTokens" }; // The resource name of the personal access token. // Format: users/{user}/personalAccessTokens/{personal_access_token} string name = 1 [(google.api.field_behavior) = IDENTIFIER]; // The description of the token. string description = 2 [(google.api.field_behavior) = OPTIONAL]; // Output only. The creation timestamp. google.protobuf.Timestamp created_at = 3 [(google.api.field_behavior) = OUTPUT_ONLY]; // Optional. The expiration timestamp. google.protobuf.Timestamp expires_at = 4 [(google.api.field_behavior) = OPTIONAL]; // Output only. The last used timestamp. google.protobuf.Timestamp last_used_at = 5 [(google.api.field_behavior) = OUTPUT_ONLY]; } message ListPersonalAccessTokensRequest { // Required. The parent resource whose personal access tokens will be listed. // Format: users/{user} string parent = 1 [ (google.api.field_behavior) = REQUIRED, (google.api.resource_reference) = {type: "memos.api.v1/User"} ]; // Optional. The maximum number of tokens to return. int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL]; // Optional. A page token for pagination. string page_token = 3 [(google.api.field_behavior) = OPTIONAL]; } message ListPersonalAccessTokensResponse { // The list of personal access tokens. repeated PersonalAccessToken personal_access_tokens = 1; // A token for the next page of results. string next_page_token = 2; // The total count of personal access tokens. int32 total_size = 3; } message CreatePersonalAccessTokenRequest { // Required. The parent resource where this token will be created. // Format: users/{user} string parent = 1 [ (google.api.field_behavior) = REQUIRED, (google.api.resource_reference) = {type: "memos.api.v1/User"} ]; // Optional. Description of the personal access token. string description = 2 [(google.api.field_behavior) = OPTIONAL]; // Optional. Expiration duration in days (0 = never expires). int32 expires_in_days = 3 [(google.api.field_behavior) = OPTIONAL]; } message CreatePersonalAccessTokenResponse { // The personal access token metadata. PersonalAccessToken personal_access_token = 1; // The actual token value - only returned on creation. // This is the only time the token value will be visible. string token = 2; } message DeletePersonalAccessTokenRequest { // Required. The resource name of the personal access token to delete. // Format: users/{user}/personalAccessTokens/{personal_access_token} string name = 1 [ (google.api.field_behavior) = REQUIRED, (google.api.resource_reference) = {type: "memos.api.v1/PersonalAccessToken"} ]; } // UserWebhook represents a webhook owned by a user. message UserWebhook { // The name of the webhook. // Format: users/{user}/webhooks/{webhook} string name = 1; // The URL to send the webhook to. string url = 2; // Optional. Human-readable name for the webhook. string display_name = 3; // The creation time of the webhook. google.protobuf.Timestamp create_time = 4 [(google.api.field_behavior) = OUTPUT_ONLY]; // The last update time of the webhook. google.protobuf.Timestamp update_time = 5 [(google.api.field_behavior) = OUTPUT_ONLY]; } message ListUserWebhooksRequest { // The parent user resource. // Format: users/{user} string parent = 1 [(google.api.field_behavior) = REQUIRED]; } message ListUserWebhooksResponse { // The list of webhooks. repeated UserWebhook webhooks = 1; } message CreateUserWebhookRequest { // The parent user resource. // Format: users/{user} string parent = 1 [(google.api.field_behavior) = REQUIRED]; // The webhook to create. UserWebhook webhook = 2 [(google.api.field_behavior) = REQUIRED]; } message UpdateUserWebhookRequest { // The webhook to update. UserWebhook webhook = 1 [(google.api.field_behavior) = REQUIRED]; // The list of fields to update. google.protobuf.FieldMask update_mask = 2; } message DeleteUserWebhookRequest { // The name of the webhook to delete. // Format: users/{user}/webhooks/{webhook} string name = 1 [(google.api.field_behavior) = REQUIRED]; } message UserNotification { option (google.api.resource) = { type: "memos.api.v1/UserNotification" pattern: "users/{user}/notifications/{notification}" name_field: "name" singular: "notification" plural: "notifications" }; // The resource name of the notification. // Format: users/{user}/notifications/{notification} string name = 1 [ (google.api.field_behavior) = OUTPUT_ONLY, (google.api.field_behavior) = IDENTIFIER ]; // The sender of the notification. // Format: users/{user} string sender = 2 [ (google.api.field_behavior) = OUTPUT_ONLY, (google.api.resource_reference) = {type: "memos.api.v1/User"} ]; // The status of the notification. Status status = 3 [(google.api.field_behavior) = OPTIONAL]; // The creation timestamp. google.protobuf.Timestamp create_time = 4 [(google.api.field_behavior) = OUTPUT_ONLY]; // The type of the notification. Type type = 5 [(google.api.field_behavior) = OUTPUT_ONLY]; // The activity ID associated with this notification. optional int32 activity_id = 6 [(google.api.field_behavior) = OPTIONAL]; enum Status { STATUS_UNSPECIFIED = 0; UNREAD = 1; ARCHIVED = 2; } enum Type { TYPE_UNSPECIFIED = 0; MEMO_COMMENT = 1; } } message ListUserNotificationsRequest { // The parent user resource. // Format: users/{user} string parent = 1 [ (google.api.field_behavior) = REQUIRED, (google.api.resource_reference) = {type: "memos.api.v1/User"} ]; int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL]; string page_token = 3 [(google.api.field_behavior) = OPTIONAL]; string filter = 4 [(google.api.field_behavior) = OPTIONAL]; } message ListUserNotificationsResponse { repeated UserNotification notifications = 1; string next_page_token = 2; } message UpdateUserNotificationRequest { UserNotification notification = 1 [(google.api.field_behavior) = REQUIRED]; google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = REQUIRED]; } message DeleteUserNotificationRequest { // Format: users/{user}/notifications/{notification} string name = 1 [ (google.api.field_behavior) = REQUIRED, (google.api.resource_reference) = {type: "memos.api.v1/UserNotification"} ]; }