Skip to content

Trending Courses/Professors Feature | UI & Analytics#1248

Open
ArislanT wants to merge 33 commits into
devfrom
feature/trending-analytics-full
Open

Trending Courses/Professors Feature | UI & Analytics#1248
ArislanT wants to merge 33 commits into
devfrom
feature/trending-analytics-full

Conversation

@ArislanT
Copy link
Copy Markdown
Collaborator

@ArislanT ArislanT commented Apr 19, 2026

Context

Created a feature that illustrates the popularity of courses and professor
This PR includes the Analytics, how the data is getting tracked, and the Frontend, the retrieval and display of the analytics.

Frontend simply changes landing.html & landing.css, the other changes are towards the analytics or general fixes

Key Aspects

Analytics Aspect:

Previously, no metric/method of tracking views/popularity. So I had to build the methodology from scratch: Views are collected passively at the routing layer. Not from client-side JavaScript, pixel tracking, or separate API call, as user accessibility and site stability is the priority. Rather, when a user hits a course or instructor page via a standard GET request, the view function fires record_course_view or record_instructor_view before returning the response. This increments a view_count counter in DynamoDB for that entity's daily row using an atomic ADD operation, which is safe under concurrent writes without any locking.

Page views are recorded asynchronously so analytics writes never block the request/response cycle

  • Fire-and-Forget: Sends work elsewhere to not hold up user and makes necessary checks
  • ThreadedPoolExecutor: _MAX_WORKERS = 5, to handles concurrent writes and to have not to much not too many idle threads consuming resources. _MAX_BACKLOG = 100 which acts as a circuit breaker. The backlog is very important as if the queue fills up during a massive traffic spike, new analytics are silently dropped rather than backing up the server, reflecting the design philosophy of prioritizing site performance over perfect analytical precision. If there was no backlog, users may have to wait a while to get rendered onto the page.
    (On shutdown, atexit ensures all pending tasks cleanly flush before the process exits)

DynamoDB Schema && TTL:

  • Only one row per entity per day using pk = entity_type: id, sk = date
  • Segments views by day without manually cleanup. Downside is that the trending is judged by just the segments and not total value. However, this stops from table from clogging up as if there was no segments then TTL would keep on renewing for the old views if someone viewed the course again.
  • TTL is set to 7 days via expires_at, as discussed as shorter TTL would be too volatile specifically if we are not in enrollment and a longer TTL surfaces stale data that just clogs up the DB. The max is there in order the floor is never set to 0 or negative (which is unlikely but still placed in case) ANALYTICS_TTL_DAYS allows it to be tuned in production without a code change if the 7-day window proves too long or too short after observing real traffic patterns.
  • if_not_exists, allows each row to have a fixed lifespan regardless of popularity

Safe Initialization:

  • The boto3 session initialization is wrapped in a try/except at module load time. If credentials are malformed, the AWS region is invalid, or any other initialization error occurs, _ANALYTICS_ENABLED stays False and the error is logged rather than crashing the server on startup. This means a misconfigured analytics setup can never take down the application — the worst case is silent no-ops on all analytics calls.

24-Hour Cache

Trending results are cached in Django's cache backend for 24 hours. DynamoDB is only hit on a cache miss, meaning the GSI query runs at most once per day per entity type regardless of traffic volume. This makes the feature effectively zero-cost at runtime for the vast majority of requests.

GSI (Entity Index) & Retrieval Logic: Replaces the original full table scan, making trending lookups efficient at scale

  • Partitions by entity_type and sorts by view_count descending.
  • Safely handles DynamoDB's Limit/Filter execution order by relying on LastEvaluatedKey. It won't exit early on pages of expired data, and max_pages = 10 prevents infinite loops on malformed datasets.
  • Replaced the original seen set with a scores_by_id dictionary. This is vital because DynamoDB's GSI queries can return multiple "daily" rows for the same entity across different result pages. This dictionary acts as a rolling accumulator, summing up view_count from every page of results to provide an accurate 7-day popularity score rather than just a snapshot of the most recent page.
  • ProjectionExpression strictly limits returned attributes to only pk, expires_at, and view_count, minimizing network transfer and Read Capacity Unit (RCU) consumption.

