Skip to content

1.0#567

Merged
ashwin31 merged 51 commits intomasterfrom
dev
Dec 6, 2025
Merged

1.0#567
ashwin31 merged 51 commits intomasterfrom
dev

Conversation

@ashwin31
Copy link
Copy Markdown
Member

@ashwin31 ashwin31 commented Dec 6, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Row-Level Security (RLS) for enhanced multi-tenant data isolation
    • Implemented API Key authentication as primary auth method
    • Added organization settings management (currency, country preferences)
    • Introduced comprehensive seed data command for testing
    • Enhanced currency support across accounts, leads, and invoices
  • Documentation

    • Added RLS setup guide for database configuration
    • Added comprehensive API schema documentation
  • Bug Fixes

    • Improved data consistency with updated field relationships and constraints

✏️ Tip: You can customize this high-level summary in your review settings.

…ponents, introducing editable fields and updating backend serializers.
…ties, add a development roadmap, and include MCP server configuration.
…iting, row details, and drag-and-drop functionality.
…ies, and remove stats cards and column customizer from frontend list pages.
…2M assignment utilities, and introduce new migrations for task and opportunity assignments.
…icators with supporting backend updates and OpenAPI definition.
…S middleware for session scope, add RLS setup documentation, and enhance task UI with parent entity names.
Copilot AI review requested due to automatic review settings December 6, 2025 17:40
const newPayload = decodeJwtPayload(switchResult.access_token);
event.locals.org_settings = newPayload?.org_settings || {
default_currency: 'USD',
currency_symbol: '$',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Expected an assignment or function call and instead saw an expression.
Missing semicolon.
Too many errors. (81% scanned).

// Decode new token to get org_settings
const newPayload = decodeJwtPayload(switchResult.access_token);
event.locals.org_settings = newPayload?.org_settings || {
default_currency: 'USD',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Label 'default_currency' on USD statement.

event.locals.org_name = switchResult.current_org?.name || 'Organization';
// Decode new token to get org_settings
const newPayload = decodeJwtPayload(switchResult.access_token);
event.locals.org_settings = newPayload?.org_settings || {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Expected ':' and instead saw 'org_settings'.
Expected an identifier and instead saw '.'.
Expected an identifier and instead saw '||'.
Missing semicolon.

};
event.locals.org_name = switchResult.current_org?.name || 'Organization';
// Decode new token to get org_settings
const newPayload = decodeJwtPayload(switchResult.access_token);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

org: switchResult.current_org,
role: 'USER' // Will be in new JWT
};
event.locals.org_name = switchResult.current_org?.name || 'Organization';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Expected ':' and instead saw 'name'.
Expected an assignment or function call and instead saw an expression.
Expected an identifier and instead saw '.'.
Expected an identifier and instead saw '||'.
Missing semicolon.

};
} else {
// Token doesn't have org context, need to switch (1 API call)
const switchResult = await switchOrg(token, orgId);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
Missing semicolon.

// Profile fetch failed, clear org cookie
event.cookies.delete('org', { path: '/' });
}
const token = /** @type {string} */ (accessToken);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

