Skip to content
Notifications
Clear all

Help: Our early metrics show high login rates but zero task completion. What's wrong?

3 Posts
3 Users
0 Reactions
2 Views
(@backend_builder)
Reputable Member
Joined: 4 months ago
Posts: 164
Topic starter   [#7904]

Hey folks, I need a second pair of eyes on a rollout puzzle. We just launched a new internal task management tool for our engineering teams. The stack is Go (Fiber) backend, Postgres for the main datastore, Redis for sessions, and a React frontend.

The adoption metrics from our first week are confusing, almost contradictory:
* **Login Rate:** 95% of the target team is logging in daily. Auth system (JWT via Redis) is getting hammered.
* **Task Completion Rate:** Literally zero. The `tasks` table shows creations, but `completed_at` is null across the board.

My gut says this isn't a "people problem" but a "tooling problem" — probably in the API or the data flow. The login success tells me the onboarding and basic access work. The zero completion screams that a critical path is broken.

Here's our basic task completion endpoint logic (simplified):

```go
func (h *TaskHandler) CompleteTask(c *fiber.Ctx) error {
taskID := c.Params("id")
userID := c.Locals("userID").(string)

var task Task
// Check ownership and status
result := h.db.Where("id = ? AND assignee_id = ? AND status = 'open'", taskID, userID).First(&task)
if result.Error != nil {
return c.SendStatus(fiber.StatusNotFound)
}

// Update within a transaction
tx := h.db.Begin()
if err := tx.Model(&task).Updates(map[string]interface{}{
"status": "completed",
"completed_at": time.Now(),
}).Error; err != nil {
tx.Rollback()
return c.SendStatus(fiber.StatusInternalServerError)
}
// Log event to Redis stream for analytics
h.redis.XAdd(ctx, &redis.XAddArgs{
Stream: "task_events",
Values: map[string]interface{}{"event": "completed", "task_id": taskID},
})
tx.Commit()
return c.SendStatus(fiber.StatusOK)
}
```

Things we've already checked:
* Network calls in the browser dev tools show the `PUT /api/tasks/:id/complete` call is being made... but it returns a `404`.
* The frontend team swears the payload is correct.
* Database permissions are fine for the service role.

My current hypotheses:
1. The `WHERE` clause in the completion query is too restrictive. Maybe the `status` field isn't `'open'` but `'pending'`?
2. The `assignee_id` check is failing. Could the frontend be sending the task creation's `owner_id` instead of the `assignee_id`?
3. The Redis stream addition might be slowing things down or erroring, causing a rollback? (We moved it after the commit to test, no change).

Has anyone run into this "all-access, no-action" metric pattern before? Where would you instrument next? I'm thinking of adding verbose logging right before the rollback and maybe tracing the exact DB query being executed.

--builder


Latency is the enemy, but consistency is the goal.


   
Quote
(@cloud_rookie_em)
Estimable Member
Joined: 3 months ago
Posts: 138
 

Oh man, zero completions is such a clear signal. That endpoint logic you showed cuts off, but my first thought is the database check. If it's failing the `status = 'open'` or `assignee_id` condition, the API might be returning a silent error the frontend isn't handling.

Are you logging the result.Error from that First() query? The users might be clicking "complete" and nothing happens on their screen because the request fails. Maybe the frontend expects a 200 but gets a 404 and just... doesn't tell anyone.

Could also be a race where the UI shows them a task but the backend uses a different ID? Just guessing here.



   
ReplyQuote
(@ivank)
Eminent Member
Joined: 1 week ago
Posts: 26
 

The silent error theory is good, but I'd check the session flow first. You have a Redis-backed JWT system hammered by logins. Could the `userID` cached in `c.Locals` be expiring or mismatched between the auth middleware and the task endpoint? If the user context is lost mid-session, the ownership check `assignee_id = ?` would fail for every request after login.

A quick test: log the actual `userID` value hitting the CompleteTask endpoint versus the one stored in the task record. A mismatch would produce a silent "not found" from that First() query.



   
ReplyQuote