This is an automated email from the ASF dual-hosted git repository.

pabloem pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git


The following commit(s) were added to refs/heads/master by this push:
     new dc0548e  Merge pull request #15761 from [BEAM-13008] Create gradle 
tasks for the Beam Playground
dc0548e is described below

commit dc0548e20ca047cfa991d4138d63806e9d15086c
Author: Damon Douglas <damondoug...@users.noreply.github.com>
AuthorDate: Thu Oct 21 16:17:13 2021 +0000

    Merge pull request #15761 from [BEAM-13008] Create gradle tasks for the 
Beam Playground
    
    * Implement Beam Playground gradle tasks
    
    * Fix trailing whitespace
    
    * Remove format from precommit
    
    * Fix order of includes and add descriptions
    
    * [BEAM-13008] add generated files and fix analysis issues (#2)
    
    * Reconcile errors with playgroundPrecommit output
    
    Co-authored-by: Aydar Farrakhov <stranni...@gmail.com>
---
 .gitignore                                         |   7 +
 build.gradle.kts                                   |  13 +-
 playground/README.md                               |  57 +++
 .../v1/playground.proto => api/v1/api.proto}       |   6 +-
 playground/backend/build.gradle.kts                |  52 +++
 playground/backend/cmd/server/controller.go        |   3 +-
 playground/backend/cmd/server/controller_test.go   |   2 +-
 playground/backend/cmd/server/server.go            |  11 +-
 playground/backend/go.sum                          |  55 +--
 .../api/{playground.pb.go => v1/api.pb.go}         | 338 ++++++++--------
 .../{playground_grpc.pb.go => v1/api_grpc.pb.go}   |  27 +-
 .../go_helper.go => environment/environment.go}    |  17 +-
 playground/backend/internal/executors/executor.go  |   2 +-
 playground/backend/internal/executors/go_helper.go |   2 +
 .../backend/internal/executors/java_helper_test.go |   2 +-
 playground/backend/internal/fs_tool/fs.go          |   2 +-
 playground/backend/internal/fs_tool/fs_test.go     |   2 +-
 playground/buf.gen.yaml                            |  32 ++
 playground/build.gradle.kts                        |  30 ++
 playground/frontend/README.md                      |   6 +-
 playground/frontend/analysis_options.yaml          |   4 +
 playground/frontend/build.gradle.kts               |  74 ++++
 playground/frontend/lib/api/v1/api.pb.dart         | 450 +++++++++++++++++++++
 playground/frontend/lib/api/v1/api.pbenum.dart     |  68 ++++
 playground/frontend/lib/api/v1/api.pbgrpc.dart     | 158 ++++++++
 playground/frontend/lib/api/v1/api.pbjson.dart     | 137 +++++++
 .../code_client/grpc_code_client.dart              |   2 +-
 .../code_repository_test.mocks.dart                |  86 ++++
 settings.gradle.kts                                |   3 +
 29 files changed, 1403 insertions(+), 245 deletions(-)

diff --git a/.gitignore b/.gitignore
index 33aac5b..857d52d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -113,3 +113,10 @@ website/www/site/code_samples
 website/www/site/_config_branch_repo.toml
 website/www/yarn-error.log
 !website/www/site/content
+
+# Dart/Flutter
+**/.dart_tool
+**/.packages
+**/.flutter-plugins
+**/.flutter-plugins-dependencies
+**/generated_plugin_registrant.dart
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index a0f6313..b10b88d 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -124,9 +124,7 @@ tasks.rat {
     // Ignore Flutter autogenerated files for Playground
     "playground/frontend/.metadata",
     "playground/frontend/pubspec.lock",
-    "playground/frontend/assets/**/*.svg",
-    "playground/frontend/assets/**/*.png",
-    "playground/frontend/assets/**/*.jpg",
+    "playground/frontend/**/*.svg",
 
     // Ignore .gitkeep file
     "**/.gitkeep"
@@ -249,6 +247,15 @@ task("goIntegrationTests") {
   dependsOn(":runners:google-cloud-dataflow-java:worker:shadowJar")
 }
 
+task("playgroundPreCommit") {
+  dependsOn(":playground:backend:tidy")
+  dependsOn(":playground:backend:test")
+
+  dependsOn(":playground:frontend:pubGet")
+  dependsOn(":playground:frontend:analyze")
+  dependsOn(":playground:frontend:test")
+}
+
 task("pythonPreCommit") {
   dependsOn(":sdks:python:test-suites:tox:pycommon:preCommitPyCommon")
   dependsOn(":sdks:python:test-suites:tox:py36:preCommitPy36")
diff --git a/playground/README.md b/playground/README.md
new file mode 100644
index 0000000..fe90b2e
--- /dev/null
+++ b/playground/README.md
@@ -0,0 +1,57 @@
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+# Playground
+
+The Beam Playground is a web application to run Beam code snippets in a modern
+browser.  This directory holds code to build, test, and deploy the frontend
+and backend services.
+
+# Requirements
+
+The following requirements are needed for development, testing, and deploying.
+
+- [go 1.16+](https://golang.org)
+- [flutter](https://flutter.dev/)
+- Go protobuf dependencies (See [Go gRPC 
Quickstart](https://grpc.io/docs/languages/go/quickstart/))
+- Dart protobuf dependencies (See [Dart gRPC 
Quickstart](https://grpc.io/docs/languages/dart/))
+- [buf](https://docs.buf.build/installation)
+
+# Available Gradle Tasks
+
+## Perform overall pre-commit checks
+
+```
+cd beam
+./gradlew playgroundPrecommit
+```
+
+## To see available gradle tasks for playground:
+
+```
+cd beam
+./gradlew playground:tasks
+```
+
+## Re-generate protobuf
+
+```
+cd beam
+./gradlew playground:generateProto
+```
diff --git a/playground/playground/v1/playground.proto 
b/playground/api/v1/api.proto
similarity index 96%
rename from playground/playground/v1/playground.proto
rename to playground/api/v1/api.proto
index 7c26e00..b132980 100644
--- a/playground/playground/v1/playground.proto
+++ b/playground/api/v1/api.proto
@@ -17,9 +17,9 @@
  */
 
 syntax = "proto3";
+option go_package = "beam.apache.org/playground/backend/internal;playground";
 
-option go_package = "github.com/apache/beam/playground/v1;playground";
-package playground.v1;
+package api.v1;
 
 enum Sdk {
   SDK_UNSPECIFIED = 0;
@@ -92,4 +92,4 @@ service PlaygroundService {
 
   // Get the result of pipeline compilation.
   rpc GetCompileOutput(GetCompileOutputRequest) returns 
(GetCompileOutputResponse);
-}
\ No newline at end of file
+}
diff --git a/playground/backend/build.gradle.kts 
b/playground/backend/build.gradle.kts
new file mode 100644
index 0000000..0547b7c
--- /dev/null
+++ b/playground/backend/build.gradle.kts
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * License); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+description = "Apache Beam :: Playground :: Backend"
+
+task("format") {
+  group = "build"
+  description = "Format backend go code"
+  doLast {
+    exec {
+      executable("gofmt")
+      args("-w", ".")
+    }
+  }
+}
+
+task("tidy") {
+  group = "build"
+  description = "Run go mod tidy"
+  doLast {
+    exec {
+      executable("go")
+      args("mod", "tidy")
+    }
+  }
+}
+
+task("test") {
+  group = "verification"
+  description = "Test the backend"
+  doLast {
+    exec {
+      executable("go")
+      args("test", "internal/...")
+    }
+  }
+}
diff --git a/playground/backend/cmd/server/controller.go 
b/playground/backend/cmd/server/controller.go
index 13ab658..d38ff98 100644
--- a/playground/backend/cmd/server/controller.go
+++ b/playground/backend/cmd/server/controller.go
@@ -15,8 +15,9 @@
 package main
 
 import (
-       pb "beam.apache.org/playground/backend/internal/api"
        "context"
+
+       pb "beam.apache.org/playground/backend/internal/api/v1"
        "github.com/google/uuid"
 )
 
diff --git a/playground/backend/cmd/server/controller_test.go 
b/playground/backend/cmd/server/controller_test.go
index 38885ec..a7f971e 100644
--- a/playground/backend/cmd/server/controller_test.go
+++ b/playground/backend/cmd/server/controller_test.go
@@ -15,7 +15,7 @@
 package main
 
 import (
-       pb "beam.apache.org/playground/backend/internal/api"
+       pb "beam.apache.org/playground/backend/internal/api/v1"
        "context"
        "github.com/google/uuid"
        "google.golang.org/grpc"
diff --git a/playground/backend/cmd/server/server.go 
b/playground/backend/cmd/server/server.go
index 05045ea..3102188 100644
--- a/playground/backend/cmd/server/server.go
+++ b/playground/backend/cmd/server/server.go
@@ -16,14 +16,15 @@
 package main
 
 import (
-       pb "beam.apache.org/playground/backend/internal/api"
-       "beam.apache.org/playground/backend/internal/environment"
        "context"
+       "log"
+       "os"
+
+       pb "beam.apache.org/playground/backend/internal/api/v1"
+       "beam.apache.org/playground/backend/internal/environment"
        "github.com/improbable-eng/grpc-web/go/grpcweb"
        "google.golang.org/grpc"
        "google.golang.org/grpc/grpclog"
-       "log"
-       "os"
 )
 
 // runServer is starting http server wrapped on grpc
@@ -39,7 +40,7 @@ func runServer() error {
        handler := Wrap(grpcServer, getGrpcWebOptions())
        errChan := make(chan error)
 
-       go listenHttp(ctx, errChan, envService.ServerEnvs, handler)
+       go listenHttp(ctx, errChan, envService, handler)
 
        for {
                select {
diff --git a/playground/backend/go.sum b/playground/backend/go.sum
index 3c4a244..5c43280 100644
--- a/playground/backend/go.sum
+++ b/playground/backend/go.sum
@@ -4,7 +4,6 @@ dmitri.shuralyov.com/gpu/mtl 
v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
 github.com/BurntSushi/toml v0.3.1/go.mod 
h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod 
h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/Knetic/govaluate 
v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod 
h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
-github.com/OneOfOne/xxhash v1.2.2/go.mod 
h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/Shopify/sarama v1.19.0/go.mod 
h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
 github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod 
h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
 github.com/VividCortex/gohistogram v1.0.0/go.mod 
h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
@@ -31,13 +30,11 @@ github.com/bgentry/speakeasy v0.1.0/go.mod 
h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
 github.com/casbin/casbin/v2 v2.1.2/go.mod 
h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
 github.com/cenkalti/backoff v2.2.1+incompatible/go.mod 
h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod 
h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v1.1.0/go.mod 
h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod 
h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod 
h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
 github.com/client9/misspell v0.3.4/go.mod 
h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod 
h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod 
h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod 
h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod 
h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod 
h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
 github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod 
h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
@@ -47,6 +44,7 @@ github.com/coreos/pkg 
v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod 
h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/creack/pty v1.1.7/go.mod 
h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
 github.com/davecgh/go-spew v1.1.0/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f 
h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I=
 github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod 
h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE=
@@ -61,7 +59,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod 
h1:YTl/9mNaCwkRvm6d1a2C3ymF
 github.com/envoyproxy/go-control-plane 
v0.9.1-0.20191026205805-5f8ba28d4473/go.mod 
h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod 
h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
 github.com/envoyproxy/go-control-plane 
v0.9.9-0.20201210154907-fd9021fe5dad/go.mod 
h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane 
v0.9.9-0.20210512163311-63b5d3c536b0/go.mod 
h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
 github.com/envoyproxy/go-control-plane 
v0.9.10-0.20210907150352-cf90f659a021/go.mod 
h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod 
h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/fatih/color v1.7.0/go.mod 
h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
@@ -69,8 +66,10 @@ github.com/franela/goblin 
v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVB
 github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod 
h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
 github.com/fsnotify/fsnotify v1.4.7/go.mod 
h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/ghodss/yaml v1.0.0/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gin-contrib/sse v0.1.0 
h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
 github.com/gin-contrib/sse v0.1.0/go.mod 
h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 github.com/gin-gonic/gin v1.5.0/go.mod 
h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
+github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
 github.com/gin-gonic/gin v1.6.3/go.mod 
h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod 
h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-kit/kit v0.8.0/go.mod 
h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -81,14 +80,20 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod 
h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
 github.com/go-logfmt/logfmt v0.5.0/go.mod 
h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
 github.com/go-playground/assert/v2 v2.0.1/go.mod 
h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
 github.com/go-playground/locales v0.12.1/go.mod 
h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
+github.com/go-playground/locales v0.13.0 
h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
 github.com/go-playground/locales v0.13.0/go.mod 
h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
 github.com/go-playground/universal-translator v0.16.0/go.mod 
h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
+github.com/go-playground/universal-translator v0.17.0 
h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
 github.com/go-playground/universal-translator v0.17.0/go.mod 
h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
+github.com/go-playground/validator/v10 v10.2.0 
h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
 github.com/go-playground/validator/v10 v10.2.0/go.mod 
h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
 github.com/go-sql-driver/mysql v1.4.0/go.mod 
h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-stack/stack v1.8.0/go.mod 
h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee 
h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
 github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod 
h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
+github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
 github.com/gobwas/pool v0.2.0/go.mod 
h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
 github.com/gobwas/ws v1.0.2/go.mod 
h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
 github.com/gogo/googleapis v1.1.0/go.mod 
h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
 github.com/gogo/protobuf v1.1.1/go.mod 
h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -113,8 +118,6 @@ github.com/golang/protobuf v1.4.2/go.mod 
h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
 github.com/golang/protobuf v1.4.3/go.mod 
h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0 
h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
 github.com/golang/protobuf v1.5.0/go.mod 
h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2 
h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
-github.com/golang/protobuf v1.5.2/go.mod 
h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod 
h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod 
h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod 
h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@@ -136,6 +139,7 @@ github.com/gorilla/context v1.1.1/go.mod 
h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51
 github.com/gorilla/mux v1.6.2/go.mod 
h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/mux v1.7.3/go.mod 
h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
 github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod 
h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.1 
h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
 github.com/gorilla/websocket v1.4.1/go.mod 
h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/grpc-ecosystem/go-grpc-middleware 
v1.0.1-0.20190118093823-f849b5445de4/go.mod 
h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod 
h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
@@ -175,6 +179,7 @@ github.com/json-iterator/go v1.1.6/go.mod 
h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
 github.com/json-iterator/go v1.1.7/go.mod 
h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.8/go.mod 
h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.9/go.mod 
h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10 
h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
 github.com/json-iterator/go v1.1.10/go.mod 
h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod 
h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod 
h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
@@ -182,9 +187,8 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod 
h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
 github.com/kisielk/errcheck v1.1.0/go.mod 
h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/gotool v1.0.0/go.mod 
h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/compress v1.10.3/go.mod 
h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.11.7 
h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=
 github.com/klauspost/compress v1.11.7/go.mod 
h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
-github.com/klauspost/compress v1.13.6 
h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
-github.com/klauspost/compress v1.13.6/go.mod 
h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod 
h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod 
h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod 
h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@@ -192,6 +196,7 @@ github.com/kr/pretty v0.1.0/go.mod 
h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod 
h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/leodido/go-urn v1.1.0/go.mod 
h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
+github.com/leodido/go-urn v1.2.0 
h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
 github.com/leodido/go-urn v1.2.0/go.mod 
h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
 github.com/lightstep/lightstep-tracer-common/golang/gogo 
v0.0.0-20190605223551-bc2310a04743/go.mod 
h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
 github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod 
h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
@@ -200,6 +205,7 @@ github.com/mattn/go-colorable v0.0.9/go.mod 
h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
 github.com/mattn/go-isatty v0.0.3/go.mod 
h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.4/go.mod 
h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.9/go.mod 
h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
+github.com/mattn/go-isatty v0.0.12 
h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
 github.com/mattn/go-isatty v0.0.12/go.mod 
h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-runewidth v0.0.2/go.mod 
h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod 
h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -212,10 +218,13 @@ github.com/mitchellh/iochan v1.0.0/go.mod 
h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod 
h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2/go.mod 
h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod 
h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd 
h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod 
h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod 
h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1 
h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod 
h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod 
h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f 
h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod 
h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod 
h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo=
 github.com/nats-io/jwt v0.3.0/go.mod 
h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
@@ -250,6 +259,7 @@ github.com/pkg/errors v0.8.0/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
 github.com/pkg/errors v0.8.1/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/profile v1.2.1/go.mod 
h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
+github.com/pmezard/go-difflib v1.0.0 
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod 
h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/prometheus/client_golang v0.9.1/go.mod 
h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -294,7 +304,6 @@ github.com/smartystreets/assertions 
v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
 github.com/smartystreets/goconvey v1.6.4/go.mod 
h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/soheilhy/cmux v0.1.4/go.mod 
h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
 github.com/sony/gobreaker v0.4.1/go.mod 
h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod 
h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/cobra v0.0.3/go.mod 
h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/pflag v1.0.1/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.5/go.mod 
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
@@ -307,9 +316,12 @@ github.com/stretchr/testify v1.2.2/go.mod 
h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
 github.com/stretchr/testify v1.3.0/go.mod 
h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod 
h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod 
h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0 
h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod 
h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod 
h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
 github.com/ugorji/go v1.1.7/go.mod 
h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
+github.com/ugorji/go/codec v1.1.7 
h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
 github.com/ugorji/go/codec v1.1.7/go.mod 
h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 github.com/urfave/cli v1.20.0/go.mod 
h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/urfave/cli v1.22.1/go.mod 
h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
@@ -367,11 +379,9 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod 
h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod 
h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod 
h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod 
h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202 
h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod 
h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 
h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod 
h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.0.0-20211007125505-59d4e928ea9d 
h1:QWMn1lFvU/nZ58ssWqiFJMd3DKIII8NYc4sn708XgKs=
-golang.org/x/net v0.0.0-20211007125505-59d4e928ea9d/go.mod 
h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod 
h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod 
h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod 
h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -402,26 +412,20 @@ golang.org/x/sys 
v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd 
h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007 
h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac 
h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=
-golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod 
h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
 golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod 
h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod 
h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -454,11 +458,9 @@ google.golang.org/genproto 
v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dT
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod 
h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod 
h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod 
h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 
h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod 
h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506 
h1:uLBY0yHDCj2PMQ98KWDSIDFwn9zK2zh+tgWtbvPPBjI=
 google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod 
h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20211007155348-82e027067bd4 
h1:YXPV/eKW0ZWRdB5tyI6aPoaa2Wxb4OSlFrTREMdwn64=
-google.golang.org/genproto v0.0.0-20211007155348-82e027067bd4/go.mod 
h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/grpc v1.17.0/go.mod 
h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0/go.mod 
h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.0/go.mod 
h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@@ -474,7 +476,6 @@ google.golang.org/grpc v1.29.1/go.mod 
h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
 google.golang.org/grpc v1.32.0/go.mod 
h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.33.1/go.mod 
h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
 google.golang.org/grpc v1.36.0/go.mod 
h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.40.0/go.mod 
h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
 google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
 google.golang.org/grpc v1.41.0/go.mod 
h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod 
h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -488,7 +489,6 @@ google.golang.org/protobuf 
v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
 google.golang.org/protobuf v1.24.0/go.mod 
h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
 google.golang.org/protobuf v1.25.0/go.mod 
h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod 
h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0/go.mod 
h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.27.1 
h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
 google.golang.org/protobuf v1.27.1/go.mod 
h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod 
h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
@@ -511,15 +511,16 @@ gopkg.in/yaml.v2 v2.2.3/go.mod 
h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod 
h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b 
h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod 
h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod 
h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=
 nhooyr.io/websocket v1.8.6/go.mod 
h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
-nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
-nhooyr.io/websocket v1.8.7/go.mod 
h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
 sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod 
h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/playground/backend/internal/api/playground.pb.go 
b/playground/backend/internal/api/v1/api.pb.go
similarity index 55%
rename from playground/backend/internal/api/playground.pb.go
rename to playground/backend/internal/api/v1/api.pb.go
index cc3ebdf..b440b19 100644
--- a/playground/backend/internal/api/playground.pb.go
+++ b/playground/backend/internal/api/v1/api.pb.go
@@ -17,9 +17,9 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-//     protoc-gen-go v1.27.1
+//     protoc-gen-go v1.26.0
 //     protoc        v3.17.3
-// source: playground.proto
+// source: api/v1/api.proto
 
 package playground
 
@@ -76,11 +76,11 @@ func (x Sdk) String() string {
 }
 
 func (Sdk) Descriptor() protoreflect.EnumDescriptor {
-       return file_playground_proto_enumTypes[0].Descriptor()
+       return file_api_v1_api_proto_enumTypes[0].Descriptor()
 }
 
 func (Sdk) Type() protoreflect.EnumType {
-       return &file_playground_proto_enumTypes[0]
+       return &file_api_v1_api_proto_enumTypes[0]
 }
 
 func (x Sdk) Number() protoreflect.EnumNumber {
@@ -89,7 +89,7 @@ func (x Sdk) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use Sdk.Descriptor instead.
 func (Sdk) EnumDescriptor() ([]byte, []int) {
-       return file_playground_proto_rawDescGZIP(), []int{0}
+       return file_api_v1_api_proto_rawDescGZIP(), []int{0}
 }
 
 type Status int32
@@ -128,11 +128,11 @@ func (x Status) String() string {
 }
 
 func (Status) Descriptor() protoreflect.EnumDescriptor {
-       return file_playground_proto_enumTypes[1].Descriptor()
+       return file_api_v1_api_proto_enumTypes[1].Descriptor()
 }
 
 func (Status) Type() protoreflect.EnumType {
-       return &file_playground_proto_enumTypes[1]
+       return &file_api_v1_api_proto_enumTypes[1]
 }
 
 func (x Status) Number() protoreflect.EnumNumber {
@@ -141,7 +141,7 @@ func (x Status) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use Status.Descriptor instead.
 func (Status) EnumDescriptor() ([]byte, []int) {
-       return file_playground_proto_rawDescGZIP(), []int{1}
+       return file_api_v1_api_proto_rawDescGZIP(), []int{1}
 }
 
 // RunCodeRequest represents a code text and options of SDK which executes the 
code.
@@ -151,13 +151,13 @@ type RunCodeRequest struct {
        unknownFields protoimpl.UnknownFields
 
        Code string `protobuf:"bytes,1,opt,name=code,proto3" 
json:"code,omitempty"`
-       Sdk  Sdk    
`protobuf:"varint,2,opt,name=sdk,proto3,enum=playground.v1.Sdk" 
json:"sdk,omitempty"`
+       Sdk  Sdk    `protobuf:"varint,2,opt,name=sdk,proto3,enum=api.v1.Sdk" 
json:"sdk,omitempty"`
 }
 
 func (x *RunCodeRequest) Reset() {
        *x = RunCodeRequest{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_playground_proto_msgTypes[0]
+               mi := &file_api_v1_api_proto_msgTypes[0]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -170,7 +170,7 @@ func (x *RunCodeRequest) String() string {
 func (*RunCodeRequest) ProtoMessage() {}
 
 func (x *RunCodeRequest) ProtoReflect() protoreflect.Message {
-       mi := &file_playground_proto_msgTypes[0]
+       mi := &file_api_v1_api_proto_msgTypes[0]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -183,7 +183,7 @@ func (x *RunCodeRequest) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use RunCodeRequest.ProtoReflect.Descriptor instead.
 func (*RunCodeRequest) Descriptor() ([]byte, []int) {
-       return file_playground_proto_rawDescGZIP(), []int{0}
+       return file_api_v1_api_proto_rawDescGZIP(), []int{0}
 }
 
 func (x *RunCodeRequest) GetCode() string {
@@ -212,7 +212,7 @@ type RunCodeResponse struct {
 func (x *RunCodeResponse) Reset() {
        *x = RunCodeResponse{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_playground_proto_msgTypes[1]
+               mi := &file_api_v1_api_proto_msgTypes[1]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -225,7 +225,7 @@ func (x *RunCodeResponse) String() string {
 func (*RunCodeResponse) ProtoMessage() {}
 
 func (x *RunCodeResponse) ProtoReflect() protoreflect.Message {
-       mi := &file_playground_proto_msgTypes[1]
+       mi := &file_api_v1_api_proto_msgTypes[1]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -238,7 +238,7 @@ func (x *RunCodeResponse) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use RunCodeResponse.ProtoReflect.Descriptor instead.
 func (*RunCodeResponse) Descriptor() ([]byte, []int) {
-       return file_playground_proto_rawDescGZIP(), []int{1}
+       return file_api_v1_api_proto_rawDescGZIP(), []int{1}
 }
 
 func (x *RunCodeResponse) GetPipelineUuid() string {
@@ -260,7 +260,7 @@ type CheckStatusRequest struct {
 func (x *CheckStatusRequest) Reset() {
        *x = CheckStatusRequest{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_playground_proto_msgTypes[2]
+               mi := &file_api_v1_api_proto_msgTypes[2]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -273,7 +273,7 @@ func (x *CheckStatusRequest) String() string {
 func (*CheckStatusRequest) ProtoMessage() {}
 
 func (x *CheckStatusRequest) ProtoReflect() protoreflect.Message {
-       mi := &file_playground_proto_msgTypes[2]
+       mi := &file_api_v1_api_proto_msgTypes[2]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -286,7 +286,7 @@ func (x *CheckStatusRequest) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use CheckStatusRequest.ProtoReflect.Descriptor instead.
 func (*CheckStatusRequest) Descriptor() ([]byte, []int) {
-       return file_playground_proto_rawDescGZIP(), []int{2}
+       return file_api_v1_api_proto_rawDescGZIP(), []int{2}
 }
 
 func (x *CheckStatusRequest) GetPipelineUuid() string {
@@ -302,13 +302,13 @@ type CheckStatusResponse struct {
        sizeCache     protoimpl.SizeCache
        unknownFields protoimpl.UnknownFields
 
-       Status Status 
`protobuf:"varint,1,opt,name=status,proto3,enum=playground.v1.Status" 
json:"status,omitempty"`
+       Status Status 
`protobuf:"varint,1,opt,name=status,proto3,enum=api.v1.Status" 
json:"status,omitempty"`
 }
 
 func (x *CheckStatusResponse) Reset() {
        *x = CheckStatusResponse{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_playground_proto_msgTypes[3]
+               mi := &file_api_v1_api_proto_msgTypes[3]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -321,7 +321,7 @@ func (x *CheckStatusResponse) String() string {
 func (*CheckStatusResponse) ProtoMessage() {}
 
 func (x *CheckStatusResponse) ProtoReflect() protoreflect.Message {
-       mi := &file_playground_proto_msgTypes[3]
+       mi := &file_api_v1_api_proto_msgTypes[3]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -334,7 +334,7 @@ func (x *CheckStatusResponse) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use CheckStatusResponse.ProtoReflect.Descriptor instead.
 func (*CheckStatusResponse) Descriptor() ([]byte, []int) {
-       return file_playground_proto_rawDescGZIP(), []int{3}
+       return file_api_v1_api_proto_rawDescGZIP(), []int{3}
 }
 
 func (x *CheckStatusResponse) GetStatus() Status {
@@ -356,7 +356,7 @@ type GetCompileOutputRequest struct {
 func (x *GetCompileOutputRequest) Reset() {
        *x = GetCompileOutputRequest{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_playground_proto_msgTypes[4]
+               mi := &file_api_v1_api_proto_msgTypes[4]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -369,7 +369,7 @@ func (x *GetCompileOutputRequest) String() string {
 func (*GetCompileOutputRequest) ProtoMessage() {}
 
 func (x *GetCompileOutputRequest) ProtoReflect() protoreflect.Message {
-       mi := &file_playground_proto_msgTypes[4]
+       mi := &file_api_v1_api_proto_msgTypes[4]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -382,7 +382,7 @@ func (x *GetCompileOutputRequest) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use GetCompileOutputRequest.ProtoReflect.Descriptor instead.
 func (*GetCompileOutputRequest) Descriptor() ([]byte, []int) {
-       return file_playground_proto_rawDescGZIP(), []int{4}
+       return file_api_v1_api_proto_rawDescGZIP(), []int{4}
 }
 
 func (x *GetCompileOutputRequest) GetPipelineUuid() string {
@@ -399,13 +399,13 @@ type GetCompileOutputResponse struct {
        unknownFields protoimpl.UnknownFields
 
        Output            string `protobuf:"bytes,1,opt,name=output,proto3" 
json:"output,omitempty"`
-       CompilationStatus Status 
`protobuf:"varint,2,opt,name=compilation_status,json=compilationStatus,proto3,enum=playground.v1.Status"
 json:"compilation_status,omitempty"`
+       CompilationStatus Status 
`protobuf:"varint,2,opt,name=compilation_status,json=compilationStatus,proto3,enum=api.v1.Status"
 json:"compilation_status,omitempty"`
 }
 
 func (x *GetCompileOutputResponse) Reset() {
        *x = GetCompileOutputResponse{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_playground_proto_msgTypes[5]
+               mi := &file_api_v1_api_proto_msgTypes[5]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -418,7 +418,7 @@ func (x *GetCompileOutputResponse) String() string {
 func (*GetCompileOutputResponse) ProtoMessage() {}
 
 func (x *GetCompileOutputResponse) ProtoReflect() protoreflect.Message {
-       mi := &file_playground_proto_msgTypes[5]
+       mi := &file_api_v1_api_proto_msgTypes[5]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -431,7 +431,7 @@ func (x *GetCompileOutputResponse) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use GetCompileOutputResponse.ProtoReflect.Descriptor instead.
 func (*GetCompileOutputResponse) Descriptor() ([]byte, []int) {
-       return file_playground_proto_rawDescGZIP(), []int{5}
+       return file_api_v1_api_proto_rawDescGZIP(), []int{5}
 }
 
 func (x *GetCompileOutputResponse) GetOutput() string {
@@ -460,7 +460,7 @@ type GetRunOutputRequest struct {
 func (x *GetRunOutputRequest) Reset() {
        *x = GetRunOutputRequest{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_playground_proto_msgTypes[6]
+               mi := &file_api_v1_api_proto_msgTypes[6]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -473,7 +473,7 @@ func (x *GetRunOutputRequest) String() string {
 func (*GetRunOutputRequest) ProtoMessage() {}
 
 func (x *GetRunOutputRequest) ProtoReflect() protoreflect.Message {
-       mi := &file_playground_proto_msgTypes[6]
+       mi := &file_api_v1_api_proto_msgTypes[6]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -486,7 +486,7 @@ func (x *GetRunOutputRequest) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use GetRunOutputRequest.ProtoReflect.Descriptor instead.
 func (*GetRunOutputRequest) Descriptor() ([]byte, []int) {
-       return file_playground_proto_rawDescGZIP(), []int{6}
+       return file_api_v1_api_proto_rawDescGZIP(), []int{6}
 }
 
 func (x *GetRunOutputRequest) GetPipelineUuid() string {
@@ -503,13 +503,13 @@ type GetRunOutputResponse struct {
        unknownFields protoimpl.UnknownFields
 
        Output            string `protobuf:"bytes,1,opt,name=output,proto3" 
json:"output,omitempty"`
-       CompilationStatus Status 
`protobuf:"varint,2,opt,name=compilation_status,json=compilationStatus,proto3,enum=playground.v1.Status"
 json:"compilation_status,omitempty"`
+       CompilationStatus Status 
`protobuf:"varint,2,opt,name=compilation_status,json=compilationStatus,proto3,enum=api.v1.Status"
 json:"compilation_status,omitempty"`
 }
 
 func (x *GetRunOutputResponse) Reset() {
        *x = GetRunOutputResponse{}
        if protoimpl.UnsafeEnabled {
-               mi := &file_playground_proto_msgTypes[7]
+               mi := &file_api_v1_api_proto_msgTypes[7]
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                ms.StoreMessageInfo(mi)
        }
@@ -522,7 +522,7 @@ func (x *GetRunOutputResponse) String() string {
 func (*GetRunOutputResponse) ProtoMessage() {}
 
 func (x *GetRunOutputResponse) ProtoReflect() protoreflect.Message {
-       mi := &file_playground_proto_msgTypes[7]
+       mi := &file_api_v1_api_proto_msgTypes[7]
        if protoimpl.UnsafeEnabled && x != nil {
                ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
                if ms.LoadMessageInfo() == nil {
@@ -535,7 +535,7 @@ func (x *GetRunOutputResponse) ProtoReflect() 
protoreflect.Message {
 
 // Deprecated: Use GetRunOutputResponse.ProtoReflect.Descriptor instead.
 func (*GetRunOutputResponse) Descriptor() ([]byte, []int) {
-       return file_playground_proto_rawDescGZIP(), []int{7}
+       return file_api_v1_api_proto_rawDescGZIP(), []int{7}
 }
 
 func (x *GetRunOutputResponse) GetOutput() string {
@@ -552,130 +552,124 @@ func (x *GetRunOutputResponse) GetCompilationStatus() 
Status {
        return Status_STATUS_UNSPECIFIED
 }
 
-var File_playground_proto protoreflect.FileDescriptor
-
-var file_playground_proto_rawDesc = []byte{
-       0x0a, 0x10, 0x70, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 
0x2e, 0x70, 0x72, 0x6f,
-       0x74, 0x6f, 0x12, 0x0d, 0x70, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 
0x6e, 0x64, 0x2e, 0x76,
-       0x31, 0x22, 0x4a, 0x0a, 0x0e, 0x52, 0x75, 0x6e, 0x43, 0x6f, 0x64, 0x65, 
0x52, 0x65, 0x71, 0x75,
-       0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 
0x01, 0x20, 0x01, 0x28,
-       0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x24, 0x0a, 0x03, 0x73, 
0x64, 0x6b, 0x18, 0x02,
-       0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x70, 0x6c, 0x61, 0x79, 0x67, 
0x72, 0x6f, 0x75, 0x6e,
-       0x64, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x64, 0x6b, 0x52, 0x03, 0x73, 0x64, 
0x6b, 0x22, 0x36, 0x0a,
-       0x0f, 0x52, 0x75, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 
0x6f, 0x6e, 0x73, 0x65,
-       0x12, 0x23, 0x0a, 0x0d, 0x70, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 
0x5f, 0x75, 0x75, 0x69,
-       0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x69, 0x70, 
0x65, 0x6c, 0x69, 0x6e,
-       0x65, 0x55, 0x75, 0x69, 0x64, 0x22, 0x39, 0x0a, 0x12, 0x43, 0x68, 0x65, 
0x63, 0x6b, 0x53, 0x74,
-       0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 
0x23, 0x0a, 0x0d, 0x70,
+var File_api_v1_api_proto protoreflect.FileDescriptor
+
+var file_api_v1_api_proto_rawDesc = []byte{
+       0x0a, 0x10, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x70, 0x69, 
0x2e, 0x70, 0x72, 0x6f,
+       0x74, 0x6f, 0x12, 0x06, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x22, 0x43, 
0x0a, 0x0e, 0x52, 0x75,
+       0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 
0x12, 0x12, 0x0a, 0x04,
+       0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 
0x63, 0x6f, 0x64, 0x65,
+       0x12, 0x1d, 0x0a, 0x03, 0x73, 0x64, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 
0x0e, 0x32, 0x0b, 0x2e,
+       0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x64, 0x6b, 0x52, 0x03, 
0x73, 0x64, 0x6b, 0x22,
+       0x36, 0x0a, 0x0f, 0x52, 0x75, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 
0x73, 0x70, 0x6f, 0x6e,
+       0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x69, 0x70, 0x65, 0x6c, 0x69, 
0x6e, 0x65, 0x5f, 0x75,
+       0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 
0x69, 0x70, 0x65, 0x6c,
+       0x69, 0x6e, 0x65, 0x55, 0x75, 0x69, 0x64, 0x22, 0x39, 0x0a, 0x12, 0x43, 
0x68, 0x65, 0x63, 0x6b,
+       0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 
0x74, 0x12, 0x23, 0x0a,
+       0x0d, 0x70, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x75, 0x75, 
0x69, 0x64, 0x18, 0x01,
+       0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x69, 0x70, 0x65, 0x6c, 0x69, 
0x6e, 0x65, 0x55, 0x75,
+       0x69, 0x64, 0x22, 0x3d, 0x0a, 0x13, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 
0x74, 0x61, 0x74, 0x75,
+       0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 
0x06, 0x73, 0x74, 0x61,
+       0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 
0x61, 0x70, 0x69, 0x2e,
+       0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 
0x74, 0x61, 0x74, 0x75,
+       0x73, 0x22, 0x3e, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 
0x69, 0x6c, 0x65, 0x4f,
+       0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 
0x12, 0x23, 0x0a, 0x0d,
+       0x70, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x75, 0x75, 0x69, 
0x64, 0x18, 0x01, 0x20,
+       0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 
0x65, 0x55, 0x75, 0x69,
+       0x64, 0x22, 0x71, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 
0x69, 0x6c, 0x65, 0x4f,
+       0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 
0x65, 0x12, 0x16, 0x0a,
+       0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 
0x09, 0x52, 0x06, 0x6f,
+       0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x3d, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 
0x70, 0x69, 0x6c, 0x61,
+       0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 
0x02, 0x20, 0x01, 0x28,
+       0x0e, 0x32, 0x0e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 
0x74, 0x61, 0x74, 0x75,
+       0x73, 0x52, 0x11, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x61, 0x74, 0x69, 
0x6f, 0x6e, 0x53, 0x74,
+       0x61, 0x74, 0x75, 0x73, 0x22, 0x3a, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 
0x75, 0x6e, 0x4f, 0x75,
+       0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 
0x23, 0x0a, 0x0d, 0x70,
        0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x75, 0x75, 0x69, 0x64, 
0x18, 0x01, 0x20, 0x01,
        0x28, 0x09, 0x52, 0x0c, 0x70, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 
0x55, 0x75, 0x69, 0x64,
-       0x22, 0x44, 0x0a, 0x13, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x74, 0x61, 
0x74, 0x75, 0x73, 0x52,
-       0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x73, 
0x74, 0x61, 0x74, 0x75,
-       0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x70, 0x6c, 
0x61, 0x79, 0x67, 0x72,
-       0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 
0x75, 0x73, 0x52, 0x06,
-       0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3e, 0x0a, 0x17, 0x47, 0x65, 
0x74, 0x43, 0x6f, 0x6d,
-       0x70, 0x69, 0x6c, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 
0x71, 0x75, 0x65, 0x73,
-       0x74, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 
0x65, 0x5f, 0x75, 0x75,
-       0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x69, 
0x70, 0x65, 0x6c, 0x69,
-       0x6e, 0x65, 0x55, 0x75, 0x69, 0x64, 0x22, 0x78, 0x0a, 0x18, 0x47, 0x65, 
0x74, 0x43, 0x6f, 0x6d,
-       0x70, 0x69, 0x6c, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 
0x73, 0x70, 0x6f, 0x6e,
-       0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 
0x18, 0x01, 0x20, 0x01,
-       0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x44, 
0x0a, 0x12, 0x63, 0x6f,
-       0x6d, 0x70, 0x69, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 
0x61, 0x74, 0x75, 0x73,
-       0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x70, 0x6c, 0x61, 
0x79, 0x67, 0x72, 0x6f,
-       0x75, 0x6e, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 
0x73, 0x52, 0x11, 0x63,
-       0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 
0x61, 0x74, 0x75, 0x73,
-       0x22, 0x3a, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x4f, 0x75, 
0x74, 0x70, 0x75, 0x74,
-       0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x70, 
0x69, 0x70, 0x65, 0x6c,
-       0x69, 0x6e, 0x65, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 
0x28, 0x09, 0x52, 0x0c,
-       0x70, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x55, 0x75, 0x69, 0x64, 
0x22, 0x74, 0x0a, 0x14,
-       0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 
0x52, 0x65, 0x73, 0x70,
-       0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 
0x75, 0x74, 0x18, 0x01,
-       0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 
0x12, 0x44, 0x0a, 0x12,
-       0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 
0x73, 0x74, 0x61, 0x74,
-       0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x70, 
0x6c, 0x61, 0x79, 0x67,
-       0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 
0x74, 0x75, 0x73, 0x52,
-       0x11, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 
0x53, 0x74, 0x61, 0x74,
-       0x75, 0x73, 0x2a, 0x52, 0x0a, 0x03, 0x53, 0x64, 0x6b, 0x12, 0x13, 0x0a, 
0x0f, 0x53, 0x44, 0x4b,
-       0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 
0x10, 0x00, 0x12, 0x0c,
-       0x0a, 0x08, 0x53, 0x44, 0x4b, 0x5f, 0x4a, 0x41, 0x56, 0x41, 0x10, 0x01, 
0x12, 0x0a, 0x0a, 0x06,
-       0x53, 0x44, 0x4b, 0x5f, 0x47, 0x4f, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 
0x53, 0x44, 0x4b, 0x5f,
-       0x50, 0x59, 0x54, 0x48, 0x4f, 0x4e, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 
0x53, 0x44, 0x4b, 0x5f,
-       0x53, 0x43, 0x49, 0x4f, 0x10, 0x04, 0x2a, 0x5d, 0x0a, 0x06, 0x53, 0x74, 
0x61, 0x74, 0x75, 0x73,
-       0x12, 0x16, 0x0a, 0x12, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 
0x4e, 0x53, 0x50, 0x45,
-       0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 
0x53, 0x54, 0x41, 0x54,
-       0x55, 0x53, 0x5f, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x49, 0x4e, 0x47, 
0x10, 0x01, 0x12, 0x13,
-       0x0a, 0x0f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x49, 0x4e, 
0x49, 0x53, 0x48, 0x45,
-       0x44, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x54, 0x55, 
0x53, 0x5f, 0x45, 0x52,
-       0x52, 0x4f, 0x52, 0x10, 0x03, 0x32, 0xf1, 0x02, 0x0a, 0x11, 0x50, 0x6c, 
0x61, 0x79, 0x67, 0x72,
-       0x6f, 0x75, 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 
0x48, 0x0a, 0x07, 0x52,
-       0x75, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1d, 0x2e, 0x70, 0x6c, 0x61, 
0x79, 0x67, 0x72, 0x6f,
-       0x75, 0x6e, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x75, 0x6e, 0x43, 0x6f, 
0x64, 0x65, 0x52, 0x65,
-       0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x70, 0x6c, 0x61, 0x79, 
0x67, 0x72, 0x6f, 0x75,
-       0x6e, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x75, 0x6e, 0x43, 0x6f, 0x64, 
0x65, 0x52, 0x65, 0x73,
-       0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x43, 0x68, 0x65, 
0x63, 0x6b, 0x53, 0x74,
-       0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x2e, 0x70, 0x6c, 0x61, 0x79, 0x67, 
0x72, 0x6f, 0x75, 0x6e,
-       0x64, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x74, 
0x61, 0x74, 0x75, 0x73,
-       0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x70, 0x6c, 
0x61, 0x79, 0x67, 0x72,
-       0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 
0x6b, 0x53, 0x74, 0x61,
-       0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 
0x57, 0x0a, 0x0c, 0x47,
-       0x65, 0x74, 0x52, 0x75, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 
0x22, 0x2e, 0x70, 0x6c,
-       0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x76, 0x31, 0x2e, 
0x47, 0x65, 0x74, 0x52,
-       0x75, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 
0x65, 0x73, 0x74, 0x1a,
-       0x23, 0x2e, 0x70, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 
0x2e, 0x76, 0x31, 0x2e,
-       0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 
0x52, 0x65, 0x73, 0x70,
-       0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, 
0x6f, 0x6d, 0x70, 0x69,
-       0x6c, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x26, 0x2e, 0x70, 
0x6c, 0x61, 0x79, 0x67,
-       0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 
0x43, 0x6f, 0x6d, 0x70,
-       0x69, 0x6c, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 
0x75, 0x65, 0x73, 0x74,
-       0x1a, 0x27, 0x2e, 0x70, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 
0x64, 0x2e, 0x76, 0x31,
-       0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x4f, 
0x75, 0x74, 0x70, 0x75,
-       0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x31, 0x5a, 
0x2f, 0x67, 0x69, 0x74,
-       0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, 
0x68, 0x65, 0x2f, 0x62,
-       0x65, 0x61, 0x6d, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 
0x6e, 0x64, 0x2f, 0x76,
-       0x31, 0x3b, 0x70, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 
0x62, 0x06, 0x70, 0x72,
-       0x6f, 0x74, 0x6f, 0x33,
+       0x22, 0x6d, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x4f, 0x75, 
0x74, 0x70, 0x75, 0x74,
+       0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 
0x6f, 0x75, 0x74, 0x70,
+       0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 
0x74, 0x70, 0x75, 0x74,
+       0x12, 0x3d, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x61, 0x74, 
0x69, 0x6f, 0x6e, 0x5f,
+       0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 
0x32, 0x0e, 0x2e, 0x61,
+       0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 
0x52, 0x11, 0x63, 0x6f,
+       0x6d, 0x70, 0x69, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 
0x74, 0x75, 0x73, 0x2a,
+       0x52, 0x0a, 0x03, 0x53, 0x64, 0x6b, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x44, 
0x4b, 0x5f, 0x55, 0x4e,
+       0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 
0x0c, 0x0a, 0x08, 0x53,
+       0x44, 0x4b, 0x5f, 0x4a, 0x41, 0x56, 0x41, 0x10, 0x01, 0x12, 0x0a, 0x0a, 
0x06, 0x53, 0x44, 0x4b,
+       0x5f, 0x47, 0x4f, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x44, 0x4b, 
0x5f, 0x50, 0x59, 0x54,
+       0x48, 0x4f, 0x4e, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x44, 0x4b, 
0x5f, 0x53, 0x43, 0x49,
+       0x4f, 0x10, 0x04, 0x2a, 0x5d, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 
0x73, 0x12, 0x16, 0x0a,
+       0x12, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 
0x45, 0x43, 0x49, 0x46,
+       0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x54, 0x41, 
0x54, 0x55, 0x53, 0x5f,
+       0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 
0x13, 0x0a, 0x0f, 0x53,
+       0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x48, 
0x45, 0x44, 0x10, 0x02,
+       0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 
0x52, 0x52, 0x4f, 0x52,
+       0x10, 0x03, 0x32, 0xb9, 0x02, 0x0a, 0x11, 0x50, 0x6c, 0x61, 0x79, 0x67, 
0x72, 0x6f, 0x75, 0x6e,
+       0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3a, 0x0a, 0x07, 
0x52, 0x75, 0x6e, 0x43,
+       0x6f, 0x64, 0x65, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 
0x2e, 0x52, 0x75, 0x6e,
+       0x43, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 
0x17, 0x2e, 0x61, 0x70,
+       0x69, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x75, 0x6e, 0x43, 0x6f, 0x64, 0x65, 
0x52, 0x65, 0x73, 0x70,
+       0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x43, 0x68, 0x65, 0x63, 
0x6b, 0x53, 0x74, 0x61,
+       0x74, 0x75, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 
0x2e, 0x43, 0x68, 0x65,
+       0x63, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 
0x65, 0x73, 0x74, 0x1a,
+       0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 
0x63, 0x6b, 0x53, 0x74,
+       0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 
0x12, 0x49, 0x0a, 0x0c,
+       0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 
0x12, 0x1b, 0x2e, 0x61,
+       0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 
0x4f, 0x75, 0x74, 0x70,
+       0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 
0x61, 0x70, 0x69, 0x2e,
+       0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x75, 0x6e, 0x4f, 0x75, 0x74, 
0x70, 0x75, 0x74, 0x52,
+       0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, 0x0a, 0x10, 0x47, 
0x65, 0x74, 0x43, 0x6f,
+       0x6d, 0x70, 0x69, 0x6c, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 
0x1f, 0x2e, 0x61, 0x70,
+       0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 
0x69, 0x6c, 0x65, 0x4f,
+       0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 
0x1a, 0x20, 0x2e, 0x61,
+       0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 
0x70, 0x69, 0x6c, 0x65,
+       0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 
0x73, 0x65, 0x42, 0x38,
+       0x5a, 0x36, 0x62, 0x65, 0x61, 0x6d, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 
0x65, 0x2e, 0x6f, 0x72,
+       0x67, 0x2f, 0x70, 0x6c, 0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 
0x2f, 0x62, 0x61, 0x63,
+       0x6b, 0x65, 0x6e, 0x64, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 
0x6c, 0x3b, 0x70, 0x6c,
+       0x61, 0x79, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 
0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
-       file_playground_proto_rawDescOnce sync.Once
-       file_playground_proto_rawDescData = file_playground_proto_rawDesc
+       file_api_v1_api_proto_rawDescOnce sync.Once
+       file_api_v1_api_proto_rawDescData = file_api_v1_api_proto_rawDesc
 )
 
-func file_playground_proto_rawDescGZIP() []byte {
-       file_playground_proto_rawDescOnce.Do(func() {
-               file_playground_proto_rawDescData = 
protoimpl.X.CompressGZIP(file_playground_proto_rawDescData)
+func file_api_v1_api_proto_rawDescGZIP() []byte {
+       file_api_v1_api_proto_rawDescOnce.Do(func() {
+               file_api_v1_api_proto_rawDescData = 
protoimpl.X.CompressGZIP(file_api_v1_api_proto_rawDescData)
        })
-       return file_playground_proto_rawDescData
-}
-
-var file_playground_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
-var file_playground_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
-var file_playground_proto_goTypes = []interface{}{
-       (Sdk)(0),                         // 0: playground.v1.Sdk
-       (Status)(0),                      // 1: playground.v1.Status
-       (*RunCodeRequest)(nil),           // 2: playground.v1.RunCodeRequest
-       (*RunCodeResponse)(nil),          // 3: playground.v1.RunCodeResponse
-       (*CheckStatusRequest)(nil),       // 4: playground.v1.CheckStatusRequest
-       (*CheckStatusResponse)(nil),      // 5: 
playground.v1.CheckStatusResponse
-       (*GetCompileOutputRequest)(nil),  // 6: 
playground.v1.GetCompileOutputRequest
-       (*GetCompileOutputResponse)(nil), // 7: 
playground.v1.GetCompileOutputResponse
-       (*GetRunOutputRequest)(nil),      // 8: 
playground.v1.GetRunOutputRequest
-       (*GetRunOutputResponse)(nil),     // 9: 
playground.v1.GetRunOutputResponse
-}
-var file_playground_proto_depIdxs = []int32{
-       0, // 0: playground.v1.RunCodeRequest.sdk:type_name -> playground.v1.Sdk
-       1, // 1: playground.v1.CheckStatusResponse.status:type_name -> 
playground.v1.Status
-       1, // 2: 
playground.v1.GetCompileOutputResponse.compilation_status:type_name -> 
playground.v1.Status
-       1, // 3: 
playground.v1.GetRunOutputResponse.compilation_status:type_name -> 
playground.v1.Status
-       2, // 4: playground.v1.PlaygroundService.RunCode:input_type -> 
playground.v1.RunCodeRequest
-       4, // 5: playground.v1.PlaygroundService.CheckStatus:input_type -> 
playground.v1.CheckStatusRequest
-       8, // 6: playground.v1.PlaygroundService.GetRunOutput:input_type -> 
playground.v1.GetRunOutputRequest
-       6, // 7: playground.v1.PlaygroundService.GetCompileOutput:input_type -> 
playground.v1.GetCompileOutputRequest
-       3, // 8: playground.v1.PlaygroundService.RunCode:output_type -> 
playground.v1.RunCodeResponse
-       5, // 9: playground.v1.PlaygroundService.CheckStatus:output_type -> 
playground.v1.CheckStatusResponse
-       9, // 10: playground.v1.PlaygroundService.GetRunOutput:output_type -> 
playground.v1.GetRunOutputResponse
-       7, // 11: playground.v1.PlaygroundService.GetCompileOutput:output_type 
-> playground.v1.GetCompileOutputResponse
+       return file_api_v1_api_proto_rawDescData
+}
+
+var file_api_v1_api_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
+var file_api_v1_api_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
+var file_api_v1_api_proto_goTypes = []interface{}{
+       (Sdk)(0),                         // 0: api.v1.Sdk
+       (Status)(0),                      // 1: api.v1.Status
+       (*RunCodeRequest)(nil),           // 2: api.v1.RunCodeRequest
+       (*RunCodeResponse)(nil),          // 3: api.v1.RunCodeResponse
+       (*CheckStatusRequest)(nil),       // 4: api.v1.CheckStatusRequest
+       (*CheckStatusResponse)(nil),      // 5: api.v1.CheckStatusResponse
+       (*GetCompileOutputRequest)(nil),  // 6: api.v1.GetCompileOutputRequest
+       (*GetCompileOutputResponse)(nil), // 7: api.v1.GetCompileOutputResponse
+       (*GetRunOutputRequest)(nil),      // 8: api.v1.GetRunOutputRequest
+       (*GetRunOutputResponse)(nil),     // 9: api.v1.GetRunOutputResponse
+}
+var file_api_v1_api_proto_depIdxs = []int32{
+       0, // 0: api.v1.RunCodeRequest.sdk:type_name -> api.v1.Sdk
+       1, // 1: api.v1.CheckStatusResponse.status:type_name -> api.v1.Status
+       1, // 2: api.v1.GetCompileOutputResponse.compilation_status:type_name 
-> api.v1.Status
+       1, // 3: api.v1.GetRunOutputResponse.compilation_status:type_name -> 
api.v1.Status
+       2, // 4: api.v1.PlaygroundService.RunCode:input_type -> 
api.v1.RunCodeRequest
+       4, // 5: api.v1.PlaygroundService.CheckStatus:input_type -> 
api.v1.CheckStatusRequest
+       8, // 6: api.v1.PlaygroundService.GetRunOutput:input_type -> 
api.v1.GetRunOutputRequest
+       6, // 7: api.v1.PlaygroundService.GetCompileOutput:input_type -> 
api.v1.GetCompileOutputRequest
+       3, // 8: api.v1.PlaygroundService.RunCode:output_type -> 
api.v1.RunCodeResponse
+       5, // 9: api.v1.PlaygroundService.CheckStatus:output_type -> 
api.v1.CheckStatusResponse
+       9, // 10: api.v1.PlaygroundService.GetRunOutput:output_type -> 
api.v1.GetRunOutputResponse
+       7, // 11: api.v1.PlaygroundService.GetCompileOutput:output_type -> 
api.v1.GetCompileOutputResponse
        8, // [8:12] is the sub-list for method output_type
        4, // [4:8] is the sub-list for method input_type
        4, // [4:4] is the sub-list for extension type_name
@@ -683,13 +677,13 @@ var file_playground_proto_depIdxs = []int32{
        0, // [0:4] is the sub-list for field type_name
 }
 
-func init() { file_playground_proto_init() }
-func file_playground_proto_init() {
-       if File_playground_proto != nil {
+func init() { file_api_v1_api_proto_init() }
+func file_api_v1_api_proto_init() {
+       if File_api_v1_api_proto != nil {
                return
        }
        if !protoimpl.UnsafeEnabled {
-               file_playground_proto_msgTypes[0].Exporter = func(v 
interface{}, i int) interface{} {
+               file_api_v1_api_proto_msgTypes[0].Exporter = func(v 
interface{}, i int) interface{} {
                        switch v := v.(*RunCodeRequest); i {
                        case 0:
                                return &v.state
@@ -701,7 +695,7 @@ func file_playground_proto_init() {
                                return nil
                        }
                }
-               file_playground_proto_msgTypes[1].Exporter = func(v 
interface{}, i int) interface{} {
+               file_api_v1_api_proto_msgTypes[1].Exporter = func(v 
interface{}, i int) interface{} {
                        switch v := v.(*RunCodeResponse); i {
                        case 0:
                                return &v.state
@@ -713,7 +707,7 @@ func file_playground_proto_init() {
                                return nil
                        }
                }
-               file_playground_proto_msgTypes[2].Exporter = func(v 
interface{}, i int) interface{} {
+               file_api_v1_api_proto_msgTypes[2].Exporter = func(v 
interface{}, i int) interface{} {
                        switch v := v.(*CheckStatusRequest); i {
                        case 0:
                                return &v.state
@@ -725,7 +719,7 @@ func file_playground_proto_init() {
                                return nil
                        }
                }
-               file_playground_proto_msgTypes[3].Exporter = func(v 
interface{}, i int) interface{} {
+               file_api_v1_api_proto_msgTypes[3].Exporter = func(v 
interface{}, i int) interface{} {
                        switch v := v.(*CheckStatusResponse); i {
                        case 0:
                                return &v.state
@@ -737,7 +731,7 @@ func file_playground_proto_init() {
                                return nil
                        }
                }
-               file_playground_proto_msgTypes[4].Exporter = func(v 
interface{}, i int) interface{} {
+               file_api_v1_api_proto_msgTypes[4].Exporter = func(v 
interface{}, i int) interface{} {
                        switch v := v.(*GetCompileOutputRequest); i {
                        case 0:
                                return &v.state
@@ -749,7 +743,7 @@ func file_playground_proto_init() {
                                return nil
                        }
                }
-               file_playground_proto_msgTypes[5].Exporter = func(v 
interface{}, i int) interface{} {
+               file_api_v1_api_proto_msgTypes[5].Exporter = func(v 
interface{}, i int) interface{} {
                        switch v := v.(*GetCompileOutputResponse); i {
                        case 0:
                                return &v.state
@@ -761,7 +755,7 @@ func file_playground_proto_init() {
                                return nil
                        }
                }
-               file_playground_proto_msgTypes[6].Exporter = func(v 
interface{}, i int) interface{} {
+               file_api_v1_api_proto_msgTypes[6].Exporter = func(v 
interface{}, i int) interface{} {
                        switch v := v.(*GetRunOutputRequest); i {
                        case 0:
                                return &v.state
@@ -773,7 +767,7 @@ func file_playground_proto_init() {
                                return nil
                        }
                }
-               file_playground_proto_msgTypes[7].Exporter = func(v 
interface{}, i int) interface{} {
+               file_api_v1_api_proto_msgTypes[7].Exporter = func(v 
interface{}, i int) interface{} {
                        switch v := v.(*GetRunOutputResponse); i {
                        case 0:
                                return &v.state
@@ -790,19 +784,19 @@ func file_playground_proto_init() {
        out := protoimpl.TypeBuilder{
                File: protoimpl.DescBuilder{
                        GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-                       RawDescriptor: file_playground_proto_rawDesc,
+                       RawDescriptor: file_api_v1_api_proto_rawDesc,
                        NumEnums:      2,
                        NumMessages:   8,
                        NumExtensions: 0,
                        NumServices:   1,
                },
-               GoTypes:           file_playground_proto_goTypes,
-               DependencyIndexes: file_playground_proto_depIdxs,
-               EnumInfos:         file_playground_proto_enumTypes,
-               MessageInfos:      file_playground_proto_msgTypes,
+               GoTypes:           file_api_v1_api_proto_goTypes,
+               DependencyIndexes: file_api_v1_api_proto_depIdxs,
+               EnumInfos:         file_api_v1_api_proto_enumTypes,
+               MessageInfos:      file_api_v1_api_proto_msgTypes,
        }.Build()
-       File_playground_proto = out.File
-       file_playground_proto_rawDesc = nil
-       file_playground_proto_goTypes = nil
-       file_playground_proto_depIdxs = nil
+       File_api_v1_api_proto = out.File
+       file_api_v1_api_proto_rawDesc = nil
+       file_api_v1_api_proto_goTypes = nil
+       file_api_v1_api_proto_depIdxs = nil
 }
diff --git a/playground/backend/internal/api/playground_grpc.pb.go 
b/playground/backend/internal/api/v1/api_grpc.pb.go
similarity index 89%
rename from playground/backend/internal/api/playground_grpc.pb.go
rename to playground/backend/internal/api/v1/api_grpc.pb.go
index f8e11ca..63c0748 100644
--- a/playground/backend/internal/api/playground_grpc.pb.go
+++ b/playground/backend/internal/api/v1/api_grpc.pb.go
@@ -12,7 +12,6 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 
 package playground
@@ -53,7 +52,7 @@ func NewPlaygroundServiceClient(cc grpc.ClientConnInterface) 
PlaygroundServiceCl
 
 func (c *playgroundServiceClient) RunCode(ctx context.Context, in 
*RunCodeRequest, opts ...grpc.CallOption) (*RunCodeResponse, error) {
        out := new(RunCodeResponse)
-       err := c.cc.Invoke(ctx, "/playground.v1.PlaygroundService/RunCode", in, 
out, opts...)
+       err := c.cc.Invoke(ctx, "/api.v1.PlaygroundService/RunCode", in, out, 
opts...)
        if err != nil {
                return nil, err
        }
@@ -62,7 +61,7 @@ func (c *playgroundServiceClient) RunCode(ctx 
context.Context, in *RunCodeReques
 
 func (c *playgroundServiceClient) CheckStatus(ctx context.Context, in 
*CheckStatusRequest, opts ...grpc.CallOption) (*CheckStatusResponse, error) {
        out := new(CheckStatusResponse)
-       err := c.cc.Invoke(ctx, "/playground.v1.PlaygroundService/CheckStatus", 
in, out, opts...)
+       err := c.cc.Invoke(ctx, "/api.v1.PlaygroundService/CheckStatus", in, 
out, opts...)
        if err != nil {
                return nil, err
        }
@@ -71,7 +70,7 @@ func (c *playgroundServiceClient) CheckStatus(ctx 
context.Context, in *CheckStat
 
 func (c *playgroundServiceClient) GetRunOutput(ctx context.Context, in 
*GetRunOutputRequest, opts ...grpc.CallOption) (*GetRunOutputResponse, error) {
        out := new(GetRunOutputResponse)
-       err := c.cc.Invoke(ctx, 
"/playground.v1.PlaygroundService/GetRunOutput", in, out, opts...)
+       err := c.cc.Invoke(ctx, "/api.v1.PlaygroundService/GetRunOutput", in, 
out, opts...)
        if err != nil {
                return nil, err
        }
@@ -80,7 +79,7 @@ func (c *playgroundServiceClient) GetRunOutput(ctx 
context.Context, in *GetRunOu
 
 func (c *playgroundServiceClient) GetCompileOutput(ctx context.Context, in 
*GetCompileOutputRequest, opts ...grpc.CallOption) (*GetCompileOutputResponse, 
error) {
        out := new(GetCompileOutputResponse)
-       err := c.cc.Invoke(ctx, 
"/playground.v1.PlaygroundService/GetCompileOutput", in, out, opts...)
+       err := c.cc.Invoke(ctx, "/api.v1.PlaygroundService/GetCompileOutput", 
in, out, opts...)
        if err != nil {
                return nil, err
        }
@@ -88,7 +87,7 @@ func (c *playgroundServiceClient) GetCompileOutput(ctx 
context.Context, in *GetC
 }
 
 // PlaygroundServiceServer is the server API for PlaygroundService service.
-// All implementations must embed UnimplementedPlaygroundServiceServer
+// All implementations should embed UnimplementedPlaygroundServiceServer
 // for forward compatibility
 type PlaygroundServiceServer interface {
        // Submit the job for an execution and get the pipeline uuid.
@@ -99,10 +98,9 @@ type PlaygroundServiceServer interface {
        GetRunOutput(context.Context, *GetRunOutputRequest) 
(*GetRunOutputResponse, error)
        // Get the result of pipeline compilation.
        GetCompileOutput(context.Context, *GetCompileOutputRequest) 
(*GetCompileOutputResponse, error)
-       mustEmbedUnimplementedPlaygroundServiceServer()
 }
 
-// UnimplementedPlaygroundServiceServer must be embedded to have forward 
compatible implementations.
+// UnimplementedPlaygroundServiceServer should be embedded to have forward 
compatible implementations.
 type UnimplementedPlaygroundServiceServer struct {
 }
 
@@ -118,7 +116,6 @@ func (UnimplementedPlaygroundServiceServer) 
GetRunOutput(context.Context, *GetRu
 func (UnimplementedPlaygroundServiceServer) GetCompileOutput(context.Context, 
*GetCompileOutputRequest) (*GetCompileOutputResponse, error) {
        return nil, status.Errorf(codes.Unimplemented, "method GetCompileOutput 
not implemented")
 }
-func (UnimplementedPlaygroundServiceServer) 
mustEmbedUnimplementedPlaygroundServiceServer() {}
 
 // UnsafePlaygroundServiceServer may be embedded to opt out of forward 
compatibility for this service.
 // Use of this interface is not recommended, as added methods to 
PlaygroundServiceServer will
@@ -141,7 +138,7 @@ func _PlaygroundService_RunCode_Handler(srv interface{}, 
ctx context.Context, de
        }
        info := &grpc.UnaryServerInfo{
                Server:     srv,
-               FullMethod: "/playground.v1.PlaygroundService/RunCode",
+               FullMethod: "/api.v1.PlaygroundService/RunCode",
        }
        handler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
                return srv.(PlaygroundServiceServer).RunCode(ctx, 
req.(*RunCodeRequest))
@@ -159,7 +156,7 @@ func _PlaygroundService_CheckStatus_Handler(srv 
interface{}, ctx context.Context
        }
        info := &grpc.UnaryServerInfo{
                Server:     srv,
-               FullMethod: "/playground.v1.PlaygroundService/CheckStatus",
+               FullMethod: "/api.v1.PlaygroundService/CheckStatus",
        }
        handler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
                return srv.(PlaygroundServiceServer).CheckStatus(ctx, 
req.(*CheckStatusRequest))
@@ -177,7 +174,7 @@ func _PlaygroundService_GetRunOutput_Handler(srv 
interface{}, ctx context.Contex
        }
        info := &grpc.UnaryServerInfo{
                Server:     srv,
-               FullMethod: "/playground.v1.PlaygroundService/GetRunOutput",
+               FullMethod: "/api.v1.PlaygroundService/GetRunOutput",
        }
        handler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
                return srv.(PlaygroundServiceServer).GetRunOutput(ctx, 
req.(*GetRunOutputRequest))
@@ -195,7 +192,7 @@ func _PlaygroundService_GetCompileOutput_Handler(srv 
interface{}, ctx context.Co
        }
        info := &grpc.UnaryServerInfo{
                Server:     srv,
-               FullMethod: "/playground.v1.PlaygroundService/GetCompileOutput",
+               FullMethod: "/api.v1.PlaygroundService/GetCompileOutput",
        }
        handler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
                return srv.(PlaygroundServiceServer).GetCompileOutput(ctx, 
req.(*GetCompileOutputRequest))
@@ -207,7 +204,7 @@ func _PlaygroundService_GetCompileOutput_Handler(srv 
interface{}, ctx context.Co
 // It's only intended for direct use with grpc.RegisterService,
 // and not to be introspected or modified (even as a copy)
 var PlaygroundService_ServiceDesc = grpc.ServiceDesc{
-       ServiceName: "playground.v1.PlaygroundService",
+       ServiceName: "api.v1.PlaygroundService",
        HandlerType: (*PlaygroundServiceServer)(nil),
        Methods: []grpc.MethodDesc{
                {
@@ -228,5 +225,5 @@ var PlaygroundService_ServiceDesc = grpc.ServiceDesc{
                },
        },
        Streams:  []grpc.StreamDesc{},
-       Metadata: "playground.proto",
+       Metadata: "api/v1/api.proto",
 }
diff --git a/playground/backend/internal/executors/go_helper.go 
b/playground/backend/internal/environment/environment.go
similarity index 71%
copy from playground/backend/internal/executors/go_helper.go
copy to playground/backend/internal/environment/environment.go
index a9d72bb..910dec9 100644
--- a/playground/backend/internal/executors/go_helper.go
+++ b/playground/backend/internal/environment/environment.go
@@ -13,15 +13,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// Package executors
-package executors
+// TODO: remove this code when merging 
https://github.com/apache/beam/pull/15654
 
-// NewGoExecutor creates an executor with Go specifics
-func NewGoExecutor(fs *fs_tool.LifeCycle, javaValidators *[]validatorWithArgs) 
*Executor {
-       return nil
+package environment
+
+type ServerEnvs struct {}
+
+func (envs ServerEnvs) Address() string {
+       return ""
 }
 
-// GetGoValidators return validators methods that needed for Go file
-func GetGoValidators() *[]validatorWithArgs {
-       return nil
+func NewEnvironment() ServerEnvs {
+       return ServerEnvs{}
 }
diff --git a/playground/backend/internal/executors/executor.go 
b/playground/backend/internal/executors/executor.go
index a5e258d..b85641b 100644
--- a/playground/backend/internal/executors/executor.go
+++ b/playground/backend/internal/executors/executor.go
@@ -17,7 +17,7 @@
 package executors
 
 import (
-       pb "beam.apache.org/playground/backend/internal/api"
+       pb "beam.apache.org/playground/backend/internal/api/v1"
        "beam.apache.org/playground/backend/internal/fs_tool"
        "fmt"
        "os/exec"
diff --git a/playground/backend/internal/executors/go_helper.go 
b/playground/backend/internal/executors/go_helper.go
index a9d72bb..6772145 100644
--- a/playground/backend/internal/executors/go_helper.go
+++ b/playground/backend/internal/executors/go_helper.go
@@ -16,6 +16,8 @@
 // Package executors
 package executors
 
+import "beam.apache.org/playground/backend/internal/fs_tool"
+
 // NewGoExecutor creates an executor with Go specifics
 func NewGoExecutor(fs *fs_tool.LifeCycle, javaValidators *[]validatorWithArgs) 
*Executor {
        return nil
diff --git a/playground/backend/internal/executors/java_helper_test.go 
b/playground/backend/internal/executors/java_helper_test.go
index 332717a..19b3934 100644
--- a/playground/backend/internal/executors/java_helper_test.go
+++ b/playground/backend/internal/executors/java_helper_test.go
@@ -16,7 +16,7 @@
 package executors
 
 import (
-       pb "beam.apache.org/playground/backend/internal/api"
+       pb "beam.apache.org/playground/backend/internal/api/v1"
        "beam.apache.org/playground/backend/internal/fs_tool"
        "github.com/google/uuid"
        "testing"
diff --git a/playground/backend/internal/fs_tool/fs.go 
b/playground/backend/internal/fs_tool/fs.go
index 481fade..7b99fd9 100644
--- a/playground/backend/internal/fs_tool/fs.go
+++ b/playground/backend/internal/fs_tool/fs.go
@@ -16,7 +16,7 @@
 package fs_tool
 
 import (
-       pb "beam.apache.org/playground/backend/internal/api"
+       pb "beam.apache.org/playground/backend/internal/api/v1"
        "errors"
        "fmt"
        "github.com/google/uuid"
diff --git a/playground/backend/internal/fs_tool/fs_test.go 
b/playground/backend/internal/fs_tool/fs_test.go
index 1b1b304..c1b00d2 100644
--- a/playground/backend/internal/fs_tool/fs_test.go
+++ b/playground/backend/internal/fs_tool/fs_test.go
@@ -16,7 +16,7 @@
 package fs_tool
 
 import (
-       pb "beam.apache.org/playground/backend/internal/api"
+       pb "beam.apache.org/playground/backend/internal/api/v1"
        "fmt"
        "github.com/google/uuid"
        "io/fs"
diff --git a/playground/buf.gen.yaml b/playground/buf.gen.yaml
new file mode 100644
index 0000000..bd9b9f3d
--- /dev/null
+++ b/playground/buf.gen.yaml
@@ -0,0 +1,32 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+version: v1
+plugins:
+- name: go
+  out: backend/internal
+  opt: paths=source_relative
+- name: go-grpc
+  out: backend/internal
+  opt:
+  - paths=source_relative
+  - require_unimplemented_servers=false
+- name: dart
+  out: frontend/lib
+  opt: grpc
\ No newline at end of file
diff --git a/playground/build.gradle.kts b/playground/build.gradle.kts
new file mode 100644
index 0000000..b511c48
--- /dev/null
+++ b/playground/build.gradle.kts
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * License); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+description = "Apache Beam :: Playground"
+
+// generate protobuf client and server stubs
+task("generateProto") {
+  group = "build"
+  doLast {
+    exec {
+      executable("buf")
+      args("generate")
+    }
+  }
+}
diff --git a/playground/frontend/README.md b/playground/frontend/README.md
index acdea1d..7c3b489 100644
--- a/playground/frontend/README.md
+++ b/playground/frontend/README.md
@@ -26,11 +26,7 @@ It provides a portable API layer for building sophisticated 
data-parallel proces
 
 ## Getting Started
 
-Website development requires 
[Flutter](https://flutter.dev/docs/get-started/install) installed.
-
-Create /lib/generated folder and run the next command to generate grpc files 
from proto:
-
-`$ protoc playground.proto --dart_out=grpc:lib/generated 
--proto_path=$(pwd)/../playground/v1`
+See [playground/README.md](../README.md) for details on requirements and setup.
 
 The following command is used to build and serve the website locally:
 
diff --git a/playground/frontend/analysis_options.yaml 
b/playground/frontend/analysis_options.yaml
index 38742fe..41ffd37 100644
--- a/playground/frontend/analysis_options.yaml
+++ b/playground/frontend/analysis_options.yaml
@@ -26,6 +26,10 @@
 # packages, and plugins designed to encourage good coding practices.
 include: package:flutter_lints/flutter.yaml
 
+# exclude generated files
+analyzer:
+  exclude: [lib/api/**, test/**.mocks.dart, lib/**.g.dart]
+
 linter:
   # The lint rules applied to this project can be customized in the
   # section below to disable rules from the 
`package:flutter_lints/flutter.yaml`
diff --git a/playground/frontend/build.gradle.kts 
b/playground/frontend/build.gradle.kts
new file mode 100644
index 0000000..5533526
--- /dev/null
+++ b/playground/frontend/build.gradle.kts
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * License); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+description = "Apache Beam :: Playground :: Frontend"
+
+task("analyze") {
+  group = "verification"
+  description = "Analyze dart code"
+  doLast {
+    exec {
+      executable("dart")
+      args("analyze", ".")
+    }
+  }
+}
+
+task("pubGet") {
+  group = "build"
+  description = "Get packages for the playground frontend project"
+  doLast {
+    exec {
+      executable("flutter")
+      args("pub", "get")
+    }
+  }
+}
+
+task("format") {
+  group = "build"
+  description = "Idiomatically format Dart source code"
+  doLast {
+    exec {
+      executable("dart")
+      args("format", ".")
+    }
+  }
+}
+
+task("run") {
+  group = "application"
+  description = "Run application on Google Chrome"
+  doLast {
+    exec {
+      executable("flutter")
+      args("run", "-d", "chrome")
+    }
+  }
+}
+
+task("test") {
+  group = "verification"
+  description = "flutter test"
+  doLast {
+    exec {
+      executable("flutter")
+      args("test")
+    }
+  }
+}
\ No newline at end of file
diff --git a/playground/frontend/lib/api/v1/api.pb.dart 
b/playground/frontend/lib/api/v1/api.pb.dart
new file mode 100644
index 0000000..9c503e4
--- /dev/null
+++ b/playground/frontend/lib/api/v1/api.pb.dart
@@ -0,0 +1,450 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///
+//  Generated code. Do not modify.
+//  source: api/v1/api.proto
+//
+// @dart = 2.12
+// ignore_for_file: 
annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
+
+import 'dart:core' as $core;
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'api.pbenum.dart';
+
+export 'api.pbenum.dart';
+
+class RunCodeRequest extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 
'RunCodeRequest', package: const $pb.PackageName(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'api.v1'), 
createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? 
'' : 'code')
+    ..e<Sdk>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') 
? '' : 'sdk', $pb.PbFieldType.OE, defaultOrMaker: Sdk.SDK_UNSPECIFIED, valueOf: 
Sdk.valueOf, enumValues: Sdk.values)
+    ..hasRequiredFields = false
+  ;
+
+  RunCodeRequest._() : super();
+  factory RunCodeRequest({
+    $core.String? code,
+    Sdk? sdk,
+  }) {
+    final _result = create();
+    if (code != null) {
+      _result.code = code;
+    }
+    if (sdk != null) {
+      _result.sdk = sdk;
+    }
+    return _result;
+  }
+  factory RunCodeRequest.fromBuffer($core.List<$core.int> i, 
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => 
create()..mergeFromBuffer(i, r);
+  factory RunCodeRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = 
$pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  RunCodeRequest clone() => RunCodeRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  RunCodeRequest copyWith(void Function(RunCodeRequest) updates) => 
super.copyWith((message) => updates(message as RunCodeRequest)) as 
RunCodeRequest; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static RunCodeRequest create() => RunCodeRequest._();
+  RunCodeRequest createEmptyInstance() => create();
+  static $pb.PbList<RunCodeRequest> createRepeated() => 
$pb.PbList<RunCodeRequest>();
+  @$core.pragma('dart2js:noInline')
+  static RunCodeRequest getDefault() => _defaultInstance ??= 
$pb.GeneratedMessage.$_defaultFor<RunCodeRequest>(create);
+  static RunCodeRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get code => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set code($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasCode() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearCode() => clearField(1);
+
+  @$pb.TagNumber(2)
+  Sdk get sdk => $_getN(1);
+  @$pb.TagNumber(2)
+  set sdk(Sdk v) { setField(2, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasSdk() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearSdk() => clearField(2);
+}
+
+class RunCodeResponse extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 
'RunCodeResponse', package: const $pb.PackageName(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'api.v1'), 
createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? 
'' : 'pipelineUuid')
+    ..hasRequiredFields = false
+  ;
+
+  RunCodeResponse._() : super();
+  factory RunCodeResponse({
+    $core.String? pipelineUuid,
+  }) {
+    final _result = create();
+    if (pipelineUuid != null) {
+      _result.pipelineUuid = pipelineUuid;
+    }
+    return _result;
+  }
+  factory RunCodeResponse.fromBuffer($core.List<$core.int> i, 
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => 
create()..mergeFromBuffer(i, r);
+  factory RunCodeResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = 
$pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  RunCodeResponse clone() => RunCodeResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  RunCodeResponse copyWith(void Function(RunCodeResponse) updates) => 
super.copyWith((message) => updates(message as RunCodeResponse)) as 
RunCodeResponse; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static RunCodeResponse create() => RunCodeResponse._();
+  RunCodeResponse createEmptyInstance() => create();
+  static $pb.PbList<RunCodeResponse> createRepeated() => 
$pb.PbList<RunCodeResponse>();
+  @$core.pragma('dart2js:noInline')
+  static RunCodeResponse getDefault() => _defaultInstance ??= 
$pb.GeneratedMessage.$_defaultFor<RunCodeResponse>(create);
+  static RunCodeResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get pipelineUuid => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set pipelineUuid($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPipelineUuid() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPipelineUuid() => clearField(1);
+}
+
+class CheckStatusRequest extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 
'CheckStatusRequest', package: const $pb.PackageName(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'api.v1'), 
createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? 
'' : 'pipelineUuid')
+    ..hasRequiredFields = false
+  ;
+
+  CheckStatusRequest._() : super();
+  factory CheckStatusRequest({
+    $core.String? pipelineUuid,
+  }) {
+    final _result = create();
+    if (pipelineUuid != null) {
+      _result.pipelineUuid = pipelineUuid;
+    }
+    return _result;
+  }
+  factory CheckStatusRequest.fromBuffer($core.List<$core.int> i, 
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => 
create()..mergeFromBuffer(i, r);
+  factory CheckStatusRequest.fromJson($core.String i, [$pb.ExtensionRegistry r 
= $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  CheckStatusRequest clone() => CheckStatusRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  CheckStatusRequest copyWith(void Function(CheckStatusRequest) updates) => 
super.copyWith((message) => updates(message as CheckStatusRequest)) as 
CheckStatusRequest; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static CheckStatusRequest create() => CheckStatusRequest._();
+  CheckStatusRequest createEmptyInstance() => create();
+  static $pb.PbList<CheckStatusRequest> createRepeated() => 
$pb.PbList<CheckStatusRequest>();
+  @$core.pragma('dart2js:noInline')
+  static CheckStatusRequest getDefault() => _defaultInstance ??= 
$pb.GeneratedMessage.$_defaultFor<CheckStatusRequest>(create);
+  static CheckStatusRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get pipelineUuid => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set pipelineUuid($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPipelineUuid() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPipelineUuid() => clearField(1);
+}
+
+class CheckStatusResponse extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 
'CheckStatusResponse', package: const $pb.PackageName(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'api.v1'), 
createEmptyInstance: create)
+    ..e<Status>(1, const 
$core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'status', 
$pb.PbFieldType.OE, defaultOrMaker: Status.STATUS_UNSPECIFIED, valueOf: 
Status.valueOf, enumValues: Status.values)
+    ..hasRequiredFields = false
+  ;
+
+  CheckStatusResponse._() : super();
+  factory CheckStatusResponse({
+    Status? status,
+  }) {
+    final _result = create();
+    if (status != null) {
+      _result.status = status;
+    }
+    return _result;
+  }
+  factory CheckStatusResponse.fromBuffer($core.List<$core.int> i, 
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => 
create()..mergeFromBuffer(i, r);
+  factory CheckStatusResponse.fromJson($core.String i, [$pb.ExtensionRegistry 
r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  CheckStatusResponse clone() => CheckStatusResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  CheckStatusResponse copyWith(void Function(CheckStatusResponse) updates) => 
super.copyWith((message) => updates(message as CheckStatusResponse)) as 
CheckStatusResponse; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static CheckStatusResponse create() => CheckStatusResponse._();
+  CheckStatusResponse createEmptyInstance() => create();
+  static $pb.PbList<CheckStatusResponse> createRepeated() => 
$pb.PbList<CheckStatusResponse>();
+  @$core.pragma('dart2js:noInline')
+  static CheckStatusResponse getDefault() => _defaultInstance ??= 
$pb.GeneratedMessage.$_defaultFor<CheckStatusResponse>(create);
+  static CheckStatusResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  Status get status => $_getN(0);
+  @$pb.TagNumber(1)
+  set status(Status v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasStatus() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearStatus() => clearField(1);
+}
+
+class GetCompileOutputRequest extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 
'GetCompileOutputRequest', package: const $pb.PackageName(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'api.v1'), 
createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? 
'' : 'pipelineUuid')
+    ..hasRequiredFields = false
+  ;
+
+  GetCompileOutputRequest._() : super();
+  factory GetCompileOutputRequest({
+    $core.String? pipelineUuid,
+  }) {
+    final _result = create();
+    if (pipelineUuid != null) {
+      _result.pipelineUuid = pipelineUuid;
+    }
+    return _result;
+  }
+  factory GetCompileOutputRequest.fromBuffer($core.List<$core.int> i, 
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => 
create()..mergeFromBuffer(i, r);
+  factory GetCompileOutputRequest.fromJson($core.String i, 
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => 
create()..mergeFromJson(i, r);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetCompileOutputRequest clone() => 
GetCompileOutputRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetCompileOutputRequest copyWith(void Function(GetCompileOutputRequest) 
updates) => super.copyWith((message) => updates(message as 
GetCompileOutputRequest)) as GetCompileOutputRequest; // ignore: 
deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static GetCompileOutputRequest create() => GetCompileOutputRequest._();
+  GetCompileOutputRequest createEmptyInstance() => create();
+  static $pb.PbList<GetCompileOutputRequest> createRepeated() => 
$pb.PbList<GetCompileOutputRequest>();
+  @$core.pragma('dart2js:noInline')
+  static GetCompileOutputRequest getDefault() => _defaultInstance ??= 
$pb.GeneratedMessage.$_defaultFor<GetCompileOutputRequest>(create);
+  static GetCompileOutputRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get pipelineUuid => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set pipelineUuid($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPipelineUuid() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPipelineUuid() => clearField(1);
+}
+
+class GetCompileOutputResponse extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 
'GetCompileOutputResponse', package: const $pb.PackageName(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'api.v1'), 
createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? 
'' : 'output')
+    ..e<Status>(2, const 
$core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 
'compilationStatus', $pb.PbFieldType.OE, defaultOrMaker: 
Status.STATUS_UNSPECIFIED, valueOf: Status.valueOf, enumValues: Status.values)
+    ..hasRequiredFields = false
+  ;
+
+  GetCompileOutputResponse._() : super();
+  factory GetCompileOutputResponse({
+    $core.String? output,
+    Status? compilationStatus,
+  }) {
+    final _result = create();
+    if (output != null) {
+      _result.output = output;
+    }
+    if (compilationStatus != null) {
+      _result.compilationStatus = compilationStatus;
+    }
+    return _result;
+  }
+  factory GetCompileOutputResponse.fromBuffer($core.List<$core.int> i, 
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => 
create()..mergeFromBuffer(i, r);
+  factory GetCompileOutputResponse.fromJson($core.String i, 
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => 
create()..mergeFromJson(i, r);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetCompileOutputResponse clone() => 
GetCompileOutputResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetCompileOutputResponse copyWith(void Function(GetCompileOutputResponse) 
updates) => super.copyWith((message) => updates(message as 
GetCompileOutputResponse)) as GetCompileOutputResponse; // ignore: 
deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static GetCompileOutputResponse create() => GetCompileOutputResponse._();
+  GetCompileOutputResponse createEmptyInstance() => create();
+  static $pb.PbList<GetCompileOutputResponse> createRepeated() => 
$pb.PbList<GetCompileOutputResponse>();
+  @$core.pragma('dart2js:noInline')
+  static GetCompileOutputResponse getDefault() => _defaultInstance ??= 
$pb.GeneratedMessage.$_defaultFor<GetCompileOutputResponse>(create);
+  static GetCompileOutputResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get output => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set output($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasOutput() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearOutput() => clearField(1);
+
+  @$pb.TagNumber(2)
+  Status get compilationStatus => $_getN(1);
+  @$pb.TagNumber(2)
+  set compilationStatus(Status v) { setField(2, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasCompilationStatus() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearCompilationStatus() => clearField(2);
+}
+
+class GetRunOutputRequest extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 
'GetRunOutputRequest', package: const $pb.PackageName(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'api.v1'), 
createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? 
'' : 'pipelineUuid')
+    ..hasRequiredFields = false
+  ;
+
+  GetRunOutputRequest._() : super();
+  factory GetRunOutputRequest({
+    $core.String? pipelineUuid,
+  }) {
+    final _result = create();
+    if (pipelineUuid != null) {
+      _result.pipelineUuid = pipelineUuid;
+    }
+    return _result;
+  }
+  factory GetRunOutputRequest.fromBuffer($core.List<$core.int> i, 
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => 
create()..mergeFromBuffer(i, r);
+  factory GetRunOutputRequest.fromJson($core.String i, [$pb.ExtensionRegistry 
r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetRunOutputRequest clone() => GetRunOutputRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetRunOutputRequest copyWith(void Function(GetRunOutputRequest) updates) => 
super.copyWith((message) => updates(message as GetRunOutputRequest)) as 
GetRunOutputRequest; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static GetRunOutputRequest create() => GetRunOutputRequest._();
+  GetRunOutputRequest createEmptyInstance() => create();
+  static $pb.PbList<GetRunOutputRequest> createRepeated() => 
$pb.PbList<GetRunOutputRequest>();
+  @$core.pragma('dart2js:noInline')
+  static GetRunOutputRequest getDefault() => _defaultInstance ??= 
$pb.GeneratedMessage.$_defaultFor<GetRunOutputRequest>(create);
+  static GetRunOutputRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get pipelineUuid => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set pipelineUuid($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPipelineUuid() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPipelineUuid() => clearField(1);
+}
+
+class GetRunOutputResponse extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 
'GetRunOutputResponse', package: const $pb.PackageName(const 
$core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'api.v1'), 
createEmptyInstance: create)
+    ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? 
'' : 'output')
+    ..e<Status>(2, const 
$core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 
'compilationStatus', $pb.PbFieldType.OE, defaultOrMaker: 
Status.STATUS_UNSPECIFIED, valueOf: Status.valueOf, enumValues: Status.values)
+    ..hasRequiredFields = false
+  ;
+
+  GetRunOutputResponse._() : super();
+  factory GetRunOutputResponse({
+    $core.String? output,
+    Status? compilationStatus,
+  }) {
+    final _result = create();
+    if (output != null) {
+      _result.output = output;
+    }
+    if (compilationStatus != null) {
+      _result.compilationStatus = compilationStatus;
+    }
+    return _result;
+  }
+  factory GetRunOutputResponse.fromBuffer($core.List<$core.int> i, 
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => 
create()..mergeFromBuffer(i, r);
+  factory GetRunOutputResponse.fromJson($core.String i, [$pb.ExtensionRegistry 
r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetRunOutputResponse clone() => 
GetRunOutputResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetRunOutputResponse copyWith(void Function(GetRunOutputResponse) updates) 
=> super.copyWith((message) => updates(message as GetRunOutputResponse)) as 
GetRunOutputResponse; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static GetRunOutputResponse create() => GetRunOutputResponse._();
+  GetRunOutputResponse createEmptyInstance() => create();
+  static $pb.PbList<GetRunOutputResponse> createRepeated() => 
$pb.PbList<GetRunOutputResponse>();
+  @$core.pragma('dart2js:noInline')
+  static GetRunOutputResponse getDefault() => _defaultInstance ??= 
$pb.GeneratedMessage.$_defaultFor<GetRunOutputResponse>(create);
+  static GetRunOutputResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get output => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set output($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasOutput() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearOutput() => clearField(1);
+
+  @$pb.TagNumber(2)
+  Status get compilationStatus => $_getN(1);
+  @$pb.TagNumber(2)
+  set compilationStatus(Status v) { setField(2, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasCompilationStatus() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearCompilationStatus() => clearField(2);
+}
+
diff --git a/playground/frontend/lib/api/v1/api.pbenum.dart 
b/playground/frontend/lib/api/v1/api.pbenum.dart
new file mode 100644
index 0000000..e1cf849
--- /dev/null
+++ b/playground/frontend/lib/api/v1/api.pbenum.dart
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///
+//  Generated code. Do not modify.
+//  source: api/v1/api.proto
+//
+// @dart = 2.12
+// ignore_for_file: 
annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
+
+// ignore_for_file: UNDEFINED_SHOWN_NAME
+import 'dart:core' as $core;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+class Sdk extends $pb.ProtobufEnum {
+  static const Sdk SDK_UNSPECIFIED = Sdk._(0, const 
$core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 
'SDK_UNSPECIFIED');
+  static const Sdk SDK_JAVA = Sdk._(1, const 
$core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SDK_JAVA');
+  static const Sdk SDK_GO = Sdk._(2, const 
$core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SDK_GO');
+  static const Sdk SDK_PYTHON = Sdk._(3, const 
$core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SDK_PYTHON');
+  static const Sdk SDK_SCIO = Sdk._(4, const 
$core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SDK_SCIO');
+
+  static const $core.List<Sdk> values = <Sdk> [
+    SDK_UNSPECIFIED,
+    SDK_JAVA,
+    SDK_GO,
+    SDK_PYTHON,
+    SDK_SCIO,
+  ];
+
+  static final $core.Map<$core.int, Sdk> _byValue = 
$pb.ProtobufEnum.initByValue(values);
+  static Sdk? valueOf($core.int value) => _byValue[value];
+
+  const Sdk._($core.int v, $core.String n) : super(v, n);
+}
+
+class Status extends $pb.ProtobufEnum {
+  static const Status STATUS_UNSPECIFIED = Status._(0, const 
$core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 
'STATUS_UNSPECIFIED');
+  static const Status STATUS_EXECUTING = Status._(1, const 
$core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 
'STATUS_EXECUTING');
+  static const Status STATUS_FINISHED = Status._(2, const 
$core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 
'STATUS_FINISHED');
+  static const Status STATUS_ERROR = Status._(3, const 
$core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'STATUS_ERROR');
+
+  static const $core.List<Status> values = <Status> [
+    STATUS_UNSPECIFIED,
+    STATUS_EXECUTING,
+    STATUS_FINISHED,
+    STATUS_ERROR,
+  ];
+
+  static final $core.Map<$core.int, Status> _byValue = 
$pb.ProtobufEnum.initByValue(values);
+  static Status? valueOf($core.int value) => _byValue[value];
+
+  const Status._($core.int v, $core.String n) : super(v, n);
+}
+
diff --git a/playground/frontend/lib/api/v1/api.pbgrpc.dart 
b/playground/frontend/lib/api/v1/api.pbgrpc.dart
new file mode 100644
index 0000000..3cfd258
--- /dev/null
+++ b/playground/frontend/lib/api/v1/api.pbgrpc.dart
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///
+//  Generated code. Do not modify.
+//  source: api/v1/api.proto
+//
+// @dart = 2.12
+// ignore_for_file: 
annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
+
+import 'dart:async' as $async;
+
+import 'dart:core' as $core;
+
+import 'package:grpc/service_api.dart' as $grpc;
+import 'api.pb.dart' as $0;
+export 'api.pb.dart';
+
+class PlaygroundServiceClient extends $grpc.Client {
+  static final _$runCode =
+      $grpc.ClientMethod<$0.RunCodeRequest, $0.RunCodeResponse>(
+          '/api.v1.PlaygroundService/RunCode',
+          ($0.RunCodeRequest value) => value.writeToBuffer(),
+          ($core.List<$core.int> value) =>
+              $0.RunCodeResponse.fromBuffer(value));
+  static final _$checkStatus =
+      $grpc.ClientMethod<$0.CheckStatusRequest, $0.CheckStatusResponse>(
+          '/api.v1.PlaygroundService/CheckStatus',
+          ($0.CheckStatusRequest value) => value.writeToBuffer(),
+          ($core.List<$core.int> value) =>
+              $0.CheckStatusResponse.fromBuffer(value));
+  static final _$getRunOutput =
+      $grpc.ClientMethod<$0.GetRunOutputRequest, $0.GetRunOutputResponse>(
+          '/api.v1.PlaygroundService/GetRunOutput',
+          ($0.GetRunOutputRequest value) => value.writeToBuffer(),
+          ($core.List<$core.int> value) =>
+              $0.GetRunOutputResponse.fromBuffer(value));
+  static final _$getCompileOutput = $grpc.ClientMethod<
+          $0.GetCompileOutputRequest, $0.GetCompileOutputResponse>(
+      '/api.v1.PlaygroundService/GetCompileOutput',
+      ($0.GetCompileOutputRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) =>
+          $0.GetCompileOutputResponse.fromBuffer(value));
+
+  PlaygroundServiceClient($grpc.ClientChannel channel,
+      {$grpc.CallOptions? options,
+      $core.Iterable<$grpc.ClientInterceptor>? interceptors})
+      : super(channel, options: options, interceptors: interceptors);
+
+  $grpc.ResponseFuture<$0.RunCodeResponse> runCode($0.RunCodeRequest request,
+      {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$runCode, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.CheckStatusResponse> checkStatus(
+      $0.CheckStatusRequest request,
+      {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$checkStatus, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.GetRunOutputResponse> getRunOutput(
+      $0.GetRunOutputRequest request,
+      {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$getRunOutput, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$0.GetCompileOutputResponse> getCompileOutput(
+      $0.GetCompileOutputRequest request,
+      {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$getCompileOutput, request, options: options);
+  }
+}
+
+abstract class PlaygroundServiceBase extends $grpc.Service {
+  $core.String get $name => 'api.v1.PlaygroundService';
+
+  PlaygroundServiceBase() {
+    $addMethod($grpc.ServiceMethod<$0.RunCodeRequest, $0.RunCodeResponse>(
+        'RunCode',
+        runCode_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.RunCodeRequest.fromBuffer(value),
+        ($0.RunCodeResponse value) => value.writeToBuffer()));
+    $addMethod(
+        $grpc.ServiceMethod<$0.CheckStatusRequest, $0.CheckStatusResponse>(
+            'CheckStatus',
+            checkStatus_Pre,
+            false,
+            false,
+            ($core.List<$core.int> value) =>
+                $0.CheckStatusRequest.fromBuffer(value),
+            ($0.CheckStatusResponse value) => value.writeToBuffer()));
+    $addMethod(
+        $grpc.ServiceMethod<$0.GetRunOutputRequest, $0.GetRunOutputResponse>(
+            'GetRunOutput',
+            getRunOutput_Pre,
+            false,
+            false,
+            ($core.List<$core.int> value) =>
+                $0.GetRunOutputRequest.fromBuffer(value),
+            ($0.GetRunOutputResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$0.GetCompileOutputRequest,
+            $0.GetCompileOutputResponse>(
+        'GetCompileOutput',
+        getCompileOutput_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) =>
+            $0.GetCompileOutputRequest.fromBuffer(value),
+        ($0.GetCompileOutputResponse value) => value.writeToBuffer()));
+  }
+
+  $async.Future<$0.RunCodeResponse> runCode_Pre(
+      $grpc.ServiceCall call, $async.Future<$0.RunCodeRequest> request) async {
+    return runCode(call, await request);
+  }
+
+  $async.Future<$0.CheckStatusResponse> checkStatus_Pre($grpc.ServiceCall call,
+      $async.Future<$0.CheckStatusRequest> request) async {
+    return checkStatus(call, await request);
+  }
+
+  $async.Future<$0.GetRunOutputResponse> getRunOutput_Pre(
+      $grpc.ServiceCall call,
+      $async.Future<$0.GetRunOutputRequest> request) async {
+    return getRunOutput(call, await request);
+  }
+
+  $async.Future<$0.GetCompileOutputResponse> getCompileOutput_Pre(
+      $grpc.ServiceCall call,
+      $async.Future<$0.GetCompileOutputRequest> request) async {
+    return getCompileOutput(call, await request);
+  }
+
+  $async.Future<$0.RunCodeResponse> runCode(
+      $grpc.ServiceCall call, $0.RunCodeRequest request);
+  $async.Future<$0.CheckStatusResponse> checkStatus(
+      $grpc.ServiceCall call, $0.CheckStatusRequest request);
+  $async.Future<$0.GetRunOutputResponse> getRunOutput(
+      $grpc.ServiceCall call, $0.GetRunOutputRequest request);
+  $async.Future<$0.GetCompileOutputResponse> getCompileOutput(
+      $grpc.ServiceCall call, $0.GetCompileOutputRequest request);
+}
diff --git a/playground/frontend/lib/api/v1/api.pbjson.dart 
b/playground/frontend/lib/api/v1/api.pbjson.dart
new file mode 100644
index 0000000..4b29e56
--- /dev/null
+++ b/playground/frontend/lib/api/v1/api.pbjson.dart
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///
+//  Generated code. Do not modify.
+//  source: api/v1/api.proto
+//
+// @dart = 2.12
+// ignore_for_file: 
annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package
+
+import 'dart:core' as $core;
+import 'dart:convert' as $convert;
+import 'dart:typed_data' as $typed_data;
+@$core.Deprecated('Use sdkDescriptor instead')
+const Sdk$json = const {
+  '1': 'Sdk',
+  '2': const [
+    const {'1': 'SDK_UNSPECIFIED', '2': 0},
+    const {'1': 'SDK_JAVA', '2': 1},
+    const {'1': 'SDK_GO', '2': 2},
+    const {'1': 'SDK_PYTHON', '2': 3},
+    const {'1': 'SDK_SCIO', '2': 4},
+  ],
+};
+
+/// Descriptor for `Sdk`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List sdkDescriptor = 
$convert.base64Decode('CgNTZGsSEwoPU0RLX1VOU1BFQ0lGSUVEEAASDAoIU0RLX0pBVkEQARIKCgZTREtfR08QAhIOCgpTREtfUFlUSE9OEAMSDAoIU0RLX1NDSU8QBA==');
+@$core.Deprecated('Use statusDescriptor instead')
+const Status$json = const {
+  '1': 'Status',
+  '2': const [
+    const {'1': 'STATUS_UNSPECIFIED', '2': 0},
+    const {'1': 'STATUS_EXECUTING', '2': 1},
+    const {'1': 'STATUS_FINISHED', '2': 2},
+    const {'1': 'STATUS_ERROR', '2': 3},
+  ],
+};
+
+/// Descriptor for `Status`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List statusDescriptor = 
$convert.base64Decode('CgZTdGF0dXMSFgoSU1RBVFVTX1VOU1BFQ0lGSUVEEAASFAoQU1RBVFVTX0VYRUNVVElORxABEhMKD1NUQVRVU19GSU5JU0hFRBACEhAKDFNUQVRVU19FUlJPUhAD');
+@$core.Deprecated('Use runCodeRequestDescriptor instead')
+const RunCodeRequest$json = const {
+  '1': 'RunCodeRequest',
+  '2': const [
+    const {'1': 'code', '3': 1, '4': 1, '5': 9, '10': 'code'},
+    const {'1': 'sdk', '3': 2, '4': 1, '5': 14, '6': '.api.v1.Sdk', '10': 
'sdk'},
+  ],
+};
+
+/// Descriptor for `RunCodeRequest`. Decode as a 
`google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List runCodeRequestDescriptor = 
$convert.base64Decode('Cg5SdW5Db2RlUmVxdWVzdBISCgRjb2RlGAEgASgJUgRjb2RlEh0KA3NkaxgCIAEoDjILLmFwaS52MS5TZGtSA3Nkaw==');
+@$core.Deprecated('Use runCodeResponseDescriptor instead')
+const RunCodeResponse$json = const {
+  '1': 'RunCodeResponse',
+  '2': const [
+    const {'1': 'pipeline_uuid', '3': 1, '4': 1, '5': 9, '10': 'pipelineUuid'},
+  ],
+};
+
+/// Descriptor for `RunCodeResponse`. Decode as a 
`google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List runCodeResponseDescriptor = 
$convert.base64Decode('Cg9SdW5Db2RlUmVzcG9uc2USIwoNcGlwZWxpbmVfdXVpZBgBIAEoCVIMcGlwZWxpbmVVdWlk');
+@$core.Deprecated('Use checkStatusRequestDescriptor instead')
+const CheckStatusRequest$json = const {
+  '1': 'CheckStatusRequest',
+  '2': const [
+    const {'1': 'pipeline_uuid', '3': 1, '4': 1, '5': 9, '10': 'pipelineUuid'},
+  ],
+};
+
+/// Descriptor for `CheckStatusRequest`. Decode as a 
`google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List checkStatusRequestDescriptor = 
$convert.base64Decode('ChJDaGVja1N0YXR1c1JlcXVlc3QSIwoNcGlwZWxpbmVfdXVpZBgBIAEoCVIMcGlwZWxpbmVVdWlk');
+@$core.Deprecated('Use checkStatusResponseDescriptor instead')
+const CheckStatusResponse$json = const {
+  '1': 'CheckStatusResponse',
+  '2': const [
+    const {'1': 'status', '3': 1, '4': 1, '5': 14, '6': '.api.v1.Status', 
'10': 'status'},
+  ],
+};
+
+/// Descriptor for `CheckStatusResponse`. Decode as a 
`google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List checkStatusResponseDescriptor = 
$convert.base64Decode('ChNDaGVja1N0YXR1c1Jlc3BvbnNlEiYKBnN0YXR1cxgBIAEoDjIOLmFwaS52MS5TdGF0dXNSBnN0YXR1cw==');
+@$core.Deprecated('Use getCompileOutputRequestDescriptor instead')
+const GetCompileOutputRequest$json = const {
+  '1': 'GetCompileOutputRequest',
+  '2': const [
+    const {'1': 'pipeline_uuid', '3': 1, '4': 1, '5': 9, '10': 'pipelineUuid'},
+  ],
+};
+
+/// Descriptor for `GetCompileOutputRequest`. Decode as a 
`google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getCompileOutputRequestDescriptor = 
$convert.base64Decode('ChdHZXRDb21waWxlT3V0cHV0UmVxdWVzdBIjCg1waXBlbGluZV91dWlkGAEgASgJUgxwaXBlbGluZVV1aWQ=');
+@$core.Deprecated('Use getCompileOutputResponseDescriptor instead')
+const GetCompileOutputResponse$json = const {
+  '1': 'GetCompileOutputResponse',
+  '2': const [
+    const {'1': 'output', '3': 1, '4': 1, '5': 9, '10': 'output'},
+    const {'1': 'compilation_status', '3': 2, '4': 1, '5': 14, '6': 
'.api.v1.Status', '10': 'compilationStatus'},
+  ],
+};
+
+/// Descriptor for `GetCompileOutputResponse`. Decode as a 
`google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getCompileOutputResponseDescriptor = 
$convert.base64Decode('ChhHZXRDb21waWxlT3V0cHV0UmVzcG9uc2USFgoGb3V0cHV0GAEgASgJUgZvdXRwdXQSPQoSY29tcGlsYXRpb25fc3RhdHVzGAIgASgOMg4uYXBpLnYxLlN0YXR1c1IRY29tcGlsYXRpb25TdGF0dXM=');
+@$core.Deprecated('Use getRunOutputRequestDescriptor instead')
+const GetRunOutputRequest$json = const {
+  '1': 'GetRunOutputRequest',
+  '2': const [
+    const {'1': 'pipeline_uuid', '3': 1, '4': 1, '5': 9, '10': 'pipelineUuid'},
+  ],
+};
+
+/// Descriptor for `GetRunOutputRequest`. Decode as a 
`google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getRunOutputRequestDescriptor = 
$convert.base64Decode('ChNHZXRSdW5PdXRwdXRSZXF1ZXN0EiMKDXBpcGVsaW5lX3V1aWQYASABKAlSDHBpcGVsaW5lVXVpZA==');
+@$core.Deprecated('Use getRunOutputResponseDescriptor instead')
+const GetRunOutputResponse$json = const {
+  '1': 'GetRunOutputResponse',
+  '2': const [
+    const {'1': 'output', '3': 1, '4': 1, '5': 9, '10': 'output'},
+    const {'1': 'compilation_status', '3': 2, '4': 1, '5': 14, '6': 
'.api.v1.Status', '10': 'compilationStatus'},
+  ],
+};
+
+/// Descriptor for `GetRunOutputResponse`. Decode as a 
`google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getRunOutputResponseDescriptor = 
$convert.base64Decode('ChRHZXRSdW5PdXRwdXRSZXNwb25zZRIWCgZvdXRwdXQYASABKAlSBm91dHB1dBI9ChJjb21waWxhdGlvbl9zdGF0dXMYAiABKA4yDi5hcGkudjEuU3RhdHVzUhFjb21waWxhdGlvblN0YXR1cw==');
diff --git 
a/playground/frontend/lib/modules/editor/repository/code_repository/code_client/grpc_code_client.dart
 
b/playground/frontend/lib/modules/editor/repository/code_repository/code_client/grpc_code_client.dart
index 5173542..93ee0ef 100644
--- 
a/playground/frontend/lib/modules/editor/repository/code_repository/code_client/grpc_code_client.dart
+++ 
b/playground/frontend/lib/modules/editor/repository/code_repository/code_client/grpc_code_client.dart
@@ -18,7 +18,7 @@
 
 import 'package:grpc/grpc_web.dart';
 import 'package:playground/constants/api.dart';
-import 'package:playground/generated/playground.pbgrpc.dart' as grpc;
+import 'package:playground/api/v1/api.pbgrpc.dart' as grpc;
 import 
'package:playground/modules/editor/repository/code_repository/code_client/check_status_response.dart';
 import 
'package:playground/modules/editor/repository/code_repository/code_client/code_client.dart';
 import 
'package:playground/modules/editor/repository/code_repository/code_client/output_response.dart';
diff --git 
a/playground/frontend/test/modules/editor/repository/code_repository/code_repository_test.mocks.dart
 
b/playground/frontend/test/modules/editor/repository/code_repository/code_repository_test.mocks.dart
new file mode 100644
index 0000000..11c8517
--- /dev/null
+++ 
b/playground/frontend/test/modules/editor/repository/code_repository/code_repository_test.mocks.dart
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Mocks generated by Mockito 5.0.16 from annotations
+// in 
playground/test/modules/editor/repository/code_repository/code_repository_test.dart.
+// Do not manually edit this file.
+
+import 'dart:async' as _i6;
+
+import 'package:mockito/mockito.dart' as _i1;
+import 
'package:playground/modules/editor/repository/code_repository/code_client/check_status_response.dart'
+    as _i3;
+import 
'package:playground/modules/editor/repository/code_repository/code_client/code_client.dart'
+    as _i5;
+import 
'package:playground/modules/editor/repository/code_repository/code_client/output_response.dart'
+    as _i4;
+import 
'package:playground/modules/editor/repository/code_repository/code_client/run_code_response.dart'
+    as _i2;
+import 
'package:playground/modules/editor/repository/code_repository/run_code_request.dart'
+    as _i7;
+
+// ignore_for_file: avoid_redundant_argument_values
+// ignore_for_file: avoid_setters_without_getters
+// ignore_for_file: comment_references
+// ignore_for_file: implementation_imports
+// ignore_for_file: invalid_use_of_visible_for_testing_member
+// ignore_for_file: prefer_const_constructors
+// ignore_for_file: unnecessary_parenthesis
+// ignore_for_file: camel_case_types
+
+class _FakeRunCodeResponse_0 extends _i1.Fake implements _i2.RunCodeResponse {}
+
+class _FakeCheckStatusResponse_1 extends _i1.Fake
+    implements _i3.CheckStatusResponse {}
+
+class _FakeOutputResponse_2 extends _i1.Fake implements _i4.OutputResponse {}
+
+/// A class which mocks [CodeClient].
+///
+/// See the documentation for Mockito's code generation for more information.
+class MockCodeClient extends _i1.Mock implements _i5.CodeClient {
+  MockCodeClient() {
+    _i1.throwOnMissingStub(this);
+  }
+
+  @override
+  _i6.Future<_i2.RunCodeResponse> runCode(_i7.RunCodeRequestWrapper? request) 
=>
+      (super.noSuchMethod(Invocation.method(#runCode, [request]),
+              returnValue:
+                  Future<_i2.RunCodeResponse>.value(_FakeRunCodeResponse_0()))
+          as _i6.Future<_i2.RunCodeResponse>);
+  @override
+  _i6.Future<_i3.CheckStatusResponse> checkStatus(String? pipelineUuid) =>
+      (super.noSuchMethod(Invocation.method(#checkStatus, [pipelineUuid]),
+              returnValue: Future<_i3.CheckStatusResponse>.value(
+                  _FakeCheckStatusResponse_1()))
+          as _i6.Future<_i3.CheckStatusResponse>);
+  @override
+  _i6.Future<_i4.OutputResponse> getCompileOutput(String? pipelineUuid) =>
+      (super.noSuchMethod(Invocation.method(#getCompileOutput, [pipelineUuid]),
+              returnValue:
+                  Future<_i4.OutputResponse>.value(_FakeOutputResponse_2()))
+          as _i6.Future<_i4.OutputResponse>);
+  @override
+  _i6.Future<_i4.OutputResponse> getRunOutput(String? pipelineUuid) =>
+      (super.noSuchMethod(Invocation.method(#getRunOutput, [pipelineUuid]),
+              returnValue:
+                  Future<_i4.OutputResponse>.value(_FakeOutputResponse_2()))
+          as _i6.Future<_i4.OutputResponse>);
+  @override
+  String toString() => super.toString();
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index d9d4593..4c74386 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -56,6 +56,9 @@ include(":examples:kotlin")
 include(":model:fn-execution")
 include(":model:job-management")
 include(":model:pipeline")
+include(":playground")
+include(":playground:backend")
+include(":playground:frontend")
 include(":runners:core-construction-java")
 include(":runners:core-java")
 include(":runners:direct-java")

Reply via email to