Memebrships: Refactor Store interface

Use unified memberships table.
Add few internal API endpoints.

Change-Id: I80ac5a0f5c262e04d7898cca571b938a35d68d39
diff --git a/core/installer/app_configs/app_global_env.cue b/core/installer/app_configs/app_global_env.cue
index 6b0c1ec..0bd3c8f 100644
--- a/core/installer/app_configs/app_global_env.cue
+++ b/core/installer/app_configs/app_global_env.cue
@@ -124,7 +124,7 @@
 					upstream:       "\(service.name).\(release.namespace).svc.cluster.local:\(service.port)"
 					whoAmIAddr:     "https://accounts.\(g.domain)/sessions/whoami"
 					loginAddr:      "https://accounts-ui.\(g.domain)/login"
-					membershipAddr: "http://memberships-api.\(g.namespacePrefix)core-auth-memberships.svc.cluster.local/api/user"
+					membershipAddr: "http://memberships-api.\(g.namespacePrefix)core-auth-memberships.svc.cluster.local"
 					if g.privateDomain == "" {
 						membershipPublicAddr: "https://memberships.\(g.domain)"
 					}
diff --git a/core/installer/server/welcome/server.go b/core/installer/server/welcome/server.go
index 198f637..23f9e00 100644
--- a/core/installer/server/welcome/server.go
+++ b/core/installer/server/welcome/server.go
@@ -177,12 +177,17 @@
 	}
 }
 
+type identityCreateResp struct {
+	Id string `json:"id"`
+}
+
 func (s *Server) createAccount(w http.ResponseWriter, r *http.Request) {
 	req, err := extractReq(r)
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
+	var idResp identityCreateResp
 	{
 		var buf bytes.Buffer
 		cr := apiCreateAccountReq{req.Username, req.Password}
@@ -223,8 +228,12 @@
 			})
 			return
 		}
+		if err := json.NewDecoder(resp.Body).Decode(&idResp); err != nil {
+			http.Error(w, "Error Decoding JSON", http.StatusInternalServerError)
+			return
+		}
 	}
-	if err := s.createUser(req.Username); err != nil {
+	if err := s.createUser(idResp.Id, req.Username); err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
@@ -232,23 +241,29 @@
 }
 
 type firstAccount struct {
-	Created bool     `json:"created"`
-	Domain  string   `json:"domain"`
-	Groups  []string `json:"groups"`
+	Created bool    `json:"created"`
+	Domain  string  `json:"domain"`
+	Groups  []group `json:"groups"`
+}
+
+type user struct {
+	Id       string `json:"id"`
+	Username string `json:"username"`
+	Email    string `json:"email"`
+}
+
+type group struct {
+	Id          string `json:"id"`
+	Title       string `json:"title"`
+	Description string `json:"description"`
 }
 
 type initRequest struct {
-	User   string   `json:"user"`
-	Email  string   `json:"email"`
-	Groups []string `json:"groups"`
+	User   user    `json:"user"`
+	Groups []group `json:"groups"`
 }
 
-type createUserRequest struct {
-	User  string `json:"user"`
-	Email string `json:"email"`
-}
-
-func (s *Server) createUser(username string) error {
+func (s *Server) createUser(id, username string) error {
 	_, err := s.repo.Do(func(r soft.RepoFS) (string, error) {
 		var fa firstAccount
 		if err := soft.ReadYaml(r, "first-account.yaml", &fa); err != nil {
@@ -256,10 +271,14 @@
 		}
 		var resp *http.Response
 		var err error
+		u := user{
+			id,
+			username,
+			fmt.Sprintf("%s@%s", username, fa.Domain),
+		}
 		if fa.Created {
-			req := createUserRequest{username, fmt.Sprintf("%s@%s", username, fa.Domain)}
 			var buf bytes.Buffer
-			if err := json.NewEncoder(&buf).Encode(req); err != nil {
+			if err := json.NewEncoder(&buf).Encode(u); err != nil {
 				return "", err
 			}
 			resp, err = http.Post(
@@ -268,7 +287,10 @@
 				&buf,
 			)
 		} else {
-			req := initRequest{username, fmt.Sprintf("%s@%s", username, fa.Domain), fa.Groups}
+			req := initRequest{
+				u,
+				fa.Groups,
+			}
 			var buf bytes.Buffer
 			if err := json.NewEncoder(&buf).Encode(req); err != nil {
 				return "", err
diff --git a/core/installer/tasks/infra.go b/core/installer/tasks/infra.go
index d69ba3a..907bba0 100644
--- a/core/installer/tasks/infra.go
+++ b/core/installer/tasks/infra.go
@@ -10,7 +10,19 @@
 	"github.com/giolekva/pcloud/core/installer/soft"
 )
 
-var initGroups = []string{"admin"}
+type group struct {
+	Id          string `json:"id"`
+	Title       string `json:"title"`
+	Description string `json:"description"`
+}
+
+var initGroups = []group{
+	group{
+		"admin",
+		"Admin",
+		"Administrators",
+	},
+}
 
 func CreateRepoClient(env installer.EnvConfig, st *state) Task {
 	t := newLeafTask("Create repo client", func() error {
@@ -77,9 +89,9 @@
 }
 
 type firstAccount struct {
-	Created bool     `json:"created"`
-	Domain  string   `json:"domain"`
-	Groups  []string `json:"groups"`
+	Created bool    `json:"created"`
+	Domain  string  `json:"domain"`
+	Groups  []group `json:"groups"`
 }
 
 func ConfigureFirstAccount(env installer.EnvConfig, st *state) Task {
@@ -407,11 +419,15 @@
 		if env.PrivateDomain != "" {
 			network = "Private"
 		}
+		var initGroupIds []string
+		for _, g := range initGroups {
+			initGroupIds = append(initGroupIds, g.Id)
+		}
 		if _, err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
 			"network":       network,
 			"repoAddr":      st.ssClient.GetRepoAddress("config"),
 			"sshPrivateKey": string(keys.RawPrivateKey()),
-			"authGroups":    strings.Join(initGroups, ","),
+			"authGroups":    strings.Join(initGroupIds, ","),
 		}); err != nil {
 			return err
 		}