# User Activity Controller Documentation **File:** `controllers/admin/user_activity.controller.js` **Base URL:** `/api/admin/activity` and `/api/admin/users/:id/activity` **Guards:** `authenticate → requireAdmin() → adminLimiter` --- ## Table of Contents - [Get Global Activity Feed](#get-global-activity-feed) - [Get Per-User Activity](#get-per-user-activity) --- ## Notes - `user_activity` rows are **never soft-deleted** — this is an append-only audit log. - `created_at` is the timestamp column (no `createdAt` alias — Sequelize `timestamps: false`). - The global feed endpoint joins the `users` table and enriches each row with `full_name` and `avatar_url`. - The per-user endpoint skips the join for performance since user context is already known. --- ## Activity Object Shape ```json { "activity_id": 1, "user_id": 42, "email": "user@example.com", "full_name": "Kenneth Obsequio", "avatar_url": "https://...", "acc_type": "admin", "action": "login", "entity_type": "session", "entity_id": 7, "details": { "session_id": 7, "reg_type": "system" }, "created_at": "2026-06-21T08:00:00.000Z" } ``` ### Common `action` Values | Action | Entity Type | Details Keys | |--------|-------------|--------------| | `login` | `session` | `session_id`, `reg_type` | | `deactivate_user` | `user` | `target_email` | | `lesson_read` | `lesson` | `lesson_uuid`, `status` | | `submit_task` | `task` | `task_id` | | `set_user_status` | `user` | `is_active` | | `create_course` | `course` | `title` | | `update_course` | `course` | `title` | | `archive_course` | `course` | — | | `create_task_list` | `task_list` | `name` | | `create_advertisement` | `advertisement` | `type` | | `grant_tier` | `tier` | `user_id`, `tier`, `plan_id` | | `revoke_tier` | `tier` | `user_id`, `tier` | --- ## Get Global Activity Feed **`GET /api/admin/activity`** Returns a paginated, reverse-chronological feed of all user activity across the system. ### Query Parameters | Parameter | Type | Required | Description | |-----------|--------|----------|-------------| | `page` | number | No | Default: `1` | | `limit` | number | No | Default: `20`, max: `100` | | `action` | string | No | Filter by exact action string (e.g. `login`) | | `from` | date | No | ISO date — `created_at >= from` | | `to` | date | No | ISO date — `created_at <= to` | ### Response `200` ```json { "status": "success", "message": "Activity feed retrieved.", "data": { "total": 500, "page": 1, "totalPages": 25, "activities": [ ... ] } } ``` --- ## Get Per-User Activity **`GET /api/admin/users/:id/activity`** Returns a paginated, reverse-chronological activity log for a single user. ### Query Parameters Same as global feed (`page`, `limit`, `action`, `from`, `to`). ### Response `200` ```json { "status": "success", "message": "User activity retrieved.", "data": { "total": 45, "page": 1, "totalPages": 3, "activities": [ { "activity_id": 1, "user_id": 42, "session_id": null, "action": "update_course", "entity_type": "course", "entity_id": 3, "details": { "title": "Advanced JS" }, "created_at": "2026-06-21T09:00:00.000Z" } ] } } ``` ### Error Responses | Status | Message | |--------|---------| | `400` | `Invalid User ID.` | | `404` | `User not found.` |