UI Aspect: (Location and design is just a mock-up. Created for quicker advancement in the development cycle)

  • Top 5 trending courses & professors displayed on front. Pulls correctly from DynamoDB, which ensures the functionality of the backend engine
  • Cards are clickable and correctly sends us to its respective location
  • If hovered, there is a hovering effect
  • Course Symbol, Mnemonic, and Full Name Displayed
  • Professor's name displayed (Departments are not displayed as some have multiple)

Changes

Backend:

tcf_website/views/catalog/browse.py

  • Imports get_trending_courses and get_trending_instructors and injects them into the browse page context so trending data appears on the browse page as well as the landing page

Both course.py & course_instructor.py makes it so that the write is dispatched to a background thread immediately and the view continues rendering without waiting for DB to complete, meaning 0 latency impact on page load
tcf_website/views/courses/course.py

  • Imports record_course_view and fires it on every GET request, feeding view data into the analytics write path
    tcf_website/views/courses/course_instructor.py
  • Imports record_instructor_view and fires it on every GET request, feeding instructor view data into the analytics write path

tcf_website/analytics_utils.py

  • changes described above in the Key Aspects section. Analytics_utils.py newly introduced as no previous analytics infrastructure existed.

tcf_website/views/home/pages.py

  • Pages.py edited for retrieval, adding the GSI (get top 5 from DB) and our two getters (get to view)
  • Refactored the index view to use context.update() following the landing_spotlight_context initialization. This ensures that analytics data takes priority and prevents a bug where empty spotlight results would overwrite valid trending data

.env.example

  • credentials for dynamoDB table

Design Decision

  • analytics_utils.py owns the write path exclusively with fire-and-forget recording, thread pool management, and DynamoDB writes. It has no knowledge of Django models, caching, or business logic.
  • pages.py owns the read path as a view-layer concern as it has querying DynamoDB, mapping IDs back to Django ORM objects, applying caching, and building template context.
  • Putting GSI query logic in analytics_utils.py would mix Django model imports and cache logic into what should be a thin infrastructure-only module. Which aligns with that the only public interface analytics_utils.py exposes is get_table(), record_course_view(), and record_instructor_view()

UI:
tcf_website/static/css/site/pages/landing.css

  • Fixed: 5rem fixed height to ensure perfect alignment between cards, also hardcoded a min-width on the rank numbers to prevent UI jitter if going from single-digit to double-digit ranking
  • Media Queries: ensures grid stacks vertically on mobile devices and expand to a dual-column layout elsewhere
  • Design System Alignment: Adhered to existing CSS vars for spacing, typography, and colors

tcf_website/templates/site/home/landing.html

  • Displays feature on the front page
  • Dynamic Grid Layout: Built out the dual-column trending sections using a responsive stack architecture
  • Empty States: Implemented {% empty %} fallback blocks (role="status") so the UI remains polished even if the database has zero trending data
  • Semantic & Accessible HTML: Structured the sections using proper semantic tags (
    , ) and ARIA labels to ensure screen-reader compatibility.
  • Direct Routing: Wired up the Django {% url %} tags to dynamically generate links to the specific course or instructor detail pages based on the GSI query results.

Screenshots

UI/Frontend
image

Testing

Backend:

  • Used Locust to verify the stability of the asynchronous pipeline under high-concurrency conditions within the local Docker environment.
  • Passed stability and stress test (100 concurrent users at 40 users/second, and 200 concurrent users at 20 users/second)
  • Only 7 failures of out of 9,900 which confirms that the ThreadPoolExecutor backlog limits were reached. This validates the system's ability to prioritize site stability over analytic precision during extreme traffic spikes by dropping excess events rather than blocking the main request cycle.
    (The seven views were successfully rendered for users but just not counted in analytics)
  • More data on locust test but data a little outdated as even more safety measures has been added

