diff options
Diffstat (limited to 'proto/admin.proto')
| -rw-r--r-- | proto/admin.proto | 341 | +341 −0 |
1 files changed, 341 insertions, 0 deletions
diff --git a/proto/admin.proto b/proto/admin.proto new file mode 100644 --- /dev/null +++ b/proto/admin.proto @@ -0,0 +1,341 @@ +// Copyright (c) 2026 Nikolay Govorov +// SPDX-License-Identifier: AGPL-3.0-or-later + +syntax = "proto3"; + +package mirum; + +import "buf/validate/validate.proto"; +import "google/protobuf/timestamp.proto"; + +option go_package = "dimidiumlabs/mirum/internal/protocol/pb"; + +service Admin { + rpc UserCreate(UserCreateRequest) returns (UserCreateResponse); + rpc UserGet(UserGetRequest) returns (UserGetResponse); + rpc UserList(UserListRequest) returns (UserListResponse); + rpc UserUpdate(UserUpdateRequest) returns (UserUpdateResponse); + rpc UserDelete(UserDeleteRequest) returns (UserDeleteResponse); + + rpc OrgCreate(OrgCreateRequest) returns (OrgCreateResponse); + rpc OrgGet(OrgGetRequest) returns (OrgGetResponse); + rpc OrgList(OrgListRequest) returns (OrgListResponse); + rpc OrgUpdate(OrgUpdateRequest) returns (OrgUpdateResponse); + rpc OrgDelete(OrgDeleteRequest) returns (OrgDeleteResponse); + + rpc OrgMemberAdd(OrgMemberAddRequest) returns (OrgMemberAddResponse); + rpc OrgMemberGet(OrgMemberGetRequest) returns (OrgMemberGetResponse); + rpc OrgMemberList(OrgMemberListRequest) returns (OrgMemberListResponse); + rpc OrgMemberUpdate(OrgMemberUpdateRequest) returns (OrgMemberUpdateResponse); + rpc OrgMemberRemove(OrgMemberRemoveRequest) returns (OrgMemberRemoveResponse); + + rpc WorkerCreate(WorkerCreateRequest) returns (WorkerCreateResponse); + rpc WorkerGet(WorkerGetRequest) returns (WorkerGetResponse); + rpc WorkerList(WorkerListRequest) returns (WorkerListResponse); + rpc WorkerDelete(WorkerDeleteRequest) returns (WorkerDeleteResponse); +} + +// Common types + +enum Role { + ROLE_NONE = 0; + ROLE_OWNER = 1; + ROLE_ADMIN = 2; + ROLE_MEMBER = 3; +} + +enum Perm { + PERM_NONE = 0; + + PERM_USER_READ = 1; + PERM_USER_WRITE = 2; + PERM_USER_DELETE = 3; + + PERM_ORG_READ = 4; + PERM_ORG_WRITE = 5; + PERM_ORG_DELETE = 6; + PERM_ORG_MEMBER_READ = 7; + PERM_ORG_MEMBER_WRITE = 8; + + PERM_WORKER_READ = 9; + PERM_WORKER_WRITE = 10; +} + +// ErrorInfo is attached as a ConnectError detail on every error. +// The ConnectError message field is always empty — the server never sends +// human-readable text. Clients switch on reason to select user-facing copy. +message ErrorInfo { + ErrorReason reason = 1; + + // Short stable identifiers for UI targeting (e.g. {"field": "slug"}). + // Never human-readable text. + map<string, string> metadata = 2; +} + +enum ErrorReason { + ERROR_REASON_UNSPECIFIED = 0; + ERROR_REASON_INTERNAL = 1; + + // Lookup failures + ERROR_REASON_USER_NOT_FOUND = 10; + ERROR_REASON_ORG_NOT_FOUND = 11; + ERROR_REASON_WORKER_NOT_FOUND = 12; + ERROR_REASON_MEMBER_NOT_FOUND = 13; + + // Conflicts + ERROR_REASON_EMAIL_TAKEN = 20; + ERROR_REASON_SLUG_TAKEN = 21; + ERROR_REASON_ALREADY_MEMBER = 22; + + // State preconditions + ERROR_REASON_LAST_OWNER = 30; + ERROR_REASON_SOLE_OWNER = 31; + + // Validation + ERROR_REASON_INVALID_SLUG = 40; + ERROR_REASON_INVALID_ROLE = 41; + ERROR_REASON_RESERVED_EMAIL = 42; + + // Auth + ERROR_REASON_UNAUTHENTICATED = 50; + ERROR_REASON_PERMISSION_DENIED = 51; + ERROR_REASON_INVALID_CREDENTIALS = 52; + ERROR_REASON_INVALID_CSRF = 53; + + // Infrastructure + ERROR_REASON_RATE_LIMITED = 60; + ERROR_REASON_UNAVAILABLE = 61; + ERROR_REASON_UNIMPLEMENTED = 62; +} + +message UserRef { + oneof ref { + option (buf.validate.oneof).required = true; + bytes id = 1 [(buf.validate.field).bytes = { + min_len: 16 + max_len: 16 + }]; + string email = 2 [(buf.validate.field).string.email = true]; + } +} + +message OrgRef { + oneof ref { + option (buf.validate.oneof).required = true; + bytes id = 1 [(buf.validate.field).bytes = { + min_len: 16 + max_len: 16 + }]; + string slug = 2 [(buf.validate.field).string = { + min_len: 2 + max_len: 64 + }]; + } +} + +message PageRequest { + bytes cursor = 1; + int32 page_size = 2; +} +message PageResponse { + bytes next_cursor = 1; + int32 total_count = 2; +} + +// User management + +message User { + bytes id = 1; + string email = 2; + google.protobuf.Timestamp created_at = 3; +} + +message UserCreateRequest { + string email = 1 [(buf.validate.field).string.email = true]; + string password = 2 [(buf.validate.field).string.min_len = 1]; +} +message UserCreateResponse { + bytes id = 1; +} + +message UserGetRequest { + UserRef user = 1 [(buf.validate.field).required = true]; +} +message UserGetResponse { + User user = 1; +} + +message UserListRequest { + optional PageRequest page = 1; + optional string filter = 2; +} +message UserListResponse { + PageResponse page = 1; + repeated User users = 2; +} + +message UserUpdateRequest { + UserRef user = 1 [(buf.validate.field).required = true]; + optional string email = 2 [(buf.validate.field).string.email = true]; + optional string password = 3 [(buf.validate.field).string.min_len = 1]; +} +message UserUpdateResponse {} + +message UserDeleteRequest { + UserRef user = 1 [(buf.validate.field).required = true]; +} +message UserDeleteResponse {} + +// Organization management + +message Org { + bytes id = 1; + string name = 2; + string slug = 3; + bool public = 4; + google.protobuf.Timestamp created_at = 5; +} + +message OrgCreateRequest { + string name = 1 [(buf.validate.field).string.min_len = 1]; + string slug = 2 [(buf.validate.field).string = { + min_len: 2 + max_len: 64 + }]; + UserRef owner = 3 [(buf.validate.field).required = true]; + bool public = 4; +} +message OrgCreateResponse { + bytes id = 1; +} + +message OrgGetRequest { + OrgRef org = 1 [(buf.validate.field).required = true]; +} +message OrgGetResponse { + Org org = 1; +} + +message OrgListRequest { + optional PageRequest page = 1; + optional string filter = 2; +} +message OrgListResponse { + PageResponse page = 1; + repeated Org organizations = 2; +} + +message OrgUpdateRequest { + OrgRef org = 1 [(buf.validate.field).required = true]; + optional string name = 2 [(buf.validate.field).string.min_len = 1]; + optional string slug = 3 [(buf.validate.field).string = { + min_len: 2 + max_len: 64 + }]; + optional bool public = 4; +} +message OrgUpdateResponse {} + +message OrgDeleteRequest { + OrgRef org = 1 [(buf.validate.field).required = true]; +} +message OrgDeleteResponse {} + +// Organization members + +message OrgMemberInfo { + User user = 1; + Role role = 2; + google.protobuf.Timestamp joined_at = 3; +} + +message OrgMemberGetRequest { + OrgRef org = 1 [(buf.validate.field).required = true]; + UserRef user = 2 [(buf.validate.field).required = true]; +} +message OrgMemberGetResponse { + OrgMemberInfo member = 1; +} + +message OrgMemberAddRequest { + OrgRef org = 1 [(buf.validate.field).required = true]; + UserRef user = 2 [(buf.validate.field).required = true]; + Role role = 3 [(buf.validate.field).enum = { + defined_only: true + not_in: [0] + }]; +} +message OrgMemberAddResponse {} + +message OrgMemberListRequest { + optional PageRequest page = 1; + OrgRef org = 2 [(buf.validate.field).required = true]; + optional string filter = 3; +} +message OrgMemberListResponse { + PageResponse page = 1; + repeated OrgMemberInfo members = 2; +} + +message OrgMemberUpdateRequest { + OrgRef org = 1 [(buf.validate.field).required = true]; + UserRef user = 2 [(buf.validate.field).required = true]; + Role role = 3 [(buf.validate.field).enum = { + defined_only: true + not_in: [0] + }]; +} +message OrgMemberUpdateResponse {} + +message OrgMemberRemoveRequest { + OrgRef org = 1 [(buf.validate.field).required = true]; + UserRef user = 2 [(buf.validate.field).required = true]; +} +message OrgMemberRemoveResponse {} + +// Worker management + +message Worker { + bytes id = 1; + bytes public_key = 2; + optional bytes org_id = 3; + google.protobuf.Timestamp created_at = 4; +} + +message WorkerCreateRequest { + bytes public_key = 1 [(buf.validate.field).bytes = { + min_len: 32 + max_len: 32 + }]; + optional OrgRef org = 2; +} +message WorkerCreateResponse { + bytes id = 1; +} + +message WorkerGetRequest { + bytes id = 1 [(buf.validate.field).bytes = { + min_len: 16 + max_len: 16 + }]; +} +message WorkerGetResponse { + Worker worker = 1; +} + +message WorkerListRequest { + optional PageRequest page = 1; + optional string filter = 2; +} +message WorkerListResponse { + PageResponse page = 1; + repeated Worker workers = 2; +} + +message WorkerDeleteRequest { + bytes id = 1 [(buf.validate.field).bytes = { + min_len: 16 + max_len: 16 + }]; +} +message WorkerDeleteResponse {} |
