Author: James Derick Billate
Reviewer: Jethro Lagmay and Sean Patrick Caintic
Creation Date: June 29, 2026
Status: Published
References: https://github.com/wyzlab/WyzQuests/issues/49
INTRODUCTION AND GOALS
Problem Summary: Agency Admins need to export agency team and learner dashboard data for reporting. The current feature supports CSV generation from the Agency Team and Agency Learners pages using already-loaded dashboard data.
Goals and Non-Goals: The goal is to allow Agency Owners/Admins to view and export member and learner progress data in CSV format. The feature should support reporting for creators, reviewers, learners, and learner quest progress. The feature does not provide PDF export, scheduled reports, cross-agency reports, login history, or deeper business intelligence dashboards.
HIGH-LEVEL ARCHITECTURE
System Diagram:
Technologies Used:
Frontend: Next.js App Router, React client components, Tailwind CSS, Shadcn UI components, Sonner toast, Lucide icons, PapaParse.
Backend: RESTful API routes, TypeScript, Clerk authentication, agency authorization helpers, Supabase queries, standardized API responses.
Storage/Database: Supabase Postgres tables for agencies, agency_members, app_users, quests, public_share, and quest_enrollments.
External Services: Clerk for authentication and user identity.
DETAILED DESIGN AND IMPLEMENTATION
Schema:
Export Data does not create a dedicated export table. It reads from existing agency, user, quest, and enrollment data. CSV files are generated from in-memory frontend data.
Relevant data sources:
agencies: Stores agency ID, name, plan, owner Clerk ID, and monthly token budget.
agency_members: Stores agency member role, status, invited email, user Clerk ID, and token limit.
app_users: Provides display name, email, platform role, app user ID, and Clerk ID.
quests: Provides creator-owned quest data for agency creator analytics.
public_share: Used to identify shared quests for creator analytics.
quest_enrollments: Provides learner enrollment and progress data.
API Specification:
GET /api/agency/status
Checks the authenticated user's agency membership, ownership, effective role, and agency info.
| |
|---|---|
Status | Return |
401 | Unauthorized |
500 | Failed to check membership or fetch agency info |
200 OK | Data: |
GET /api/agency/team/list
Fetches agency details, agency members, enriched display names/platform roles, creator quest analytics, and current user Clerk ID.
| |
|---|---|
Status | Return |
401 | Unauthorized |
403 | Forbidden when user is not an Agency Owner/Admin |
404 | Agency not found |
500 | Failed to fetch members |
200 OK | Data: |
GET /api/agency/learners
Fetches learners connected to agency-created quests and includes their enrolled quest progress.
| |
|---|---|
Status | Return |
401 | Unauthorized |
403 | Forbidden when user is not an Agency Owner/Admin |
404 | Agency not found |
500 | Failed to fetch members, quests, enrollments, or learners |
200 OK | Data: |
POST /api/agency/team/claim
Best-effort endpoint called before loading agency pages to claim pending invites for the current user.
| |
|---|---|
Status | Return |
401 | Unauthorized |
200 OK | Invite claim result or no-op response |
Client CSV Generation:
Team export uses Papa.unparse on agency member data after removing internal fields such as agency_id, created_at, user_clerk_id, platform_role, and isCurrentUser.
Learner export uses Papa.unparse on a flattened learner quest dataset:
learner_idlearner_namequest_titlepercentagelast_visited_at
Core Logic and Workflow:
Agency page calls
/api/agency/statusto determine whether the user can manage agency data.Team page calls
/api/agency/team/listand stores agency, members, and quest analytics data.Learners page calls
/api/agency/learnersand stores agency and learner quest progress data.Admin clicks Export Team Data or Export Learner Data.
Frontend maps the loaded dataset into an export-safe shape.
PapaParse converts the mapped data into CSV.
Browser creates a Blob object URL and downloads the CSV using an agency-name filename.
Success or failure is shown through toast feedback.
INFRASTRUCTURE AND OPERATIONS
Dependencies: Clerk Authentication, Supabase Database, agency authorization helpers, PapaParse, Agency Team dashboard, Agency Learners dashboard, standardized API response helper.
Monitoring and Alerting:
Monitor API errors from
/api/agency/team/listand/api/agency/learners.Monitor Supabase query failures for agency members, app users, quests, and enrollments.
Check browser/client errors for CSV generation and file download failures.
Deployment Plan:
Ensure agency membership and agency ownership authorization is configured.
Ensure agency team and learner APIs return only scoped agency data.
Ensure PapaParse is installed and bundled with the frontend.
Validate CSV export behavior in common browsers.
TESTING AND QUALITY ASSURANCE
Testing Strategy:
Sign in as Agency Owner and export Team CSV.
Sign in as Agency Owner and export Learner CSV.
Verify non-owner/non-admin agency member cannot access export pages.
Verify CSV filename sanitizes agency name spaces and special characters.
Verify exported team CSV excludes internal fields.
Verify exported learner CSV flattens multiple quests per learner into separate rows.
Verify no-agency, no-member, and no-learner states do not crash export pages.
Known Limitations:
CSV generation is currently client-side and depends on already-loaded dashboard data.
There is no dedicated backend route such as
/api/agency/admin/export-csv.Large agencies may generate heavy client-side CSV files.
Export does not currently support date range filters.
Export does not currently support PDF or scheduled delivery.
MAINTENANCE AND SUPPORT
Maintain CSV field mapping whenever agency member, learner, quest, or enrollment response shapes change.
Review exported fields before adding sensitive data such as private IDs, emails, or internal role metadata.
If export volume grows, move CSV generation to a backend route with streaming or paginated export.
Ensure future analytics changes remain scoped by agency authorization rules.
Document Version
1.0 - Draft, feature enhanced from current hand-off documentation 07/07/2026
1.1 - Draft, enhancement of documentation 07/09/2026
1.2 - Draft, minor enhancements 07/14/2026