UI/Frontend

  • Simply verified across various screen widths in local Docker environment
  • Passed status 200 rendering tests using Django Test Client, proving that every url tag found a valid route, sub department logic was fixed, and get_trending_ids (query) logic successfully returned data that the template could use
  • Used select_related in the view to ensure the frontend renders efficiently without N+1 query overhead, as it allows for just 1 database round-trip

Summary by CodeRabbit

  • New Features
    • Added a "Trending" section to the landing page displaying the most-used courses and instructors with their rankings
    • Implemented view tracking for course and instructor detail pages
    • Added new analytics configuration settings to support the trending functionality

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 19, 2026

Warning

Rate limit exceeded

@ArislanT has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 51 minutes and 24 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 51 minutes and 24 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 60a7f76a-6e5b-427e-be08-89824b9a6472

📥 Commits

Reviewing files that changed from the base of the PR and between d34947c and b3d0e35.

📒 Files selected for processing (2)
  • tcf_website/analytics_utils.py
  • tcf_website/views/home/pages.py
📝 Walkthrough

Walkthrough

Adds a DynamoDB-backed trending analytics feature: env config, an async recorder module, view-side recording on GET requests, retrieval/caching of top trending IDs, and UI/templates/styles to display trending courses and instructors.

Changes

Cohort / File(s) Summary
Environment
\.env.example
Added trailing newline, blank line after # REVIEW_DRIVE_PASSWORD=, and new env placeholders for Trending Analytics (ANALYTICS_ENABLED, AWS_ANALYTICS_*, AWS_REGION, DYNAMODB_TABLE_NAME, ANALYTICS_TTL_DAYS).
Analytics module
tcf_website/analytics_utils.py
New module that conditionally initializes boto3/DynamoDB, exposes record_course_view and record_instructor_view, queues bounded async update tasks, computes TTL, and gracefully disables on init failure.
Views — recording
tcf_website/views/courses/course.py, tcf_website/views/courses/course_instructor.py
On HTTP GET, calls to record_course_view(course.id) and record_instructor_view(instructor.id) were added before rendering.
Trending retrieval & integration
tcf_website/views/home/pages.py, tcf_website/views/catalog/browse.py
Added get_top_trending_ids, get_trending_courses, get_trending_instructors (DynamoDB query + aggregation + caching) and injected trending lists into home and browse contexts.
Templates & styling
tcf_website/templates/site/home/landing.html, tcf_website/static/css/site/pages/landing.css
Landing template updated with trending sections and markup; CSS added for responsive trending cards, interactions, and empty-state styling.
Docker config
docker-compose.yml
web service now loads environment from an external .env via env_file.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant View as Django View
    participant Analytics as analytics_utils
    participant Executor as ThreadPoolExecutor
    participant DynamoDB
    User->>View: GET /course/{id}
    View->>Analytics: record_course_view(course_id)
    Analytics->>Executor: submit async update task
    Executor-->>DynamoDB: update_item (ADD view_count, set expires_at, set entity_type)
    View->>User: render course page
Loading
sequenceDiagram
    actor User
    participant HomeView as Home view
    participant Cache as Django Cache
    participant DynamoDB
    participant ORM as Course/Instructor ORM
    User->>HomeView: GET /
    HomeView->>Cache: get(trending_key)
    alt cache hit
        Cache-->>HomeView: return cached list
    else cache miss
        HomeView->>DynamoDB: query EntityIndex (expires_at filter, paginate)
        DynamoDB-->>HomeView: return items
        HomeView->>HomeView: aggregate and sort IDs
        HomeView->>ORM: fetch objects by id__in
        ORM-->>HomeView: return ORM instances
        HomeView->>Cache: set(trending_key)
    end
    HomeView->>User: render landing with trending lists
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 I hopped through code at break of dawn,

