Skip to content

UMS Task: https://katha.shikshalokam.org/story-view-1885.html - #7

Merged
kiranharidas187 merged 6 commits into
ELEVATE-Project:release-1.0.0from
darshilbabel:feature/ums
Jun 29, 2026
Merged

UMS Task: https://katha.shikshalokam.org/story-view-1885.html#7
kiranharidas187 merged 6 commits into
ELEVATE-Project:release-1.0.0from
darshilbabel:feature/ums

Conversation

@KUNALTEMPEST

@KUNALTEMPEST KUNALTEMPEST commented Jun 19, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for passing Elevate profile context through the chat flow.
    • Added OpenRouter as a supported LLM provider option.
  • Bug Fixes

    • Improved WebSocket stability during disconnect and tightened authentication/error handling.
    • Refined company-bot selection to use the profile’s company when available.
    • Standardized Elevate profile fetch behavior and reduced debug/noisy output.
  • Other Changes

    • Updated profile-related API response to return a smaller set of fields.
    • Streamlined onboarding context persistence and updated profile/bot uniqueness rules and related constraints.

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@KUNALTEMPEST, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 19 minutes and 58 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b9a48f49-318c-4e61-b1fc-c7aaa2e4eed3

📥 Commits

Reviewing files that changed from the base of the PR and between d64d1d1 and 3718bfc.

📒 Files selected for processing (3)
  • chatbot/consumers/async_consumer.py
  • chatbot/models/profile_models.py
  • chatbot/utils/elevate/profile_utils.py

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR threads Elevate UMS profile data through websocket authentication, chat service execution, and profile-related endpoints. It also relaxes profile constraints, updates onboarding persistence, and adds bot vernacular uniqueness rules.

Changes

Elevate UMS Profile Integration

Layer / File(s) Summary
Profile model and schema changes
chatbot/models/profile_models.py, chatbot/migrations/0086_alter_profile_unique_together_and_more.py, chatbot/migrations/0087_remove_profile_chatbot_pro_userid_3d404e_idx_and_more.py, observability/migrations/0009_alter_companybottcrun_provider_and_more.py, chatbot/admin/profile_admin.py
Profile allows nullable company/email values, userid grows to 500, conditional uniqueness replaces unique_together, and related migrations update provider choices and indexes. Admin filtering adds userid.
Bot vernacular uniqueness
chatbot/models/bot_vernacular_model.py, chatbot/migrations/0088_remove_botvernacular_bot_vernacu_company_483975_idx_and_more.py
BotVernacular replaces its company_bot index with a unique constraint on (company_bot, language), and the migration removes the old index and adds the constraint.
Elevate profile fetch rewrite
chatbot/utils/elevate/profile_utils.py
handle_elevate_profile adds structured logging, safe body handling, explicit HTTP responses, minimal userid-keyed persistence, and a new ums_profile-shaped return payload.
WebSocket Elevate authentication
chatbot/consumers/async_consumer.py, chatbot/consumers/async_base_consumer.py
AsyncSocketConsumer stores ums_profile, resolves Elevate profile data during authenticate, closes early on Elevate errors, forwards ums_profile into the Celery flow task, and tightens JWT and disconnect handling. Base consumer close and company-bot lookup guards are also updated.
ums_profile through chat services
chatbot/celery_tasks/flow_tasks.py, chatbot/services/core/orchestrator.py, chatbot/services/core/prompt_builder.py, chatbot/services/core/base_service.py
get_flow_response, process_chat_request, build_system_prompt, and get_session_data accept ums_profile, propagate it into response parameters, and suppress address derivation when ums_profile is present. Orchestrator exception handling now relies on logger.error(..., exc_info=True).
Onboarding context update
chatbot/services/response_handlers/common_handler.py
submit_user_context now marks onboarding completion in profile.other_params, sends district and state to Elevate, stops writing those fields to local ProfileAddress, and updates the related docstring and unknown-function logging.
Profile endpoint responses
chatbot/views/api_views.py, shikshalokam/views/profile_views.py, chatbot/views/profile_views.py
get_profile_view returns a reduced success payload, and read_elevate_profile now validates DEFAULT_COMPANY_SLUG, handles Elevate errors through returned status codes, and emits a curated success response. The commented-out profile view block is removed.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • ELEVATE-Project/saathi-backend#3: Touches the same Elevate/profile integration path, including handle_elevate_profile and related profile flow code.
  • ELEVATE-Project/saathi-backend#2: Modifies ChatOrchestrator.process_chat_request and PromptBuilder.build_system_prompt, which this PR extends with ums_profile propagation.

