From 5fab713186a80c22cf00c2d73e127f41c116a84f Mon Sep 17 00:00:00 2001 From: Ephemerish Date: Tue, 5 May 2026 15:49:23 +0800 Subject: [PATCH 1/3] feat(ripple): add experimental UI preferences RPCs and messages Co-authored-by: Copilot --- iam/v1/iam.proto | 61 +++++++++++++++- openapiv2/apidocs.swagger.json | 124 +++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+), 1 deletion(-) diff --git a/iam/v1/iam.proto b/iam/v1/iam.proto index bc06a7bb..e9e159ed 100644 --- a/iam/v1/iam.proto +++ b/iam/v1/iam.proto @@ -9,6 +9,7 @@ import "api/rbac.proto"; import "google/api/annotations.proto"; import "protoc-gen-openapiv2/options/annotations.proto"; import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; option go_package = "github.com/alphauslabs/blueapi/iam"; option java_package = "cloud.alphaus.api.iam"; @@ -297,7 +298,22 @@ service Iam { post: "/iam/v1/ripple/password:reset" body: "*" }; - } + } + + // Gets experimental UI preferences for the authenticated MSP. + rpc GetRippleExperimentalPreferences(GetRippleExperimentalPreferencesRequest) returns (GetRippleExperimentalPreferencesResponse) { + option (google.api.http) = { + get: "/iam/v1/ripple/experimental-ui-preferences" + }; + } + + // Creates or updates an experimental UI preference for a specific component. + rpc UpsertRippleExperimentalPreference(UpsertRippleExperimentalPreferenceRequest) returns (UpsertRippleExperimentalPreferenceResponse) { + option (google.api.http) = { + put: "/iam/v1/ripple/experimental-ui-preferences/{component_id}" + body: "*" + }; + } } // Request message for the Iam.WhoAmI rpc. @@ -672,3 +688,46 @@ message ResetRipplePasswordResponse { string userName = 1; string email = 2; } + +// RippleExperimentalPreference holds the UI version preference and banner state for a single component. +message RippleExperimentalPreference { + // The component identifier this preference applies to. + string component_id = 1; + + // The selected UI version for the component (e.g. "v1" or "v2"). + string version = 2; + + // Whether the experimental banner has been dismissed for this component. + bool banner_dismissed = 3; + + // The timestamp of the last update. + google.protobuf.Timestamp updated_at = 4; +} + +// Request message for the Iam.GetRippleExperimentalPreferences rpc. +// The MSP identity is derived from the auth token server-side. +message GetRippleExperimentalPreferencesRequest {} + +// Response message for the Iam.GetRippleExperimentalPreferences rpc. +message GetRippleExperimentalPreferencesResponse { + // The list of experimental UI preferences for the authenticated MSP. + repeated RippleExperimentalPreference preferences = 1; +} + +// Request message for the Iam.UpsertRippleExperimentalPreference rpc. +message UpsertRippleExperimentalPreferenceRequest { + // The component identifier to create or update a preference for. + string component_id = 1; + + // The selected UI version for the component (e.g. "v1" or "v2"). + string version = 2; + + // Whether the experimental banner has been dismissed for this component. + bool banner_dismissed = 3; +} + +// Response message for the Iam.UpsertRippleExperimentalPreference rpc. +message UpsertRippleExperimentalPreferenceResponse { + // The created or updated preference. + RippleExperimentalPreference preference = 1; +} diff --git a/openapiv2/apidocs.swagger.json b/openapiv2/apidocs.swagger.json index ec518060..52f0eac1 100644 --- a/openapiv2/apidocs.swagger.json +++ b/openapiv2/apidocs.swagger.json @@ -1806,6 +1806,69 @@ ] } }, + "/iam/v1/ripple/experimental-ui-preferences": { + "get": { + "summary": "Gets experimental UI preferences for the authenticated MSP.", + "operationId": "Iam_GetRippleExperimentalPreferences", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1GetRippleExperimentalPreferencesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googlerpcStatus" + } + } + }, + "tags": [ + "Iam" + ] + } + }, + "/iam/v1/ripple/experimental-ui-preferences/{component_id}": { + "put": { + "summary": "Creates or updates an experimental UI preference for a specific component.", + "operationId": "Iam_UpsertRippleExperimentalPreference", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1UpsertRippleExperimentalPreferenceResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googlerpcStatus" + } + } + }, + "parameters": [ + { + "name": "component_id", + "description": "The component identifier to create or update a preference for.", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1UpsertRippleExperimentalPreferenceRequest" + } + } + ], + "tags": [ + "Iam" + ] + } + }, "/iam/v1/ripple/password:reset": { "post": { "summary": "WORK-IN-PROGRESS: Reset ripple password using code from email", @@ -40233,6 +40296,67 @@ }, "title": "Response message for ResetPassword" }, + "v1RippleExperimentalPreference": { + "type": "object", + "properties": { + "component_id": { + "type": "string", + "description": "The component identifier this preference applies to." + }, + "version": { + "type": "string", + "description": "The selected UI version for the component (e.g. \"v1\" or \"v2\")." + }, + "banner_dismissed": { + "type": "boolean", + "description": "Whether the experimental banner has been dismissed for this component." + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "The timestamp of the last update." + } + }, + "description": "RippleExperimentalPreference holds the UI version preference and banner state for a single component." + }, + "v1GetRippleExperimentalPreferencesResponse": { + "type": "object", + "properties": { + "preferences": { + "type": "array", + "items": { + "$ref": "#/definitions/v1RippleExperimentalPreference" + }, + "description": "The list of experimental UI preferences for the authenticated MSP." + } + } + }, + "v1UpsertRippleExperimentalPreferenceRequest": { + "type": "object", + "properties": { + "component_id": { + "type": "string", + "description": "The component identifier to create or update a preference for." + }, + "version": { + "type": "string", + "description": "The selected UI version for the component (e.g. \"v1\" or \"v2\")." + }, + "banner_dismissed": { + "type": "boolean", + "description": "Whether the experimental banner has been dismissed for this component." + } + } + }, + "v1UpsertRippleExperimentalPreferenceResponse": { + "type": "object", + "properties": { + "preference": { + "$ref": "#/definitions/v1RippleExperimentalPreference", + "description": "The created or updated preference." + } + } + }, "v1ResetRipplePasswordRequest": { "type": "object", "properties": { From 0571e1582bdd5ffde7df0702c6befb8e5df02d52 Mon Sep 17 00:00:00 2001 From: Ephemerish Date: Tue, 5 May 2026 17:43:30 +0800 Subject: [PATCH 2/3] fix: address PR review - remove Ripple prefix, use /experimentalui/preferences path --- iam/v1/iam.proto | 32 ++++++++++++++++---------------- openapiv2/apidocs.swagger.json | 26 +++++++++++++------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/iam/v1/iam.proto b/iam/v1/iam.proto index 3516a86e..c5c1f39c 100644 --- a/iam/v1/iam.proto +++ b/iam/v1/iam.proto @@ -301,16 +301,16 @@ service Iam { } // Gets experimental UI preferences for the authenticated MSP. - rpc GetRippleExperimentalPreferences(GetRippleExperimentalPreferencesRequest) returns (GetRippleExperimentalPreferencesResponse) { + rpc GetExperimentalPreferences(GetExperimentalPreferencesRequest) returns (GetExperimentalPreferencesResponse) { option (google.api.http) = { - get: "/iam/v1/ripple/experimental-ui-preferences" + get: "/iam/v1/experimentalui/preferences" }; } // Creates or updates an experimental UI preference for a specific component. - rpc UpsertRippleExperimentalPreference(UpsertRippleExperimentalPreferenceRequest) returns (UpsertRippleExperimentalPreferenceResponse) { + rpc UpsertExperimentalPreference(UpsertExperimentalPreferenceRequest) returns (UpsertExperimentalPreferenceResponse) { option (google.api.http) = { - put: "/iam/v1/ripple/experimental-ui-preferences/{component_id}" + put: "/iam/v1/experimentalui/preferences/{component_id}" body: "*" }; } @@ -697,8 +697,8 @@ message ResetRipplePasswordResponse { string email = 2; } -// RippleExperimentalPreference holds the UI version preference and banner state for a single component. -message RippleExperimentalPreference { +// ExperimentalPreference holds the UI version preference and banner state for a single component. +message ExperimentalPreference { // The component identifier this preference applies to. string component_id = 1; @@ -712,18 +712,18 @@ message RippleExperimentalPreference { google.protobuf.Timestamp updated_at = 4; } -// Request message for the Iam.GetRippleExperimentalPreferences rpc. +// Request message for the Iam.GetExperimentalPreferences rpc. // The MSP identity is derived from the auth token server-side. -message GetRippleExperimentalPreferencesRequest {} +message GetExperimentalPreferencesRequest {} -// Response message for the Iam.GetRippleExperimentalPreferences rpc. -message GetRippleExperimentalPreferencesResponse { +// Response message for the Iam.GetExperimentalPreferences rpc. +message GetExperimentalPreferencesResponse { // The list of experimental UI preferences for the authenticated MSP. - repeated RippleExperimentalPreference preferences = 1; + repeated ExperimentalPreference preferences = 1; } -// Request message for the Iam.UpsertRippleExperimentalPreference rpc. -message UpsertRippleExperimentalPreferenceRequest { +// Request message for the Iam.UpsertExperimentalPreference rpc. +message UpsertExperimentalPreferenceRequest { // The component identifier to create or update a preference for. string component_id = 1; @@ -734,10 +734,10 @@ message UpsertRippleExperimentalPreferenceRequest { bool banner_dismissed = 3; } -// Response message for the Iam.UpsertRippleExperimentalPreference rpc. -message UpsertRippleExperimentalPreferenceResponse { +// Response message for the Iam.UpsertExperimentalPreference rpc. +message UpsertExperimentalPreferenceResponse { // The created or updated preference. - RippleExperimentalPreference preference = 1; + ExperimentalPreference preference = 1; } message UnlockUserAccountRequest { diff --git a/openapiv2/apidocs.swagger.json b/openapiv2/apidocs.swagger.json index e48eebff..84aa7f03 100644 --- a/openapiv2/apidocs.swagger.json +++ b/openapiv2/apidocs.swagger.json @@ -1924,15 +1924,15 @@ ] } }, - "/iam/v1/ripple/experimental-ui-preferences": { + "/iam/v1/experimentalui/preferences": { "get": { "summary": "Gets experimental UI preferences for the authenticated MSP.", - "operationId": "Iam_GetRippleExperimentalPreferences", + "operationId": "Iam_GetExperimentalPreferences", "responses": { "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/v1GetRippleExperimentalPreferencesResponse" + "$ref": "#/definitions/v1GetExperimentalPreferencesResponse" } }, "default": { @@ -1947,15 +1947,15 @@ ] } }, - "/iam/v1/ripple/experimental-ui-preferences/{component_id}": { + "/iam/v1/experimentalui/preferences/{component_id}": { "put": { "summary": "Creates or updates an experimental UI preference for a specific component.", - "operationId": "Iam_UpsertRippleExperimentalPreference", + "operationId": "Iam_UpsertExperimentalPreference", "responses": { "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/v1UpsertRippleExperimentalPreferenceResponse" + "$ref": "#/definitions/v1UpsertExperimentalPreferenceResponse" } }, "default": { @@ -1978,7 +1978,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/v1UpsertRippleExperimentalPreferenceRequest" + "$ref": "#/definitions/v1UpsertExperimentalPreferenceRequest" } } ], @@ -48625,7 +48625,7 @@ }, "title": "Response message for ResetPassword" }, - "v1RippleExperimentalPreference": { + "v1ExperimentalPreference": { "type": "object", "properties": { "component_id": { @@ -48648,19 +48648,19 @@ }, "description": "RippleExperimentalPreference holds the UI version preference and banner state for a single component." }, - "v1GetRippleExperimentalPreferencesResponse": { + "v1GetExperimentalPreferencesResponse": { "type": "object", "properties": { "preferences": { "type": "array", "items": { - "$ref": "#/definitions/v1RippleExperimentalPreference" + "$ref": "#/definitions/v1ExperimentalPreference" }, "description": "The list of experimental UI preferences for the authenticated MSP." } } }, - "v1UpsertRippleExperimentalPreferenceRequest": { + "v1UpsertExperimentalPreferenceRequest": { "type": "object", "properties": { "component_id": { @@ -48677,11 +48677,11 @@ } } }, - "v1UpsertRippleExperimentalPreferenceResponse": { + "v1UpsertExperimentalPreferenceResponse": { "type": "object", "properties": { "preference": { - "$ref": "#/definitions/v1RippleExperimentalPreference", + "$ref": "#/definitions/v1ExperimentalPreference", "description": "The created or updated preference." } } From 49b242bc233d44cb98f262b5cb13e5666d3f409d Mon Sep 17 00:00:00 2001 From: Ephemerish Date: Tue, 5 May 2026 18:04:09 +0800 Subject: [PATCH 3/3] fix: rename ExperimentalPreference to ExperimentalUIPreference for clarity --- iam/v1/iam.proto | 28 ++++++++++++++-------------- openapiv2/apidocs.swagger.json | 22 +++++++++++----------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/iam/v1/iam.proto b/iam/v1/iam.proto index c5c1f39c..3076ef62 100644 --- a/iam/v1/iam.proto +++ b/iam/v1/iam.proto @@ -301,14 +301,14 @@ service Iam { } // Gets experimental UI preferences for the authenticated MSP. - rpc GetExperimentalPreferences(GetExperimentalPreferencesRequest) returns (GetExperimentalPreferencesResponse) { + rpc GetExperimentalUIPreferences(GetExperimentalUIPreferencesRequest) returns (GetExperimentalUIPreferencesResponse) { option (google.api.http) = { get: "/iam/v1/experimentalui/preferences" }; } // Creates or updates an experimental UI preference for a specific component. - rpc UpsertExperimentalPreference(UpsertExperimentalPreferenceRequest) returns (UpsertExperimentalPreferenceResponse) { + rpc UpsertExperimentalUIPreference(UpsertExperimentalUIPreferenceRequest) returns (UpsertExperimentalUIPreferenceResponse) { option (google.api.http) = { put: "/iam/v1/experimentalui/preferences/{component_id}" body: "*" @@ -697,8 +697,8 @@ message ResetRipplePasswordResponse { string email = 2; } -// ExperimentalPreference holds the UI version preference and banner state for a single component. -message ExperimentalPreference { +// ExperimentalUIPreference holds the UI version preference and banner state for a single component. +message ExperimentalUIPreference { // The component identifier this preference applies to. string component_id = 1; @@ -712,18 +712,18 @@ message ExperimentalPreference { google.protobuf.Timestamp updated_at = 4; } -// Request message for the Iam.GetExperimentalPreferences rpc. +// Request message for the Iam.GetExperimentalUIPreferences rpc. // The MSP identity is derived from the auth token server-side. -message GetExperimentalPreferencesRequest {} +message GetExperimentalUIPreferencesRequest {} -// Response message for the Iam.GetExperimentalPreferences rpc. -message GetExperimentalPreferencesResponse { +// Response message for the Iam.GetExperimentalUIPreferences rpc. +message GetExperimentalUIPreferencesResponse { // The list of experimental UI preferences for the authenticated MSP. - repeated ExperimentalPreference preferences = 1; + repeated ExperimentalUIPreference preferences = 1; } -// Request message for the Iam.UpsertExperimentalPreference rpc. -message UpsertExperimentalPreferenceRequest { +// Request message for the Iam.UpsertExperimentalUIPreference rpc. +message UpsertExperimentalUIPreferenceRequest { // The component identifier to create or update a preference for. string component_id = 1; @@ -734,10 +734,10 @@ message UpsertExperimentalPreferenceRequest { bool banner_dismissed = 3; } -// Response message for the Iam.UpsertExperimentalPreference rpc. -message UpsertExperimentalPreferenceResponse { +// Response message for the Iam.UpsertExperimentalUIPreference rpc. +message UpsertExperimentalUIPreferenceResponse { // The created or updated preference. - ExperimentalPreference preference = 1; + ExperimentalUIPreference preference = 1; } message UnlockUserAccountRequest { diff --git a/openapiv2/apidocs.swagger.json b/openapiv2/apidocs.swagger.json index 84aa7f03..5c81651c 100644 --- a/openapiv2/apidocs.swagger.json +++ b/openapiv2/apidocs.swagger.json @@ -1927,12 +1927,12 @@ "/iam/v1/experimentalui/preferences": { "get": { "summary": "Gets experimental UI preferences for the authenticated MSP.", - "operationId": "Iam_GetExperimentalPreferences", + "operationId": "Iam_GetExperimentalUIPreferences", "responses": { "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/v1GetExperimentalPreferencesResponse" + "$ref": "#/definitions/v1GetExperimentalUIPreferencesResponse" } }, "default": { @@ -1950,12 +1950,12 @@ "/iam/v1/experimentalui/preferences/{component_id}": { "put": { "summary": "Creates or updates an experimental UI preference for a specific component.", - "operationId": "Iam_UpsertExperimentalPreference", + "operationId": "Iam_UpsertExperimentalUIPreference", "responses": { "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/v1UpsertExperimentalPreferenceResponse" + "$ref": "#/definitions/v1UpsertExperimentalUIPreferenceResponse" } }, "default": { @@ -1978,7 +1978,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/v1UpsertExperimentalPreferenceRequest" + "$ref": "#/definitions/v1UpsertExperimentalUIPreferenceRequest" } } ], @@ -48625,7 +48625,7 @@ }, "title": "Response message for ResetPassword" }, - "v1ExperimentalPreference": { + "v1ExperimentalUIPreference": { "type": "object", "properties": { "component_id": { @@ -48648,19 +48648,19 @@ }, "description": "RippleExperimentalPreference holds the UI version preference and banner state for a single component." }, - "v1GetExperimentalPreferencesResponse": { + "v1GetExperimentalUIPreferencesResponse": { "type": "object", "properties": { "preferences": { "type": "array", "items": { - "$ref": "#/definitions/v1ExperimentalPreference" + "$ref": "#/definitions/v1ExperimentalUIPreference" }, "description": "The list of experimental UI preferences for the authenticated MSP." } } }, - "v1UpsertExperimentalPreferenceRequest": { + "v1UpsertExperimentalUIPreferenceRequest": { "type": "object", "properties": { "component_id": { @@ -48677,11 +48677,11 @@ } } }, - "v1UpsertExperimentalPreferenceResponse": { + "v1UpsertExperimentalUIPreferenceResponse": { "type": "object", "properties": { "preference": { - "$ref": "#/definitions/v1ExperimentalPreference", + "$ref": "#/definitions/v1ExperimentalUIPreference", "description": "The created or updated preference." } }