From 6ab077b53d3f029ed5e00abf52900254be4c2001 Mon Sep 17 00:00:00 2001 From: Yared Yemane Date: Wed, 20 May 2026 06:17:15 -0700 Subject: [PATCH] Rename LMS persona image field to profile_picture. Add migration 000064 renaming avatar_url column; expose profile_picture in API, sqlc, and Swagger. Co-authored-by: Cursor --- ...0064_lms_personas_profile_picture.down.sql | 2 + ...000064_lms_personas_profile_picture.up.sql | 3 + db/query/lms_personas.sql | 6 +- docs/docs.go | 12 ++-- docs/swagger.json | 12 ++-- docs/swagger.yaml | 8 +-- gen/db/lms_personas.sql.go | 58 +++++++++---------- gen/db/models.go | 14 ++--- internal/domain/lms_persona.go | 30 +++++----- internal/repository/lms_personas.go | 20 +++---- 10 files changed, 85 insertions(+), 80 deletions(-) create mode 100644 db/migrations/000064_lms_personas_profile_picture.down.sql create mode 100644 db/migrations/000064_lms_personas_profile_picture.up.sql diff --git a/db/migrations/000064_lms_personas_profile_picture.down.sql b/db/migrations/000064_lms_personas_profile_picture.down.sql new file mode 100644 index 0000000..45d938e --- /dev/null +++ b/db/migrations/000064_lms_personas_profile_picture.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE lms_personas + RENAME COLUMN profile_picture TO avatar_url; diff --git a/db/migrations/000064_lms_personas_profile_picture.up.sql b/db/migrations/000064_lms_personas_profile_picture.up.sql new file mode 100644 index 0000000..01a8020 --- /dev/null +++ b/db/migrations/000064_lms_personas_profile_picture.up.sql @@ -0,0 +1,3 @@ +-- Persona profile image URL stored as profile_picture (replaces avatar_url naming). +ALTER TABLE lms_personas + RENAME COLUMN avatar_url TO profile_picture; diff --git a/db/query/lms_personas.sql b/db/query/lms_personas.sql index 352bfb0..c1e6693 100644 --- a/db/query/lms_personas.sql +++ b/db/query/lms_personas.sql @@ -1,5 +1,5 @@ -- name: CreateLmsPersona :one -INSERT INTO lms_personas (name, description, avatar_url, is_active) +INSERT INTO lms_personas (name, description, profile_picture, is_active) VALUES ($1, $2, $3, $4) RETURNING *; @@ -13,7 +13,7 @@ UPDATE lms_personas SET name = COALESCE(sqlc.narg('name')::varchar, name), description = COALESCE(sqlc.narg('description')::text, description), - avatar_url = COALESCE(sqlc.narg('avatar_url')::text, avatar_url), + profile_picture = COALESCE(sqlc.narg('profile_picture')::text, profile_picture), is_active = COALESCE(sqlc.narg('is_active')::boolean, is_active), updated_at = CURRENT_TIMESTAMP WHERE id = sqlc.arg('id') @@ -29,7 +29,7 @@ SELECT p.id, p.name, p.description, - p.avatar_url, + p.profile_picture, p.is_active, p.created_at, p.updated_at diff --git a/docs/docs.go b/docs/docs.go index 77c4854..23b742f 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -10641,9 +10641,6 @@ const docTemplate = `{ "name" ], "properties": { - "avatar_url": { - "type": "string" - }, "description": { "type": "string" }, @@ -10652,6 +10649,9 @@ const docTemplate = `{ }, "name": { "type": "string" + }, + "profile_picture": { + "type": "string" } } }, @@ -11581,9 +11581,6 @@ const docTemplate = `{ "domain.UpdateLmsPersonaInput": { "type": "object", "properties": { - "avatar_url": { - "type": "string" - }, "description": { "type": "string" }, @@ -11592,6 +11589,9 @@ const docTemplate = `{ }, "name": { "type": "string" + }, + "profile_picture": { + "type": "string" } } }, diff --git a/docs/swagger.json b/docs/swagger.json index b137b00..a772f1d 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -10633,9 +10633,6 @@ "name" ], "properties": { - "avatar_url": { - "type": "string" - }, "description": { "type": "string" }, @@ -10644,6 +10641,9 @@ }, "name": { "type": "string" + }, + "profile_picture": { + "type": "string" } } }, @@ -11573,9 +11573,6 @@ "domain.UpdateLmsPersonaInput": { "type": "object", "properties": { - "avatar_url": { - "type": "string" - }, "description": { "type": "string" }, @@ -11584,6 +11581,9 @@ }, "name": { "type": "string" + }, + "profile_picture": { + "type": "string" } } }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 4b0c345..98ee719 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -449,14 +449,14 @@ definitions: type: object domain.CreateLmsPersonaInput: properties: - avatar_url: - type: string description: type: string is_active: type: boolean name: type: string + profile_picture: + type: string required: - name type: object @@ -1096,14 +1096,14 @@ definitions: type: object domain.UpdateLmsPersonaInput: properties: - avatar_url: - type: string description: type: string is_active: type: boolean name: type: string + profile_picture: + type: string type: object domain.UpdateModuleInput: properties: diff --git a/gen/db/lms_personas.sql.go b/gen/db/lms_personas.sql.go index b7d0126..ac43b8c 100644 --- a/gen/db/lms_personas.sql.go +++ b/gen/db/lms_personas.sql.go @@ -12,23 +12,23 @@ import ( ) const CreateLmsPersona = `-- name: CreateLmsPersona :one -INSERT INTO lms_personas (name, description, avatar_url, is_active) +INSERT INTO lms_personas (name, description, profile_picture, is_active) VALUES ($1, $2, $3, $4) -RETURNING id, name, description, avatar_url, is_active, created_at, updated_at +RETURNING id, name, description, profile_picture, is_active, created_at, updated_at ` type CreateLmsPersonaParams struct { - Name string `json:"name"` - Description pgtype.Text `json:"description"` - AvatarUrl pgtype.Text `json:"avatar_url"` - IsActive bool `json:"is_active"` + Name string `json:"name"` + Description pgtype.Text `json:"description"` + ProfilePicture pgtype.Text `json:"profile_picture"` + IsActive bool `json:"is_active"` } func (q *Queries) CreateLmsPersona(ctx context.Context, arg CreateLmsPersonaParams) (LmsPersona, error) { row := q.db.QueryRow(ctx, CreateLmsPersona, arg.Name, arg.Description, - arg.AvatarUrl, + arg.ProfilePicture, arg.IsActive, ) var i LmsPersona @@ -36,7 +36,7 @@ func (q *Queries) CreateLmsPersona(ctx context.Context, arg CreateLmsPersonaPara &i.ID, &i.Name, &i.Description, - &i.AvatarUrl, + &i.ProfilePicture, &i.IsActive, &i.CreatedAt, &i.UpdatedAt, @@ -55,7 +55,7 @@ func (q *Queries) DeleteLmsPersona(ctx context.Context, id int64) error { } const GetLmsPersonaByID = `-- name: GetLmsPersonaByID :one -SELECT id, name, description, avatar_url, is_active, created_at, updated_at +SELECT id, name, description, profile_picture, is_active, created_at, updated_at FROM lms_personas WHERE id = $1 ` @@ -67,7 +67,7 @@ func (q *Queries) GetLmsPersonaByID(ctx context.Context, id int64) (LmsPersona, &i.ID, &i.Name, &i.Description, - &i.AvatarUrl, + &i.ProfilePicture, &i.IsActive, &i.CreatedAt, &i.UpdatedAt, @@ -81,7 +81,7 @@ SELECT p.id, p.name, p.description, - p.avatar_url, + p.profile_picture, p.is_active, p.created_at, p.updated_at @@ -101,14 +101,14 @@ type ListLmsPersonasParams struct { } type ListLmsPersonasRow struct { - TotalCount int64 `json:"total_count"` - ID int64 `json:"id"` - Name string `json:"name"` - Description pgtype.Text `json:"description"` - AvatarUrl pgtype.Text `json:"avatar_url"` - IsActive bool `json:"is_active"` - CreatedAt pgtype.Timestamptz `json:"created_at"` - UpdatedAt pgtype.Timestamptz `json:"updated_at"` + TotalCount int64 `json:"total_count"` + ID int64 `json:"id"` + Name string `json:"name"` + Description pgtype.Text `json:"description"` + ProfilePicture pgtype.Text `json:"profile_picture"` + IsActive bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` } func (q *Queries) ListLmsPersonas(ctx context.Context, arg ListLmsPersonasParams) ([]ListLmsPersonasRow, error) { @@ -125,7 +125,7 @@ func (q *Queries) ListLmsPersonas(ctx context.Context, arg ListLmsPersonasParams &i.ID, &i.Name, &i.Description, - &i.AvatarUrl, + &i.ProfilePicture, &i.IsActive, &i.CreatedAt, &i.UpdatedAt, @@ -145,26 +145,26 @@ UPDATE lms_personas SET name = COALESCE($1::varchar, name), description = COALESCE($2::text, description), - avatar_url = COALESCE($3::text, avatar_url), + profile_picture = COALESCE($3::text, profile_picture), is_active = COALESCE($4::boolean, is_active), updated_at = CURRENT_TIMESTAMP WHERE id = $5 -RETURNING id, name, description, avatar_url, is_active, created_at, updated_at +RETURNING id, name, description, profile_picture, is_active, created_at, updated_at ` type UpdateLmsPersonaParams struct { - Name pgtype.Text `json:"name"` - Description pgtype.Text `json:"description"` - AvatarUrl pgtype.Text `json:"avatar_url"` - IsActive pgtype.Bool `json:"is_active"` - ID int64 `json:"id"` + Name pgtype.Text `json:"name"` + Description pgtype.Text `json:"description"` + ProfilePicture pgtype.Text `json:"profile_picture"` + IsActive pgtype.Bool `json:"is_active"` + ID int64 `json:"id"` } func (q *Queries) UpdateLmsPersona(ctx context.Context, arg UpdateLmsPersonaParams) (LmsPersona, error) { row := q.db.QueryRow(ctx, UpdateLmsPersona, arg.Name, arg.Description, - arg.AvatarUrl, + arg.ProfilePicture, arg.IsActive, arg.ID, ) @@ -173,7 +173,7 @@ func (q *Queries) UpdateLmsPersona(ctx context.Context, arg UpdateLmsPersonaPara &i.ID, &i.Name, &i.Description, - &i.AvatarUrl, + &i.ProfilePicture, &i.IsActive, &i.CreatedAt, &i.UpdatedAt, diff --git a/gen/db/models.go b/gen/db/models.go index 966b23b..452a196 100644 --- a/gen/db/models.go +++ b/gen/db/models.go @@ -139,13 +139,13 @@ type LevelToSubCourse struct { } type LmsPersona struct { - ID int64 `json:"id"` - Name string `json:"name"` - Description pgtype.Text `json:"description"` - AvatarUrl pgtype.Text `json:"avatar_url"` - IsActive bool `json:"is_active"` - CreatedAt pgtype.Timestamptz `json:"created_at"` - UpdatedAt pgtype.Timestamptz `json:"updated_at"` + ID int64 `json:"id"` + Name string `json:"name"` + Description pgtype.Text `json:"description"` + ProfilePicture pgtype.Text `json:"profile_picture"` + IsActive bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` } type LmsPractice struct { diff --git a/internal/domain/lms_persona.go b/internal/domain/lms_persona.go index 2e1256d..9759b39 100644 --- a/internal/domain/lms_persona.go +++ b/internal/domain/lms_persona.go @@ -10,25 +10,25 @@ var ErrPersonaNotFound = errors.New("persona not found") // LmsPersona is a coach / character profile stored in lms_personas and referenced by practice shells. type LmsPersona struct { - ID int64 `json:"id"` - Name string `json:"name"` - Description *string `json:"description,omitempty"` - AvatarURL *string `json:"avatar_url,omitempty"` - IsActive bool `json:"is_active"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` + ID int64 `json:"id"` + Name string `json:"name"` + Description *string `json:"description,omitempty"` + ProfilePicture *string `json:"profile_picture,omitempty"` // image URL (e.g. MinIO or HTTPS) + IsActive bool `json:"is_active"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` } type CreateLmsPersonaInput struct { - Name string `json:"name" validate:"required"` - Description *string `json:"description,omitempty"` - AvatarURL *string `json:"avatar_url,omitempty"` - IsActive *bool `json:"is_active,omitempty"` + Name string `json:"name" validate:"required"` + Description *string `json:"description,omitempty"` + ProfilePicture *string `json:"profile_picture,omitempty"` + IsActive *bool `json:"is_active,omitempty"` } type UpdateLmsPersonaInput struct { - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - AvatarURL *string `json:"avatar_url,omitempty"` - IsActive *bool `json:"is_active,omitempty"` + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + ProfilePicture *string `json:"profile_picture,omitempty"` + IsActive *bool `json:"is_active,omitempty"` } diff --git a/internal/repository/lms_personas.go b/internal/repository/lms_personas.go index 68ecce6..bbe0d2a 100644 --- a/internal/repository/lms_personas.go +++ b/internal/repository/lms_personas.go @@ -18,7 +18,7 @@ func lmsPersonaToDomain(p dbgen.LmsPersona) domain.LmsPersona { IsActive: p.IsActive, } out.Description = fromPgText(p.Description) - out.AvatarURL = fromPgText(p.AvatarUrl) + out.ProfilePicture = fromPgText(p.ProfilePicture) out.CreatedAt = p.CreatedAt.Time if p.UpdatedAt.Valid { t := p.UpdatedAt.Time @@ -42,7 +42,7 @@ func (s *Store) CreateLmsPersona(ctx context.Context, in domain.CreateLmsPersona p, err := s.queries.CreateLmsPersona(ctx, dbgen.CreateLmsPersonaParams{ Name: in.Name, Description: toPgText(in.Description), - AvatarUrl: toPgText(in.AvatarURL), + ProfilePicture: toPgText(in.ProfilePicture), IsActive: active, }) if err != nil { @@ -67,7 +67,7 @@ func (s *Store) UpdateLmsPersona(ctx context.Context, id int64, in domain.Update ID: id, Name: optionalTextUpdate(in.Name), Description: optionalTextUpdate(in.Description), - AvatarUrl: optionalTextUpdate(in.AvatarURL), + ProfilePicture: optionalTextUpdate(in.ProfilePicture), IsActive: optionalBoolUpdatePB(in.IsActive), }) if err != nil { @@ -102,13 +102,13 @@ func (s *Store) ListLmsPersonas(ctx context.Context, activeOnly bool, limit, off total = r.TotalCount } out = append(out, lmsPersonaToDomain(dbgen.LmsPersona{ - ID: r.ID, - Name: r.Name, - Description: r.Description, - AvatarUrl: r.AvatarUrl, - IsActive: r.IsActive, - CreatedAt: r.CreatedAt, - UpdatedAt: r.UpdatedAt, + ID: r.ID, + Name: r.Name, + Description: r.Description, + ProfilePicture: r.ProfilePicture, + IsActive: r.IsActive, + CreatedAt: r.CreatedAt, + UpdatedAt: r.UpdatedAt, })) } return out, total, nil