Reusable Django planner app — tasks, calendar events, reminders with GenericFK linking, Celery reminders, and optional FCM push.
Project description
nai-planner
Reusable Django planner — tasks, calendar events, and reminders with GenericFK linking, Celery-powered reminders, and optional FCM push notifications.
Architecture
Single model (PlannerItem) handles three item types:
| Type | Purpose | Key Fields |
|---|---|---|
task |
To-do items with deadlines | due_at, priority, is_completed |
event |
Calendar events with duration | due_at, end_at, is_all_day |
reminder |
Time-triggered notifications | remind_at, is_reminder_sent |
GenericFK — any item can link to any Django model (Note, Chat, Project, etc.) via content_type + object_id.
Soft delete — items are never hard-deleted. deleted_at timestamp hides them from default queries. Restore anytime.
Managers — PlannerItem.objects excludes soft-deleted items. PlannerItem.all_objects includes everything.
Install
# Core only (models + signals + admin)
pip install nai-planner
# With Django REST Framework support
pip install nai-planner[drf]
# With Django Ninja support
pip install nai-planner[ninja]
# With FCM push notifications
pip install nai-planner[fcm]
# With Celery periodic tasks
pip install nai-planner[celery]
# Everything
pip install nai-planner[all]
Quick Start
1. Add to INSTALLED_APPS
INSTALLED_APPS = [
# ...
"nai_planner",
]
2. Run migrations
python manage.py migrate nai_planner
3. Wire up URLs
DRF:
from nai_planner.contrib.drf.urls import urlpatterns as planner_urls
urlpatterns = [
path("api/v1/", include(planner_urls)),
]
Django Ninja:
from nai_planner.contrib.ninja.views import router as planner_router
api.add_router("/planner", planner_router)
4. Setup Celery Beat (optional)
python manage.py setup_planner_beat
5. Configure FCM (optional)
# settings.py
NAI_PLANNER_FCM_ENABLED = True
NAI_PLANNER_FCM_CREDENTIALS_PATH = "/path/to/firebase-credentials.json"
NAI_PLANNER_FCM_TOKEN_GETTER = "myapp.utils.get_user_fcm_tokens"
The FCM_TOKEN_GETTER must be a dotted path to a callable: callable(user) -> list[str]
API Endpoints
DRF (ViewSet at /api/v1/planner/)
| Method | Endpoint | Description |
|---|---|---|
| GET | /planner/ |
List user's items (filterable) |
| POST | /planner/ |
Create item |
| GET | /planner/{uuid}/ |
Get item detail |
| PUT/PATCH | /planner/{uuid}/ |
Update item |
| DELETE | /planner/{uuid}/ |
Soft delete item |
| POST | /planner/{uuid}/complete/ |
Mark as completed |
| POST | /planner/{uuid}/restore/ |
Restore soft-deleted item |
Filters: ?item_type=task, ?priority=high, ?is_completed=true, ?due_after=2025-01-01, ?due_before=2025-12-31
Ninja (Router)
Same endpoints at your configured path. All require authentication.
Linking to Other Models
Link a planner item to any model using linked_model + linked_object_id:
{
"item_type": "task",
"title": "Review meeting notes",
"linked_model": "notes.Note",
"linked_object_id": 42
}
Both fields are required together. The target model and object are validated on creation.
Signals
from django.dispatch import receiver
from nai_planner.signals import reminder_due
@receiver(reminder_due)
def handle_reminder(sender, user, item, **kwargs):
# Send email, WebSocket, in-app notification, etc.
pass
Fired when remind_at <= now and is_reminder_sent=False. The Celery task checks every 60 seconds (configurable).
Settings
| Setting | Default | Description |
|---|---|---|
NAI_PLANNER_FCM_ENABLED |
False |
Enable FCM push for reminders |
NAI_PLANNER_FCM_CREDENTIALS_PATH |
None |
Path to Firebase credentials JSON |
NAI_PLANNER_FCM_TOKEN_GETTER |
None |
Dotted path to token getter callable |
NAI_PLANNER_REMINDER_CHECK_INTERVAL_SECONDS |
60 |
How often Celery checks for due reminders |
NAI_PLANNER_SOFT_DELETE |
True |
Enable soft delete (deleted_at) |
NAI_PLANNER_USER_UUID_FIELD |
"uuid" |
User model UUID field for API lookups |
NAI_PLANNER_DEFAULT_PRIORITY |
"medium" |
Default priority for new items |
Development
# Clone and install with dev deps
git clone https://github.com/NEMATI-AI/nai-planner.git
cd nai-planner
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Lint
ruff check nai_planner/ tests/
# Format
ruff format nai_planner/ tests/
Project Structure
nai_planner/
├── contrib/
│ ├── drf/ # DRF ViewSet, serializers, filters, URLs
│ └── ninja/ # Ninja router, schemas
├── management/commands/ # setup_planner_beat
├── migrations/ # Django migrations
├── models/ # PlannerItem model + managers
├── admin.py # Django admin config
├── apps.py # NaiPlannerConfig
├── conf.py # Centralised settings (NAI_PLANNER_* prefix)
├── signals.py # reminder_due signal
└── tasks.py # Celery task + FCM push helper
tests/
├── settings.py # SQLite in-memory test config
├── test_models.py # Model + manager tests
└── test_tasks.py # Celery task + signal tests
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nai_planner-0.1.1.tar.gz.
File metadata
- Download URL: nai_planner-0.1.1.tar.gz
- Upload date:
- Size: 17.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba7139a9740cb03e84c426ef081352741058cf7e216a5707f8e73c4a7fefba59
|
|
| MD5 |
083b8de1001a3aa27dd3cb14cf4cfac2
|
|
| BLAKE2b-256 |
10f9d8df522f8e4439cf2288109fd26687253650a5c944bfd5dfb48b104b8de6
|
File details
Details for the file nai_planner-0.1.1-py3-none-any.whl.
File metadata
- Download URL: nai_planner-0.1.1-py3-none-any.whl
- Upload date:
- Size: 17.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f6cfc4e6d36daba9fb5277f8472d208928a98711690822b65a0988f633462ac
|
|
| MD5 |
dbff2a4061b2367eb171adf304d13c63
|
|
| BLAKE2b-256 |
b21541ec6d38e74b788604b1335339d0acb0199941d65a778930d915eb0e28ab
|