Counting views on every lawn.
DynamoDB keeps tally true,
Courses climb and instructors too.
Async hops — the trends are drawn.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 61.54% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Trending Courses/Professors Feature | UI & Analytics' accurately summarizes the main change—implementing a trending feature with both frontend UI and backend analytics components.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description is comprehensive and detailed, covering all major aspects: context, key technical decisions, implementation details, architecture rationale, testing methodology, and design choices.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/trending-analytics-full

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ArislanT ArislanT added Feature New feature Performance Performance improvements, refactoring labels Apr 19, 2026
@ArislanT ArislanT marked this pull request as ready for review April 21, 2026 01:24
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
tcf_website/views/catalog/browse.py (1)

15-15: Move trending retrieval out of the home view module.

browse.py now imports from ..home.pages, coupling catalog views to home-page code. Consider moving get_trending_courses() / get_trending_instructors() into a dedicated analytics/trending service module and importing that from both views.

Also applies to: 128-129

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tcf_website/views/catalog/browse.py` at line 15, The catalog view is tightly
coupled to home page code because browse.py imports get_trending_courses and
get_trending_instructors from ..home.pages; extract those functions into a
dedicated module (e.g., a new analytics/trending service) and update import
sites to use that service: move the implementation of get_trending_courses and
get_trending_instructors out of home.pages into the new module, export them from
there, then change browse.py and home.pages to import the functions from the new
trending service to remove the cross-module dependency.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.env.example:
- Around line 52-58: The .env.example trending analytics block is missing the
ANALYTICS_TTL_DAYS variable (used by analytics_utils.py) and an explicit opt-in
flag; update the example to include a commented ANALYTICS_TTL_DAYS= (number of
days) and add a commented enable flag (e.g., ENABLE_TRENDING_ANALYTICS=
true/false) so operators can discover the TTL knob and opt-in behavior;
reference analytics_utils.py and the ANALYTICS_TTL_DAYS environment variable
when adding these entries.

In `@tcf_website/analytics_utils.py`:
- Around line 17-55: Move all analytics configuration parsing into the safe init
path and make analytics opt-in: stop initializing _TTL_DAYS, AWS keys, and table
name at import time; introduce a feature flag (e.g., ANALYTICS_ENABLED default
False) and only set _ANALYTICS_ENABLED = True after validating access by
performing a cheap, synchronous check (e.g., a describe_table or a simple
DynamoDB call) using the created _SESSION; ensure _SESSION is created inside the
try block and on any failure set _ANALYTICS_ENABLED = False (don’t rely on
boto3.Session() alone), cache the resolved DYNAMODB_TABLE_NAME during init
instead of calling env() inside get_table(), and keep get_table() returning None
when _ANALYTICS_ENABLED is False; reference symbols to change: _TTL_DAYS,
_ANALYTICS_ENABLED, ANALYTICS_ENABLED (new flag), _SESSION, get_table, and
_BOTO_CONFIG.

In `@tcf_website/static/css/site/pages/landing.css`:
- Around line 310-319: In .trending-card__title remove the stray blank line
before the white-space declaration so there is no empty line between margin-top:
var(--space-1); and white-space: nowrap; (this fixes the
declaration-empty-line-before Stylelint rule); update the selector block in
landing.css to have contiguous declarations with no empty line.

In `@tcf_website/templates/site/home/landing.html`:
- Line 112: The decorative fire emoji inside the span with class
trending-card__badge is being announced to assistive tech; make it ignored by
screen readers by adding aria-hidden="true" (and optionally focusable="false"
for SVGs but here the span is sufficient) to the span element(s) where
trending-card__badge is used (both occurrences shown), ensuring the visual badge
remains but is not read aloud.

In `@tcf_website/views/home/pages.py`:
- Around line 101-103: The empty-result path in get_top_trending_ids handling
returns before populating the cache, causing repeated cold reads; change the
early-return branches (the one after course_ids = get_top_trending_ids("course")
and the similar block at the other occurrence) to first call cache.set(...) with
an empty list and a short TTL (e.g., a few minutes) using the same cache key
used for successful results, then return the empty list; ensure you reuse the
exact cache key construction and keep the short TTL so new trends aren’t hidden
for 24 hours.
- Around line 35-89: The loop prematurely stops when items is empty even though
response may include LastEvaluatedKey and it also only deduplicates by entity_id
without summing view_count across date-partitioned rows; change the aggregation
to track totals per entity (replace seen/list with a dict like entity_totals
mapping entity_id -> total_views), include "view_count" in ProjectionExpression
in query_kwargs, and when iterating items parse pk as before, read view_count =
int(item.get("view_count", 0)) and add it to entity_totals[entity_id]; only
append entity IDs to unique_ids (or build a sorted final list) once their totals
are accumulated and you have enough unique entities; also remove the early "if
not items: break" so pagination continues when Items is empty but
response.get("LastEvaluatedKey") exists (still break only when no
LastEvaluatedKey or pages >= max_pages).

---

Nitpick comments:
In `@tcf_website/views/catalog/browse.py`:
- Line 15: The catalog view is tightly coupled to home page code because
browse.py imports get_trending_courses and get_trending_instructors from
..home.pages; extract those functions into a dedicated module (e.g., a new
analytics/trending service) and update import sites to use that service: move
the implementation of get_trending_courses and get_trending_instructors out of
home.pages into the new module, export them from there, then change browse.py
and home.pages to import the functions from the new trending service to remove
the cross-module dependency.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c6edcadb-b446-4da3-9743-21e4a7432d50

📥 Commits

Reviewing files that changed from the base of the PR and between 6d73dd6 and 3907a1c.

📒 Files selected for processing (8)
  • .env.example
  • tcf_website/analytics_utils.py
  • tcf_website/static/css/site/pages/landing.css
  • tcf_website/templates/site/home/landing.html
  • tcf_website/views/catalog/browse.py
  • tcf_website/views/courses/course.py
  • tcf_website/views/courses/course_instructor.py
  • tcf_website/views/home/pages.py

Comment thread .env.example
Comment thread tcf_website/analytics_utils.py Outdated
Comment thread tcf_website/static/css/site/pages/landing.css
Comment thread tcf_website/templates/site/home/landing.html Outdated
Comment thread tcf_website/views/home/pages.py Outdated
Comment thread tcf_website/views/home/pages.py
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tcf_website/views/home/pages.py (1)

1-256: ⚠️ Potential issue | 🟠 Major

Fix ruff formatting to unblock CI.

The CI pipeline reports ruff format --check failed. Run uv run ruff format . locally and commit the result before merge.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tcf_website/views/home/pages.py` around lines 1 - 256, The PR fails ruff
formatting; run the formatter and commit the fixes: run the exact command
suggested (uv run ruff format .) in your repo root, review changes touching the
functions/classes in this file such as get_top_trending_ids,
get_trending_courses, get_trending_instructors, index and AboutView (including
_normalize_member/_normalize_members), save the formatted file, run tests/ruff
--check again, and commit the resulting changes so CI will pass.
🧹 Nitpick comments (2)
tcf_website/views/home/pages.py (2)