Poem

🐇 Hop-hop, the profiles shift and glow,
UMS winds through the backend flow.
A carrot of logs, nice and neat,
No noisy prints from ear to feet.
The bunny beams with schema cheer,
And Elevate hums now crystal-clear.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title points to a task link and generic UMS wording, but does not describe the actual code changes. Replace it with a short, specific summary of the main implementation change, such as UMS profile handling or flow orchestration updates.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@KUNALTEMPEST KUNALTEMPEST changed the title Feature/ums Do not merge for now Jun 19, 2026
@KUNALTEMPEST

Copy link
Copy Markdown
Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (2)
chatbot/services/response_handlers/common_handler.py (1)

845-863: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Persist onboarding completion only after Elevate profile sync succeeds.

Line 846-Line 849 marks onboarding complete before the Elevate write at Line 853-Line 860, and the Elevate result is ignored. Since district/state are no longer stored locally, a failed update_elevate_profile(...) can silently drop submitted profile context while is_onboarding_completed is already True.

Proposed fix
-            other_params = profile.other_params or {}
-            other_params['is_onboarding_completed'] = True
-            profile.other_params = other_params
-            profile.save(update_fields=['other_params'])
-            logger.info('[submit_user_context] marked onboarding complete for profile id=%s', profile_id)
-
-            if access_token:
+            elevate_synced = True
+            if access_token:
                 from chatbot.utils.elevate.profile_utils import update_elevate_profile
-                update_elevate_profile(
+                elevate_resp = update_elevate_profile(
                     access_token=access_token,
                     name=arguments.get('name'),
                     role=arguments.get('role'),
                     school_name=arguments.get('school_name'),
                     district=arguments.get('district'),
                     state=arguments.get('state'),
                 )
+                elevate_synced = bool(elevate_resp)
+
+            if not elevate_synced:
+                logger.error('[submit_user_context] elevate sync failed; onboarding not marked complete for id=%s', profile_id)
+                return
+
+            other_params = profile.other_params or {}
+            other_params['is_onboarding_completed'] = True
+            profile.other_params = other_params
+            profile.save(update_fields=['other_params'])
+            logger.info('[submit_user_context] marked onboarding complete for profile id=%s', profile_id)
🤖 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 `@chatbot/services/response_handlers/common_handler.py` around lines 845 - 863,
The onboarding completion is being persisted to the profile before the
update_elevate_profile call completes. If update_elevate_profile fails,
is_onboarding_completed is already set to True while the profile context may not
have been synced to Elevate. Move the profile.other_params assignment and
profile.save(update_fields=['other_params']) call to execute after the
successful completion of update_elevate_profile, ensuring that onboarding is
only marked complete when the Elevate profile sync succeeds.
chatbot/models/profile_models.py (1)

17-20: ⚠️ Potential issue | 🟡 Minor

Remove or clarify the unused get_file_upload_path method.

The method at lines 17–20 is never used by any FileField in the Profile model and appears to be dead code. Additionally, if it were called, it would crash when company is None (line 18: self.company.slug) since the field is now nullable (line 32). Either remove this method or document why it's retained.

🤖 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 `@chatbot/models/profile_models.py` around lines 17 - 20, The
`get_file_upload_path` method is unused dead code that will crash when the
company field is None (since it attempts to access self.company.slug without
null checking). Either remove this method entirely if it is not needed, or if
you must retain it, add a null check for self.company before accessing its slug
attribute and include a clear comment documenting the intended use case and why
it is being kept despite not currently being referenced by any FileField.
🧹 Nitpick comments (4)
shikshalokam/views/profile_views.py (1)

24-50: ⚡ Quick win

Fail fast on DEFAULT_COMPANY_SLUG before calling Elevate.

Line 47-Line 50 checks configuration after the Elevate call at Line 24. If env is misconfigured, this endpoint still does external work and then returns 500 on every request.

Proposed refactor
-    profile_details = handle_elevate_profile(access_token=access_token)
+    company_slug = os.getenv('DEFAULT_COMPANY_SLUG')
+    if not company_slug:
+        logger.error('[read_elevate_profile] DEFAULT_COMPANY_SLUG is not set')
+        return Response({'status': 'error', 'message': 'Server misconfiguration.'}, status=500)
+
+    profile_details = handle_elevate_profile(access_token=access_token)
@@
-    company_slug = os.getenv('DEFAULT_COMPANY_SLUG')
-    if not company_slug:
-        logger.error('[read_elevate_profile] DEFAULT_COMPANY_SLUG is not set')
-        return Response({'status': 'error', 'message': 'Server misconfiguration.'}, status=500)
-
🤖 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 `@shikshalokam/views/profile_views.py` around lines 24 - 50, The
DEFAULT_COMPANY_SLUG environment variable check is occurring after the expensive
handle_elevate_profile external API call, causing unnecessary work when the
configuration is misconfigured. Move the DEFAULT_COMPANY_SLUG validation logic
(which checks if the environment variable exists and returns a 500 error if not)
to the beginning of the function before calling handle_elevate_profile, so the
endpoint fails fast without making external API calls when the required
configuration is missing.
chatbot/consumers/async_consumer.py (1)

62-72: ⚡ Quick win

Elevate profile fetch is called even when access_token is None.

sync_elevate_profile is called unconditionally on line 62. If the client doesn't provide an access_token, this will make a request to Elevate with a None token in the X-auth-token header, likely returning 401. While this is handled, it's an unnecessary network call.

Consider guarding:

♻️ Proposed optimization
-                elevate_result = await self.sync_elevate_profile(self.access_token)
+                elevate_result = {}
+                if self.access_token:
+                    elevate_result = await self.sync_elevate_profile(self.access_token)
🤖 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 `@chatbot/consumers/async_consumer.py` around lines 62 - 72, The
`sync_elevate_profile` method is called unconditionally on line 62 even when
`self.access_token` is `None`, which results in unnecessary network requests to
the Elevate server that will fail with a 401 response. Add a guard condition to
check if `self.access_token` is not `None` before calling
`sync_elevate_profile`. If the token is `None`, you should return early or
handle the authentication failure directly without making the unnecessary
network request.
chatbot/models/profile_models.py (1)

62-70: ⚖️ Poor tradeoff

Application-level duplicate check is susceptible to race conditions.

Removing the unique_together DB constraint and replacing it with an application-level check in save() allows concurrent requests to create duplicate (email, company_id) profiles if they pass the .exists() check simultaneously before either commits.

If duplicates must be prevented reliably, consider adding a partial unique index at the database level for the traditional flow:

CREATE UNIQUE INDEX profile_email_company_uniq 
ON chatbot_profile (email, company_id) 
WHERE userid IS NULL;

Alternatively, accept that duplicates are rare and handle them via error recovery.

🤖 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 `@chatbot/models/profile_models.py` around lines 62 - 70, The duplicate check
in the Profile save() method using the .exists() query is vulnerable to race
conditions where concurrent requests can both pass the check before either
commits. To fix this reliably, add a database-level constraint by creating a
migration that adds a partial unique index on the (email, company_id) columns
where userid IS NULL. Alternatively, remove the application-level check in
save() and wrap the super().save() call in a try-except block to catch
IntegrityError exceptions (which would be raised by the database constraint),
then handle the error appropriately by raising a ValueError with a user-friendly
message or logging the conflict.
chatbot/consumers/async_base_consumer.py (1)

39-42: 💤 Low value

Consider logging the swallowed exception for debugging.

Silently swallowing exceptions makes debugging harder. While the intent (avoiding double-close errors) is valid, logging at debug level would help diagnose unexpected issues.

♻️ Proposed improvement
         finally:
             try:
                 await self.close()
-            except Exception:
-                pass
+            except Exception as e:
+                logger.debug('close() raised during disconnect: %s', 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 `@chatbot/consumers/async_base_consumer.py` around lines 39 - 42, The exception
handler for the `await self.close()` call in the try-except block is silently
swallowing the exception with `pass`, which makes debugging difficult. Add a
debug-level logging statement in the except Exception block to capture and log
the exception details before the pass statement, so that unexpected errors
during the close operation can be investigated if needed.

Source: Linters/SAST tools

🤖 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 `@chatbot/consumers/async_consumer.py`:
- Around line 191-206: Rename the variable JWT_PUBLIC_KEY to JWT_SECRET_KEY (or
JWT_SYMMETRIC_SECRET) throughout the codebase to accurately reflect that HS256
is a symmetric HMAC algorithm requiring a shared secret key, not a public key.
This includes updating the reference in the handle_access_token function where
it checks PUBLIC_KEY and in any configuration or environment variable
definitions. Additionally, locate and correct the misleading comment in
free_flow_consumer.py around line 160 that incorrectly references RS256 to
instead reference HS256, ensuring consistency with the actual algorithm
implementation at line 166.

In `@chatbot/services/core/base_service.py`:
- Around line 17-20: The CompanyBot model lacks a uniqueness constraint on the
route field, causing the fallback route-only lookup in the conditional block to
be unsafe in multi-tenant scenarios. Add a unique_together constraint to the
CompanyBot.Meta class that enforces uniqueness on the combination of company and
route fields, ensuring that the database prevents duplicate route values within
the same company. If a global route uniqueness is required instead, use
unique=True on the route field. Alternatively, if company context should always
be required, replace the fallback else block with a raise ValueError statement
instead of attempting the unsafe route-only get() lookup.

In `@chatbot/services/core/prompt_builder.py`:
- Around line 15-17: The address assignment in the prompt builder uses a
truthiness check on ums_profile which fails for empty dictionaries, causing the
code to incorrectly fall back to ProfileAddress lookup. Replace the truthiness
check `if ums_profile` with an explicit None check `if ums_profile is not None`
in the ternary conditional that assigns the address variable. This ensures that
even empty ums_profile dictionaries are properly recognized and prevent the
unwanted fallback to the profile.profile_address.all().first() lookup.

In `@chatbot/utils/elevate/profile_utils.py`:
- Around line 17-23: The handle_elevate_profile function constructs a URL using
elevate_base_url without verifying it has been properly set from the
ELEVATE_BASE_URL environment variable. Add a guard at the beginning of the
function to check if elevate_base_url is None, and raise a clear exception with
a descriptive error message indicating that the ELEVATE_BASE_URL environment
variable is not configured, rather than allowing the function to proceed and
create a malformed URL that results in confusing requests errors.

---

Outside diff comments:
In `@chatbot/models/profile_models.py`:
- Around line 17-20: The `get_file_upload_path` method is unused dead code that
will crash when the company field is None (since it attempts to access
self.company.slug without null checking). Either remove this method entirely if
it is not needed, or if you must retain it, add a null check for self.company
before accessing its slug attribute and include a clear comment documenting the
intended use case and why it is being kept despite not currently being
referenced by any FileField.

In `@chatbot/services/response_handlers/common_handler.py`:
- Around line 845-863: The onboarding completion is being persisted to the
profile before the update_elevate_profile call completes. If
update_elevate_profile fails, is_onboarding_completed is already set to True
while the profile context may not have been synced to Elevate. Move the
profile.other_params assignment and profile.save(update_fields=['other_params'])
call to execute after the successful completion of update_elevate_profile,
ensuring that onboarding is only marked complete when the Elevate profile sync
succeeds.

---

Nitpick comments:
In `@chatbot/consumers/async_base_consumer.py`:
- Around line 39-42: The exception handler for the `await self.close()` call in
the try-except block is silently swallowing the exception with `pass`, which
makes debugging difficult. Add a debug-level logging statement in the except
Exception block to capture and log the exception details before the pass
statement, so that unexpected errors during the close operation can be
investigated if needed.

In `@chatbot/consumers/async_consumer.py`:
- Around line 62-72: The `sync_elevate_profile` method is called unconditionally
on line 62 even when `self.access_token` is `None`, which results in unnecessary
network requests to the Elevate server that will fail with a 401 response. Add a
guard condition to check if `self.access_token` is not `None` before calling
`sync_elevate_profile`. If the token is `None`, you should return early or
handle the authentication failure directly without making the unnecessary
network request.

In `@chatbot/models/profile_models.py`:
- Around line 62-70: The duplicate check in the Profile save() method using the
.exists() query is vulnerable to race conditions where concurrent requests can
both pass the check before either commits. To fix this reliably, add a
database-level constraint by creating a migration that adds a partial unique
index on the (email, company_id) columns where userid IS NULL. Alternatively,
remove the application-level check in save() and wrap the super().save() call in
a try-except block to catch IntegrityError exceptions (which would be raised by
the database constraint), then handle the error appropriately by raising a
ValueError with a user-friendly message or logging the conflict.

In `@shikshalokam/views/profile_views.py`:
- Around line 24-50: The DEFAULT_COMPANY_SLUG environment variable check is
occurring after the expensive handle_elevate_profile external API call, causing
unnecessary work when the configuration is misconfigured. Move the
DEFAULT_COMPANY_SLUG validation logic (which checks if the environment variable
exists and returns a 500 error if not) to the beginning of the function before
calling handle_elevate_profile, so the endpoint fails fast without making
external API calls when the required configuration is missing.
🪄 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: 8224272d-9ea3-4b72-8f4c-12f5da646cc5

📥 Commits

Reviewing files that changed from the base of the PR and between 63f4655 and baad02b.

📒 Files selected for processing (14)
  • chatbot/celery_tasks/flow_tasks.py
  • chatbot/consumers/async_base_consumer.py
  • chatbot/consumers/async_consumer.py
  • chatbot/migrations/0086_alter_profile_unique_together_and_more.py
  • chatbot/models/profile_models.py
  • chatbot/services/core/base_service.py
  • chatbot/services/core/orchestrator.py
  • chatbot/services/core/prompt_builder.py
  • chatbot/services/response_handlers/common_handler.py
  • chatbot/utils/elevate/profile_utils.py
  • chatbot/views/api_views.py
  • chatbot/views/profile_views.py
  • observability/migrations/0009_alter_companybottcrun_provider_and_more.py
  • shikshalokam/views/profile_views.py
💤 Files with no reviewable changes (1)
  • chatbot/views/profile_views.py

Comment thread chatbot/consumers/async_consumer.py
Comment thread chatbot/services/core/base_service.py
Comment thread chatbot/services/core/prompt_builder.py
Comment thread chatbot/utils/elevate/profile_utils.py Outdated
@KUNALTEMPEST

Copy link
Copy Markdown
Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@KUNALTEMPEST

Copy link
Copy Markdown
Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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 `@chatbot/consumers/async_consumer.py`:
- Around line 60-77: The sync_elevate_profile method is being called
unconditionally at line 62 regardless of whether self.access_token exists, which
causes non-Elevate flows without a token to fail with authentication errors.
Wrap the entire sync_elevate_profile call and its associated error handling
blocks (lines 62-75) in a conditional check that only executes when
self.access_token is truthy, allowing non-Elevate sessions without tokens to
proceed past the authentication step and reach the get_profile call on line 77.

In `@chatbot/models/profile_models.py`:
- Around line 62-77: The Profile model's Meta class has data-integrity gaps that
allow duplicate `userid` values and race-condition vulnerabilities in the
email/company_id uniqueness check. In the Meta class of the Profile model,
replace the current indexes list with a combination of a regular index on fields
email and phone, plus two UniqueConstraint definitions: one for userid with a
condition that userid is not null to prevent duplicates while allowing null
values, and another for the email and company_id combination with a condition
that userid is null and email is not null to ensure this constraint only applies
to traditional flow profiles. This moves validation from the error-prone save()
method checks to database-level enforcement, while keeping the save() method
checks as pre-validation only.

In `@shikshalokam/views/profile_views.py`:
- Around line 26-31: The error handling in the Elevate profile check is using
500 (Internal Server Error) as the fallback status code when status_code is not
provided, but 500 incorrectly represents a local server issue. For upstream
dependency failures like Elevate service outages, use 502 (Bad Gateway) as the
appropriate fallback to correctly indicate an external service failure. In the
Response return statement within the 'elevate_server_error' condition, change
the fallback value in the status parameter from 500 to 502 so that
profile_details.get('status_code') or 502 is used instead.
- Around line 17-43: The function calls handle_elevate_profile() without first
validating local preconditions, which causes unnecessary upstream calls and
potential data persistence when those preconditions aren't met. Move the
DEFAULT_COMPANY_SLUG environment variable check that currently happens after the
handle_elevate_profile() call (around line 39) to execute BEFORE the
handle_elevate_profile() call at line 17. Additionally, add a validation check
for the access_token parameter itself before calling handle_elevate_profile() to
ensure the token exists and is valid before making the upstream call. This
ensures all local preconditions are validated first, preventing wasted Elevate
service calls and Profile object updates when the request is missing required
configuration or credentials.
🪄 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: 23073713-d330-4f66-be6e-7c10dac8231d

📥 Commits

Reviewing files that changed from the base of the PR and between 428fe4f and c246c9f.

📒 Files selected for processing (14)
  • chatbot/celery_tasks/flow_tasks.py
  • chatbot/consumers/async_base_consumer.py
  • chatbot/consumers/async_consumer.py
  • chatbot/migrations/0086_alter_profile_unique_together_and_more.py
  • chatbot/models/profile_models.py
  • chatbot/services/core/base_service.py
  • chatbot/services/core/orchestrator.py
  • chatbot/services/core/prompt_builder.py
  • chatbot/services/response_handlers/common_handler.py
  • chatbot/utils/elevate/profile_utils.py
  • chatbot/views/api_views.py
  • chatbot/views/profile_views.py
  • observability/migrations/0009_alter_companybottcrun_provider_and_more.py
  • shikshalokam/views/profile_views.py
💤 Files with no reviewable changes (1)
  • chatbot/views/profile_views.py
🚧 Files skipped from review as they are similar to previous changes (6)
  • chatbot/services/core/prompt_builder.py
  • chatbot/services/core/base_service.py
  • chatbot/views/api_views.py
  • chatbot/celery_tasks/flow_tasks.py
  • chatbot/services/core/orchestrator.py
  • chatbot/services/response_handlers/common_handler.py

Comment thread chatbot/consumers/async_consumer.py
Comment thread chatbot/models/profile_models.py
Comment thread shikshalokam/views/profile_views.py Outdated
Comment thread shikshalokam/views/profile_views.py Outdated
@KUNALTEMPEST

Copy link
Copy Markdown
Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
chatbot/admin/profile_admin.py (1)

42-49: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid list_filter on the high-cardinality userid; use search_fields instead.

userid is a free-text CharField(max_length=500) with one (near-)unique value per row. As a list_filter it renders Django's AllValuesFieldListFilter, which runs a SELECT DISTINCT userid over the whole Profile table on every list-page render and produces an unusable dropdown containing every userid. Filtering by an identifier like this belongs in search_fields.

♻️ Proposed change
     list_filter = (
         CustomAdvanceDateFilter,
         'email',
-        'userid',
         'phone',
         ProfileCompanyFilter,
         'profile_type'
     )
     actions = ['export_selected']
     inlines = [ProfileAddressInline, ProfileMediaInline]
-    search_fields = ['first_name', 'email', 'phone']
+    search_fields = ['first_name', 'email', 'phone', 'userid']
🤖 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 `@chatbot/admin/profile_admin.py` around lines 42 - 49, Remove `userid` from
the list_filter tuple in the ProfileAdmin class (the tuple starting at line 42
and containing CustomAdvanceDateFilter, email, userid, phone,
ProfileCompanyFilter, and profile_type) and instead add userid to a
search_fields attribute in the same ProfileAdmin class. This will allow
filtering by userid through search functionality rather than an inefficient
dropdown filter that queries all distinct userid values.
chatbot/migrations/0087_remove_profile_chatbot_pro_userid_3d404e_idx_and_more.py (1)

17-24: 🩺 Stability & Availability | 🔵 Trivial

Verify no pre-existing duplicate userid/(email,company_id) rows before applying these constraints.

AddConstraint(UniqueConstraint(...)) creates partial unique indexes. If production data already contains two rows with the same non-null userid (this column was previously non-unique and written via update_or_create), the migration will fail mid-deploy with an IntegrityError. Same risk for duplicate (email, company_id) where userid IS NULL.

Run a pre-check (and de-dupe if needed) before deploying:

SELECT userid, COUNT(*) FROM chatbot_profile
WHERE userid IS NOT NULL GROUP BY userid HAVING COUNT(*) > 1;

SELECT email, company_id, COUNT(*) FROM chatbot_profile
WHERE userid IS NULL AND email IS NOT NULL
GROUP BY email, company_id HAVING COUNT(*) > 1;
🤖 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
`@chatbot/migrations/0087_remove_profile_chatbot_pro_userid_3d404e_idx_and_more.py`
around lines 17 - 24, Before applying the UniqueConstraint migrations for the
profile model, add a RunPython data migration step that validates there are no
duplicate userid values (where userid IS NOT NULL) or duplicate (email,
company_id) pairs (where userid IS NULL and email IS NOT NULL) in existing data.
Use the provided SQL queries to detect duplicates and either raise an error with
clear instructions for manual remediation or implement deduplication logic that
keeps the most recent or highest priority record. This prevents the
AddConstraint operations on the userid and email-company_id fields from failing
with IntegrityError during deployment.
🤖 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.

Nitpick comments:
In `@chatbot/admin/profile_admin.py`:
- Around line 42-49: Remove `userid` from the list_filter tuple in the
ProfileAdmin class (the tuple starting at line 42 and containing
CustomAdvanceDateFilter, email, userid, phone, ProfileCompanyFilter, and
profile_type) and instead add userid to a search_fields attribute in the same
ProfileAdmin class. This will allow filtering by userid through search
functionality rather than an inefficient dropdown filter that queries all
distinct userid values.

In
`@chatbot/migrations/0087_remove_profile_chatbot_pro_userid_3d404e_idx_and_more.py`:
- Around line 17-24: Before applying the UniqueConstraint migrations for the
profile model, add a RunPython data migration step that validates there are no
duplicate userid values (where userid IS NOT NULL) or duplicate (email,
company_id) pairs (where userid IS NULL and email IS NOT NULL) in existing data.
Use the provided SQL queries to detect duplicates and either raise an error with
clear instructions for manual remediation or implement deduplication logic that
keeps the most recent or highest priority record. This prevents the
AddConstraint operations on the userid and email-company_id fields from failing
with IntegrityError during deployment.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 181be378-e252-4ed5-97bc-5e44562d9355

📥 Commits

Reviewing files that changed from the base of the PR and between c246c9f and 09b2f6d.

📒 Files selected for processing (5)
  • chatbot/admin/profile_admin.py
  • chatbot/consumers/async_consumer.py
  • chatbot/migrations/0087_remove_profile_chatbot_pro_userid_3d404e_idx_and_more.py
  • chatbot/models/profile_models.py
  • shikshalokam/views/profile_views.py
💤 Files with no reviewable changes (1)
  • chatbot/consumers/async_consumer.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • shikshalokam/views/profile_views.py

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@KUNALTEMPEST

Copy link
Copy Markdown
Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@KUNALTEMPEST KUNALTEMPEST changed the title Do not merge for now UMS Task: https://katha.shikshalokam.org/story-view-1885.html Jun 25, 2026
Switch from full profile DB storage to a minimal model where only
userid is persisted for Elevate users. Non-PII profile data
(designation, org, district, state) is fetched on every WS
authenticate and threaded in-memory through the Celery task chain
as ums_profile — never written to DB.

Key changes:
- Profile model: userid max_length 500, email/company nullable,
  unique_together removed, save() guard enforces UMS vs traditional
  flow rules, userid index added
- handle_elevate_profile: lookup by userid, writes only userid +
  source to DB, returns ums_profile dict with session-scoped data
- WS authenticate: calls Elevate after JWT decode, closes connection
  on auth/server errors, stores self.ums_profile
- ums_profile threaded: flow_tasks → orchestrator → build_system_prompt
  (Jinja2 context includes ums_profile, skips ProfileAddress query)
- _save_submitted_user_context: removed writes to first_name,
  designation, org_associated, ProfileAddress; keeps only
  is_onboarding_completed flag and update_elevate_profile call
- get_profile_view: slimmed to id, is_tnc_accepted, is_profile_complete
- CompanyBot lookup guards added for null company in async_consumer,
  async_base_consumer, base_service

# Conflicts:
#	shikshalokam/views/profile_views.py
- Send auth error messages directly via self.send() instead of channel_layer
  to ensure delivery before connection closes
- Guard base consumer disconnect() against double-close ASGI error
- Fail loudly in read_elevate_profile if DEFAULT_COMPANY_SLUG is not set
@KUNALTEMPEST

Copy link
Copy Markdown
Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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 `@chatbot/consumers/async_consumer.py`:
- Line 293: The translate_message logging in async_consumer is leaking user chat
content because it logs the full transliteration response at INFO level. Update
the logger.info call in the transliteration path to record only non-sensitive
status or metadata (for example, success/failure, response type, or keys/length)
and avoid including the response payload itself. Keep the change scoped to the
translate_message flow so the log remains useful without exposing translated
message contents.
- Around line 61-76: The authentication flow in AsyncConsumer currently only
closes on explicit Elevate error values, but it can still proceed when
sync_elevate_profile() returns no bound profile. Update the authenticate path in
AsyncConsumer to treat a missing profileid from sync_elevate_profile() as a
failure: only assign self.profile_id and call get_profile() when elevate_result
contains a valid profileid, otherwise log and send the same auth failure
response, then close the socket. Use the existing sync_elevate_profile(),
self.profile_id, and get_profile() branch as the location to enforce this
fail-closed behavior.
- Around line 207-209: The sync_elevate_profile path in
chatbot/consumers/async_consumer.py is wrapping both the blocking Elevate HTTP
fetch and the ORM write in database_sync_to_async, which can tie up the DB
thread pool during auth bursts. Refactor handle_elevate_profile usage so the
requests.get call happens in a separate sync_to_async(thread_sensitive=False)
helper (or an async HTTP client), and keep only the update_or_create/database
write portion inside the database_sync_to_async wrapper in sync_elevate_profile.

In `@chatbot/models/profile_models.py`:
- Around line 77-87: The partial unique constraints in Profile.Meta still treat
blank strings as valid values, so `userid=''` can collide with the
`uniq_profile_userid` constraint and similar blank `email` values may affect
`uniq_profile_email_company`. Update the constraint conditions in `Profile` to
exclude empty strings as well as NULLs, or normalize blanks to `None` in
`Profile.save()` before persistence; use the existing `models.UniqueConstraint`
definitions and `Profile.save()` logic as the places to fix.
🪄 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: 84cafe3f-107b-47fb-ba95-a60c7a649d3c

📥 Commits

Reviewing files that changed from the base of the PR and between 09b2f6d and d64d1d1.

📒 Files selected for processing (18)
  • chatbot/admin/profile_admin.py
  • chatbot/celery_tasks/flow_tasks.py
  • chatbot/consumers/async_base_consumer.py
  • chatbot/consumers/async_consumer.py
  • chatbot/migrations/0086_alter_profile_unique_together_and_more.py
  • chatbot/migrations/0087_remove_profile_chatbot_pro_userid_3d404e_idx_and_more.py
  • chatbot/migrations/0088_remove_botvernacular_bot_vernacu_company_483975_idx_and_more.py
  • chatbot/models/bot_vernacular_model.py
  • chatbot/models/profile_models.py
  • chatbot/services/core/base_service.py
  • chatbot/services/core/orchestrator.py
  • chatbot/services/core/prompt_builder.py
  • chatbot/services/response_handlers/common_handler.py
  • chatbot/utils/elevate/profile_utils.py
  • chatbot/views/api_views.py
  • chatbot/views/profile_views.py
  • observability/migrations/0009_alter_companybottcrun_provider_and_more.py
  • shikshalokam/views/profile_views.py
💤 Files with no reviewable changes (1)
  • chatbot/views/profile_views.py
🚧 Files skipped from review as they are similar to previous changes (9)
  • chatbot/services/core/prompt_builder.py
  • chatbot/services/core/base_service.py
  • chatbot/admin/profile_admin.py
  • chatbot/celery_tasks/flow_tasks.py
  • chatbot/models/bot_vernacular_model.py
  • chatbot/views/api_views.py
  • chatbot/services/core/orchestrator.py
  • chatbot/services/response_handlers/common_handler.py
  • shikshalokam/views/profile_views.py

Comment thread chatbot/consumers/async_consumer.py Outdated
Comment thread chatbot/consumers/async_consumer.py Outdated
Comment thread chatbot/consumers/async_consumer.py
Comment thread chatbot/models/profile_models.py
@KUNALTEMPEST

KUNALTEMPEST commented Jun 29, 2026

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@kiranharidas187
kiranharidas187 merged commit 217e2fe into ELEVATE-Project:release-1.0.0 Jun 29, 2026
1 check passed
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.

2 participants