/** @type {UserInfo | null} */
let user = null;
/** @type {JWTPayload | null} */
let jwtPayload = null;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

}
});
function verifyTokenLocally(accessToken) {
const payload = decodeJwtPayload(accessToken);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

const newPayload = decodeJwtPayload(switchResult.access_token);
event.locals.org_settings = newPayload?.org_settings || {
default_currency: 'USD',
currency_symbol: '$',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Expected an assignment or function call and instead saw an expression.
Missing semicolon.
Too many errors. (81% scanned).

// Decode new token to get org_settings
const newPayload = decodeJwtPayload(switchResult.access_token);
event.locals.org_settings = newPayload?.org_settings || {
default_currency: 'USD',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Label 'default_currency' on USD statement.

event.locals.org_name = switchResult.current_org?.name || 'Organization';
// Decode new token to get org_settings
const newPayload = decodeJwtPayload(switchResult.access_token);
event.locals.org_settings = newPayload?.org_settings || {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Expected ':' and instead saw 'org_settings'.
Expected an identifier and instead saw '.'.
Expected an identifier and instead saw '||'.
Missing semicolon.

};
event.locals.org_name = switchResult.current_org?.name || 'Organization';
// Decode new token to get org_settings
const newPayload = decodeJwtPayload(switchResult.access_token);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

org: switchResult.current_org,
role: 'USER' // Will be in new JWT
};
event.locals.org_name = switchResult.current_org?.name || 'Organization';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Expected ':' and instead saw 'name'.
Expected an assignment or function call and instead saw an expression.
Expected an identifier and instead saw '.'.
Expected an identifier and instead saw '||'.
Missing semicolon.

export { default as FocusBar } from './FocusBar.svelte';
export { default as MiniPipeline } from './MiniPipeline.svelte';
export { default as PipelineChart } from './PipelineChart.svelte';
export { default as TaskList } from './TaskList.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

export { default as ActivityFeed } from './ActivityFeed.svelte';
export { default as FocusBar } from './FocusBar.svelte';
export { default as MiniPipeline } from './MiniPipeline.svelte';
export { default as PipelineChart } from './PipelineChart.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

export { default as KPICard } from './KPICard.svelte';
export { default as ActivityFeed } from './ActivityFeed.svelte';
export { default as FocusBar } from './FocusBar.svelte';
export { default as MiniPipeline } from './MiniPipeline.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,8 @@
export { default as KPICard } from './KPICard.svelte';
export { default as ActivityFeed } from './ActivityFeed.svelte';
export { default as FocusBar } from './FocusBar.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,8 @@
export { default as KPICard } from './KPICard.svelte';
export { default as ActivityFeed } from './ActivityFeed.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,8 @@
export { default as KPICard } from './KPICard.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

export { default as AppShell } from './AppShell.svelte';
export { default as AppSidebar } from './AppSidebar.svelte';
export { default as FilterPopover } from './FilterPopover.svelte';
export { default as PageHeader } from './PageHeader.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as AppShell } from './AppShell.svelte';
export { default as AppSidebar } from './AppSidebar.svelte';
export { default as FilterPopover } from './FilterPopover.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as AppShell } from './AppShell.svelte';
export { default as AppSidebar } from './AppSidebar.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as AppShell } from './AppShell.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

import Overlay from './alert-dialog-overlay.svelte';
import Content from './alert-dialog-content.svelte';
import Header from './alert-dialog-header.svelte';
import Footer from './alert-dialog-footer.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Trigger from './alert-dialog-trigger.svelte';
import Overlay from './alert-dialog-overlay.svelte';
import Content from './alert-dialog-content.svelte';
import Header from './alert-dialog-header.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import Trigger from './alert-dialog-trigger.svelte';
import Overlay from './alert-dialog-overlay.svelte';
import Content from './alert-dialog-content.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,36 @@
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import Trigger from './alert-dialog-trigger.svelte';
import Overlay from './alert-dialog-overlay.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,36 @@
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import Trigger from './alert-dialog-trigger.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,8 @@
export { default as KPICard } from './KPICard.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

export { default as AppShell } from './AppShell.svelte';
export { default as AppSidebar } from './AppSidebar.svelte';
export { default as FilterPopover } from './FilterPopover.svelte';
export { default as PageHeader } from './PageHeader.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as AppShell } from './AppShell.svelte';
export { default as AppSidebar } from './AppSidebar.svelte';
export { default as FilterPopover } from './FilterPopover.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as AppShell } from './AppShell.svelte';
export { default as AppSidebar } from './AppSidebar.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as AppShell } from './AppShell.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

import Overlay from './alert-dialog-overlay.svelte';
import Content from './alert-dialog-content.svelte';
import Header from './alert-dialog-header.svelte';
import Footer from './alert-dialog-footer.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Trigger from './alert-dialog-trigger.svelte';
import Overlay from './alert-dialog-overlay.svelte';
import Content from './alert-dialog-content.svelte';
import Header from './alert-dialog-header.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import Trigger from './alert-dialog-trigger.svelte';
import Overlay from './alert-dialog-overlay.svelte';
import Content from './alert-dialog-content.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,36 @@
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import Trigger from './alert-dialog-trigger.svelte';
import Overlay from './alert-dialog-overlay.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,36 @@
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import Trigger from './alert-dialog-trigger.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,8 @@
export { default as KPICard } from './KPICard.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

export { default as AppShell } from './AppShell.svelte';
export { default as AppSidebar } from './AppSidebar.svelte';
export { default as FilterPopover } from './FilterPopover.svelte';
export { default as PageHeader } from './PageHeader.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as AppShell } from './AppShell.svelte';
export { default as AppSidebar } from './AppSidebar.svelte';
export { default as FilterPopover } from './FilterPopover.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as AppShell } from './AppShell.svelte';
export { default as AppSidebar } from './AppSidebar.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as AppShell } from './AppShell.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

import Overlay from './alert-dialog-overlay.svelte';
import Content from './alert-dialog-content.svelte';
import Header from './alert-dialog-header.svelte';
import Footer from './alert-dialog-footer.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Trigger from './alert-dialog-trigger.svelte';
import Overlay from './alert-dialog-overlay.svelte';
import Content from './alert-dialog-content.svelte';
import Header from './alert-dialog-header.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import Trigger from './alert-dialog-trigger.svelte';
import Overlay from './alert-dialog-overlay.svelte';
import Content from './alert-dialog-content.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,36 @@
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import Trigger from './alert-dialog-trigger.svelte';
import Overlay from './alert-dialog-overlay.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,36 @@
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import Trigger from './alert-dialog-trigger.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 6, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This PR represents a major restructuring of the Django CRM codebase, encompassing removal of legacy CI/build infrastructure, modularization of API views from a monolithic file into separate feature modules, comprehensive addition of Row-Level Security (RLS) context propagation across Celery tasks and views, replacement of phone number fields with CharField, addition of currency tracking across multiple models, and database schema migrations to support new fields and relationships.

Changes

Cohort / File(s) Change Summary
Legacy Infrastructure Removal
.deepsource.toml, .travis.yml, Jenkinsfile
Removed configuration files for DeepSource analysis, Travis CI pipeline, and Jenkins build/deploy orchestration.
Documentation & Workspace
CLAUDE.md, Steps, RLS_SETUP.md
Deleted CLAUDE.md and procedural steps list; added comprehensive RLS_SETUP.md documentation for PostgreSQL Row-Level Security configuration.
.gitignore & .env
.gitignore, backend/.env.example
Added entries for openapi.json, .mcp.json, CLAUDE.md, TODO.md, .playwright-mcp; added ALLOWED_HOSTS, CORS_ALLOWED_ORIGINS, CSRF_TRUSTED_ORIGINS environment variables.
Backend Settings & Configuration
backend/crm/settings.py, backend/invoices/urls.py
Updated authentication from CustomDualAuthentication to APIKeyAuthentication; added ENUM_NAME_OVERRIDES for OpenAPI; enforced environment-driven CORS/CSRF/security settings; shortened JWT token lifetimes and enabled rotation; emptied invoices urlpatterns.
Common App Views Restructuring
backend/common/views.py (removed), backend/common/views/__init__.py, backend/common/views/auth_views.py, backend/common/views/dashboard_views.py, backend/common/views/document_views.py, backend/common/views/org_settings_views.py, backend/common/views/organization_views.py, backend/common/views/settings_views.py, backend/common/views/tags_views.py, backend/common/views/team_views.py, backend/common/views/user_views.py
Removed monolithic views.py file; refactored all API views into modular, feature-specific view files with enhanced schema documentation and org-context enforcement across authentication, organizations, documents, tags, teams, and user management.
Common App Utilities & Models
backend/common/utils.py, backend/common/models.py, backend/common/serializer.py
Replaced jwt_payload_handler; added get_or_create_tags, handle_m2m_assignment, create_attachment utilities; replaced CURRENCY_CODES with CURRENCY_SYMBOLS; added OrgSettingsSerializer, TagsSerializer; replaced PhoneNumberField with CharField; added default_currency and default_country to Org; increased apikey field length; added org context to CommentFiles; extended OrgAwareRefreshToken with org context injection.
Common App Authentication & Permissions
backend/common/external_auth.py, backend/common/permissions.py, backend/common/access_decorators_mixins.py
Replaced JWT verification with APIKeyAuthentication and APIKeyAuthenticationScheme; removed legacy decorators (sales_access_required, marketing_access_required, admin_login_required) and permission classes (IsOrgMember, HasSalesAccess, HasMarketingAccess, CanAccessObject).
Common App RLS & Middleware
backend/common/rls/__init__.py, backend/common/middleware/rls_context.py, backend/common/middleware/get_company.py
Changed RLS set_config from transaction-scoped to session-scoped; added commentFiles, invoice_line_item, product to org-scoped tables; enhanced logging in RequireOrgContext; removed get_actual_value function.
Common App Other
backend/common/celery_utils.py (removed), backend/common/custom_auth.py (removed), backend/common/tasks.py, backend/common/status.py, backend/common/token_generator.py, backend/common/templatetags/common_tags.py (removed), backend/common/mixins.py
Removed org-aware celery utilities, legacy JWT auth, and file-type template tag helpers; removed organizational mixins; removed HTTP status predicate functions; removed send_email_to_reset_password task; added blank=True to UserAuditModel ForeignKeys.
Common App Migrations
backend/common/migrations/0003_add_org_to_commentfiles.py, backend/common/migrations/0004_populate_commentfiles_org_and_rls.py, backend/common/migrations/0005_increase_apikey_length.py, backend/common/migrations/0006_remove_phonenumberfield.py, backend/common/migrations/0007_add_currency_fields.py, backend/common/migrations/0008_enable_rls_product_invoice_line_item.py
Added org field to CommentFiles with RLS enablement; increased apikey max_length to 64; converted phone fields to CharField; added default_currency and default_country to Org; altered user audit fields (created_by, updated_by) across 13+ models to be nullable with SET_NULL and dynamic related_names; enabled RLS on product and invoice_line_item tables.
Common App Management Commands
backend/common/management/commands/migrate_from_prisma.py (removed), backend/common/management/commands/manage_rls.py, backend/common/management/commands/seed_data.py
Removed Prisma-to-Django migration utility; enhanced RLS testing to handle edge cases with multiple orgs; added comprehensive seed_data command with support for generating realistic test data across multiple organizations with proper RLS context.
Common App URLs
backend/common/urls.py
Refactored from aggregated imports to explicit granular imports of view classes; added routing for org settings, authentication/profile endpoints, tags, dashboard activities, and new modular views; updated path names and handlers.
Accounts App
backend/accounts/models.py, backend/accounts/serializer.py, backend/accounts/views.py, backend/accounts/tasks.py, backend/accounts/tests_celery_tasks.py
Added currency, industry, number_of_employees fields to Account; changed phone to CharField; added related_name to tags; removed convenience methods (get_complete_address, created_on_arrow); added org context to Celery tasks; added HasOrgContext permission; enhanced tag handling with get_or_create_tags; updated email tasks with org_id parameters; refactored serializers with currency defaults; removed AccountReadSerializer and redundant computed fields.
Accounts Migrations
backend/accounts/migrations/0003_add_tags_related_name.py, backend/accounts/migrations/0004_remove_phonenumberfield.py, backend/accounts/migrations/0005_add_currency_fields.py
Added related_name to Account.tags; changed Account.phone to CharField; added Account.currency field; altered created_by/updated_by fields across Account, AccountEmail, AccountEmailLog with SET_NULL and dynamic related_names.
Cases App
backend/cases/models.py, backend/cases/serializer.py, backend/cases/solution_serializers.py, backend/cases/solution_views.py, backend/cases/views.py, backend/cases/tasks.py, backend/cases/tests_celery_tasks.py
Added Tags import and M2M field with related_name to Case; changed case_type default to None; removed created_on_arrow property; added HasOrgContext to views; enhanced tag and attachment handling; added org context to Celery tasks; added @extend_schema_field decorators for schema generation; updated serializers with tags support and closed_on field.
Cases Migrations
backend/cases/migrations/0003_fix_contacts_related_name.py, backend/cases/migrations/0004_add_tags_field.py, backend/cases/migrations/0005_add_tags_related_name.py, backend/cases/migrations/0006_fix_case_type_default.py, backend/cases/migrations/0007_alter_case_created_by_alter_case_updated_by_and_more.py
Added related_name to Case.contacts; added Case.tags M2M field; set related_name on tags; changed case_type default; altered created_by/updated_by fields to nullable with SET_NULL.
Contacts App
backend/contacts/models.py, backend/contacts/serializer.py, backend/contacts/swagger_params.py, backend/contacts/views.py, backend/contacts/tasks.py, backend/contacts/tests_celery_tasks.py
Changed phone to CharField; added account FK relation; renamed linked_in_url to linkedin_url; added related_name to tags; removed computed properties (created_on_arrow, created_on); updated indexes; added HasOrgContext to views; enhanced tag/attachment handling; added org context to Celery tasks; updated serializers and Swagger parameters.
Contacts Migrations
backend/contacts/migrations/0002_change_phone_to_charfield.py, backend/contacts/migrations/0003_add_account_fk.py, backend/contacts/migrations/0004_change_phone_to_phonenumberfield.py, backend/contacts/migrations/0005_rename_linked_in_url_to_linkedin_url.py, backend/contacts/migrations/0006_add_tags_related_name.py, backend/contacts/migrations/0007_remove_organization_index.py, backend/contacts/migrations/0008_change_phone_to_charfield.py, backend/contacts/migrations/0009_alter_contact_created_by_alter_contact_updated_by.py
Converted phone between PhoneNumberField and CharField; added account FK; renamed linkedin_url; added tags related_name; removed org index; altered created_by/updated_by fields.
Leads App
backend/leads/models.py, backend/leads/serializer.py, backend/leads/services.py, backend/leads/forms.py, backend/leads/tasks.py, backend/leads/tests_celery_tasks.py, backend/leads/urls.py
Removed Company model and replaced with company_name field; changed phone to CharField; added salutation, job_title, currency fields; renamed title field handling; changed tags related_name; removed legacy properties; added convert_lead_to_account service function; added org context to Celery tasks; updated imports and view routing.
Leads Migrations
backend/leads/migrations/0002_add_converted_account_fk.py through backend/leads/migrations/0010_add_currency_fields.py
Added converted_account/contact/opportunity FKs; removed Company model with data migration; renamed title/contact_title fields; added tags related_name; removed unused fields; converted phone to CharField; added currency field; altered created_by/updated_by fields.
Invoices App
backend/invoices/models.py, backend/invoices/serializer.py, backend/invoices/swagger_params.py, backend/invoices/tasks.py, backend/invoices/tests_celery_tasks.py, backend/invoices/api_views.py, backend/invoices/forms.py
Changed phone to CharField; added currency fields to Product; updated monetary formatting defaults; removed legacy forms; added org context to Celery tasks; enhanced email task signatures with org_id; added currency defaulting logic in serializers; added invoice history org field and RLS context.
Invoices Migrations
backend/invoices/migrations/0002_remove_phonenumberfield.py, backend/invoices/migrations/0003_add_currency_fields.py
Changed phone to CharField; added Product.currency; altered created_by/updated_by across Invoice, InvoiceHistory, InvoiceLineItem, Product models.
Backend README
backend/README.md
Added "Generating Schema" section with OpenAPI schema generation command.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

  • Scope & Complexity: Extremely large and heterogeneous changes spanning the entire backend codebase with multiple types of modifications (model schema, serializers, views, tasks, migrations, settings, utilities).
  • File Spread: Changes touch ~150+ files across all major Django apps and infrastructure.
  • Logic Density: Mix of data model changes, RLS context propagation, view restructuring, and authentication refactoring requires careful review of each cohort.

Areas requiring extra attention:

  • RLS Context Propagation: Verify org_id context is correctly threaded through all Celery tasks and that set_rls_context calls are properly placed to prevent data leakage across organizations.
  • Database Migrations: Review the ordering and dependencies of migrations, especially the RLS enablement migrations (0004, 0008) and currency field additions to ensure no data loss or integrity issues.
  • Authentication Changes: Validate APIKeyAuthentication implementation and ensure backward compatibility or proper migration path from previous JWT/CustomDualAuthentication.
  • View Restructuring: Ensure all 20+ new modular view files are properly wired, that permission classes (HasOrgContext, IsAuthenticated) are correctly applied, and inline serializers match expected response contracts.
  • Model Schema Changes: Verify phone field conversions from PhoneNumberField to CharField don't break existing phone parsing; confirm currency field defaults and choices are consistent across all models; validate related_name changes don't conflict with existing relationships.
  • Serializer Updates: Review currency defaulting logic in create methods across Account, Invoice, Lead, and Product serializers to ensure correct org context is used.
  • Tests: Confirm Celery task tests are updated to pass new org_id arguments and that RLS context validation is comprehensive.

Possibly related PRs

  • PR #561: Adds CLAUDE.md documentation (opposite of this PR's deletion), indicating documentation management changes in parallel work.
  • PR #562: Modifies backend/common/serializer.py (OrgAwareRefreshToken), backend/common/rls, and Celery utilities, overlapping with core RLS and auth refactoring in this PR.

Poem

🐰 A warren of views now organized neat,
With RLS context for every beat,
Phone fields transformed, currencies gleam,
Legacy code swept into the stream—
Our Django CRM's grand rebirth complete! 🌟

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fee5b64 and 615d201.

📒 Files selected for processing (107)
  • .deepsource.toml (0 hunks)
  • .gitignore (1 hunks)
  • .travis.yml (0 hunks)
  • CLAUDE.md (0 hunks)
  • Jenkinsfile (0 hunks)
  • RLS_SETUP.md (1 hunks)
  • Steps (0 hunks)
  • backend/.env.example (1 hunks)
  • backend/README.md (1 hunks)
  • backend/accounts/migrations/0003_add_tags_related_name.py (1 hunks)
  • backend/accounts/migrations/0004_remove_phonenumberfield.py (1 hunks)
  • backend/accounts/migrations/0005_add_currency_fields.py (1 hunks)
  • backend/accounts/models.py (4 hunks)
  • backend/accounts/serializer.py (5 hunks)
  • backend/accounts/tasks.py (2 hunks)
  • backend/accounts/tests_celery_tasks.py (3 hunks)
  • backend/accounts/views.py (21 hunks)
  • backend/cases/migrations/0003_fix_contacts_related_name.py (1 hunks)
  • backend/cases/migrations/0004_add_tags_field.py (1 hunks)
  • backend/cases/migrations/0005_add_tags_related_name.py (1 hunks)
  • backend/cases/migrations/0006_fix_case_type_default.py (1 hunks)
  • backend/cases/migrations/0007_alter_case_created_by_alter_case_updated_by_and_more.py (1 hunks)
  • backend/cases/models.py (2 hunks)
  • backend/cases/serializer.py (4 hunks)
  • backend/cases/solution_serializers.py (3 hunks)
  • backend/cases/solution_views.py (3 hunks)
  • backend/cases/tasks.py (1 hunks)
  • backend/cases/tests_celery_tasks.py (1 hunks)
  • backend/cases/views.py (17 hunks)
  • backend/common/access_decorators_mixins.py (1 hunks)
  • backend/common/celery_utils.py (0 hunks)
  • backend/common/custom_auth.py (0 hunks)
  • backend/common/external_auth.py (1 hunks)
  • backend/common/management/commands/manage_rls.py (2 hunks)
  • backend/common/management/commands/migrate_from_prisma.py (0 hunks)
  • backend/common/management/commands/seed_data.py (1 hunks)
  • backend/common/middleware/get_company.py (1 hunks)
  • backend/common/middleware/rls_context.py (4 hunks)
  • backend/common/migrations/0003_add_org_to_commentfiles.py (1 hunks)
  • backend/common/migrations/0004_populate_commentfiles_org_and_rls.py (1 hunks)
  • backend/common/migrations/0005_increase_apikey_length.py (1 hunks)
  • backend/common/migrations/0006_remove_phonenumberfield.py (1 hunks)
  • backend/common/migrations/0007_add_currency_fields.py (1 hunks)
  • backend/common/migrations/0008_enable_rls_product_invoice_line_item.py (1 hunks)
  • backend/common/mixins.py (1 hunks)
  • backend/common/models.py (7 hunks)
  • backend/common/permissions.py (0 hunks)
  • backend/common/rls/__init__.py (3 hunks)
  • backend/common/serializer.py (10 hunks)
  • backend/common/status.py (0 hunks)
  • backend/common/tasks.py (1 hunks)
  • backend/common/templatetags/common_tags.py (0 hunks)
  • backend/common/token_generator.py (0 hunks)
  • backend/common/urls.py (1 hunks)
  • backend/common/utils.py (2 hunks)
  • backend/common/views.py (0 hunks)
  • backend/common/views/__init__.py (1 hunks)
  • backend/common/views/auth_views.py (1 hunks)
  • backend/common/views/dashboard_views.py (1 hunks)
  • backend/common/views/document_views.py (1 hunks)
  • backend/common/views/org_settings_views.py (1 hunks)
  • backend/common/views/organization_views.py (1 hunks)
  • backend/common/views/settings_views.py (1 hunks)
  • backend/common/views/tags_views.py (1 hunks)
  • backend/common/views/team_views.py (1 hunks)
  • backend/common/views/user_views.py (1 hunks)
  • backend/contacts/migrations/0002_change_phone_to_charfield.py (1 hunks)
  • backend/contacts/migrations/0003_add_account_fk.py (1 hunks)
  • backend/contacts/migrations/0004_change_phone_to_phonenumberfield.py (1 hunks)
  • backend/contacts/migrations/0005_rename_linked_in_url_to_linkedin_url.py (1 hunks)
  • backend/contacts/migrations/0006_add_tags_related_name.py (1 hunks)
  • backend/contacts/migrations/0007_remove_organization_index.py (1 hunks)
  • backend/contacts/migrations/0008_change_phone_to_charfield.py (1 hunks)
  • backend/contacts/migrations/0009_alter_contact_created_by_alter_contact_updated_by.py (1 hunks)
  • backend/contacts/models.py (4 hunks)
  • backend/contacts/serializer.py (5 hunks)
  • backend/contacts/swagger_params.py (2 hunks)
  • backend/contacts/tasks.py (1 hunks)
  • backend/contacts/tests_celery_tasks.py (1 hunks)
  • backend/contacts/views.py (17 hunks)
  • backend/crm/settings.py (5 hunks)
  • backend/invoices/api_views.py (11 hunks)
  • backend/invoices/forms.py (0 hunks)
  • backend/invoices/migrations/0002_remove_phonenumberfield.py (1 hunks)
  • backend/invoices/migrations/0003_add_currency_fields.py (1 hunks)
  • backend/invoices/models.py (7 hunks)
  • backend/invoices/serializer.py (2 hunks)
  • backend/invoices/swagger_params.py (1 hunks)
  • backend/invoices/tasks.py (5 hunks)
  • backend/invoices/tests_celery_tasks.py (1 hunks)
  • backend/invoices/urls.py (1 hunks)
  • backend/leads/forms.py (1 hunks)
  • backend/leads/migrations/0002_add_converted_account_fk.py (1 hunks)
  • backend/leads/migrations/0003_add_full_conversion_fields.py (1 hunks)
  • backend/leads/migrations/0004_remove_company_model.py (1 hunks)
  • backend/leads/migrations/0005_rename_title_to_salutation.py (1 hunks)
  • backend/leads/migrations/0006_add_tags_related_name.py (1 hunks)
  • backend/leads/migrations/0007_add_title_field.py (1 hunks)
  • backend/leads/migrations/0008_remove_unused_fields.py (1 hunks)
  • backend/leads/migrations/0009_change_phone_to_charfield.py (1 hunks)
  • backend/leads/migrations/0010_add_currency_fields.py (1 hunks)
  • backend/leads/models.py (5 hunks)
  • backend/leads/serializer.py (7 hunks)
  • backend/leads/services.py (1 hunks)
  • backend/leads/tasks.py (5 hunks)
  • backend/leads/tests_celery_tasks.py (5 hunks)
  • backend/leads/urls.py (1 hunks)
⛔ Files not processed due to max files limit (30)
  • backend/leads/views/init.py
  • backend/leads/views/lead_interactions.py
  • backend/leads/views/lead_views.py
  • backend/opportunity/migrations/0002_add_tags_related_name.py
  • backend/opportunity/migrations/0003_alter_opportunity_assigned_to.py
  • backend/opportunity/migrations/0004_alter_opportunity_created_by_and_more.py
  • backend/opportunity/models.py
  • backend/opportunity/serializer.py
  • backend/opportunity/tasks.py
  • backend/opportunity/tests_celery_tasks.py
  • backend/opportunity/urls.py
  • backend/opportunity/views/init.py
  • backend/opportunity/views/opportunity_interactions.py
  • backend/opportunity/views/opportunity_views.py
  • backend/requirements.txt
  • backend/seed.md
  • backend/tasks/admin.py
  • backend/tasks/celery_tasks.py
  • backend/tasks/migrations/0002_add_opportunity_case_lead_fks.py
  • backend/tasks/migrations/0003_fix_contacts_related_name.py
  • backend/tasks/migrations/0004_add_tags_field.py
  • backend/tasks/migrations/0005_add_tags_related_name.py
  • backend/tasks/migrations/0006_alter_task_assigned_to.py
  • backend/tasks/migrations/0007_alter_board_created_by_alter_board_updated_by_and_more.py
  • backend/tasks/models.py
  • backend/tasks/serializer.py
  • backend/tasks/tests_celery_tasks.py
  • backend/tasks/urls.py
  • backend/tasks/views/init.py
  • backend/tasks/views/board_views.py

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.

Copy link
Copy Markdown

@code-review-doctor code-review-doctor Bot left a comment

Choose a reason for hiding this comment

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

Some food for thought. View full project report here.

max_length=3, choices=CURRENCY_CODES, blank=True, null=True
)
phone = PhoneNumberField(null=True, blank=True)
phone = models.CharField(max_length=20, null=True, blank=True)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
phone = models.CharField(max_length=20, null=True, blank=True)
phone = models.CharField(max_length=20, default="", blank=True)

null=True on a string field causes inconsistent data types because the value can be either str or None. This adds complexity and maybe bugs, but can be solved by replacing null=True with default="". Read more.

max_length=3, choices=CURRENCY_CODES, blank=True, null=True
)
phone = PhoneNumberField(null=True, blank=True)
phone = models.CharField(max_length=20, null=True, blank=True)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
phone = models.CharField(max_length=20, null=True, blank=True)
phone = models.CharField(max_length=20, default="", blank=True)

