syntax = "proto3";

package confidence.flags.admin.v1;

import "google/api/client.proto";
import "google/api/httpbody.proto";
import "google/api/resource.proto";
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";
import "google/type/decimal.proto";

import "confidence/flags/types/v1/target.proto";
import "confidence/flags/admin/v1/types.proto";
import "confidence/flags/resolver/v1/events/events.proto";
import "confidence/auth/v1/auth.proto";
import "confidence/api/annotations.proto";

// This import is needed for the events service to be able to introspect what messages exist in the service.
import "confidence/flags/admin/v1/events/events.proto";
import "confidence/flags/admin/v1/events/events_internal.proto";

option java_package = "com.spotify.confidence.flags.admin.v1";
option java_multiple_files = true;
option java_outer_classname = "ApiProto";

// The service manages flags and its related resources: rules, segments, and
// variants.
service FlagAdminService {
  option (confidence.api.service_name) = "Flags";
  option (confidence.api.hosts) = "flags.eu.confidence.dev";
  option (confidence.api.hosts) = "flags.us.confidence.dev";

  option (confidence.api.service_rate_limit).rps_limit = 50;

  // Creates a new flag. Flags are used to control part of an application by
  // defining a set of rules that deterministically or randomly assign variants
  // to users.
  //
  // Only the `flag_id` is required when creating the flag, the remaining
  // attributes can be set by calling `UpdateFlag`. When creating a flag it will
  // start in the `ACTIVE` state, when you no longer need a flag you can call
  // `ArchiveFlag`.
  rpc CreateFlag(CreateFlagRequest) returns (Flag) {
    option (google.api.http) = {
      post: "/v1/flags"
      body: "flag"
    };
    option (google.api.method_signature) = "flag,flag_id";
    option (confidence.auth.v1.auth) = {
      required_permission: CREATE_FLAGS,
      required_relation: "can_create_flag",
      object_field: "account"
    };
  }

  // Updates the flag. When updating a flag, all variants must match the schema,
  // segments and variants referenced by rules must exist.
  rpc UpdateFlag(UpdateFlagRequest) returns (Flag) {
    option (google.api.http) = {
      patch: "/v1/{flag.name=flags/*}"
      body: "flag"
    };
    option (google.api.method_signature) = "flag,update_mask";
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_FLAGS,
      required_relation: "can_edit",
      object_field: "flag.name"
    };
  }

  // Get a flag.
  rpc GetFlag(GetFlagRequest) returns (Flag) {
    option (google.api.http) = {
      get: "/v1/{name=flags/*}"
    };
    option (google.api.method_signature) = "name";
    option (confidence.auth.v1.auth) = {
      required_permission: READ_FLAGS,
      required_relation: "can_read",
      object_field: "name"
    };
  }

  // List all flags optionally filtered by state. The flags are ordered by
  // `updateTime`.
  rpc ListFlags(ListFlagsRequest) returns (ListFlagsResponse) {
    option (google.api.http) = {
      get: "/v1/flags"
    };
    option (confidence.auth.v1.auth) = {
      required_permission: LIST_FLAGS
    };
  }

  // Archive a flag. It will no longer be possible to resolve this flag, and it
  // will no be included in batch resolves.
  rpc ArchiveFlag(ArchiveFlagRequest) returns (Flag) {
    option (google.api.http) = {
      post: "/v1/{name=flags/*}:archive"
      body: "*"
    };
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_FLAGS,
      required_relation: "can_edit",
      object_field: "name"
    };
  }

  // Enables the client to resolve the given flag.
  rpc AddFlagClient(AddFlagClientRequest) returns (Flag) {
    option (google.api.http) = {
      post: "/v1/{flag=flags/*}:addFlagClient"
      body: "*"
    };
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_FLAGS,
      required_relation: "can_edit",
      object_field: "flag"
    };
  }

  // Disables the client from resolving the given flag.
  rpc RemoveFlagClient(RemoveFlagClientRequest) returns (Flag) {
    option (google.api.http) = {
      post: "/v1/{flag=flags/*}:removeFlagClient"
      body: "*"
    };
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_FLAGS,
      required_relation: "can_edit",
      object_field: "flag"
    };
  }

  // Query time series data about how much this flag was used recently. You
  // cannot query more than 7 days back in time.
  rpc QueryFlagUsage(QueryFlagUsageRequest) returns (QueryFlagUsageResponse) {
    option (google.api.http) = {
      post: "/v1/{flag=flags/*}/usage:query"
      body: "*"
    };
    option (confidence.auth.v1.auth) = {
      required_permission: READ_FLAGS,
      required_relation: "can_read",
      object_field: "flag"
    };
    option (confidence.api.resource_method).type = "flags.confidence.dev/Flag";
  }

  // Get a specific variant of the given flag.
  rpc GetVariant(GetVariantRequest) returns (Flag.Variant) {
    option (google.api.http) = {
      get: "/v1/{name=flags/*/variants/*}"
    };
    option (google.api.method_signature) = "name";
    option (confidence.auth.v1.auth) = {
      required_permission: READ_FLAGS,
      required_relation: "can_read",
      object_field: "name"
    };
  }

  // Creates a new variant and add it to the given flag. A variant is a named
  // value that typically represents a group of settings that can be used to
  // control part of an application.
  //
  // Before you can create a variant the flag must have a schema, and the
  // variant must satisfy the schema.
  rpc CreateVariant(CreateVariantRequest) returns (Flag.Variant) {
    option (google.api.http) = {
      post: "/v1/{parent=flags/*}/variants"
      body: "variant"
    };
    option (google.api.method_signature) = "parent,variant";
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_FLAGS,
      required_relation: "can_create_variant",
      object_field: "parent"
    };
  }

  // Updates a variant of a flag. The updated variant must satisfy the schema
  // of the flag.
  rpc UpdateVariant(UpdateVariantRequest) returns (Flag.Variant) {
    option (google.api.http) = {
      patch:"/v1/{variant.name=flags/*/variants/*}"
      body: "variant"
    };
    option (google.api.method_signature) = "variant,update_mask";
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_FLAGS,
      required_relation: "can_edit",
      object_field: "variant.name"
    };
  }

  // Deletes a variant. Variants that are used by one or more rules cannot be
  // deleted.
  rpc DeleteVariant(DeleteVariantRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v1/{name=flags/*/variants/*}"
    };
    option (google.api.method_signature) = "name";
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_FLAGS,
      required_relation: "can_edit",
      object_field: "name"
    };
  }

  // List all the variants of this flag. The variants are returned in the order
  // they were added to the flag.
  rpc ListVariants(ListVariantsRequest) returns (ListVariantsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=flags/*}/variants"
    };
    option (google.api.method_signature) = "parent";
    option (confidence.auth.v1.auth) = {
      required_permission: READ_FLAGS
    };
  }

  // Get a rule of a flag.
  rpc GetRule(GetRuleRequest) returns (Flag.Rule) {
    option (google.api.http) = {
      get: "/v1/{name=flags/*/rules/*}"
    };
    option (google.api.method_signature) = "name";
    option (confidence.auth.v1.auth) = {
      required_permission: READ_FLAGS,
      required_relation: "can_read",
      object_field: "name"
    };
  }

  // Create a new rule. A rule decides at which proportions user from a specific
  // segment should be assigned variants from the flag.
  rpc CreateRule(CreateRuleRequest) returns (Flag.Rule) {
    option (google.api.http) = {
      post: "/v1/{parent=flags/*}/rules"
      body: "rule"
    };
    option (google.api.method_signature) = "parent,rule";
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_FLAGS,
      required_relation: "can_create_rule",
      object_field: "parent"
    };
  }

  // Update a rule. The segment and variants referred to by the rule must exist.
  rpc UpdateRule(UpdateRuleRequest) returns (Flag.Rule) {
    option (google.api.http) = {
      patch: "/v1/{rule.name=flags/*/rules/*}"
      body: "rule"
    };
    option (google.api.method_signature) = "rule,update_mask";
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_FLAGS,
      required_relation: "can_edit",
      object_field: "rule.name"
    };
  }

  // Delete a rule. Note, entities that previously matched this rule, will
  // now be passed on to the next rule.
  rpc DeleteRule(DeleteRuleRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v1/{name=flags/*/rules/*}"
    };
    option (google.api.method_signature) = "name";
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_FLAGS,
      required_relation: "can_edit",
      object_field: "name"
    };
  }

  // List all rules of the flag. Rules are returned in the same order as they
  // are evaluated.
  rpc ListRules(ListRulesRequest) returns (ListRulesResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=flags/*}/rules"
    };
    option (google.api.method_signature) = "parent";
    option (confidence.auth.v1.auth) = {
      required_permission: READ_FLAGS
    };
  }

  // Create a new segment. A segment defines a part of the population of an
  // entity, for example, the population of users. It contains an overall
  // proportion of the population as well as optional targeting criteria, like
  // the country a user is from. A segment can also be coordinated with other
  // segments, by setting `exclusivity_tags` and `exclusive_to`, preventing one
  // user to be included in two segments, that are exclusive to each other,
  // simultaneously.
  //
  // Note, the segment is not active until it is allocated.
  rpc CreateSegment(CreateSegmentRequest) returns (Segment) {
    option (google.api.http) = {
      post: "/v1/segments"
      body: "segment"
    };
    option (google.api.method_signature) = "segment";
    option (confidence.auth.v1.auth) = {
      required_permission: CREATE_SEGMENTS,
      required_relation: "can_create_segment",
      object_field: "account"
    };
  }

  // Update the segment. Only segments in state UNALLOCATED can be updated.
  rpc UpdateSegment(UpdateSegmentRequest) returns (Segment) {
    option (google.api.http) = {
      patch: "/v1/{segment.name=segments/*}"
      body: "segment"
    };
    option (google.api.method_signature) = "segment,update_mask";
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_SEGMENTS,
      required_relation: "can_edit",
      object_field: "segment.name"
    };
  }

  // Get a segment.
  rpc GetSegment(GetSegmentRequest) returns (Segment) {
    option (google.api.http) = {
      get: "/v1/{name=segments/*}"
    };
    option (google.api.method_signature) = "name";
    option (confidence.auth.v1.auth) = {
      required_permission: READ_SEGMENTS,
      required_relation: "can_read",
      object_field: "name"
    };
  }

  // List segments. Segments are listed in no particular order.
  rpc ListSegments(ListSegmentsRequest) returns (ListSegmentsResponse) {
    option (google.api.http) = {
      get: "/v1/segments"
    };
    option (confidence.auth.v1.auth) = {
      required_permission: LIST_SEGMENTS
    };
  }

  // Allocate the segment so that it can be used. Note, if the segment is
  // coordinated, it can only be allocated if there is remaining space.
  rpc AllocateSegment(AllocateSegmentRequest) returns (Segment) {
    option (google.api.http) = {
      post: "/v1/{name=segments/*}:allocate"
      body: "*"
    };
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_SEGMENTS,
      required_relation: "can_edit",
      object_field: "name"
    };
  }

  // Archive the segment. To archive the segment it must be `ALLOCATED` and
  // there must be no rules currently referencing the segment.
  rpc ArchiveSegment(ArchiveSegmentRequest) returns (Segment) {
    option (google.api.http) = {
      post: "/v1/{name=segments/*}:archive"
      body: "*"
    };
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_SEGMENTS,
      required_relation: "can_edit",
      object_field: "name"
    };
  }

  // Check if there is space available for a specific segment to be allocated.
  // Used when a segment is coordinated before trying to allocate it.
  rpc SegmentAvailableSpace(SegmentAvailableSpaceRequest) returns (SegmentAvailableSpaceResponse) {
    option (google.api.http) = {
      post: "/v1/{segment=segments/*}:segmentAvailableSpace"
      body: "*"
    };
    option (confidence.auth.v1.auth) = {
      required_permission: READ_SEGMENTS,
      required_relation: "can_view_segment",
      object_field: "account"
    };
    option (confidence.api.resource_method).type = "flags.confidence.dev/Segment";
  }

  // Infer the schema of the evaluation context for a specific set of clients,
  // that has previously been used to resolve one or more flags.
  rpc DeriveClientEvaluationContextSchema(DeriveClientEvaluationContextSchemaRequest) returns (DeriveClientEvaluationContextSchemaResponse) {
    option (google.api.http) = {
      post: "/v1/clientEvaluationContextSchema:derive"
      body: "*"
    };
    option (confidence.auth.v1.auth) = {
      required_permission: READ_CLIENT_SCHEMA
      required_relation: "can_read",
      object_field: "clients"
    };
    option (confidence.api.resource_method).type = "iam.confidence.dev/Client";
  }

  // Writes pre-aggregated information about how a flag has been resolved. Mostly called from the resolver
  rpc WriteResolveInfo(WriteResolveInfoRequest) returns (WriteResolveInfoResponse){
    option (google.api.http) = {
      post: "/v1/resolveInfo:write"
      body: "*"
    };
    option (confidence.auth.v1.auth) = {
      required_permission: CREATE_RESOLVE_INFO
      allow_basic_auth: true
      required_relation: "can_write_resolve_info"
      object_field: "account"
    };
  }

  // Writes flag assignment events. Mostly called from the sidecar resolver.
  // (-- api-linter: core::0136::http-uri-suffix=disabled
  //     aip.dev/not-precedent: Disabled because the additional binding. --)
  rpc WriteFlagAssigned(WriteFlagAssignedRequest) returns (WriteFlagAssignedResponse){
    option (google.api.http) = {
      post: "/v1/flagAssigned:write"
      body: "*"
      additional_bindings {
        post: "/v1/flagAssigned:writeArray"
        body: "flag_assigned"
      }
    };
    option (confidence.auth.v1.auth) = {
      required_permission: CREATE_FLAG_ASSIGNED
      allow_basic_auth: true
      required_relation: "can_write_flag_assigned"
      object_field: "account"
    };
  }

  // Create a new materialized segment. The materialization can then be attached to rules.
  rpc CreateMaterializedSegment(CreateMaterializedSegmentRequest) returns (MaterializedSegment) {
    option (google.api.http) = {
      post: "/v1/materializedSegments"
      body: "materialized_segment"
    };
    option (google.api.method_signature) = "materialized_segment,materialized_segment_id";
    option (confidence.auth.v1.auth) = {
      required_permission: CREATE_MATERIALIZED_SEGMENTS,
      required_relation: "can_create_materialized_segment",
      object_field: "account"
    };
  }

  // Update a rule. The segment and variants referred to by the rule must exist.
  rpc UpdateMaterializedSegment(UpdateMaterializedSegmentRequest) returns (MaterializedSegment) {
    option (google.api.http) = {
      patch: "/v1/{materialized_segment.name=materializedSegments/*}"
      body: "materialized_segment"
    };
    option (google.api.method_signature) = "materialized_segment,update_mask";
    option (confidence.auth.v1.auth) = {
      required_permission: UPDATE_MATERIALIZED_SEGMENTS,
      required_relation: "can_edit",
      object_field: "materialized_segment.name"
    };
  }

  // Delete a materialized segment.
  rpc DeleteMaterializedSegment(DeleteMaterializedSegmentRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v1/{name=materializedSegments/*}"
    };
    option (google.api.method_signature) = "name";
    option (confidence.auth.v1.auth) = {
      required_permission: DELETE_MATERIALIZED_SEGMENTS,
      required_relation: "can_edit",
      object_field: "name"
    };
  }

  // List all materialized segments.
  rpc ListMaterializedSegments(ListMaterializedSegmentsRequest) returns (ListMaterializedSegmentsResponse) {
    option (google.api.http) = {
      get: "/v1/materializedSegments"
    };
    option (google.api.method_signature) = "parent";
    option (confidence.auth.v1.auth) = {
      required_permission: LIST_MATERIALIZED_SEGMENTS
    };
  }

  // Get a materialized segment.
  rpc GetMaterializedSegment(GetMaterializedSegmentRequest) returns (MaterializedSegment) {
    option (google.api.http) = {
      get: "/v1/{name=materializedSegments/*}"
    };
    option (google.api.method_signature) = "name";
    option (confidence.auth.v1.auth) = {
      required_permission: READ_MATERIALIZED_SEGMENTS,
      required_relation: "can_read",
      object_field: "name"
    };
  }

  // Challenge response endpoint for Fastly logging.
  // See: https://docs.fastly.com/en/guides/log-streaming-https#prerequisites
  // (-- api-linter: core::0127::http-template-syntax=disabled
  //     api-linter: core::0131::request-message-name=disabled
  //     api-linter: core::0131::http-uri-name=disabled
  //     api-linter: core::0131::method-signature=disabled
  //     api-linter: core::0131::response-message-name=disabled
  //     aip.dev/not-precedent: This is a non-AIP-conforming endpoint. --)
  rpc GetFastlyLoggingChallenge(google.protobuf.Empty) returns (google.api.HttpBody) {
    option (google.api.http) = {
      get: "/.well-known/fastly/logging/challenge"
    };
    option (confidence.auth.v1.auth) = {
      disable_authorization: true
    };
  }


  // Creates a new context field override.
  rpc CreateEvaluationContextFieldOverride(CreateEvaluationContextFieldOverrideRequest) returns (EvaluationContextFieldOverride) {
    option (google.api.http) = {
      post: "/v1/evaluationContextFieldOverrides"
      body: "evaluation_context_field_override"
    };
    option (google.api.method_signature) = "evaluation_context_field_override";
    option (confidence.auth.v1.auth) = {
      required_relation: "can_create_evaluation_context_field_override",
      object_field: "account"
    };
  }

  // Updates an existing context field override.
  rpc UpdateEvaluationContextFieldOverride(UpdateEvaluationContextFieldOverrideRequest) returns (EvaluationContextFieldOverride) {
    option (google.api.http) = {
      patch: "/v1/{evaluation_context_field_override.name=evaluationContextFieldOverrides/*}"
      body: "evaluation_context_field_override"
    };
    option (google.api.method_signature) = "evaluation_context_field_override,update_mask";
    option (confidence.auth.v1.auth) = {
      required_relation: "can_edit",
      object_field: "evaluation_context_field_override.name"
    };
  }

  // Get a context field override.
  rpc GetEvaluationContextFieldOverride(GetEvaluationContextFieldOverrideRequest) returns (EvaluationContextFieldOverride) {
    option (google.api.http) = {
      get: "/v1/{name=evaluationContextFieldOverrides/*}"
    };
    option (google.api.method_signature) = "name";
    option (confidence.auth.v1.auth) = {
      required_relation: "can_read",
      object_field: "name"
    };
  }

  // List context field overrides.
  rpc ListEvaluationContextFieldOverrides(ListEvaluationContextFieldOverridesRequest) returns (ListEvaluationContextFieldOverridesResponse) {
    option (google.api.http) = {
      get: "/v1/evaluationContextFieldOverrides"
    };
    option (confidence.auth.v1.auth) = {
    };
  }


  // Delete a context field override.
  rpc DeleteEvaluationContextFieldOverride(DeleteEvaluationContextFieldOverrideRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v1/{name=evaluationContextFieldOverrides/*}"
    };
    option (google.api.method_signature) = "name";
    option (confidence.auth.v1.auth) = {
      required_relation: "can_edit",
      object_field: "name"
    };
  }
}

// Request to delete a context field override.
message DeleteEvaluationContextFieldOverrideRequest {
  // The resource reference to the context field override that you want to delete.
  string name = 1 [
    (google.api.resource_reference).type = "flags.confidence.dev/EvaluationContextFieldOverride",
    (google.api.field_behavior) = REQUIRED
  ];
}

// Request to get a context field override.
message GetEvaluationContextFieldOverrideRequest {
  // The resource reference to the context field override that you want to fetch.
  string name = 1 [
    (google.api.resource_reference).type = "flags.confidence.dev/EvaluationContextFieldOverride",
    (google.api.field_behavior) = REQUIRED
  ];
}

// List the context field overrides.
message ListEvaluationContextFieldOverridesRequest {
  // The maximum number of overrides to fetch.
  int32 page_size = 1;

  // Token used for pagination.
  string page_token = 2;

  // Filter to apply to the overrides. This follows the lucene query string format
  string filter = 3;
}

// The returned list of overrides.
message ListEvaluationContextFieldOverridesResponse {
  // The list of overrides.
  repeated EvaluationContextFieldOverride evaluation_context_field_overrides = 1 [(google.api.field_behavior) = REQUIRED];

  // A token that can be used to fetch more overrides, empty if no more overrides are available.
  string next_page_token = 2 [(google.api.field_behavior) = OPTIONAL];
}

// Updates an existing override for a context field.
message UpdateEvaluationContextFieldOverrideRequest {
  // The updated field.
  EvaluationContextFieldOverride evaluation_context_field_override = 1 [(google.api.field_behavior) = REQUIRED];
  // The list of fields in the Rule that you want to update e.g. 'display_name',
  // if empty all mutable properties are updated.
  // Fields are specified relative to evaluation_context_field_override.
  google.protobuf.FieldMask update_mask = 2 [(google.api.field_behavior) = OPTIONAL];
}

// Create a new override for a context field.
message CreateEvaluationContextFieldOverrideRequest {
  // The properties to use for the override.
  EvaluationContextFieldOverride evaluation_context_field_override = 1 [(google.api.field_behavior) = REQUIRED];
}

// Create a new materialized segment.
message CreateMaterializedSegmentRequest {
  // The properties of the materialization to be created.
  MaterializedSegment materialized_segment = 1 [(google.api.field_behavior) = REQUIRED];

  // The id of the materialization which would be the the last segment of the resource name
  // such as 'materializedSegments/{materialized_segment_id}'. If none is specified a server generated one
  // will be used.
  string materialized_segment_id = 2 [(google.api.field_behavior) = OPTIONAL];
}

// Update an existing materialized segment.
message UpdateMaterializedSegmentRequest {
  // The properties of the materialization to update.
  MaterializedSegment materialized_segment = 1 [(google.api.field_behavior) = REQUIRED];

  // The list of fields in the Rule that you want to update e.g. 'display_name',
  // if empty all mutable properties are updated.
  // Fields are specified relative to the materialization.
  google.protobuf.FieldMask update_mask = 2;
}

// List the materialized segments.
message ListMaterializedSegmentsRequest {
  // The maximum number of materialized segments to fetch.
  int32 page_size = 1;

  // Token used for pagination.
  string page_token = 2;

  // Filter to apply to the materialized segments. This follows the lucene query string format
  string filter = 3;
}

// The returned list of rules.
message ListMaterializedSegmentsResponse {
  // The list of materialized segments.
  repeated MaterializedSegment materialized_segments = 1 [(google.api.field_behavior) = REQUIRED];

  // A token that can be used to fetch more materializations, empty if no more materializations
  // are available.
  string next_page_token = 2;
}

// Request to delete a materialized segment
message DeleteMaterializedSegmentRequest {
  // The resource reference to a materialized segment that you want to delete.
  string name = 1 [
    (google.api.resource_reference).type = "flags.confidence.dev/MaterializedSegment",
    (google.api.field_behavior) = REQUIRED
  ];
}

// Request to get a materialized segment.
message GetMaterializedSegmentRequest {
  // The resource reference to a materialized segment that you want to fetch.
  string name = 1 [
    (google.api.resource_reference).type = "flags.confidence.dev/MaterializedSegment",
    (google.api.field_behavior) = REQUIRED
  ];
}


// A request to write flag assignments
message WriteFlagAssignedRequest {
  // List of flag assigned events to write
  repeated confidence.flags.resolver.v1.events.FlagAssigned flag_assigned = 1;
}

// Response to writing flag assignments
message WriteFlagAssignedResponse {
  // The total number of assigned flags, should equal the sum of the flag counts in each flag
  // assigned event.
  int64 assigned_flags = 1;
}

// A request to write flag resolve info
message WriteResolveInfoRequest {
  // Information about how clients have resolved
  repeated ClientResolveInfo client_resolve_info = 1;
  // Information about how flags were resolved
  repeated FlagResolveInfo flag_resolve_info = 2;
}

// Response to writing resolve info
message WriteResolveInfoResponse {

}

// Query a time series of resolves for a flag.
message QueryFlagUsageRequest {
  // Resource name of a flag.
  string flag = 1 [
    (google.api.resource_reference).type = "flags.confidence.dev/Flag",
    (google.api.field_behavior) = REQUIRED
  ];

  // Start time of the query, can at most be 7 days before the current date.
  google.protobuf.Timestamp start_time = 2 [(google.api.field_behavior) = REQUIRED];

  // End time of the query.
  google.protobuf.Timestamp end_time = 3 [(google.api.field_behavior) = REQUIRED];
}

// The measured usage at specific hour.
message FlagUsageEntry {
  // The hour the usage was recorded.
  google.protobuf.Timestamp hour_time = 1 [(google.api.field_behavior) = REQUIRED];

  // The usage of each variant of the flag.
  map<string, VariantUsage>  variants = 2;

  // The usage of a specific variant.
  message VariantUsage {
    // The number of times this variant was resolved in the time interval.
    int64 resolve_count = 1;

    // The number of times this variant was applied in the time interval.
    int64 apply_count = 2;
  }
}

// The measured usage in the queried time period.
message QueryFlagUsageResponse {
  // The usage time series.
  repeated FlagUsageEntry usage = 1;
}

// Request the schema of the evaluation context for one or more clients. The
// schema is inferred from historical data from flag resolves.
message DeriveClientEvaluationContextSchemaRequest {
  // The list of clients to infer the schema for.
  repeated string clients = 1 [
    (google.api.resource_reference).type = "iam.confidence.dev/Client",
    (google.api.field_behavior) = REQUIRED
  ];

  // Filter the available options by finding only options that can be used in combination with this existing schema.
  // For instance if field `country` is selected, only find schemas where `country` exists.
  EvaluationContextSchema must_match_schema = 2;
}

// The derived schema for a set of clients.
message DeriveClientEvaluationContextSchemaResponse {
  // The client specific derived schemas.
  repeated ClientEvaluationContextSchema client_schema = 1;

  // The schema created by merging the schema from all clients.
  EvaluationContextSchema merged_schema = 2;
}


// The evaluation context schema of a client.
message ClientEvaluationContextSchema {
  // Resource reference to a client.
  string client = 1 [
    (google.api.resource_reference).type = "iam.confidence.dev/Client",
    (google.api.field_behavior) = REQUIRED
  ];

  // The evaluation context schema of the client.
  EvaluationContextSchema schema = 2;
}

// Schema of an evaluation context.
message EvaluationContextSchema {
  // Schema of each field in the evaluation context.
  map<string, EvaluationContextSchemaField> schema = 1;
}

// Create a new flag, only an id is required.
message CreateFlagRequest {
  // Properties to initialize the flag with.
  Flag flag = 1 [(google.api.field_behavior) = REQUIRED];

  // The ID to use for the flag, which will become the final component of
  // the flag's resource name.
  //
  // This value should be 4-63 characters, and valid characters
  // are /[a-z][0-9]-/.
  string flag_id = 2 [(google.api.field_behavior) = REQUIRED];
}

// Update an existing flag.
message UpdateFlagRequest {
  // The properties to update.
  Flag flag = 1 [(google.api.field_behavior) = REQUIRED];

  // The list of fields in Flag that you want to update e.g. 'rules', if empty
  // all mutable properties are updated.
  google.protobuf.FieldMask update_mask = 2;
}

// Get an existing variant.
message GetVariantRequest {
  // The resource reference to the variant.
  string name = 1  [
    (google.api.resource_reference).type = "flags.confidence.dev/Variant",
    (google.api.field_behavior) = REQUIRED
  ];
}

// Create a new variant.
message CreateVariantRequest {
  // The properties of the variant to create.
  Flag.Variant variant = 1 [(google.api.field_behavior) = REQUIRED];

  // The resource reference to the flag that owns this variant.
  string parent = 2 [
    (google.api.resource_reference).type = "flags.confidence.dev/Flag",
    (google.api.field_behavior) = REQUIRED
  ];
}

// Update an existing variant.
message UpdateVariantRequest {
  // The properties of the variant to update.
  Flag.Variant variant = 1 [(google.api.field_behavior) = REQUIRED];

  // The list of fields in Variant that you want to update e.g. 'description',
  // if empty all mutable properties are updated.
  // Fields are specified relative to the variant.
  google.protobuf.FieldMask update_mask = 2;
}

// List all variants of a flag.
message ListVariantsRequest {
  // The maximum number of variants to fetch.
  int32 page_size = 1;

  // Token used for pagination.
  string page_token = 2;

  // The resource reference to the flag that owns the variants that you want
  // to list.
  string parent = 3 [
    (google.api.resource_reference).type = "flags.confidence.dev/Flag",
    (google.api.field_behavior) = REQUIRED
  ];
}

// The list of variants.
message ListVariantsResponse {
  // List of variants.
  repeated Flag.Variant variants = 1 [(google.api.field_behavior) = REQUIRED];

  // A token that can be used to fetch more variants, empty if no more variants
  // are available.
  string next_page_token = 2;
}

// Delete a variant.
message DeleteVariantRequest {
  // The resource reference to the variant that you want to delete.
  string name = 1 [
    (google.api.resource_reference).type = "flags.confidence.dev/Variant",
    (google.api.field_behavior) = REQUIRED
  ];
}

// Get an existing flag.
message GetFlagRequest {
  // The resource reference to the flag.
  string name = 1  [
    (google.api.resource_reference).type = "flags.confidence.dev/Flag",
    (google.api.field_behavior) = REQUIRED
  ];
}

// Archive a flag, the flag can not be resolved after being archived.
message ArchiveFlagRequest {
  // The resource reference to the flag.
  string name = 1  [
    (google.api.resource_reference).type = "flags.confidence.dev/Flag",
    (google.api.field_behavior) = REQUIRED
  ];
}

// Request to add a client to a flag. This means that the flag will resolvable by the client.
message AddFlagClientRequest {
  // The reference to the client
  string client = 1 [
    (google.api.resource_reference).type = "iam.confidence.dev/Client",
    (google.api.field_behavior) = REQUIRED
  ];
  // The flag to add the client to
  string flag = 2  [
    (google.api.resource_reference).type = "flags.confidence.dev/Flag",
    (google.api.field_behavior) = REQUIRED
  ];
}

// Request to remove a client from a flag. This client will no longer be able to resolve the flag.
message RemoveFlagClientRequest {
  // The reference to the client
  string client = 1 [
    (google.api.resource_reference).type = "iam.confidence.dev/Client",
    (google.api.field_behavior) = REQUIRED
  ];
  // The flag to remove the client from
  string flag = 2  [
    (google.api.resource_reference).type = "flags.confidence.dev/Flag",
    (google.api.field_behavior) = REQUIRED
  ];
}


// List flags.
message ListFlagsRequest {
  // The maximum number of flags to fetch.
  int32 page_size = 1;

  // Token used for pagination.
  string page_token = 2;

  // Filter to apply to the flags. This follows the lucene query string format
  string filter = 4;
}

// The list of flags.
message ListFlagsResponse {
  // List of flags.
  repeated Flag flags = 1 [(google.api.field_behavior) = REQUIRED];

  // A token that can be used to fetch more flags, empty if no more flags
  // are available.
  string next_page_token = 2;
}

// Create a new rule for a given flag.
message CreateRuleRequest {
  // The properties of the rule to be created.
  Flag.Rule rule = 1 [(google.api.field_behavior) = REQUIRED];

  // A resource reference to the flag that will own this rule.
  string parent = 2 [
    (google.api.resource_reference).type = "flags.confidence.dev/Flag",
    (google.api.field_behavior) = REQUIRED
  ];
}

// Update an existing rule.
message UpdateRuleRequest {
  // The properties of the rule to update.
  Flag.Rule rule = 1 [(google.api.field_behavior) = REQUIRED];

  // The list of fields in the Rule that you want to update e.g. 'segment',
  // if empty all mutable properties are updated.
  // Fields are specified relative to the rule.
  google.protobuf.FieldMask update_mask = 2;
}

// List the rules of flag.
message ListRulesRequest {
  // The maximum number of rules to fetch.
  int32 page_size = 1;

  // Token used for pagination.
  string page_token = 2;

  // The resource reference to the flag that owns the rules that you want
  // to list.
  string parent = 3 [
    (google.api.resource_reference).type = "flags.confidence.dev/Flag",
    (google.api.field_behavior) = REQUIRED
  ];
}

// The returned list of rules.
message ListRulesResponse {
  // The list of rules.
  repeated Flag.Rule rules = 1 [(google.api.field_behavior) = REQUIRED];

  // A token that can be used to fetch more rules, empty if no more rules
  // are available.
  string next_page_token = 2;
}

// Request to delete a rule
message DeleteRuleRequest {
  // The resource reference to a rule that you want to delete.
  string name = 1 [
    (google.api.resource_reference).type = "flags.confidence.dev/Rule",
    (google.api.field_behavior) = REQUIRED
  ];
}

// Request to get a rule
message GetRuleRequest {
  // The resource reference to a rule that you want to fetch.
  string name = 1 [
    (google.api.resource_reference).type = "flags.confidence.dev/Rule",
    (google.api.field_behavior) = REQUIRED
  ];
}


// Create a new segment.
message CreateSegmentRequest {
  // The properties of the segment that you want to create.
  Segment segment = 1 [
    (google.api.field_behavior) = REQUIRED
  ];
}

// Update an existing segment.
message UpdateSegmentRequest {
  // The properties of the segment that you want to update.
  Segment segment = 1 [(google.api.field_behavior) = REQUIRED];

  // The list of fields in the Segment that you want to update e.g. 'targeting',
  // if empty all mutable properties are updated.
  // Fields are specified relative to the segment.
  google.protobuf.FieldMask update_mask = 2;
}

// Get a segment.
message GetSegmentRequest {
  // The resource reference to a segment.
  string name = 1  [
    (google.api.resource_reference).type = "flags.confidence.dev/Segment",
    (google.api.field_behavior) = REQUIRED
  ];

  // Specifies which fields of the segment that should be set.
  SegmentView view = 2;
}

// List segments.
message ListSegmentsRequest {
  // The maximum number of segments to fetch.
  int32 page_size = 1;

  // Token used for pagination.
  string page_token = 2;

  // Specifies which fields of the segments that should be set.
  SegmentView view = 4;

  // Filter to apply to the flags. This follows the lucene query string format
  string filter = 5;
}

// The returned list of segments.
message ListSegmentsResponse {
  // The list of segments.
  repeated Segment segments = 1 [(google.api.field_behavior) = REQUIRED];

  // A token that can be used to fetch more segments, empty if no more rules
  // are available.
  string next_page_token = 2;
}

// Archive the specified segment.
message ArchiveSegmentRequest {
  // Resource reference to the segment to archive.
  string name = 1  [
    (google.api.resource_reference).type = "flags.confidence.dev/Segment",
    (google.api.field_behavior) = REQUIRED
  ];
}

// Allocate the specified segment.
message AllocateSegmentRequest {
  // Resource reference to the segment to allocate.
  string name = 1 [
    (google.api.resource_reference).type = "flags.confidence.dev/Segment",
    (google.api.field_behavior) = REQUIRED
  ];
}

// Check if space is available to allocated a segment. Either query by an existing
// segment, or by a combination of exclusivity tags + targeting.
message SegmentAvailableSpaceRequest {
  oneof query {
    // Resource reference to a segment.
    string segment = 1  [
      (google.api.resource_reference).type = "flags.confidence.dev/Segment"
    ];
    // Parameters to query the segment by
    SegmentAvailableSpaceRequest.QueryParams query_params = 2;
  }

  // Container of parameters to use when querying available space
  message QueryParams {
    // The targeting to filter by. More space can be free if specific targeting is used. For instance an already
    // existing segment in one country may use space in that country, but targeting another country can safely overlap.
    flags.types.v1.Targeting targeting = 1;
    // Set of tags that can be used to coordinate this segment with others.
    repeated string exclusivity_tags = 2;
    // (-- api-linter: core::0140::prepositions=disabled
    //     aip.dev/not-precedent: It means that we're exclusive to other tags, makes sense. --)
    // List of tags that this segment is exclusive to, meaning that an entity
    // cannot be in this segment and also in any segment that has a tag in the
    // list.
    repeated string exclusive_to = 3;
  }
}

// The available space of the segment.
message SegmentAvailableSpaceResponse {
  // The amount of space available to the segment.
  google.type.Decimal available_space = 1;
}