97-102: Redundant exclude(number__isnull=True).

Course.number is a non-nullable IntegerField (see tcf_website/models/models.py lines 632-634), so this exclude is a no-op. Consider dropping it for clarity.

♻️ Proposed simplification
     courses = list(
         Course.objects.filter(id__in=course_ids)
         .select_related("subdepartment")
         .exclude(subdepartment__mnemonic="")
-        .exclude(number__isnull=True)
     )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tcf_website/views/home/pages.py` around lines 97 - 102, The query that builds
courses uses
Course.objects.filter(...).select_related("subdepartment").exclude(subdepartment__mnemonic="").exclude(number__isnull=True),
but Course.number is a non-nullable IntegerField so exclude(number__isnull=True)
is a no-op; remove that redundant .exclude(number__isnull=True) from the
expression that assigns courses to simplify the query (look for the
Course.objects.filter(...) call that produces the courses list in
views/home/pages.py).

40-82: LGTM on the trending query.

The fixes from previous reviews are correctly applied: per-entity view_count aggregation via scores_by_id, pagination continues through empty result pages (driven solely by LastEvaluatedKey), view_count is in the ProjectionExpression, and errors are caught at the outer boundary with exc_info=True. ScanIndexForward=False + Limit=20 correctly assumes the EntityIndex GSI is sorted by view_count descending — verify this assumption matches the actual GSI definition in AWS, as there is no schema or IaC definition for EntityIndex in the repository.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tcf_website/views/home/pages.py` around lines 40 - 82, The code assumes the
EntityIndex GSI is sorted by view_count (using ScanIndexForward=False) which may
not match the actual AWS GSI; verify the GSI definition and if its sort key is
not view_count, update the query to use the correct sort key (or remove the
descending assumption) in the query building logic (see query_kwargs/IndexName
"EntityIndex" and ScanIndexForward), or change to a scan/secondary query that
orders by the correct attribute; ensure the ProjectionExpression and
KeyConditionExpression align with the GSI key schema and adjust Query parameters
accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@tcf_website/views/home/pages.py`:
- Around line 1-256: The PR fails ruff formatting; run the formatter and commit
the fixes: run the exact command suggested (uv run ruff format .) in your repo
root, review changes touching the functions/classes in this file such as
get_top_trending_ids, get_trending_courses, get_trending_instructors, index and
AboutView (including _normalize_member/_normalize_members), save the formatted
file, run tests/ruff --check again, and commit the resulting changes so CI will
pass.

---

Nitpick comments:
In `@tcf_website/views/home/pages.py`:
- Around line 97-102: The query that builds courses uses
Course.objects.filter(...).select_related("subdepartment").exclude(subdepartment__mnemonic="").exclude(number__isnull=True),
but Course.number is a non-nullable IntegerField so exclude(number__isnull=True)
is a no-op; remove that redundant .exclude(number__isnull=True) from the
expression that assigns courses to simplify the query (look for the
Course.objects.filter(...) call that produces the courses list in
views/home/pages.py).
- Around line 40-82: The code assumes the EntityIndex GSI is sorted by
view_count (using ScanIndexForward=False) which may not match the actual AWS
GSI; verify the GSI definition and if its sort key is not view_count, update the
query to use the correct sort key (or remove the descending assumption) in the
query building logic (see query_kwargs/IndexName "EntityIndex" and
ScanIndexForward), or change to a scan/secondary query that orders by the
correct attribute; ensure the ProjectionExpression and KeyConditionExpression
align with the GSI key schema and adjust Query parameters accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f7b9f3e8-4718-43b1-986a-a76aef28c249

📥 Commits

Reviewing files that changed from the base of the PR and between 3907a1c and d34947c.

📒 Files selected for processing (6)
  • .env.example
  • docker-compose.yml
  • tcf_website/analytics_utils.py
  • tcf_website/static/css/site/pages/landing.css
  • tcf_website/templates/site/home/landing.html
  • tcf_website/views/home/pages.py
✅ Files skipped from review due to trivial changes (3)
  • docker-compose.yml
  • .env.example
  • tcf_website/static/css/site/pages/landing.css
🚧 Files skipped from review as they are similar to previous changes (1)
  • tcf_website/analytics_utils.py

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

Labels

Feature New feature Performance Performance improvements, refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant