238 lines
6.8 KiB
Markdown
238 lines
6.8 KiB
Markdown
|
|
# Epic and Wiki Models - Implementation Summary
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
This document summarizes the implementation of Epic and Wiki models for the Kanban application.
|
||
|
|
|
||
|
|
## What Was Implemented
|
||
|
|
|
||
|
|
### 1. Epic Model (`backend/app/models/epic.py`)
|
||
|
|
- Tracks large features across multiple cards
|
||
|
|
- Hierarchical structure (parent-child epics)
|
||
|
|
- Rich text content support (Slate.js JSON)
|
||
|
|
- Color-coded badges for visual identification
|
||
|
|
- Metrics tracking (card count)
|
||
|
|
|
||
|
|
**Key Fields:**
|
||
|
|
- `id`, `name`, `description`, `content` (JSONB)
|
||
|
|
- `color` (hex code for epic badge)
|
||
|
|
- `closed`, `pos`, `depth_limit` (default 5)
|
||
|
|
- `board_id`, `parent_epic_id`
|
||
|
|
- `date_last_activity`, `created_at`, `updated_at`
|
||
|
|
- `metrics` (JSONB - stores card_count)
|
||
|
|
|
||
|
|
**Relationships:**
|
||
|
|
- Board: One-to-many (Board has many Epics)
|
||
|
|
- Cards: One-to-many (Epic has many Cards)
|
||
|
|
- Parent Epic: Self-referential (hierarchical)
|
||
|
|
- File Attachments: Polymorphic (like Cards)
|
||
|
|
|
||
|
|
### 2. Wiki Model (`backend/app/models/wiki.py`)
|
||
|
|
- Reusable rich text content within a board
|
||
|
|
- Board-scoped (not global across all boards)
|
||
|
|
- Polymorphic links to entities (Card, Epic, etc.)
|
||
|
|
- Categorization and tagging support
|
||
|
|
|
||
|
|
**Key Fields:**
|
||
|
|
- `id`, `name`, `slug` (URL-friendly)
|
||
|
|
- `content` (JSONB - rich text)
|
||
|
|
- `summary`, `category`, `tags` (JSONB)
|
||
|
|
- `board_id`, `created_by`, `updated_by`
|
||
|
|
- `created_at`, `updated_at`
|
||
|
|
|
||
|
|
**Relationships:**
|
||
|
|
- Board: One-to-many (Board has many Wikis)
|
||
|
|
- Entities: Many-to-many polymorphic (via wiki_entity_links)
|
||
|
|
|
||
|
|
### 3. Card Model Updates (`backend/app/models/card.py`)
|
||
|
|
- Added `epic_id` foreign key (nullable)
|
||
|
|
- Updated `to_dict()` to include `epic_id`
|
||
|
|
- One-to-one relationship: Card belongs to one Epic
|
||
|
|
|
||
|
|
### 4. Association Table (`wiki_entity_links`)
|
||
|
|
- Polymorphic many-to-many table
|
||
|
|
- Links wikis to any entity type
|
||
|
|
- Fields: `wiki_id`, `entity_type`, `entity_id`, `created_at`, `linked_by`
|
||
|
|
|
||
|
|
## Database Schema
|
||
|
|
|
||
|
|
### New Tables
|
||
|
|
1. **epics** - Epic records
|
||
|
|
2. **wikis** - Wiki content records
|
||
|
|
3. **wiki_entity_links** - Wiki-to-entity associations
|
||
|
|
|
||
|
|
### Modified Tables
|
||
|
|
1. **cards** - Added `epic_id` foreign key
|
||
|
|
|
||
|
|
### Relationships Diagram
|
||
|
|
```
|
||
|
|
Board (1) ----< (N) Epic
|
||
|
|
Epic (1) ----< (N) Card (each card belongs to one epic)
|
||
|
|
Epic (1) ----< (N) Epic (parent-child hierarchy)
|
||
|
|
|
||
|
|
Board (1) ----< (N) Wiki
|
||
|
|
Wiki (M) ----> (M) Entity (polymorphic: Card, Epic)
|
||
|
|
```
|
||
|
|
|
||
|
|
## Database Migration
|
||
|
|
|
||
|
|
**File:** `backend/migrations/versions/add_epic_and_wiki_models.py`
|
||
|
|
|
||
|
|
**Creates:**
|
||
|
|
- `epics` table with indexes on `board_id`, `closed`, `name`
|
||
|
|
- `wikis` table with indexes on `board_id`, `name`, `slug`
|
||
|
|
- `wiki_entity_links` table with composite primary key
|
||
|
|
- `epic_id` column in `cards` table with index and foreign key
|
||
|
|
|
||
|
|
**To apply migration:**
|
||
|
|
```bash
|
||
|
|
cd backend
|
||
|
|
flask db upgrade
|
||
|
|
```
|
||
|
|
|
||
|
|
**To rollback:**
|
||
|
|
```bash
|
||
|
|
flask db downgrade
|
||
|
|
```
|
||
|
|
|
||
|
|
## Model Exports
|
||
|
|
|
||
|
|
Updated `backend/app/models/__init__.py` to include:
|
||
|
|
- `from app.models.epic import Epic`
|
||
|
|
- `from app.models.wiki import Wiki`
|
||
|
|
|
||
|
|
Added to `__all__` list: `"Epic"`, `"Wiki"`
|
||
|
|
|
||
|
|
## Design Decisions
|
||
|
|
|
||
|
|
### Why "Wiki" instead of "Document"?
|
||
|
|
- Avoids confusion with file attachments
|
||
|
|
- Emphasizes reusable knowledge content
|
||
|
|
- Better semantic meaning for rich text resources
|
||
|
|
|
||
|
|
### One-to-Many Epic-Card Relationship
|
||
|
|
- Simpler, clearer ownership
|
||
|
|
- Each card belongs to one epic
|
||
|
|
- Easier to query and display
|
||
|
|
|
||
|
|
### Board-Scoped Wikis
|
||
|
|
- Wikis belong to a specific board
|
||
|
|
- Not global across all boards
|
||
|
|
- Better organization and access control
|
||
|
|
|
||
|
|
### Epic Hierarchy Depth
|
||
|
|
- Default depth limit: 5 levels
|
||
|
|
- Configurable per epic
|
||
|
|
- Backend should enforce when creating child epics
|
||
|
|
|
||
|
|
### Simplified Metrics
|
||
|
|
- Currently only tracks `card_count`
|
||
|
|
- Stored in JSONB field: `{"card_count": 10}`
|
||
|
|
- Easy to extend with more metrics later
|
||
|
|
|
||
|
|
## Next Steps
|
||
|
|
|
||
|
|
### Backend Implementation
|
||
|
|
1. ✅ Create models - **DONE**
|
||
|
|
2. ✅ Create database migration - **DONE**
|
||
|
|
3. ⏭️ Create schemas for serialization
|
||
|
|
4. ⏭️ Create API routes (CRUD operations)
|
||
|
|
5. ⏭️ Create services for business logic
|
||
|
|
6. ⏭️ Add validation for epic depth limit
|
||
|
|
7. ⏭️ Update epic metrics when cards change
|
||
|
|
8. ⏭️ Write tests for models and routes
|
||
|
|
|
||
|
|
### Frontend Implementation
|
||
|
|
1. ⏭️ Update TypeScript types
|
||
|
|
2. ⏭️ Create Epic page/component
|
||
|
|
3. ⏭️ Create Wiki page/component
|
||
|
|
4. ⏭️ Add epic dropdown to card detail
|
||
|
|
5. ⏭️ Create epic list on board detail
|
||
|
|
6. ⏭️ Implement rich text editor (Slate.js)
|
||
|
|
7. ⏭️ Add wiki linking UI
|
||
|
|
|
||
|
|
### API Endpoints (Future)
|
||
|
|
|
||
|
|
#### Epic Endpoints
|
||
|
|
```
|
||
|
|
GET /api/boards/{board_id}/epics # List all epics for board
|
||
|
|
POST /api/boards/{board_id}/epics # Create epic
|
||
|
|
GET /api/epics/{epic_id} # Get epic details with cards
|
||
|
|
PUT /api/epics/{epic_id} # Update epic
|
||
|
|
DELETE /api/epics/{epic_id} # Delete epic
|
||
|
|
POST /api/epics/{epic_id}/cards # Create card directly in epic
|
||
|
|
GET /api/epics/{epic_id}/tree # Get epic hierarchy tree
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Wiki Endpoints
|
||
|
|
```
|
||
|
|
GET /api/boards/{board_id}/wikis # List all wikis for board
|
||
|
|
POST /api/boards/{board_id}/wikis # Create wiki
|
||
|
|
GET /api/wikis/{wiki_id} # Get wiki details
|
||
|
|
PUT /api/wikis/{wiki_id} # Update wiki
|
||
|
|
DELETE /api/wikis/{wiki_id} # Delete wiki
|
||
|
|
POST /api/wikis/{wiki_id}/links # Link wiki to entity
|
||
|
|
DELETE /api/wikis/{wiki_id}/links/{link_id} # Unlink from entity
|
||
|
|
GET /api/{entity_type}/{entity_id}/wikis # Get wikis for entity
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Card Endpoints (Updated)
|
||
|
|
```
|
||
|
|
PUT /api/cards/{card_id}/epic # Link card to epic (or null to unlink)
|
||
|
|
GET /api/cards/{card_id}/epic # Get card's epic
|
||
|
|
```
|
||
|
|
|
||
|
|
## Files Created/Modified
|
||
|
|
|
||
|
|
### Created
|
||
|
|
- `backend/app/models/epic.py`
|
||
|
|
- `backend/app/models/wiki.py`
|
||
|
|
- `backend/migrations/versions/add_epic_and_wiki_models.py`
|
||
|
|
|
||
|
|
### Modified
|
||
|
|
- `backend/app/models/card.py` (added epic_id)
|
||
|
|
- `backend/app/models/__init__.py` (added Epic, Wiki imports)
|
||
|
|
|
||
|
|
## Testing the Implementation
|
||
|
|
|
||
|
|
1. **Apply migration:**
|
||
|
|
```bash
|
||
|
|
cd backend
|
||
|
|
source venv/bin/activate
|
||
|
|
flask db upgrade
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **Verify tables created:**
|
||
|
|
```bash
|
||
|
|
flask dbcurrent
|
||
|
|
# Should show: add_epic_and_wiki_models
|
||
|
|
```
|
||
|
|
|
||
|
|
3. **Test in Python shell:**
|
||
|
|
```python
|
||
|
|
from app import create_app, db
|
||
|
|
from app.models import Epic, Wiki, Card, Board
|
||
|
|
|
||
|
|
app = create_app()
|
||
|
|
with app.app_context():
|
||
|
|
# Create an epic
|
||
|
|
epic = Epic(name="My Epic", board_id=1, color="#3b82f6")
|
||
|
|
db.session.add(epic)
|
||
|
|
db.session.commit()
|
||
|
|
|
||
|
|
# Create a wiki
|
||
|
|
wiki = Wiki(name="Security Guide", board_id=1, content={})
|
||
|
|
db.session.add(wiki)
|
||
|
|
db.session.commit()
|
||
|
|
|
||
|
|
print(f"Epic created: {epic.to_dict()}")
|
||
|
|
print(f"Wiki created: {wiki.to_dict()}")
|
||
|
|
```
|
||
|
|
|
||
|
|
## Notes
|
||
|
|
|
||
|
|
- All models follow the existing project patterns
|
||
|
|
- Uses `db` from `app` module (not `flask_sqlalchemy` directly)
|
||
|
|
- Proper foreign key constraints with CASCADE/SET NULL
|
||
|
|
- Timestamps use UTC timezone
|
||
|
|
- JSONB fields for flexible data storage
|
||
|
|
- Indexed for optimal query performance
|