Same as above: consider replacing null=True with default="" (and blank=True to pass validation checks).

description = models.TextField(blank=True, null=True)
sku = models.CharField(max_length=100, blank=True, null=True)
price = models.DecimalField(max_digits=12, decimal_places=2, default=0)
currency = models.CharField(max_length=3, choices=CURRENCY_CODES, blank=True, null=True)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Same as above: consider replacing null=True with default="" (and blank=True to pass validation checks).

{
"account": (
"A task can only be linked to one parent entity "
f"(Account, Opportunity, Case, or Lead). "
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
f"(Account, Opportunity, Case, or Lead). "
"(Account, Opportunity, Case, or Lead). "

f-string is unnecessary here. This can just be a string. More info.

name = models.CharField(_("Account Name"), max_length=255)
email = models.EmailField(_("Email"), blank=True, null=True)
phone = PhoneNumberField(_("Phone"), null=True, blank=True)
phone = models.CharField(_("Phone"), max_length=20, null=True, blank=True)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
phone = models.CharField(_("Phone"), max_length=20, null=True, blank=True)
phone = models.CharField(_("Phone"), max_length=20, default="", blank=True)

null=True on a string field causes inconsistent data types because the value can be either str or None. This adds complexity and maybe bugs, but can be solved by replacing null=True with default="". Read more.

Comment on lines +110 to +111
if profiles:
team_obj.users.add(*profiles)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
if profiles:
team_obj.users.add(*profiles)
if profiles.exists():
team_obj.users.add(*profiles)

Checking profiles truthiness is less efficient than checking profiles.exists() or profiles is not None. Checking queryset truthiness evaluates the queryset, therefore reading the records from the database. More details.

Comment on lines +187 to +188
if profiles:
team_obj.users.add(*profiles)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
if profiles:
team_obj.users.add(*profiles)
if profiles.exists():
team_obj.users.add(*profiles)

Same as above: consider profiles.exists()

last_name = models.CharField(_("Last name"), max_length=255)
email = models.EmailField(_("Email"), blank=True, null=True)
phone = PhoneNumberField(_("Phone"), null=True, blank=True)
phone = models.CharField(_("Phone"), max_length=20, null=True, blank=True)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
phone = models.CharField(_("Phone"), max_length=20, null=True, blank=True)
phone = models.CharField(_("Phone"), max_length=20, default="", blank=True)

null=True on a string field causes inconsistent data types because the value can be either str or None. This adds complexity and maybe bugs, but can be solved by replacing null=True with default="". Explained here.

# Communication Preferences
do_not_call = models.BooleanField(_("Do Not Call"), default=False)
linked_in_url = models.URLField(_("LinkedIn URL"), blank=True, null=True)
linkedin_url = models.URLField(_("LinkedIn URL"), blank=True, null=True)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
linkedin_url = models.URLField(_("LinkedIn URL"), blank=True, null=True)
linkedin_url = models.URLField(_("LinkedIn URL"), blank=True, default="")

Same as above: consider replacing null=True with default="" (and blank=True to pass validation checks).

Comment thread backend/leads/models.py
Comment on lines +34 to 37
salutation = models.CharField(
_("Salutation"), max_length=64, blank=True, null=True,
help_text="e.g., Mr, Mrs, Ms, Dr"
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
salutation = models.CharField(
_("Salutation"), max_length=64, blank=True, null=True,
help_text="e.g., Mr, Mrs, Ms, Dr"
)
salutation = models.CharField(
_("Salutation"),
max_length=64,
blank=True,
default="",
help_text="e.g., Mr, Mrs, Ms, Dr",
)

null=True on a string field causes inconsistent data types because the value can be either str or None. This adds complexity and maybe bugs, but can be solved by replacing null=True with default="". More details.

Copy link
Copy Markdown

@code-review-doctor code-review-doctor Bot left a comment

Choose a reason for hiding this comment

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

Worth considering. View full project report here.

Comment thread backend/leads/models.py
phone = PhoneNumberField(null=True, blank=True)
contact_title = models.CharField(
_("Job Title"), max_length=255, blank=True, null=True
phone = models.CharField(_("Phone"), max_length=50, null=True, blank=True)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
phone = models.CharField(_("Phone"), max_length=50, null=True, blank=True)
phone = models.CharField(_("Phone"), max_length=50, default="", blank=True)

Same as above: consider replacing null=True with default="" (and blank=True to pass validation checks).

Comment thread backend/leads/models.py
Comment on lines +42 to 45
job_title = models.CharField(
_("Job Title"), max_length=255, blank=True, null=True,
help_text="Person's job title (e.g., 'VP of Sales', 'CTO')"
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
job_title = models.CharField(
_("Job Title"), max_length=255, blank=True, null=True,
help_text="Person's job title (e.g., 'VP of Sales', 'CTO')"
)
job_title = models.CharField(
_("Job Title"),
max_length=255,
blank=True,
default="",
help_text="Person"s job title (e.g., 'VP of Sales', 'CTO')",
)

Again, consider replacing null=True with default="" (and blank=True to pass validation checks).

Comment thread backend/leads/models.py
opportunity_amount = models.DecimalField(
_("Deal Value"), decimal_places=2, max_digits=12, blank=True, null=True
)
currency = models.CharField(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Same as above: consider replacing null=True with default="" (and blank=True to pass validation checks).

Comment thread backend/leads/models.py
Comment on lines +102 to 104
company_name = models.CharField(
_("Company Name"), max_length=255, blank=True, null=True
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
company_name = models.CharField(
_("Company Name"), max_length=255, blank=True, null=True
)
company_name = models.CharField(
_("Company Name"), max_length=255, blank=True, default=""
)

As above, consider replacing null=True with default="" (and blank=True to pass validation checks).

Comment thread backend/tasks/models.py
@@ -1,15 +1,15 @@
import arrow
from django.core.exceptions import ValidationError
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Boa model prefix is used quite a lot. Maybe split the models into multiple files. Explained here.

Comment thread backend/tasks/models.py
@property
def created_on_arrow(self):
return arrow.get(self.created_at).humanize()
def clean(self):
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

According to Django internal style guide, save should come before clean. More.

@ashwin31 ashwin31 merged commit c2b29af into master Dec 6, 2025
5 of 6 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request represents version "1.0" of the CRM system, implementing a comprehensive refactoring and feature enhancement across the backend. The changes focus on modernizing the codebase, improving security, consolidating functionality, and adding new features.

Key Changes:

  • Restructured view architecture by splitting monolithic view files into organized subdirectories
  • Removed deprecated dependencies (arrow, phonenumber_field, django_extensions) and replaced with Django built-ins
  • Enhanced security with improved CORS/CSRF configuration, token rotation, and org-scoped permissions
  • Added comprehensive board/task management system with Kanban-style workflow
  • Implemented lead conversion service with support for creating accounts, contacts, and opportunities

Reviewed changes

Copilot reviewed 136 out of 386 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
backend/tasks/views/board_views.py New comprehensive board management views with columns and tasks
backend/tasks/serializer.py Added schema field decorators and task parent entity validation
backend/tasks/models.py Added parent entity validation and removed deprecated arrow timestamps
backend/requirements.txt Updated Django/Celery versions, removed deprecated packages, added faker/gunicorn
backend/crm/settings.py Enhanced security settings with configurable CORS/CSRF and improved JWT tokens
backend/leads/services.py New lead conversion service extracting complex business logic
backend/leads/models.py Simplified Lead model removing Company FK, added currency support
backend/opportunity/models.py Replaced arrow with timesince for timestamps
backend/contacts/models.py Added account FK relationship and replaced phonenumber field
backend/common/views/*.py Reorganized views into logical modules with improved API documentation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread backend/crm/settings.py
Comment on lines +298 to 300
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
Copy link

Copilot AI Dec 6, 2025

Choose a reason for hiding this comment

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

HSTS with 1 year duration should only be enabled in production with HTTPS. Consider making this conditional on DEBUG=False to avoid issues in development environments.

Suggested change
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
if not DEBUG:
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
else:
SECURE_HSTS_SECONDS = 0
SECURE_HSTS_INCLUDE_SUBDOMAINS = False
SECURE_HSTS_PRELOAD = False

Copilot uses AI. Check for mistakes.
@ashwin31 ashwin31 deleted the dev branch December 6, 2025 17:41
@@ -0,0 +1,36 @@
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Image from './avatar-image.svelte';
import Fallback from './avatar-fallback.svelte';

export {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,13 @@
import Root from './avatar.svelte';
import Image from './avatar-image.svelte';
import Fallback from './avatar-fallback.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,13 @@
import Root from './avatar.svelte';
import Image from './avatar-image.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,13 @@
import Root from './avatar.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Header from './card-header.svelte';
import Title from './card-title.svelte';

export {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

import Content from './card-content.svelte';
import Description from './card-description.svelte';
import Header from './card-header.svelte';
import Title from './card-title.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Root from './card.svelte';
import Content from './card-content.svelte';
import Description from './card-description.svelte';
import Header from './card-header.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,19 @@
import Root from './card.svelte';
import Content from './card-content.svelte';
import Description from './card-description.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,19 @@
import Root from './card.svelte';
import Content from './card-content.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

return (profile.user, None)

except Org.DoesNotExist:
logger.warning(f"Invalid API key attempted: {api_key[:8]}...")

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This expression logs
sensitive data (password)
as clear text.

Copilot Autofix

AI 5 months ago

The best way to fix the problem is to avoid logging any portion of the API key in cleartext, even partial substrings. To maintain useful logging for debugging or monitoring, log only metadata (such as the fact that an invalid API key was attempted), possibly with context not involving the API key value itself—such as the requester's IP address, timestamp, etc.

Locate line 49 in backend/common/external_auth.py, which currently logs:

logger.warning(f"Invalid API key attempted: {api_key[:8]}...")

Replace it with a log message that omits the API key completely. For example:

logger.warning("Invalid API key attempted for external API access")

Optionally, additional non-sensitive context from the request (like remote IP address) could be logged if available and appropriate.

No new imports or method definitions are required.


Suggested changeset 1
backend/common/external_auth.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/backend/common/external_auth.py b/backend/common/external_auth.py
--- a/backend/common/external_auth.py
+++ b/backend/common/external_auth.py
@@ -46,7 +46,7 @@
             return (profile.user, None)
 
         except Org.DoesNotExist:
-            logger.warning(f"Invalid API key attempted: {api_key[:8]}...")
+            logger.warning("Invalid API key attempted for external API access")
             raise AuthenticationFailed("Invalid API Key")
 
 
EOF
@@ -46,7 +46,7 @@
return (profile.user, None)

except Org.DoesNotExist:
logger.warning(f"Invalid API key attempted: {api_key[:8]}...")
logger.warning("Invalid API key attempted for external API access")
raise AuthenticationFailed("Invalid API Key")


Copilot is powered by AI and may make mistakes. Always verify output.
)

except TokenError as e:
return Response({"error": str(e)}, status=status.HTTP_401_UNAUTHORIZED)

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.

Copilot Autofix

AI 5 months ago

To fix the problem:

  • The response returned in the except TokenError as e block should not include the exception message. Instead, it should respond with a generic error message such as "Invalid or expired refresh token".
  • No changes to the logic or exception handling are needed, just a change to the error message.
  • Only modify lines 395-396 in backend/common/views/auth_views.py.
  • No new dependencies are required.
  • Only change what is shown in the context.

Suggested changeset 1
backend/common/views/auth_views.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/backend/common/views/auth_views.py b/backend/common/views/auth_views.py
--- a/backend/common/views/auth_views.py
+++ b/backend/common/views/auth_views.py
@@ -393,7 +393,8 @@
             )
 
         except TokenError as e:
-            return Response({"error": str(e)}, status=status.HTTP_401_UNAUTHORIZED)
+            # Do not expose internal details or exception string to user.
+            return Response({"error": "Invalid or expired refresh token."}, status=status.HTTP_401_UNAUTHORIZED)
         except User.DoesNotExist:
             return Response(
                 {"error": "User not found"}, status=status.HTTP_401_UNAUTHORIZED
EOF
@@ -393,7 +393,8 @@
)

except TokenError as e:
return Response({"error": str(e)}, status=status.HTTP_401_UNAUTHORIZED)
# Do not expose internal details or exception string to user.
return Response({"error": "Invalid or expired refresh token."}, status=status.HTTP_401_UNAUTHORIZED)
except User.DoesNotExist:
return Response(
{"error": "User not found"}, status=status.HTTP_401_UNAUTHORIZED
Copilot is powered by AI and may make mistakes. Always verify output.
@@ -0,0 +1,19 @@
import Root from './card.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Trigger from './collapsible-trigger.svelte';
import Content from './collapsible-content.svelte';

export {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,13 @@
import Root from './collapsible.svelte';
import Trigger from './collapsible-trigger.svelte';
import Content from './collapsible-content.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,13 @@
import Root from './collapsible.svelte';
import Trigger from './collapsible-trigger.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,13 @@
import Root from './collapsible.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Header from "./dialog-header.svelte";
import Overlay from "./dialog-overlay.svelte";
import Content from "./dialog-content.svelte";
import Description from "./dialog-description.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Footer from "./dialog-footer.svelte";
import Header from "./dialog-header.svelte";
import Overlay from "./dialog-overlay.svelte";
import Content from "./dialog-content.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Title from "./dialog-title.svelte";
import Footer from "./dialog-footer.svelte";
import Header from "./dialog-header.svelte";
import Overlay from "./dialog-overlay.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Portal from "./dialog-portal.svelte";
import Title from "./dialog-title.svelte";
import Footer from "./dialog-footer.svelte";
import Header from "./dialog-header.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Root from "./dialog.svelte";
import Portal from "./dialog-portal.svelte";
import Title from "./dialog-title.svelte";
import Footer from "./dialog-footer.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,19 @@
import Root from './card.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Trigger from './collapsible-trigger.svelte';
import Content from './collapsible-content.svelte';

export {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,13 @@
import Root from './collapsible.svelte';
import Trigger from './collapsible-trigger.svelte';
import Content from './collapsible-content.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,13 @@
import Root from './collapsible.svelte';
import Trigger from './collapsible-trigger.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,13 @@
import Root from './collapsible.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Header from "./dialog-header.svelte";
import Overlay from "./dialog-overlay.svelte";
import Content from "./dialog-content.svelte";
import Description from "./dialog-description.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Footer from "./dialog-footer.svelte";
import Header from "./dialog-header.svelte";
import Overlay from "./dialog-overlay.svelte";
import Content from "./dialog-content.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Title from "./dialog-title.svelte";
import Footer from "./dialog-footer.svelte";
import Header from "./dialog-header.svelte";
import Overlay from "./dialog-overlay.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Portal from "./dialog-portal.svelte";
import Title from "./dialog-title.svelte";
import Footer from "./dialog-footer.svelte";
import Header from "./dialog-header.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Root from "./dialog.svelte";
import Portal from "./dialog-portal.svelte";
import Title from "./dialog-title.svelte";
import Footer from "./dialog-footer.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,19 @@
import Root from './card.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Trigger from './collapsible-trigger.svelte';
import Content from './collapsible-content.svelte';

export {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,13 @@
import Root from './collapsible.svelte';
import Trigger from './collapsible-trigger.svelte';
import Content from './collapsible-content.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,13 @@
import Root from './collapsible.svelte';
import Trigger from './collapsible-trigger.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,13 @@
import Root from './collapsible.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Header from "./dialog-header.svelte";
import Overlay from "./dialog-overlay.svelte";
import Content from "./dialog-content.svelte";
import Description from "./dialog-description.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Footer from "./dialog-footer.svelte";
import Header from "./dialog-header.svelte";
import Overlay from "./dialog-overlay.svelte";
import Content from "./dialog-content.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Title from "./dialog-title.svelte";
import Footer from "./dialog-footer.svelte";
import Header from "./dialog-header.svelte";
import Overlay from "./dialog-overlay.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Portal from "./dialog-portal.svelte";
import Title from "./dialog-title.svelte";
import Footer from "./dialog-footer.svelte";
import Header from "./dialog-header.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

import Root from "./dialog.svelte";
import Portal from "./dialog-portal.svelte";
import Title from "./dialog-title.svelte";
import Footer from "./dialog-footer.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import Root from "./dialog.svelte";
import Portal from "./dialog-portal.svelte";
import Title from "./dialog-title.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import Root from "./dialog.svelte";
import Portal from "./dialog-portal.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import Root from "./dialog.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

const Sub = DropdownMenuPrimitive.Sub;
const Root = DropdownMenuPrimitive.Root;

export {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

import Separator from './dropdown-menu-separator.svelte';
import Trigger from './dropdown-menu-trigger.svelte';
const Sub = DropdownMenuPrimitive.Sub;
const Root = DropdownMenuPrimitive.Root;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxGroup from './dropdown-menu-checkbox-group.svelte';
import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
import Content from './dropdown-menu-content.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxGroup from './dropdown-menu-checkbox-group.svelte';
import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxGroup from './dropdown-menu-checkbox-group.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1 @@
export { default as EditableMultiSelect } from './EditableMultiSelect.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import Root from "./dialog.svelte";
import Portal from "./dialog-portal.svelte";
import Title from "./dialog-title.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import Root from "./dialog.svelte";
import Portal from "./dialog-portal.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import Root from "./dialog.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

const Sub = DropdownMenuPrimitive.Sub;
const Root = DropdownMenuPrimitive.Root;

export {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

import Separator from './dropdown-menu-separator.svelte';
import Trigger from './dropdown-menu-trigger.svelte';
const Sub = DropdownMenuPrimitive.Sub;
const Root = DropdownMenuPrimitive.Root;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxGroup from './dropdown-menu-checkbox-group.svelte';
import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
import Content from './dropdown-menu-content.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxGroup from './dropdown-menu-checkbox-group.svelte';
import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxGroup from './dropdown-menu-checkbox-group.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1 @@
export { default as EditableMultiSelect } from './EditableMultiSelect.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import Root from "./dialog.svelte";
import Portal from "./dialog-portal.svelte";
import Title from "./dialog-title.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import Root from "./dialog.svelte";
import Portal from "./dialog-portal.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import Root from "./dialog.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

const Sub = DropdownMenuPrimitive.Sub;
const Root = DropdownMenuPrimitive.Root;

export {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

import Separator from './dropdown-menu-separator.svelte';
import Trigger from './dropdown-menu-trigger.svelte';
const Sub = DropdownMenuPrimitive.Sub;
const Root = DropdownMenuPrimitive.Root;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxGroup from './dropdown-menu-checkbox-group.svelte';
import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
import Content from './dropdown-menu-content.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxGroup from './dropdown-menu-checkbox-group.svelte';
import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxGroup from './dropdown-menu-checkbox-group.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1 @@
export { default as EditableMultiSelect } from './EditableMultiSelect.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import Root from "./dialog.svelte";
import Portal from "./dialog-portal.svelte";
import Title from "./dialog-title.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import Root from "./dialog.svelte";
import Portal from "./dialog-portal.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import Root from "./dialog.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

const Sub = DropdownMenuPrimitive.Sub;
const Root = DropdownMenuPrimitive.Root;

export {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

import Separator from './dropdown-menu-separator.svelte';
import Trigger from './dropdown-menu-trigger.svelte';
const Sub = DropdownMenuPrimitive.Sub;
const Root = DropdownMenuPrimitive.Root;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxGroup from './dropdown-menu-checkbox-group.svelte';
import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
import Content from './dropdown-menu-content.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxGroup from './dropdown-menu-checkbox-group.svelte';
import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckboxGroup from './dropdown-menu-checkbox-group.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,34 @@
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1 @@
export { default as EditableMultiSelect } from './EditableMultiSelect.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

export { default as SearchInput } from './SearchInput.svelte';
export { default as SelectFilter } from './SelectFilter.svelte';
export { default as DateRangeFilter } from './DateRangeFilter.svelte';
export { default as FilterBar } from './FilterBar.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as SearchInput } from './SearchInput.svelte';
export { default as SelectFilter } from './SelectFilter.svelte';
export { default as DateRangeFilter } from './DateRangeFilter.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as SearchInput } from './SearchInput.svelte';
export { default as SelectFilter } from './SelectFilter.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as SearchInput } from './SearchInput.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,7 @@
import Root from './input.svelte';

export {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

import { Popover as PopoverPrimitive } from "bits-ui";
import Content from "./popover-content.svelte";
import Trigger from "./popover-trigger.svelte";
const Root = PopoverPrimitive.Root;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

@@ -0,0 +1,17 @@
import { Popover as PopoverPrimitive } from "bits-ui";
import Content from "./popover-content.svelte";
import Trigger from "./popover-trigger.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,17 @@
import { Popover as PopoverPrimitive } from "bits-ui";
import Content from "./popover-content.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,17 @@
import { Popover as PopoverPrimitive } from "bits-ui";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,7 @@
import Root from "./progress.svelte";

export {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

export { default as SearchInput } from './SearchInput.svelte';
export { default as SelectFilter } from './SelectFilter.svelte';
export { default as DateRangeFilter } from './DateRangeFilter.svelte';
export { default as FilterBar } from './FilterBar.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as SearchInput } from './SearchInput.svelte';
export { default as SelectFilter } from './SelectFilter.svelte';
export { default as DateRangeFilter } from './DateRangeFilter.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as SearchInput } from './SearchInput.svelte';
export { default as SelectFilter } from './SelectFilter.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,4 @@
export { default as SearchInput } from './SearchInput.svelte';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,7 @@
import Root from './input.svelte';

export {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

import { Popover as PopoverPrimitive } from "bits-ui";
import Content from "./popover-content.svelte";
import Trigger from "./popover-trigger.svelte";
const Root = PopoverPrimitive.Root;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).

@@ -0,0 +1,17 @@
import { Popover as PopoverPrimitive } from "bits-ui";
import Content from "./popover-content.svelte";
import Trigger from "./popover-trigger.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,17 @@
import { Popover as PopoverPrimitive } from "bits-ui";
import Content from "./popover-content.svelte";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,17 @@
import { Popover as PopoverPrimitive } from "bits-ui";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'import' is only available in ES6 (use 'esversion: 6').

@@ -0,0 +1,7 @@
import Root from "./progress.svelte";

export {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'export' is only available in ES6 (use 'esversion: 6').

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.

3 participants