Overview
Currently, tasks must be bound to an existing project container (TaskTable.project_id is a non-null foreign key). Although the UI and authorization layers have initial scaffolding for standalone tasks (allow_standalone, can_create_standalone, and default TASK-# references), creating one fails at runtime.
This issue tracks the discussion and technical design decisions needed to enable standalone / ad-hoc tasks across the system.
Problem Statement
Users need a way to track quick one-off chores, ad-hoc bugs, or general server tasks without having to create or choose a full project container.
Currently:
TaskTable.project_id in PostgreSQL has nullable=False.
Task domain model requires project_id: UUID.
TaskService.create_task() enforces if not resolved_project_id: raise ValidationError("A project container must be specified for every task.").
- Short ID allocation (
prefix-number) assumes an active project row exists to increment next_task_number.
Design Options Under Consideration
Option A: Default "Standalone" / "General" Project Container (Recommended)
Automatically create a default project named Standalone (or General Tasks) per guild with prefix TASK.
- Pros:
- Zero DB schema changes: No nullable migration on
tasks.project_id or foreign key adjustments.
- Existing atomic allocation: Reuses existing
next_task_number counter to automatically generate TASK-1, TASK-2, TASK-3 with full concurrency safety.
- Compatibility: Tech trees, burndown metrics, outbox events, and task board views immediately work without needing
if project_id is None guards across queries.
- Task Board scoping: Users can filter directly to
[TASK] Standalone on the board to view all ad-hoc tasks.
- Channel routing: Since the default project's
discord_channel_id is None, tasks post directly in whichever channel/forum the user creates them in.
- Questions / Decisions:
- Naming & prefix:
Standalone vs General vs Inbox; prefix TASK vs STD vs GEN.
- Visibility: Should it be hidden from
/project list or categorized as a system/general container?
- Provisioning: Automatically ensure existence on guild join, seeding, or first use.
Option B: True Nullable project_id
Make tasks.project_id nullable across the database and models.
- Pros:
- Tasks truly have no parent project entity in the database.
- Cons & Required Changes:
- Alembic migration to drop NOT NULL constraint on
tasks.project_id.
- Need a new guild-level sequence / counter mechanism (e.g.
guild_task_sequences table) to atomically allocate TASK-# IDs.
- Must update all aggregations, queries, outbox workers, and board views to handle
None project IDs.
Next Steps
- Decide between Option A (Default Project) and Option B (Nullable Schema).
- Define UX for
/task create (making project_name optional to fallback to standalone).
- Wire up interactive menus (
TaskMenuView.standalone_btn and HubTaskProjectSelectView).
Overview
Currently, tasks must be bound to an existing project container (
TaskTable.project_idis a non-null foreign key). Although the UI and authorization layers have initial scaffolding for standalone tasks (allow_standalone,can_create_standalone, and defaultTASK-#references), creating one fails at runtime.This issue tracks the discussion and technical design decisions needed to enable standalone / ad-hoc tasks across the system.
Problem Statement
Users need a way to track quick one-off chores, ad-hoc bugs, or general server tasks without having to create or choose a full project container.
Currently:
TaskTable.project_idin PostgreSQL hasnullable=False.Taskdomain model requiresproject_id: UUID.TaskService.create_task()enforcesif not resolved_project_id: raise ValidationError("A project container must be specified for every task.").prefix-number) assumes an active project row exists to incrementnext_task_number.Design Options Under Consideration
Option A: Default "Standalone" / "General" Project Container (Recommended)
Automatically create a default project named
Standalone(orGeneral Tasks) per guild with prefixTASK.tasks.project_idor foreign key adjustments.next_task_numbercounter to automatically generateTASK-1,TASK-2,TASK-3with full concurrency safety.if project_id is Noneguards across queries.[TASK] Standaloneon the board to view all ad-hoc tasks.discord_channel_idisNone, tasks post directly in whichever channel/forum the user creates them in.StandalonevsGeneralvsInbox; prefixTASKvsSTDvsGEN./project listor categorized as a system/general container?Option B: True Nullable
project_idMake
tasks.project_idnullable across the database and models.tasks.project_id.guild_task_sequencestable) to atomically allocateTASK-#IDs.Noneproject IDs.Next Steps
/task create(makingproject_nameoptional to fallback to standalone).TaskMenuView.standalone_btnandHubTaskProjectSelectView).