feat(coderd/database): track user status changes over time (#16019)

RE: https://github.com/coder/coder/issues/15740,
https://github.com/coder/coder/issues/15297

In order to add a graph to the coder frontend to show user status over
time as an indicator of license usage, this PR adds the following:

* a new `api.insightsUserStatusCountsOverTime` endpoint to the API
* which calls a new `GetUserStatusCountsOverTime` query from postgres
* which relies on two new tables `user_status_changes` and
`user_deleted`
* which are populated by a new trigger and function that tracks updates
to the users table

The chart itself will be added in a subsequent PR

---------

Co-authored-by: Mathias Fredriksson <mafredri@gmail.com>
This commit is contained in:
Sas Swart
2025-01-13 13:08:16 +02:00
committed by GitHub
co-authored by Mathias Fredriksson
parent 73d8dde6ed
commit 4543b21b7c
25 changed files with 1456 additions and 3 deletions
+31
View File
@@ -282,3 +282,34 @@ func (c *Client) TemplateInsights(ctx context.Context, req TemplateInsightsReque
var result TemplateInsightsResponse
return result, json.NewDecoder(resp.Body).Decode(&result)
}
type GetUserStatusCountsResponse struct {
StatusCounts map[UserStatus][]UserStatusChangeCount `json:"status_counts"`
}
type UserStatusChangeCount struct {
Date time.Time `json:"date" format:"date-time"`
Count int64 `json:"count" example:"10"`
}
type GetUserStatusCountsRequest struct {
Offset time.Time `json:"offset" format:"date-time"`
}
func (c *Client) GetUserStatusCounts(ctx context.Context, req GetUserStatusCountsRequest) (GetUserStatusCountsResponse, error) {
qp := url.Values{}
qp.Add("offset", req.Offset.Format(insightsTimeLayout))
reqURL := fmt.Sprintf("/api/v2/insights/user-status-counts?%s", qp.Encode())
resp, err := c.Request(ctx, http.MethodGet, reqURL, nil)
if err != nil {
return GetUserStatusCountsResponse{}, xerrors.Errorf("make request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return GetUserStatusCountsResponse{}, ReadBodyAsError(resp)
}
var result GetUserStatusCountsResponse
return result, json.NewDecoder(resp.Body).Decode(&result)
}