Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated by Django 4.2.22 on 2025-09-29 15:36

from django.db import migrations, models
from django.contrib.postgres.operations import AddIndexConcurrently


class Migration(migrations.Migration):
atomic = False

dependencies = [
('db', '0110_workspaceuserproperties_navigation_control_preference_and_more'),
]
Comment on lines +1 to +12
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Migration number discrepancy with PR objectives.

The PR description references migration 0108_*, but this file is numbered 0111_*. This suggests either the PR description is outdated or there were additional migrations created between the initial plan and implementation.

Good use of atomic = False with AddIndexConcurrently to prevent table locking during index creation.


operations = [
AddIndexConcurrently(
model_name='notification',
index=models.Index(fields=['receiver', 'workspace', 'read_at', 'created_at'], name='notif_receiver_status_idx'),
),
AddIndexConcurrently(
model_name='notification',
index=models.Index(fields=['receiver', 'workspace', 'entity_name', 'read_at'], name='notif_receiver_entity_idx'),
),
AddIndexConcurrently(
model_name='notification',
index=models.Index(fields=['receiver', 'workspace', 'snoozed_till', 'archived_at'], name='notif_receiver_state_idx'),
),
AddIndexConcurrently(
model_name='notification',
index=models.Index(fields=['receiver', 'workspace', 'sender'], name='notif_receiver_sender_idx'),
),
AddIndexConcurrently(
model_name='notification',
index=models.Index(fields=['workspace', 'entity_identifier', 'entity_name'], name='notif_entity_lookup_idx'),
),
Comment on lines +14 to +34
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify composite index field order matches query patterns.

The field order in composite indexes is critical for performance due to the leftmost prefix rule. Ensure that the index field orders align with your most common query patterns:

  • notif_receiver_status_idx: Queries should filter by receiver (and optionally workspace, read_at, created_at) in that order
  • notif_receiver_entity_idx: Queries should filter by receiver (and optionally workspace, entity_name, read_at) in that order
  • Similar verification needed for the other three notification indexes

Also verify that these new indexes don't significantly overlap with existing indexes, which could waste storage and slow down writes.

Run the following script to check for existing indexes on the notification table:


🏁 Script executed:

#!/bin/bash
# Description: Check for existing indexes on notification model that might overlap

# Search for existing indexes in the Notification model Meta class
ast-grep --pattern $'class Notification($$$):
  $$$
  class Meta:
    $$$
    indexes = $$$
    $$$'

# Also search for any index-related constraints or db_index fields
rg -nP --type=py -C5 'class Notification|db_index\s*=\s*True' -g '**/models/*notification*.py'

Length of output: 917


I need to gather more complete information about the Notification model and how it's queried. Let me retrieve the full model definition and search for query patterns.


---

🏁 Script executed:

```shell
#!/bin/bash
# Get the complete Notification model file
cat apps/api/plane/db/models/notification.py

Length of output: 5145


🏁 Script executed:

#!/bin/bash
# Search for query patterns on the notification model to verify field order alignment
rg -nP --type=py 'Notification\.objects\.(filter|exclude|get)' -C3 -g '!migrations' | head -100

Length of output: 6211


🏁 Script executed:

#!/bin/bash
# Check for any existing indexes or constraints on notification fields
rg -nP --type=py 'class.*Notification.*Meta|indexes\s*=|db_index' apps/api/plane/db/models/notification.py

Length of output: 22


🏁 Script executed:

#!/bin/bash
# Look for existing index definitions in all migrations related to notification
fd '.*notification.*\.py' apps/api/plane/db/migrations/ | xargs grep -l 'AddIndex\|RemoveIndex' | head -20

Length of output: 84


🏁 Script executed:

#!/bin/bash
# Check the actual index creation/removal statements in older migrations
rg -nP --type=py 'AddIndex|RemoveIndex' apps/api/plane/db/migrations/ -B2 -A5 | grep -i notification | head -60

Length of output: 4912


I need to verify whether these indexes are redundantly defined and check migration dependencies.


---

🏁 Script executed:

```shell
#!/bin/bash
# Check all migrations to find when model indexes were added
rg -n 'notif_receiver_status_idx|notif_entity_idx|notif_receiver_entity_idx|notif_receiver_state_idx|notif_receiver_sender_idx|notif_entity_lookup_idx' apps/api/plane/db/migrations/

Length of output: 1222


🏁 Script executed:

#!/bin/bash
# Check the complete migration file 0111 to see dependencies
cat apps/api/plane/db/migrations/0111_notification_notif_receiver_status_idx_and_more.py

Length of output: 1523


🏁 Script executed:

#!/bin/bash
# Search for earlier migrations that might have added these indexes
fd '010[0-9].*\.py' apps/api/plane/db/migrations/ | sort | xargs grep -l 'notif_receiver\|notif_entity'

Length of output: 77


🏁 Script executed:

#!/bin/bash
# Check if the model Meta.indexes were recently added or always present
git log --oneline --all -- apps/api/plane/db/models/notification.py 2>/dev/null | head -20 || echo "Git history not available"

Length of output: 280


Let me check the git commits to understand the sequence of changes:


---

🏁 Script executed:

```shell
#!/bin/bash
# Check the specific commit that updated index constraints
git show 8999120ff --stat 2>/dev/null | head -30 || echo "Cannot retrieve commit"

Length of output: 376


🏁 Script executed:

#!/bin/bash
# Check if model.Meta.indexes existed before migration 0111 was created
git show 8999120ff:apps/api/plane/db/models/notification.py 2>/dev/null | grep -A 30 "class Meta:" | head -40 || echo "Cannot retrieve file"

Length of output: 1617


🏁 Script executed:

#!/bin/bash
# Get more context on queries that use receiver AND workspace together
rg -nP 'Notification\.objects\.(filter|exclude)' -A2 -B1 --type=py -g '!migrations' | grep -A3 'receiver\|workspace'

Length of output: 1347


Remove migration 0111 indexes that duplicate model Meta.indexes definitions.

The five notification indexes added in migration 0111 are already defined in the model's Meta.indexes (apps/api/plane/db/models/notification.py, lines 39-55). Indexes defined in Meta.indexes are automatically created during migration, so redefining them in migration 0111 will cause duplicate key errors.

Either:

  1. Remove the model Meta.indexes definitions and keep only migration 0111, OR
  2. Remove migration 0111 and keep only model Meta.indexes (recommended—cleaner and more maintainable)

Additionally, verify the field order ['receiver', 'workspace', 'read_at', ...] aligns with query patterns. Queries filter on workspace__slug and receiver_id together, so consider whether starting with workspace would be more optimal than starting with receiver.

🤖 Prompt for AI Agents
In
apps/api/plane/db/migrations/0111_notification_notif_receiver_status_idx_and_more.py
around lines 14 to 34, the five notification indexes added by this migration
duplicate indexes already declared on the Notification model's Meta.indexes,
causing duplicate-key migration failures; remove these index additions from
migration 0111 (recommended) so the model Meta.indexes alone create them, or
alternatively delete the Meta.indexes and keep this migration (not recommended);
after removing the duplicates, verify and adjust the indexed field order to
match actual query patterns (queries filter on workspace__slug and receiver_id
together—consider placing 'workspace' before 'receiver' in the index definitions
if appropriate).

AddIndexConcurrently(
model_name='fileasset',
index=models.Index(fields=['asset'], name='asset_asset_idx'),
),
Comment on lines +35 to +38
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Undocumented index on fileasset table.

The asset_asset_idx index on the fileasset model is not mentioned in the PR objectives. Please clarify:

  • Is this intentional or was the PR description incomplete?
  • What query patterns does this index optimize?

]
1 change: 1 addition & 0 deletions apps/api/plane/db/models/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class Meta:
models.Index(fields=["entity_type"], name="asset_entity_type_idx"),
models.Index(fields=["entity_identifier"], name="asset_entity_identifier_idx"),
models.Index(fields=["entity_type", "entity_identifier"], name="asset_entity_idx"),
models.Index(fields=["asset"], name="asset_asset_idx"),
]

def __str__(self):
Expand Down
20 changes: 20 additions & 0 deletions apps/api/plane/db/models/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@ class Meta:
models.Index(fields=["entity_name"], name="notif_entity_name_idx"),
models.Index(fields=["read_at"], name="notif_read_at_idx"),
models.Index(fields=["receiver", "read_at"], name="notif_entity_idx"),
models.Index(
fields=["receiver", "workspace", "read_at", "created_at"],
name="notif_receiver_status_idx",
),
models.Index(
fields=["receiver", "workspace", "entity_name", "read_at"],
name="notif_receiver_entity_idx",
),
models.Index(
fields=["receiver", "workspace", "snoozed_till", "archived_at"],
name="notif_receiver_state_idx",
),
models.Index(
fields=["receiver", "workspace", "sender"],
name="notif_receiver_sender_idx",
),
models.Index(
fields=["workspace", "entity_identifier", "entity_name"],
name="notif_entity_lookup_idx",
),
]

def __str__(self):
Expand Down
Loading