Posthog analytics#14
Conversation
…of backend
1. Authentication
* user_registered: Captures when a new account is created.
* Properties: email, method (password vs. google).
* user_logged_in: Captures every session start.
* Properties: method.
2. Document Management (Resources)
* resource_upload_started: Triggers as soon as a file hits our API.
* Properties: filename, content_type, size_mb, type (notes/syllabus/etc).
* resource_processed: Triggers in the Worker when OCR/Text extraction finishes.
* Properties: num_pages, filename, type.
* resource_processing_failed: Triggers if the AI fails to read the PDF.
* Properties: error (the specific reason it failed).
* resource_deleted: Triggers when a user removes a file.
3. AI Tutor (Solver)
* chat_session_created: Triggers when a new chat history starts.
* ai_question_asked: Triggers for every message sent to the AI.
* Properties: num_resources (how many files the AI is looking at), question_length (char count), delivery_mode.
4. Exam Generator
* paper_format_detected: Triggers when the AI successfully reads a syllabus and extracts a pattern (MCQs, Short Qs, etc).
* paper_generation_started: Triggers when the generation job is queued.
* paper_generated: Triggers in the Worker when the questions are ready.
* Properties: num_questions.
* paper_generation_failed: Triggers if the generator crashes.
* Properties: error.
* paper_pdf_downloaded: Triggers when the user clicks "Export to PDF".
* Properties: mode (Study Guide vs. Question Paper).
…tor, Login, Register, and Solver components
…iews, and resource upload events
…l and Landing page
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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 configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughIntegrates PostHog analytics: adds configuration and clients, initializes SDKs in backend and frontend, and instruments auth, paper/resource lifecycle, solver/chat, background tasks, and multiple frontend UI interactions with event captures. ChangesPostHog Analytics Integration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
backend/app/workers/tasks.py (2)
397-417:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
paper_generation_failedcapture will AttributeError when paper is missing.Same pattern as the resource failure path:
paper_to_failfromscalar_one_or_none()on Line 398 can beNone(paper deleted mid-generation is a real flow here — cancellation in Lines 332–343 transitions the paper out ofpending/generating, and other endpoints can delete it). Line 414 then dereferencespaper_to_fail.user_idand raisesAttributeError, which the bareexcept: passon Lines 420–421 silently swallows. Result: the failure event is never emitted exactly in the concurrent-mutation cases where it matters most.🛡️ Proposed fix
await err_db.commit() - - ph_client.capture("paper_generation_failed", distinct_id=str(paper_to_fail.user_id), properties={ - "paper_id": str(paper_id), - "error": str(e) - }) + + distinct_id = str(paper_to_fail.user_id) if paper_to_fail else str(paper_id) + ph_client.capture("paper_generation_failed", distinct_id=distinct_id, properties={ + "paper_id": str(paper_id), + "error": str(e) + })Separately (out of scope for this PR but worth tracking): replacing the bare
except: passon Lines 420–421 with at least alogger.exception(...)would prevent silently losing any future analytics errors here.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/app/workers/tasks.py` around lines 397 - 417, The capture call can raise AttributeError if paper_to_fail is None; update the error-handling block around res_upd/paper_to_fail and the ph_client.capture call (referencing paper_to_fail, res_upd, ph_client.capture, err_db, Job and j) to guard against a missing paper: after fetching paper_to_fail via res_upd.scalar_one_or_none(), check if paper_to_fail is not None before accessing paper_to_fail.user_id and paper_id in the properties; if it is None, supply a safe fallback distinct_id (e.g. use j.user_id if the Job j exists or a stable string like "unknown") or skip/adjust properties so ph_client.capture is always called with safe values; keep the existing commit of err_db and preserve setting j.status/j.error/j.completed_at as shown.
220-240:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
resource_processing_failedcapture will AttributeError when resource is missing.
res_to_failis the result ofscalar_one_or_none()(Line 221) and may beNone(e.g., the row was deleted concurrently, or it never existed for thisresource_id). The subsequent capture on Line 237 accessesres_to_fail.user_idunconditionally, raisingAttributeError. The surrounding broadexcepton Line 243 then silently swallows it, so the failure event you want to track is lost precisely when something is wrong.Guard the capture, and fall back to the input identifiers when no row is found so you still get a failure event:
🛡️ Proposed fix
await err_db.commit() - - ph_client.capture("resource_processing_failed", distinct_id=str(res_to_fail.user_id), properties={ - "resource_id": str(resource_id), - "error": str(e) - }) + + distinct_id = str(res_to_fail.user_id) if res_to_fail else str(resource_id) + ph_client.capture("resource_processing_failed", distinct_id=distinct_id, properties={ + "resource_id": str(resource_id), + "error": str(e) + })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/app/workers/tasks.py` around lines 220 - 240, The capture call can raise AttributeError because res_to_fail may be None; update the block around res_to_fail and ph_client.capture so you check if res_to_fail is truthy before accessing res_to_fail.user_id, and when it is None fall back to using the input resource_id and a safe distinct_id (e.g., str(resource_id) or None) in ph_client.capture properties; keep the existing updates to the Job (j) and commit logic (res_to_fail, job lookup, j.status/j.error/j.completed_at, await err_db.commit()) but change the distinct_id and properties passed to ph_client.capture to use res_to_fail.user_id only when res_to_fail exists, otherwise use fallback identifiers to avoid AttributeError while still emitting the failure event.
🧹 Nitpick comments (1)
backend/app/main.py (1)
5-5: ⚡ Quick winFlush analytics on app shutdown.
At Line 5, importing
ph_clientinitializes it, but there’s no explicit shutdown/flush hook. Add a FastAPI shutdown handler to call the PostHog client’s close/flush method so events aren’t dropped during restarts.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/app/main.py` at line 5, Importing ph_client in main.py initializes the PostHog client but there’s no shutdown hook to flush events; add a FastAPI shutdown handler (e.g., using `@app.on_event`("shutdown") or app.add_event_handler("shutdown", ...)) in main.py that calls the PostHog client's cleanup method (call ph_client.shutdown() or ph_client.flush() as appropriate for your client version) to ensure events are flushed on app shutdown; reference the existing ph_client import and the FastAPI app instance when adding the handler and handle async vs sync API accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/app/analytics.py`:
- Line 16: Remove any partial key exposure in the print at module
initialization: stop printing settings.POSTHOG_API_KEY (even masked). Replace
the print f-string in backend/app/analytics.py that references
settings.POSTHOG_API_KEY with a generic initialization message (e.g., "✅
[POSTHOG] Initialized") or use the existing logger to log a non-secret
"initialized" message; ensure no part of settings.POSTHOG_API_KEY appears in
logs or stdout.
- Around line 5-9: Change the Posthog client instantiation so it does not enable
verbose SDK logging by default: set the Posthog debug argument to False and wire
it to a new settings flag (e.g. settings.POSTHOG_DEBUG) so debug can only be
enabled via explicit configuration; update the settings/config module to read
POSTHOG_DEBUG from env (defaulting to False) and then construct ph_client with
Posthog(settings.POSTHOG_API_KEY, host=settings.POSTHOG_HOST,
debug=settings.POSTHOG_DEBUG) so sensitive payloads are not logged unless
deliberately turned on.
In `@backend/app/routers/resources.py`:
- Around line 98-104: ph_client.capture("resource_upload_started", ...)
currently runs before the outer try/except that performs cleanup via
storage_service.delete_file(object_name), so if analytics fails after
storage_service.upload_file(...) succeeds you can leave orphaned files; move the
ph_client.capture call into the guarded transactional/cleanup section (the same
try/except that calls storage_service.delete_file) or wrap the capture in its
own local try/except that catches and logs errors but does not re-raise, making
the analytics call best-effort while ensuring
storage_service.delete_file(object_name) always runs.
In `@backend/app/routers/solver.py`:
- Line 251: The SSE response is using an invalid MIME type; update the
StreamingResponse call in solver.py (the return that wraps event_generator()) to
use the correct SSE content type "text/event-stream" instead of
"text_event-stream", and revert any accompanying change or comment that labeled
the incorrect value as a correction so the code and any summary reflect the
proper SSE MIME type; ensure the symbol StreamingResponse(event_generator()) is
the one modified.
In `@backend/requirements.txt`:
- Around line 22-23: The requirements file contains a duplicated dependency
entry for the package "posthog"; remove the extra "posthog" line so only a
single entry remains and verify there are no other duplicate package names in
requirements.txt to avoid install conflicts.
In `@frontend/src/pages/Generator.tsx`:
- Line 152: The code currently sends raw user-entered `title` to analytics via
the trackEvent call in Generator.tsx; change it to send non-sensitive metadata
instead (e.g., titleLength: title.length, template or category identifiers,
boolean flags like isCustomTitle) and remove the raw `title` field; update the
callsite that invokes trackEvent('paper_generation_clicked', ...) so it passes a
metadata object (refer to the trackEvent usage and the local `title` variable)
rather than the free-form title string.
- Line 159: The analytics call may send a stale upgradeMessage because
setUpgradeMessage(...) is asynchronous; create the upgrade text in a local
variable inside the handler (e.g., const msg = "..."), call
setUpgradeMessage(msg), and then pass that same msg to
trackEvent('limit_reached_modal_viewed', { feature: 'generator', message: msg })
so both state and analytics use the exact same resolved string; update the code
paths in Generator.tsx where setUpgradeMessage and trackEvent are called to use
the local variable instead of reading upgradeMessage state.
In `@frontend/src/pages/Register.tsx`:
- Line 57: The analytics call trackEvent('registration_success', { email:
data.email }) is sending raw PII; remove the direct email from the payload and
replace it with a non-PII value (or omit payload entirely). Update the call in
Register.tsx (the trackEvent invocation for 'registration_success') to either
send no properties, send a generic flag like { created: true }, or send a
hashed/anonymized identifier (e.g., a one-way hash or userId) instead of
data.email to preserve privacy/compliance.
In `@frontend/src/pages/Resources.tsx`:
- Line 99: The call to trackEvent('limit_reached_modal_viewed', { feature:
'resources', message: upgradeMessage }) can capture a stale upgradeMessage
because React state updates (setUpgradeMessage) haven't occurred yet; fix by
creating a local const (e.g., const message = '<computed message>' or derived
value) before calling setUpgradeMessage, use that local message when calling
trackEvent and then call setUpgradeMessage(message) so trackEvent and state
setter use the same, up-to-date value; update references in the Resources
component around trackEvent, upgradeMessage, and setUpgradeMessage accordingly.
In `@frontend/src/pages/Solver.tsx`:
- Line 193: The analytics call may read the stale upgradeMessage state because
setUpgradeMessage(...) is async; compute the upgrade message into a local
variable (e.g., message) inside the Solver component where you build the string,
call setUpgradeMessage(message), then call
trackEvent('limit_reached_modal_viewed', { feature: 'solver', message }) so
trackEvent receives the exact message shown in the modal; update references
around setUpgradeMessage and the trackEvent call accordingly.
---
Outside diff comments:
In `@backend/app/workers/tasks.py`:
- Around line 397-417: The capture call can raise AttributeError if
paper_to_fail is None; update the error-handling block around
res_upd/paper_to_fail and the ph_client.capture call (referencing paper_to_fail,
res_upd, ph_client.capture, err_db, Job and j) to guard against a missing paper:
after fetching paper_to_fail via res_upd.scalar_one_or_none(), check if
paper_to_fail is not None before accessing paper_to_fail.user_id and paper_id in
the properties; if it is None, supply a safe fallback distinct_id (e.g. use
j.user_id if the Job j exists or a stable string like "unknown") or skip/adjust
properties so ph_client.capture is always called with safe values; keep the
existing commit of err_db and preserve setting j.status/j.error/j.completed_at
as shown.
- Around line 220-240: The capture call can raise AttributeError because
res_to_fail may be None; update the block around res_to_fail and
ph_client.capture so you check if res_to_fail is truthy before accessing
res_to_fail.user_id, and when it is None fall back to using the input
resource_id and a safe distinct_id (e.g., str(resource_id) or None) in
ph_client.capture properties; keep the existing updates to the Job (j) and
commit logic (res_to_fail, job lookup, j.status/j.error/j.completed_at, await
err_db.commit()) but change the distinct_id and properties passed to
ph_client.capture to use res_to_fail.user_id only when res_to_fail exists,
otherwise use fallback identifiers to avoid AttributeError while still emitting
the failure event.
---
Nitpick comments:
In `@backend/app/main.py`:
- Line 5: Importing ph_client in main.py initializes the PostHog client but
there’s no shutdown hook to flush events; add a FastAPI shutdown handler (e.g.,
using `@app.on_event`("shutdown") or app.add_event_handler("shutdown", ...)) in
main.py that calls the PostHog client's cleanup method (call
ph_client.shutdown() or ph_client.flush() as appropriate for your client
version) to ensure events are flushed on app shutdown; reference the existing
ph_client import and the FastAPI app instance when adding the handler and handle
async vs sync API accordingly.
🪄 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: 9cb22d19-b5ec-4066-b85e-13bb2d7bb3d5
⛔ Files ignored due to path filters (1)
frontend/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (22)
.env.examplebackend/app/analytics.pybackend/app/config.pybackend/app/main.pybackend/app/routers/auth.pybackend/app/routers/papers.pybackend/app/routers/resources.pybackend/app/routers/solver.pybackend/app/workers/tasks.pybackend/requirements.txtfrontend/.env.examplefrontend/package.jsonfrontend/src/App.tsxfrontend/src/components/UpgradeModal.tsxfrontend/src/lib/analytics.tsfrontend/src/main.tsxfrontend/src/pages/Generator.tsxfrontend/src/pages/Landing.tsxfrontend/src/pages/Login.tsxfrontend/src/pages/Register.tsxfrontend/src/pages/Resources.tsxfrontend/src/pages/Solver.tsx
| ph_client = Posthog( | ||
| settings.POSTHOG_API_KEY, | ||
| host=settings.POSTHOG_HOST, | ||
| debug=True # Helpful for debugging delivery issues | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the referenced file and surrounding context
sed -n '1,120p' backend/app/analytics.py | nl -ba
# Search for other Posthog initialization / debug flags
rg -n "Posthog\\(|debug\\s*=\\s*True|POSTHOG" backend -S || true
# Show settings related to Posthog if present
rg -n "POSTHOG_(API_KEY|HOST)" -S . || true
rg -n "class Settings|settings\\." backend -S || trueRepository: shubhamxdd/pyq-appl
Length of output: 106
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the referenced file with line numbers (nl not available)
awk '{printf "%6d\t%s\n", NR, $0}' backend/app/analytics.py | sed -n '1,160p'
# Search for other Posthog initialization / debug flags
rg -n "Posthog\\(" backend -S || true
rg -n "debug\\s*=\\s*True|debug\\s*=\\s*false|POSTHOG" backend -S || true
# Search for settings definitions / env flags around POSTHOG
rg -n "POSTHOG_(API_KEY|HOST|DEBUG)|posthog" backend -S -i || true
rg -n "class Settings|BaseSettings|settings\\s*=" backend -S || trueRepository: shubhamxdd/pyq-appl
Length of output: 2374
🏁 Script executed:
#!/bin/bash
set -euo pipefail
awk '{printf "%6d\t%s\n", NR, $0}' backend/app/config.py | sed -n '1,140p'Repository: shubhamxdd/pyq-appl
Length of output: 1449
🏁 Script executed:
#!/bin/bash
set -euo pipefail
awk '{printf "%6d\t%s\n", NR, $0}' backend/app/config.py | sed -n '1,140p'Repository: shubhamxdd/pyq-appl
Length of output: 1449
🌐 Web query:
PostHog Python Posthog debug parameter what does debug=True do logs payloads
💡 Result:
In the PostHog Python SDK, setting debug=True enables verbose logging, which helps troubleshoot issues with event capturing, feature flags, or survey rendering [1]. When enabled, the SDK changes the logging level of the posthog logger to DEBUG [2]. This causes the library to output internal operational logs to the standard logging output [1][2]. Specifically, enabling debug=True performs the following actions: - It configures the logger by calling logging.basicConfig() [2]. - It sets the log level for the posthog logger to logging.DEBUG (instead of the default logging.WARNING) [2]. - This allows you to see detailed information about the SDK's internal processes [1], which can include information regarding the processing and sending of payloads, helping you verify if events or configurations are being handled as expected [1]. You can enable this mode during client initialization or by setting the attribute directly on the client instance: python # During initialization from posthog import Posthog posthog = Posthog('<ph_project_token>', debug=True) # Or by setting the attribute posthog.debug = True If you are not seeing expected data appear in your PostHog instance, this mode is the recommended way to inspect the SDK's activity and identify why events might not be reaching the server [1].
Citations:
- 1: https://posthog.com/docs/libraries/python
- 2: https://github.com/PostHog/posthog-python/blob/master/posthog/client.py
Disable PostHog debug mode by default.
debug=True in backend/app/analytics.py turns on the PostHog SDK’s verbose logging (sets the posthog logger to DEBUG), which can cause sensitive event/payload processing details to end up in server logs. Default debug to False and gate it behind an explicit settings/env flag (the current backend/app/config.py has POSTHOG_API_KEY/POSTHOG_HOST only, with no debug toggle).
ph_client = Posthog(
settings.POSTHOG_API_KEY,
host=settings.POSTHOG_HOST,
debug=True
)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@backend/app/analytics.py` around lines 5 - 9, Change the Posthog client
instantiation so it does not enable verbose SDK logging by default: set the
Posthog debug argument to False and wire it to a new settings flag (e.g.
settings.POSTHOG_DEBUG) so debug can only be enabled via explicit configuration;
update the settings/config module to read POSTHOG_DEBUG from env (defaulting to
False) and then construct ph_client with Posthog(settings.POSTHOG_API_KEY,
host=settings.POSTHOG_HOST, debug=settings.POSTHOG_DEBUG) so sensitive payloads
are not logged unless deliberately turned on.
| ph_client.capture("resource_upload_started", distinct_id=str(current_user.id), properties={ | ||
| "filename": file.filename, | ||
| "content_type": file.content_type, | ||
| "size_mb": total_size / (1024 * 1024), | ||
| "type": type | ||
| }) | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show the relevant portion of the file with line numbers
sed -n '70,140p' backend/app/routers/resources.py | nl -ba -w3 -s': '
# Also find where the upload/try/cleanup block is defined in this file
rg -n "try:|except:|finally:|cleanup|rollback|delete|remove|capture\\(" backend/app/routers/resources.py
# Show the exact ph_client usage context (a bit wider)
rg -n "ph_client\\.capture" -n backend/app/routers/resources.pyRepository: shubhamxdd/pyq-appl
Length of output: 106
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== resources.py (lines ~1-220) with line numbers) ==="
# Use cat -n instead of nl (nl is missing in the sandbox)
sed -n '1,220p' backend/app/routers/resources.py | cat -n -w3 -s': '
echo "=== Search for upload/try/cleanup/rollback and capture usage ==="
rg -n "ph_client\\.capture|try:|except:|finally:|cleanup|rollback|delete|remove|filesystem|storage|upload" backend/app/routers/resources.pyRepository: shubhamxdd/pyq-appl
Length of output: 202
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== resources.py: lines 60-140 (with line numbers) ==="
sed -n '60,140p' backend/app/routers/resources.py | cat -n
echo "=== Exact ph_client.capture call contexts ==="
rg -n "ph_client\.capture" backend/app/routers/resources.py
echo "=== Surrounding try/except/finally around capture (context) ==="
# Print a window around the capture line(s)
CAPTURE_LINE="$(rg -n "ph_client\.capture" backend/app/routers/resources.py | head -n1 | cut -d: -f1 || true)"
if [ -n "${CAPTURE_LINE}" ]; then
START=$((CAPTURE_LINE-30))
END=$((CAPTURE_LINE+30))
echo "CAPTURE_LINE=${CAPTURE_LINE}; showing ${START}-${END}"
sed -n "${START},${END}p" backend/app/routers/resources.py | cat -n
fiRepository: shubhamxdd/pyq-appl
Length of output: 6809
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== resources.py: lines 90-170 (capture + surrounding try/except) ==="
sed -n '90,170p' backend/app/routers/resources.py | cat -n
echo "=== resources.py: find storage cleanup/delete/remove calls in this area ==="
rg -n "delete|remove|cleanup|rollback|finally" backend/app/routers/resources.py | head -n 80Repository: shubhamxdd/pyq-appl
Length of output: 4139
Move ph_client.capture inside the transactional/cleanup block (best-effort)
ph_client.capture("resource_upload_started", ...) runs before the outer try/except that cleans up storage via storage_service.delete_file(object_name). If analytics throws after storage_service.upload_file(...) succeeds, the function will exit without that cleanup, leaving orphaned files in storage. Wrap the capture in the guarded section (or add a local try/except around it) and make it best-effort.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@backend/app/routers/resources.py` around lines 98 - 104,
ph_client.capture("resource_upload_started", ...) currently runs before the
outer try/except that performs cleanup via
storage_service.delete_file(object_name), so if analytics fails after
storage_service.upload_file(...) succeeds you can leave orphaned files; move the
ph_client.capture call into the guarded transactional/cleanup section (the same
try/except that calls storage_service.delete_file) or wrap the capture in its
own local try/except that catches and logs errors but does not re-raise, making
the analytics call best-effort while ensuring
storage_service.delete_file(object_name) always runs.
| if (error.response?.status === 403) { | ||
| setUpgradeMessage(error.response?.data?.detail || "You've reached your resource storage limit."); | ||
| setIsUpgradeModalOpen(true); | ||
| trackEvent('limit_reached_modal_viewed', { feature: 'resources', message: upgradeMessage }); |
There was a problem hiding this comment.
Fix stale upgradeMessage usage in limit tracking.
Line 99 can log an old message value because state hasn’t updated yet. Use a local message constant before calling setUpgradeMessage.
Suggested fix
onError: (error: any) => {
if (error.response?.status === 403) {
- setUpgradeMessage(error.response?.data?.detail || "You've reached your resource storage limit.");
+ const message = error.response?.data?.detail || "You've reached your resource storage limit.";
+ setUpgradeMessage(message);
setIsUpgradeModalOpen(true);
- trackEvent('limit_reached_modal_viewed', { feature: 'resources', message: upgradeMessage });
+ trackEvent('limit_reached_modal_viewed', { feature: 'resources', message });
} else {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| trackEvent('limit_reached_modal_viewed', { feature: 'resources', message: upgradeMessage }); | |
| onError: (error: any) => { | |
| if (error.response?.status === 403) { | |
| const message = error.response?.data?.detail || "You've reached your resource storage limit."; | |
| setUpgradeMessage(message); | |
| setIsUpgradeModalOpen(true); | |
| trackEvent('limit_reached_modal_viewed', { feature: 'resources', message }); | |
| } else { |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/src/pages/Resources.tsx` at line 99, The call to
trackEvent('limit_reached_modal_viewed', { feature: 'resources', message:
upgradeMessage }) can capture a stale upgradeMessage because React state updates
(setUpgradeMessage) haven't occurred yet; fix by creating a local const (e.g.,
const message = '<computed message>' or derived value) before calling
setUpgradeMessage, use that local message when calling trackEvent and then call
setUpgradeMessage(message) so trackEvent and state setter use the same,
up-to-date value; update references in the Resources component around
trackEvent, upgradeMessage, and setUpgradeMessage accordingly.
| const errData = await response.json(); | ||
| setUpgradeMessage(errData.detail || "You've reached your question limit."); | ||
| setIsUpgradeModalOpen(true); | ||
| trackEvent('limit_reached_modal_viewed', { feature: 'solver', message: upgradeMessage }); |
There was a problem hiding this comment.
Track the same computed message you show in the modal.
Line 193 reads upgradeMessage right after setUpgradeMessage(...), so analytics may receive the previous value. Use a local message variable.
Suggested fix
if (response.status === 403) {
const errData = await response.json();
- setUpgradeMessage(errData.detail || "You've reached your question limit.");
+ const message = errData.detail || "You've reached your question limit.";
+ setUpgradeMessage(message);
setIsUpgradeModalOpen(true);
- trackEvent('limit_reached_modal_viewed', { feature: 'solver', message: upgradeMessage });
+ trackEvent('limit_reached_modal_viewed', { feature: 'solver', message });
setMessages(prev => prev.slice(0, -1));
setIsStreaming(false);
return;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| trackEvent('limit_reached_modal_viewed', { feature: 'solver', message: upgradeMessage }); | |
| if (response.status === 403) { | |
| const errData = await response.json(); | |
| const message = errData.detail || "You've reached your question limit."; | |
| setUpgradeMessage(message); | |
| setIsUpgradeModalOpen(true); | |
| trackEvent('limit_reached_modal_viewed', { feature: 'solver', message }); | |
| setMessages(prev => prev.slice(0, -1)); | |
| setIsStreaming(false); | |
| return; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/src/pages/Solver.tsx` at line 193, The analytics call may read the
stale upgradeMessage state because setUpgradeMessage(...) is async; compute the
upgrade message into a local variable (e.g., message) inside the Solver
component where you build the string, call setUpgradeMessage(message), then call
trackEvent('limit_reached_modal_viewed', { feature: 'solver', message }) so
trackEvent receives the exact message shown in the modal; update references
around setUpgradeMessage and the trackEvent call accordingly.
text_event-stream is not a valid MIME type. The SSE spec (and EventSource) requires text/event-stream; with an underscore and no /, browsers/proxies won't recognize the response as SSE, causing clients that expect Content-Type: text/event-stream to fail (and intermediaries may buffer the stream, defeating real-time delivery). The cohort summary describing this as a "correction" appears inverted — please revert. Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…cker documentation
Summary by CodeRabbit
New Features
Chores