feat(recommendations): collect demographics and advance age cohorts
ci / ts / ts (packages + web) (push) Successful in 3m19s
ci / db / db (push) Successful in 53s
ci / module boundaries / boundaries (push) Successful in 7s
ci / api / api (push) Successful in 51s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m3s
ci / recommender / recommender (push) Failing after 16s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m15s

This commit is contained in:
mrleo1nid committed 2026-10-22 14:19:52 +03:00
1 parent e158558da3
commit fff91c446b
24 files changed
+778 -324

No files matched your search

+27 -2
View File
@@ -29,6 +29,7 @@ import (
"github.com/redis/go-redis/v9"
"github.com/stretchr/testify/require"
"pipu/api/internal/api/gen"
"pipu/api/internal/library"
"pipu/api/internal/library/meta"
"pipu/api/internal/platform/config"
@@ -281,17 +282,41 @@ func TestUserJourney(t *testing.T) {
// 7½. Онбординг: варианты из библиотеки, выбор сохраняется, второй раз не предлагается.
var onb struct {
Required bool `json:"required"`
Choice *gen.OnboardingChoice `json:"choice"`
Required bool `json:"required"`
Artists []struct {
ID string `json:"id"`
} `json:"artists"`
}
c.ok("GET", "/api/v1/onboarding", nil, &onb)
require.NotEmpty(t, onb.Artists)
c.ok("PUT", "/api/v1/me/onboarding", map[string]any{"artist_ids": []string{onb.Artists[0].ID}, "genres": []string{}}, nil)
c.ok("PUT", "/api/v1/me/onboarding", map[string]any{"artist_ids": []string{onb.Artists[0].ID}, "genres": []string{}, "gender": "male", "age_group": "13_19", "age_group_year": 1900}, nil)
c.ok("GET", "/api/v1/onboarding", nil, &onb)
require.False(t, onb.Required)
require.NotNil(t, onb.Choice)
require.Equal(t, gen.Male, *onb.Choice.Gender)
require.Equal(t, gen.N1319, *onb.Choice.AgeGroup)
require.Greater(t, *onb.Choice.AgeGroupYear, 1900, "client cannot forge the selection year")
_, err = pool.Exec(ctx, `UPDATE user_profiles_rec SET onboarding = jsonb_set(onboarding,
'{age_group_year}', to_jsonb(EXTRACT(YEAR FROM CURRENT_DATE)::int - 20)) WHERE user_id = $1`, tokens.User.ID)
require.NoError(t, err)
c.ok("GET", "/api/v1/onboarding", nil, &onb)
require.Equal(t, gen.N3039, *onb.Choice.AgeGroup, "13–19 twenty years ago is approximately 30–39 now")
originalYear := *onb.Choice.AgeGroupYear
c.ok("PUT", "/api/v1/me/onboarding", onb.Choice, nil)
c.ok("GET", "/api/v1/onboarding", nil, &onb)
require.Equal(t, originalYear, *onb.Choice.AgeGroupYear, "editing tastes preserves the age anchor")
require.Equal(t, gen.N3039, *onb.Choice.AgeGroup)
c.ok("POST", "/api/v1/admin/users/"+tokens.User.ID+"/reset-recommendations", nil, nil)
onb.Choice = nil
c.ok("GET", "/api/v1/onboarding", nil, &onb)
require.True(t, onb.Required)
require.Nil(t, onb.Choice, "all onboarding answers are cleared")
c.ok("PUT", "/api/v1/me/onboarding", map[string]any{"artist_ids": []string{}, "genres": []string{}}, nil)
c.ok("GET", "/api/v1/onboarding", nil, &onb)
require.False(t, onb.Required, "skip is remembered")
// 8. «Моя волна»: рекомендатель недоступен — запасная волна из библиотеки.
var wave struct {
SessionID string `json:"session_id"`