diff --git a/admin/src/app/users/[id]/page.tsx b/admin/src/app/users/[id]/page.tsx
index 4f1d00d..264241d 100644
--- a/admin/src/app/users/[id]/page.tsx
+++ b/admin/src/app/users/[id]/page.tsx
@@ -512,7 +512,7 @@ function FollowManager({ userId }: { userId: string }) {
{/* Add */}
- setAddHandle(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleAdd()}
className="flex-1 px-2 py-1.5 border border-warm-300 rounded text-sm" />
diff --git a/go-backend/internal/handlers/admin_handler.go b/go-backend/internal/handlers/admin_handler.go
index ca53fc6..ff7198f 100644
--- a/go-backend/internal/handlers/admin_handler.go
+++ b/go-backend/internal/handlers/admin_handler.go
@@ -689,6 +689,22 @@ func (h *AdminHandler) AdminUpdateProfile(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "Profile updated"})
}
+// resolveUserID accepts either a UUID or a handle and returns the user's UUID.
+func (h *AdminHandler) resolveUserID(ctx context.Context, input string) (string, error) {
+ // If it parses as a UUID, return as-is
+ if _, err := uuid.Parse(input); err == nil {
+ return input, nil
+ }
+ // Otherwise, treat as a handle and look it up
+ handle := strings.TrimPrefix(input, "@")
+ var id uuid.UUID
+ err := h.pool.QueryRow(ctx, `SELECT id FROM profiles WHERE handle = $1`, handle).Scan(&id)
+ if err != nil {
+ return "", fmt.Errorf("user not found: %s", input)
+ }
+ return id.String(), nil
+}
+
// AdminManageFollow adds or removes follow relationships for official accounts.
func (h *AdminHandler) AdminManageFollow(c *gin.Context) {
ctx := c.Request.Context()
@@ -696,7 +712,7 @@ func (h *AdminHandler) AdminManageFollow(c *gin.Context) {
var req struct {
Action string `json:"action"` // "add" or "remove"
- UserID string `json:"user_id"` // the other user in the relationship
+ UserID string `json:"user_id"` // UUID or handle of the other user
Relation string `json:"relation"` // "follower" (user follows target) or "following" (target follows user)
}
if err := c.ShouldBindJSON(&req); err != nil {
@@ -713,16 +729,21 @@ func (h *AdminHandler) AdminManageFollow(c *gin.Context) {
return
}
+ // Resolve handle or UUID to a UUID
+ resolvedID, err := h.resolveUserID(ctx, req.UserID)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+
// Determine follower_id and following_id
var followerID, followingID string
if req.Relation == "follower" {
- // "user follows target" — user is follower, target is following
- followerID = req.UserID
+ followerID = resolvedID
followingID = targetUserID
} else {
- // "target follows user" — target is follower, user is following
followerID = targetUserID
- followingID = req.UserID
+ followingID = resolvedID
}
if req.Action == "add" {