Skip to content

First pass at stats_api - #440

Open
duckduckgrayduck wants to merge 2 commits into
masterfrom
stats_api
Open

First pass at stats_api#440
duckduckgrayduck wants to merge 2 commits into
masterfrom
stats_api

Conversation

@duckduckgrayduck

@duckduckgrayduck duckduckgrayduck commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Reference document

This provides a new api, stats_api, with two new endpoints: users and organizations.
The idea is that Accounts will call users with the filter active_within_days (most likely daily) to see if anyone's uploaded a document or logged in the last N days.
The user list view will return uuid, total_documents, last_upload_at, last_login_at, recent_upload_count (based on a window we can change as an environment variable). The organizations endpoint returns the same fields minus last_login_at, since organizations don't log in, and it's limited to non-individual (collective) orgs.

Because a user could be picked up by the sync for uploading a document on day 1 of the window and then go dormant the rest of the window cycle, recent_upload_count on Accounts could go stale until the next time the user was surfaced in sync. To keep that fresh, I needed something to catch stale recent_upload_counts on Accounts when that boundary is crossed. This is the intention behind the custom action aged_out.

Basically the workflow for the nightly sync would go:

GET /stats_api/users/?active_within_days=N (most likely 1, but if a sync fails, it can be calculated to be 2).
GET /stats_api/users/aged_out/?since=<last_sync_timestamp>
GET /stats_api/organizations/?active_within_days=N
GET /stats_api/organizations/aged_out/?since=<last_sync_timestamp>
& pagination.

This approach means I don't have to worry about setting/un-setting a flag on the user/org record to indicate it has changed.

We may like to easily answer questions like how many users active within the last 10 days? So I kept active_within_days as a human-friendly input while aged_out is essentially only used for boundary-catching from the last sync. Accounts will already have the last-sync timestamp for aged_out, so computing N = days since last sync costs nothing and makes active_within_days self-healing.

Lastly: If you're wondering about the language choices in the migration, looks like those never were captured since the Django 5 upgrade, shouldn't affect anything though.

If this approach looks good, I'll write tests.

@duckduckgrayduck

duckduckgrayduck commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

Should add:

  • Method to manually calculate the stats given a UUID to backfill
  • Key off AICredit spends and return that too, so we can see AI credits (requested by Allan). AICreditLogs live on the individual organization, so I'll need to retrieve that somehow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant