From aaa8cbcecc63f45ac8b4e836c3af4c764df74b3d Mon Sep 17 00:00:00 2001 From: Dylan Jeffers Date: Mon, 15 Jun 2026 16:16:28 -0700 Subject: [PATCH] feat: add last_active_at column and POST /v1/users/me/ping endpoint Adds a `last_active_at` timestamptz column to the users table and a new authenticated endpoint that upserts it on each app-open. This replaces plays-based inactivity detection with a direct activity signal. Co-Authored-By: Claude Opus 4.6 --- api/server.go | 1 + api/v1_users_ping.go | 27 +++++++++++++++++++ .../0221_add_users_last_active_at.sql | 6 +++++ 3 files changed, 34 insertions(+) create mode 100644 api/v1_users_ping.go create mode 100644 ddl/migrations/0221_add_users_last_active_at.sql diff --git a/api/server.go b/api/server.go index 1c1197de..8674f83d 100644 --- a/api/server.go +++ b/api/server.go @@ -406,6 +406,7 @@ func NewApiServer(config config.Config) *ApiServer { g.Get("/users/genre/top", app.v1UsersGenreTop) g.Get("/users/account/:wallet", app.requireAuthMiddleware, app.v1UsersAccount) g.Get("/users/verify_token", app.v1UsersVerifyToken) + g.Post("/users/me/ping", app.requireAuthMiddleware, app.postV1UsersPing) g.Use("/users/handle/:handle", app.requireHandleMiddleware) g.Get("/users/handle/:handle", app.v1User) diff --git a/api/v1_users_ping.go b/api/v1_users_ping.go new file mode 100644 index 00000000..c222b726 --- /dev/null +++ b/api/v1_users_ping.go @@ -0,0 +1,27 @@ +package api + +import ( + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" +) + +func (app *ApiServer) postV1UsersPing(c *fiber.Ctx) error { + if app.writePool == nil { + return fiber.NewError(fiber.StatusServiceUnavailable, "writes not available") + } + + wallet := app.getAuthedWallet(c) + + _, err := app.writePool.Exec(c.Context(), ` + UPDATE users + SET last_active_at = now() + WHERE wallet = $1 + AND is_current = true + `, wallet) + if err != nil { + app.logger.Error("postV1UsersPing: failed to update last_active_at", zap.Error(err)) + return fiber.NewError(fiber.StatusInternalServerError, "failed to record activity") + } + + return c.JSON(fiber.Map{"status": "ok"}) +} diff --git a/ddl/migrations/0221_add_users_last_active_at.sql b/ddl/migrations/0221_add_users_last_active_at.sql new file mode 100644 index 00000000..93ec9cdd --- /dev/null +++ b/ddl/migrations/0221_add_users_last_active_at.sql @@ -0,0 +1,6 @@ +BEGIN; + +ALTER TABLE users ADD COLUMN IF NOT EXISTS last_active_at TIMESTAMPTZ DEFAULT NULL; +COMMENT ON COLUMN users.last_active_at IS 'Timestamp of the user''s most recent app-open event, updated by POST /v1/users/me/ping.'; + +COMMIT;