Skip to content

PiqueTickets Producer Portal - Knowledge Base Feature Planning Document

Document Version: 1.0 Created: 2025-10-10 Status: Draft - Ready for Review Project: PIQUE-506 Producer Portal Knowledge Base


1. Executive Summary & Feature Overview

1.1 Feature Description

  • Feature Name: Producer Portal Knowledge Base System
  • Feature Type: New Feature
  • Priority Level: High
  • Estimated Timeline: 4-6 weeks
  • Branch: pique-506-producer-portal-knoweldge-base

1.2 Problem Statement

Current State: - No centralized documentation or help system for producers - Support requests handled manually via email/Slack - No self-service resources for common questions - Difficult to onboard new producers efficiently

Pain Points: - Producers lack easy access to platform documentation - Support team receives repetitive questions - No searchable knowledge repository - Missing visual guides and tutorials with images

User Impact: - Primary Users: Event producers using the producer portal - Secondary Users: PiqueTickets support team and administrators - Expected Impact: Reduced support burden, faster producer onboarding, improved self-service capabilities

Business Value: - Reduce support ticket volume by 40-60% - Improve producer satisfaction and retention - Scale support capabilities without additional headcount - Professional knowledge management aligned with industry standards

1.3 Expected Outcomes

Success Metrics: - 80% of producers access knowledge base within first month - 50% reduction in basic support inquiries - Average article helpfulness rating > 4.0/5.0 - Search functionality < 500ms response time - Page load time < 2 seconds

User Experience Goals: - Intuitive navigation with visual hierarchy - Fast full-text search with auto-suggestions - Mobile-responsive design matching producer portal branding - Rich media support (images, videos, embedded content) - Accessibility compliance (WCAG 2.1 AA)

Technical Goals: - Scalable architecture supporting 1000+ articles - Image optimization and CDN-ready - Analytics for content effectiveness - Easy content management for non-technical staff


2. Stakeholder Analysis & Requirements

2.1 Affected Users & Systems

Primary Users: - Event Producers: Need self-service documentation and tutorials - New Producers: Require onboarding guides and getting started content - Active Producers: Seek advanced features and troubleshooting guides

Secondary Users: - Support Team: Content creators and editors - Administrators: Knowledge base managers with analytics access - Superusers: Full editorial control and publishing rights

System Components: - Django API Backend: New knowledge app - Producer Portal Frontend: Knowledge base UI integration - PostgreSQL Database: Article storage and full-text search - S3/CloudFront: Image and media storage

Integration Points: - Authentication: Django JWT + NextAuth.js session management - User Management: Django User model + UserProfile - Media Storage: AWS S3 (existing configuration) - Email: Django email system for notifications - Search: PostgreSQL full-text search or django-watson

2.2 Functional Requirements

Must-Have Features:

  1. Article Management
  2. Rich text editor (CKEditor5 - already installed)
  3. Draft/Published/Archived workflow
  4. Featured image upload with optimization
  5. Automatic slug generation from title
  6. Category and tag assignment
  7. Estimated read time calculation
  8. View count tracking

  9. Category System

  10. Hierarchical categories (parent/child support)
  11. Icon support for visual identification
  12. Custom ordering
  13. Active/inactive status
  14. Category-based navigation

  15. Search Functionality

  16. Full-text search across title, content, tags
  17. Search result highlighting
  18. Filter by category, tags, date range
  19. Auto-suggest during typing
  20. Recent searches tracking

  21. User Feedback

  22. "Was this helpful?" voting
  23. Optional comment collection
  24. Helpful/not helpful counts per article
  25. Feedback analytics in admin

  26. Access Control

  27. Producer-only access (authenticated users)
  28. JWT authentication integration
  29. Permission-based article publishing
  30. Admin-only management interface

2.3 Non-Functional Requirements

Performance: - Page load time < 2 seconds (first contentful paint) - Search response time < 500ms - Support 100 concurrent users - Image optimization reducing file sizes by 40-60% - Lazy loading for below-the-fold images

Security: - JWT authentication for all endpoints - CSRF protection on forms - Image upload validation (type, size, dimensions) - XSS prevention on user-generated content - Rate limiting on search API (10 requests/minute) - Secure media file access control

Accessibility: - WCAG 2.1 AA compliance - Keyboard navigation support - Screen reader compatibility - Alt text required for all images - Proper heading hierarchy - Sufficient color contrast ratios

Browser/Platform Support: - Modern browsers (Chrome, Firefox, Safari, Edge - last 2 versions) - Mobile responsive (iOS Safari, Chrome Android) - Tablet optimization - Progressive enhancement approach

Reliability: - 99.9% uptime for knowledge base - Graceful degradation if search unavailable - Error handling with user-friendly messages - Database backup and recovery procedures - Monitoring and alerting for critical issues


3. Current State Analysis

3.1 Codebase Research Methodology

Tools Used: - File system exploration (mcp__serena tools) - Symbol-based code analysis (find_symbol, get_symbols_overview) - Pattern searching for existing implementations - Architecture documentation review (@CLAUDE-architecture.md) - Django settings and configuration analysis

3.2 Existing Architecture & Patterns

Tech Stack (Backend): - Framework: Django 5.1.13 - Database: PostgreSQL with connection pooling - ORM: Django ORM with optimized querysets - Storage: AWS S3 via django-storages 1.14.4 + boto3 1.36.20 - Search: PostgreSQL full-text search capabilities - Rich Text: django-ckeditor-5 0.2.17 (already installed) - Image Processing: Pillow 11.0.0 - REST API: Django REST Framework 3.15.2 - Authentication: djangorestframework-simplejwt 5.5.1

Tech Stack (Frontend - Producer Portal): - Framework: Next.js 15.2.4 with App Router - UI Library: Shadcn UI components - Styling: Tailwind CSS 4.0.0 - State: Zustand for global state - Forms: React Hook Form + Zod validation - Auth: NextAuth.js with JWT strategy

Architecture Pattern: - Service-Oriented Architecture: Business logic in service classes - RESTful API: ViewSets for CRUD, custom actions for complex operations - Layered Design: Models → Services → Serializers → Views - Template System: Django templates with Tailwind CSS - Admin Customization: Django Unfold 0.39.0 theme

Design Patterns in Use: - Slug Generation: Automatic unique slug creation (tickets/producers apps) - Image Processing: WebP conversion pipeline (Show model) - Soft Deletes: is_deleted + deleted_at pattern (Show model) - Draft Mode: Separate validation for draft vs published (Show model) - Service Layer: Transaction-decorated methods with tuple returns (ProducerService) - Signal Handlers: Auto-create related models (UserProfile creation)

Code Organization:

apps/api/
├── brktickets/          # Project settings and configuration
├── tickets/             # Core ticketing app (reference implementation)
├── producers/           # Producer management (reference for auth patterns)
├── portal/              # Producer portal backend endpoints
├── venue/               # Venue management (reference for slug/image patterns)
├── performer/           # Performer profiles (reference for rich text)
├── auth/                # Authentication views and JWT
├── email_tracking/      # Email delivery monitoring
├── theme/               # Tailwind theme configuration
└── templates/           # Shared Django templates

3.3 Relevant Existing Code

Similar Features for Reference:

  1. Show Model (apps/api/tickets/models.py):
  2. Slug generation: Automatic unique slugs from title
  3. Image processing: WebP conversion with dimension validation
  4. Draft workflow: Draft vs published with completion tracking
  5. Soft deletes: is_deleted pattern
  6. Relevance: Direct pattern match for Article model

  7. Producer Model (apps/api/producers/models.py):

  8. User association: UserProducerAssociation pattern
  9. Profile management: Extended user profiles with permissions
  10. Social media links: Multiple URL fields pattern
  11. Image uploads: Profile image handling
  12. Relevance: Author relationship and permission patterns

  13. Venue Model (apps/api/venue/models.py):

  14. Rich text content: CKEditor5 integration for descriptions
  15. Image management: Venue images with upload paths
  16. Relevance: Content management patterns

  17. Portal Views (apps/api/portal/views.py):

  18. Producer-specific filtering: Filter by authenticated user's producer
  19. Analytics aggregation: Dashboard metrics calculations
  20. Pagination patterns: DRF pagination setup
  21. Relevance: Producer portal backend patterns

  22. Authentication System (apps/api/auth/):

  23. JWT tokens: SimpleJWT configuration (48-hour access, 30-day refresh)
  24. Password reset: Token-based password recovery
  25. User permissions: Custom permission classes
  26. Relevance: Authentication and authorization patterns

Reusable Components:

  1. Slug Generation Utility (apps/api/api/utils.py):

    generate_unique_slug(instance, source_text)
    

  2. Image Processing (Show model pattern):

    def convert_image_to_webp(self, image_field)
    def validate_image_dimensions(self, field_name, width, height)
    

  3. CKEditor5 Configuration (apps/api/brktickets/settings.py):

  4. Already configured with toolbar options
  5. Image upload support
  6. Multiple configuration profiles

  7. S3 Storage Configuration (apps/api/brktickets/settings.py):

  8. STORAGES configuration for media and static files
  9. CloudFront CDN setup ready
  10. Public/private ACL patterns

  11. Serializer Patterns (DRF):

  12. Nested serializers for related data
  13. Custom validation methods
  14. SerializerMethodField for computed values

3.4 Current Dependencies

Core Dependencies (Already Installed): - ✅ Django 5.1.13 - ✅ djangorestframework 3.15.2 - ✅ Pillow 11.0.0 (image processing) - ✅ django-ckeditor-5 0.2.17 (rich text editor) - ✅ psycopg2-binary 2.9.10 (PostgreSQL) - ✅ boto3 1.36.20 (AWS S3) - ✅ django-storages 1.14.4 - ✅ djangorestframework-simplejwt 5.5.1 - ✅ django-unfold 0.39.0 (admin theme) - ✅ celery 5.4.0 (async tasks) - ✅ django-filter 24.3 (API filtering)

New Dependencies Required: - 📦 python-slugify 8.0.0 - Enhanced slug generation - 📦 markdown 3.4.0 - Markdown rendering support (optional) - 📦 django-watson 1.6.0 - Advanced search capabilities (optional alternative to PostgreSQL full-text)

Development Dependencies: - ✅ coverage 7.6.12 (test coverage) - ✅ black 25.1.0 (code formatting) - ✅ mock 5.1.0 (testing)

Version Compatibility: - Python 3.12+ (current project standard) - Django 5.1+ compatible - PostgreSQL 15+ (current database)

3.5 Potential Conflicts & Constraints

Technical Debt: - None identified that would block knowledge base implementation - Existing apps follow consistent patterns suitable for extension

Legacy Code: - No legacy code in knowledge domain (greenfield implementation) - Existing patterns are modern and well-maintained

Resource Constraints: - Database: PostgreSQL connection pooling configured (600s max age, health checks) - Storage: S3 bucket already configured with CloudFront CDN option - Memory: Image optimization will reduce memory footprint - Performance: Existing indexes strategy can be applied to knowledge tables

Compliance Requirements: - GDPR: User feedback must allow deletion (implement cascade deletes) - Accessibility: WCAG 2.1 AA compliance required (producer portal standard) - Security: Follow existing CSRF, XSS, SQL injection prevention patterns - Data Retention: Follow existing soft-delete patterns for article archival

Integration Constraints: - Must integrate with existing JWT authentication (SimpleJWT) - Must work with NextAuth.js session management in producer portal - Must use existing S3/CloudFront media configuration - Must follow Unfold admin theme patterns for consistency - Cannot modify core Django User model (use existing UserProfile pattern)

Naming Conventions: - App name: knowledge (lowercase, no underscores per Django convention) - URL prefix: /api/v1/portal/knowledge/ (nest under portal) - Model names: PascalCase (Category, Article, Tag, ArticleFeedback) - Serializer names: {Model}Serializer - ViewSet names: {Model}ViewSet


4. Research & Best Practices

4.1 Industry Standards Research

Research Sources: - Django documentation (official patterns) - Django REST Framework best practices - Knowledge base UX research (Intercom, Zendesk, GitBook patterns) - PostgreSQL full-text search documentation - Accessibility guidelines (WCAG 2.1)

Industry Best Practices:

  1. Content Organization:
  2. Hierarchical category structure (max 2-3 levels deep)
  3. Tag-based cross-referencing for discoverability
  4. Featured articles for common topics
  5. Breadcrumb navigation for context
  6. Related articles based on category/tags

  7. Search Experience:

  8. Search-as-you-type with instant results
  9. Filters for refinement (category, date, popularity)
  10. Search result highlighting
  11. "Did you mean?" suggestions for typos
  12. Recent/popular searches display

  13. Article Quality:

  14. Estimated read time (avg 200-250 words/minute)
  15. Table of contents for long articles (>500 words)
  16. Clear headings and subheadings hierarchy
  17. Visual elements every 200-300 words
  18. Actionable content with step-by-step guides

  19. Feedback Mechanisms:

  20. Binary helpful/not helpful voting
  21. Optional detailed feedback collection
  22. Feedback analytics for content improvement
  23. Display aggregate ratings to users

  24. Performance:

  25. Lazy loading for images below fold
  26. CDN for static assets and images
  27. Database query optimization (select_related, prefetch_related)
  28. Pagination for long lists

4.2 Framework-Specific Patterns

Django Best Practices:

  1. Model Design:

    # Slug generation on save
    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = generate_unique_slug(self, self.title)
        super().save(*args, **kwargs)
    
    # Calculated fields as properties
    @property
    def estimated_read_time(self):
        words = len(self.content.split())
        return max(1, round(words / 200))
    

  2. QuerySet Optimization:

    # Efficient queries with select_related/prefetch_related
    Article.objects.select_related('category', 'author').prefetch_related('tags')
    
    # Annotations for aggregated data
    Article.objects.annotate(
        helpful_percentage=F('helpful_count') * 100 / (F('helpful_count') + F('not_helpful_count'))
    )
    

  3. PostgreSQL Full-Text Search:

    from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank
    
    vector = SearchVector('title', weight='A') + SearchVector('content', weight='B')
    query = SearchQuery(search_term)
    Article.objects.annotate(
        rank=SearchRank(vector, query)
    ).filter(rank__gte=0.3).order_by('-rank')
    

  4. Admin Customization (Unfold):

    @admin.register(Article)
    class ArticleAdmin(admin.ModelAdmin):
        list_display = ['title', 'category', 'status', 'view_count', 'helpful_count']
        list_filter = ['status', 'category', 'featured', 'created_at']
        search_fields = ['title', 'content']
        prepopulated_fields = {'slug': ('title',)}
        actions = ['publish_articles', 'archive_articles']
    

Django REST Framework Patterns:

  1. ViewSet Design:

    class ArticleViewSet(viewsets.ModelViewSet):
        serializer_class = ArticleSerializer
        permission_classes = [IsAuthenticated]
        filter_backends = [DjangoFilterBackend, filters.SearchFilter]
        filterset_fields = ['category', 'tags', 'status']
        search_fields = ['title', 'content']
    
        def get_queryset(self):
            return Article.objects.filter(
                status='published'
            ).select_related('category', 'author').prefetch_related('tags')
    
        @action(detail=True, methods=['post'])
        def mark_helpful(self, request, pk=None):
            # Custom action for feedback
            pass
    

  2. Serializer Patterns:

    class ArticleSerializer(serializers.ModelSerializer):
        category_name = serializers.CharField(source='category.name', read_only=True)
        tags = TagSerializer(many=True, read_only=True)
        estimated_read_time = serializers.IntegerField(read_only=True)
    
        class Meta:
            model = Article
            fields = ['id', 'title', 'slug', 'content', 'category',
                     'category_name', 'tags', 'estimated_read_time']
            read_only_fields = ['slug', 'view_count', 'created_at']
    

4.3 Security Guidelines

OWASP Best Practices:

  1. Input Validation:
  2. Validate image file types (JPEG, PNG, WebP only)
  3. Maximum file size limits (5MB for images)
  4. Sanitize HTML content from rich text editor
  5. Validate slug format (alphanumeric + hyphens only)

  6. Output Encoding:

  7. Django template auto-escaping (already enabled)
  8. DRF JSON encoding (automatic)
  9. Image URLs with signed URLs for private content

  10. Authentication & Authorization:

  11. JWT token validation on all endpoints
  12. Producer-only access control
  13. Permission-based publishing rights
  14. CSRF tokens on admin forms

  15. Rate Limiting:

    from django_ratelimit.decorators import ratelimit
    
    @ratelimit(key='user', rate='10/m', method='GET')
    def search_articles(request):
        # Search endpoint with rate limiting
        pass
    

  16. SQL Injection Prevention:

  17. Use Django ORM (parameterized queries)
  18. Never use raw SQL with user input
  19. Use Django's Q objects for complex queries

Image Upload Security:

from PIL import Image
from django.core.exceptions import ValidationError

def validate_image(file):
    # Validate file size
    if file.size > 5 * 1024 * 1024:  # 5MB
        raise ValidationError("Image size cannot exceed 5MB")

    # Validate image type
    try:
        img = Image.open(file)
        if img.format not in ['JPEG', 'PNG', 'WEBP']:
            raise ValidationError("Only JPEG, PNG, and WebP images allowed")
    except Exception:
        raise ValidationError("Invalid image file")

4.4 Performance Benchmarks

Target Metrics: - Page load time: < 2 seconds (first contentful paint) - Search response: < 500ms - Image optimization: 40-60% size reduction - Database query count: < 10 per article page

Optimization Strategies:

  1. Database Indexes:

    class Article(models.Model):
        # ... fields ...
    
        class Meta:
            indexes = [
                models.Index(fields=['slug']),
                models.Index(fields=['status', 'published_at']),
                models.Index(fields=['category', 'status']),
                models.Index(fields=['-view_count']),
                models.Index(fields=['-helpful_count']),
            ]
    

  2. Image Optimization:

  3. WebP conversion (85% quality)
  4. Multiple sizes (thumbnail: 150x150, medium: 600x400, large: 1200x800)
  5. Lazy loading with intersection observer
  6. CDN delivery

  7. Query Optimization:

    # Efficient queryset with annotations
    Article.objects.filter(status='published').select_related(
        'category', 'author'
    ).prefetch_related('tags').annotate(
        helpful_ratio=Case(
            When(helpful_count__gt=0, then=F('helpful_count') * 100 /
                 (F('helpful_count') + F('not_helpful_count'))),
            default=0,
            output_field=FloatField()
        )
    )
    


5. Solution Design

5.1 Proposed Architecture

High-Level System Design:

┌─────────────────────────────────────────────────────────────┐
│                   Producer Portal Frontend                   │
│                    (Next.js App Router)                      │
│  ┌──────────────┬──────────────┬─────────────────────────┐  │
│  │ Knowledge    │ Article      │ Search                  │  │
│  │ Home         │ Detail       │ Results                 │  │
│  └──────────────┴──────────────┴─────────────────────────┘  │
└────────────────────────┬────────────────────────────────────┘
                         │ HTTP/JSON (JWT Auth)
┌─────────────────────────────────────────────────────────────┐
│              Django REST API Backend                         │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ knowledge.views (ViewSets & Custom Views)            │   │
│  │  ├─ ArticleViewSet                                   │   │
│  │  ├─ CategoryViewSet                                  │   │
│  │  ├─ TagViewSet                                       │   │
│  │  ├─ SearchView (custom)                              │   │
│  │  └─ FeedbackView (custom)                            │   │
│  └──────────────────────────────────────────────────────┘   │
│                         ↓                                    │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ knowledge.serializers                                │   │
│  │  ├─ ArticleSerializer                                │   │
│  │  ├─ ArticleDetailSerializer (with related data)      │   │
│  │  ├─ CategorySerializer                               │   │
│  │  └─ FeedbackSerializer                               │   │
│  └──────────────────────────────────────────────────────┘   │
│                         ↓                                    │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ knowledge.models                                     │   │
│  │  ├─ Category (hierarchical)                          │   │
│  │  ├─ Tag                                              │   │
│  │  ├─ Article (main content)                           │   │
│  │  └─ ArticleFeedback                                  │   │
│  └──────────────────────────────────────────────────────┘   │
└────────────────┬───────────────────────┬───────────────────┘
                 │                       │
                 ↓                       ↓
┌────────────────────────┐   ┌──────────────────────┐
│  PostgreSQL Database   │   │   AWS S3 Storage     │
│  - Articles            │   │   - Featured Images  │
│  - Categories          │   │   - Article Assets   │
│  - Tags                │   │   - Thumbnails       │
│  - Feedback            │   │   - WebP Optimized   │
│  - Full-text Search    │   └──────────────────────┘
└────────────────────────┘

Data Model Design:

┌────────────────────┐
│    Category        │
│                    │
│  - id (PK)         │
│  - name            │
│  - slug (unique)   │
│  - description     │
│  - icon            │
│  - order           │
│  - parent_id (FK)  │──┐ Self-referential
│  - is_active       │  │ for hierarchy
│  - created_at      │  │
│  - updated_at      │←─┘
└─────────┬──────────┘
          │ Many-to-One
┌────────────────────┐        ┌────────────────────┐
│     Article        │        │       Tag          │
│                    │        │                    │
│  - id (PK)         │        │  - id (PK)         │
│  - title           │        │  - name (unique)   │
│  - slug (unique)   │        │  - slug (unique)   │
│  - content (text)  │        │  - created_at      │
│  - excerpt         │        └────────────────────┘
│  - category_id(FK) │                 ↑
│  - author_id (FK)  │                 │
│  - status          │                 │ Many-to-Many
│  - featured        │                 │
│  - featured_image  │        ┌────────┴───────────┐
│  - image_alt_text  │        │  Article_Tags      │
│  - view_count      │        │                    │
│  - helpful_count   │        │  - article_id (FK) │
│  - not_helpful_ct  │        │  - tag_id (FK)     │
│  - published_at    │        └────────────────────┘
│  - created_at      │
│  - updated_at      │
│  - meta_desc       │
│  - est_read_time   │
└─────────┬──────────┘
          │ One-to-Many
┌────────────────────┐        ┌────────────────────┐
│ ArticleFeedback    │        │      User          │
│                    │        │  (Django Auth)     │
│  - id (PK)         │        │                    │
│  - article_id (FK) │        │  - id (PK)         │
│  - user_id (FK)    │───────→│  - username        │
│  - is_helpful      │        │  - email           │
│  - comment         │        │  - ...             │
│  - created_at      │        └────────────────────┘
└────────────────────┘

API Endpoint Design:

Base URL: /api/v1/portal/knowledge/

Endpoints:
├── /categories/
│   ├── GET /                     # List all active categories
│   ├── GET /{slug}/              # Get category by slug
│   └── GET /{slug}/articles/     # List articles in category
├── /tags/
│   ├── GET /                     # List all tags
│   └── GET /{slug}/articles/     # List articles with tag
├── /articles/
│   ├── GET /                     # List articles (paginated, filterable)
│   │   ?category={slug}
│   │   ?tag={slug}
│   │   ?status=published
│   │   ?featured=true
│   │   ?search={query}
│   │   ?page={num}
│   │   ?page_size={num}
│   │
│   ├── GET /{slug}/              # Get article detail
│   ├── GET /featured/            # Get featured articles
│   ├── GET /recent/              # Get recent articles
│   ├── GET /popular/             # Get most viewed articles
│   │
│   └── POST /{slug}/feedback/    # Submit article feedback
│       {
│         "is_helpful": true,
│         "comment": "optional"
│       }
└── /search/
    ├── GET /                     # Full-text search
    │   ?q={query}
    │   ?category={slug}
    │   ?page={num}
    └── GET /suggestions/         # Search autocomplete
        ?q={partial_query}

URL Structure (Frontend):

Producer Portal Routes:
├── /dashboard/knowledge/
│   ├── /                                 # Knowledge base home
│   ├── /category/{slug}/                 # Category view
│   ├── /article/{slug}/                  # Article detail
│   ├── /tag/{slug}/                      # Tag view
│   └── /search?q={query}                 # Search results

5.2 Technology Decisions

Backend Technology Stack:

Component Technology Justification
Rich Text Editor CKEditor5 (existing) Already configured, supports images, proven in Performer/Venue apps
Image Processing Pillow (existing) Handles WebP conversion, already used in Show model
Search Engine PostgreSQL Full-Text Search Native to PostgreSQL, no additional infrastructure, sufficient for <10K articles
Storage AWS S3 + CloudFront (existing) Already configured, CDN-ready, cost-effective
Slug Generation Django slugify + uniqueness check Proven pattern in Show/Producer models
API Framework Django REST Framework (existing) Consistent with existing portal endpoints

New Dependencies:

  1. python-slugify 8.0.0
  2. Purpose: Enhanced slug generation with Unicode support
  3. Why: Better than Django's default slugify for international characters
  4. Alternatives Considered: Django's slugify (less robust), manual implementation (more work)
  5. Risk: Minimal, stable library with 10M+ downloads

  6. markdown 3.4.0 (Optional)

  7. Purpose: Markdown rendering if we want to support Markdown in addition to HTML
  8. Why: Some users prefer Markdown for technical documentation
  9. Alternatives Considered: Rich text only (simpler but less flexible)
  10. Risk: Low, optional feature that can be added later

  11. django-watson 1.6.0 (Alternative)

  12. Purpose: Advanced full-text search with better relevance ranking
  13. Why: Better than PostgreSQL search for large scale, easier to use
  14. Alternatives Considered: PostgreSQL full-text (simpler, no dependencies), Elasticsearch (overkill)
  15. Risk: Low, can start with PostgreSQL and migrate if needed
  16. Decision: Start with PostgreSQL, add django-watson if search quality insufficient

Frontend Technology Stack:

Component Technology Justification
Framework Next.js 15 App Router (existing) Already used in producer portal
UI Components Shadcn UI (existing) Consistent with portal design system
Styling Tailwind CSS (existing) Matches existing producer portal
Forms React Hook Form + Zod (existing) Standard for producer portal
Data Fetching Native fetch with SWR pattern Consistent with portal patterns
Rich Text Display DOMPurify + dangerouslySetInnerHTML XSS protection for HTML content

Alternative Solutions Considered:

  1. Headless CMS (Contentful, Strapi)
  2. Pros: Feature-rich, managed service, non-technical content editing
  3. Cons: Additional cost, vendor lock-in, learning curve, over-engineered
  4. Decision: Rejected - Django admin sufficient for V1

  5. Wiki Software (MediaWiki, DokuWiki)

  6. Pros: Purpose-built for documentation, versioning, mature
  7. Cons: Separate authentication, difficult integration, different tech stack
  8. Decision: Rejected - Maintain tech stack consistency

  9. Static Site Generator (Docusaurus, GitBook)

  10. Pros: Fast, version-controlled, markdown-based
  11. Cons: Not dynamic, no user feedback, deployment complexity
  12. Decision: Rejected - Need dynamic features (search, feedback, analytics)

5.3 Security Considerations

Threat Model:

Threat Likelihood Impact Mitigation
Unauthorized access to articles Medium Medium JWT authentication on all endpoints
XSS via article content High High CKEditor5 sanitization + DOMPurify on frontend
SQL injection via search Low Critical PostgreSQL parameterized queries via ORM
CSRF on feedback forms Medium Medium Django CSRF tokens (already enabled)
Image upload malware Low High File type validation, size limits, virus scanning (future)
DoS via search Medium Medium Rate limiting (10 req/min per user)
Data breach of user feedback Low Medium Encrypted database, secure backups

Authentication & Authorization:

# JWT Authentication (already configured)
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
}

# Custom permission for knowledge base
class IsProducerUser(permissions.BasePermission):
    """
    Only allow access to authenticated producers.
    """
    def has_permission(self, request, view):
        return (
            request.user and
            request.user.is_authenticated and
            hasattr(request.user, 'producer_profile')
        )

Input Validation:

# Article model validation
from django.core.validators import FileExtensionValidator, MaxValueValidator

class Article(models.Model):
    # Image validation
    featured_image = models.ImageField(
        upload_to='knowledge/articles/',
        blank=True,
        validators=[
            FileExtensionValidator(['jpg', 'jpeg', 'png', 'webp']),
            validate_image_size,  # Custom validator for 5MB limit
        ]
    )

    # Content validation
    content = models.TextField(
        validators=[MaxLengthValidator(50000)]  # Prevent abuse
    )

    def clean(self):
        # Additional validation logic
        if self.status == 'published':
            if not self.title or not self.content or not self.category:
                raise ValidationError("Published articles must have title, content, and category")

Output Encoding:

# Serializer with safe HTML rendering
class ArticleSerializer(serializers.ModelSerializer):
    # Content is already sanitized by CKEditor5
    # Frontend will use DOMPurify as additional layer

    def to_representation(self, instance):
        data = super().to_representation(instance)
        # Ensure all URLs are absolute for images
        if data.get('featured_image'):
            data['featured_image'] = request.build_absolute_uri(data['featured_image'])
        return data

Rate Limiting:

# settings.py
RATELIMIT_ENABLE = True

# views.py
from django_ratelimit.decorators import ratelimit
from django_ratelimit.exceptions import Ratelimited

class SearchView(APIView):
    @ratelimit(key='user', rate='10/m', method='GET')
    def get(self, request):
        # Search implementation
        pass

Data Protection:

  1. Encryption at Rest: PostgreSQL encryption (AWS RDS default)
  2. Encryption in Transit: HTTPS only (SECURE_SSL_REDIRECT=True in production)
  3. Backup Strategy: Automated daily backups with 30-day retention
  4. Access Logs: Track all article views and feedback submissions
  5. GDPR Compliance: Allow users to delete their feedback (CASCADE deletes)

6. Implementation Plan

6.1 Development Phases

Phase 1: Foundation & Models [Timeline: Week 1]

Objective: Set up Django app structure, create database models, configure admin

Tasks: - [x] Create knowledge Django app - Files: apps/api/knowledge/__init__.py, apps/api/knowledge/apps.py - Add to INSTALLED_APPS in apps/api/brktickets/settings.py:84

  • Create database models
  • File: apps/api/knowledge/models.py
  • Models: Category, Tag, Article, ArticleFeedback
  • Include Meta classes with indexes and ordering

  • Create model admin classes

  • File: apps/api/knowledge/admin.py
  • Configure Unfold admin for all models
  • Add list_display, list_filter, search_fields
  • Configure CKEditor5 for Article.content
  • Add custom actions (publish, archive, bulk operations)

  • Create and run migrations

  • Command: python manage.py makemigrations knowledge
  • Command: python manage.py migrate
  • Verify tables created in PostgreSQL

  • Create model fixtures for testing

  • File: apps/api/knowledge/fixtures/sample_data.json
  • 5-10 categories, 20-30 tags, 50+ sample articles

  • Write unit tests for models

  • File: apps/api/knowledge/tests/test_models.py
  • Test slug generation, read time calculation
  • Test model validation and relationships
  • Test soft delete behavior

Deliverable: - Fully functional Django app with database models - Admin interface for content management - Passing unit tests (>90% model coverage)


Phase 2: API & Serializers [Timeline: Week 2]

Objective: Build REST API endpoints with DRF

Tasks: - [ ] Create serializers - File: apps/api/knowledge/serializers.py - CategorySerializer (with article count) - TagSerializer - ArticleListSerializer (summary view) - ArticleDetailSerializer (with related data) - FeedbackSerializer - Implement nested serializers for related objects

  • Create ViewSets
  • File: apps/api/knowledge/views.py
  • CategoryViewSet (read-only for producers)
  • TagViewSet (read-only)
  • ArticleViewSet (with custom actions)
    • Custom action: increment_view_count
    • Custom action: get_related_articles
    • Custom action: submit_feedback
  • Implement queryset optimization (select_related, prefetch_related)

  • Implement search functionality

  • File: apps/api/knowledge/views.py (SearchView class)
  • PostgreSQL full-text search implementation
  • Search ranking by relevance
  • Filter by category, tags, date range
  • Pagination support

  • Implement filtering

  • File: apps/api/knowledge/filters.py
  • ArticleFilter with django-filter
  • Category, tag, status, featured filters
  • Date range filters

  • Configure URL routing

  • File: apps/api/knowledge/urls.py
  • Register ViewSets with DRF router
  • Add custom search endpoint
  • Nest under /api/v1/portal/knowledge/
  • Update: apps/api/portal/urls.py to include knowledge URLs

  • Write API integration tests

  • File: apps/api/knowledge/tests/test_api.py
  • Test all endpoints with authentication
  • Test filtering, searching, pagination
  • Test feedback submission
  • Test permissions (producer-only access)

Deliverable: - Fully functional REST API - Comprehensive test coverage (>85%) - API documentation via DRF browsable API


Phase 3: Frontend Integration [Timeline: Week 3]

Objective: Build Next.js frontend for knowledge base

Tasks: - [ ] Create API client functions - File: apps/producer/src/lib/api/knowledge.ts - fetchCategories() - fetchArticles(filters) - fetchArticleBySlug(slug) - searchArticles(query) - submitFeedback(articleId, feedback)

  • Create TypeScript types
  • File: apps/producer/src/types/knowledge.ts
  • Interface: Category, Tag, Article, ArticleFeedback
  • Type: SearchFilters, ArticleStatus

  • Build page components

  • File: apps/producer/src/app/dashboard/knowledge/page.tsx

    • Knowledge base home with category grid
    • Featured articles carousel
    • Recent articles list
    • Quick stats display
  • File: apps/producer/src/app/dashboard/knowledge/category/[slug]/page.tsx

    • Category article list with filters
    • Subcategory navigation
    • Sort controls (newest, most viewed, most helpful)
  • File: apps/producer/src/app/dashboard/knowledge/article/[slug]/page.tsx

    • Article detail view with hero image
    • Breadcrumb navigation
    • Table of contents (auto-generated)
    • Related articles sidebar
    • Feedback widget
    • Social sharing buttons
  • File: apps/producer/src/app/dashboard/knowledge/search/page.tsx

    • Search results page
    • Filter sidebar
    • Result highlighting
    • Pagination controls
  • Build UI components

  • File: apps/producer/src/components/knowledge/ArticleCard.tsx
  • File: apps/producer/src/components/knowledge/CategoryCard.tsx
  • File: apps/producer/src/components/knowledge/FeedbackWidget.tsx
  • File: apps/producer/src/components/knowledge/SearchBar.tsx
  • File: apps/producer/src/components/knowledge/TableOfContents.tsx
  • Use Shadcn UI components for consistency

  • Implement search with debouncing

  • File: apps/producer/src/hooks/useSearch.ts
  • Custom hook with debounce (300ms)
  • Auto-suggest functionality
  • Search history tracking

  • Add to navigation menu

  • File: apps/producer/src/components/layout/Sidebar.tsx
  • Add "Knowledge Base" link with icon
  • Position under Dashboard, above Settings

Deliverable: - Fully functional frontend interface - Mobile-responsive design - Integrated with producer portal navigation


Phase 4: Image Processing & Optimization [Timeline: Week 4]

Objective: Implement image upload, optimization, and CDN delivery

Tasks: - [ ] Create image processing utilities - File: apps/api/knowledge/utils/image_processing.py - Function: convert_to_webp(image_file) - Function: generate_thumbnails(image_file, sizes) - Function: validate_image_dimensions(image, min_width, min_height) - Function: optimize_image_quality(image, quality=85)

  • Add image processing to Article model
  • Update: apps/api/knowledge/models.py
  • Override save() method to process featured_image
  • Generate multiple sizes on upload
  • Store WebP versions with fallbacks

  • Configure image upload in admin

  • Update: apps/api/knowledge/admin.py
  • Add image preview in list view
  • Add image cropping interface (optional)
  • Show image dimensions and file size

  • Implement lazy loading on frontend

  • Update all image components to use lazy loading
  • Use Intersection Observer API
  • Add skeleton loaders for images

  • Configure CDN headers

  • Update: S3 bucket configuration
  • Configure CloudFront distribution (if needed)

  • Create management command for image optimization

  • File: apps/api/knowledge/management/commands/optimize_images.py
  • Regenerate all thumbnails
  • Convert existing images to WebP
  • Clean orphaned media files

Deliverable: - Optimized image pipeline - 40-60% file size reduction - Fast image loading with lazy loading


Phase 5: Search Enhancement & Analytics [Timeline: Week 5]

Objective: Advanced search features and analytics dashboard

Tasks: - [ ] Enhance search with ranking - Update: apps/api/knowledge/views.py (SearchView) - Implement relevance scoring - Add search term highlighting - Add "Did you mean?" suggestions (optional)

  • Implement search autocomplete
  • File: apps/api/knowledge/views.py (SearchSuggestionsView)
  • Endpoint: /api/v1/portal/knowledge/search/suggestions/
  • Return top 5 suggestions based on partial query

  • Create analytics models

  • File: apps/api/knowledge/models.py
  • Model: SearchQuery (track popular searches)
  • Model: ArticleView (detailed view tracking)
  • Add analytics aggregation methods

  • Build admin analytics dashboard

  • File: apps/api/knowledge/admin.py
  • Custom admin view for analytics
  • Most viewed articles chart
  • Most helpful articles chart
  • Popular search terms
  • View trends over time

  • Add performance monitoring

  • Install django-debug-toolbar (dev only)
  • Monitor query counts per page
  • Optimize slow queries
  • Add database indexes as needed

Deliverable: - Enhanced search experience - Analytics dashboard for content team - Optimized performance


Phase 6: Testing, Polish & Deployment [Timeline: Week 6]

Objective: Comprehensive testing, bug fixes, and production deployment

Tasks: - [ ] Write comprehensive test suite - File: apps/api/knowledge/tests/test_views.py - File: apps/api/knowledge/tests/test_serializers.py - File: apps/api/knowledge/tests/test_search.py - File: apps/api/knowledge/tests/test_permissions.py - Achieve >85% code coverage

  • Perform accessibility audit
  • Test with screen readers (NVDA, JAWS)
  • Verify keyboard navigation
  • Check color contrast ratios
  • Validate ARIA labels
  • Run automated accessibility tests (axe)

  • Performance testing

  • Load test with 100 concurrent users
  • Verify page load times < 2s
  • Check search response times < 500ms
  • Monitor database query counts
  • Test with large datasets (1000+ articles)

  • Security audit

  • Test authentication/authorization
  • Verify XSS protection
  • Test CSRF protection
  • Validate rate limiting
  • Check image upload security
  • SQL injection testing

  • Create documentation

  • File: apps/api/knowledge/README.md
  • API documentation
  • Content management guide
  • Search optimization tips
  • Troubleshooting guide

  • Create sample content

  • Write 20-30 initial articles
  • Cover common producer questions
  • Include getting started guides
  • Add troubleshooting articles
  • Upload optimized images

  • Database migration for production

  • Create migration plan
  • Test migrations on staging
  • Plan rollback strategy
  • Schedule maintenance window

  • Deploy to staging

  • Deploy Django app changes
  • Deploy frontend changes
  • Run smoke tests
  • Verify S3 integration
  • Test search functionality

  • User acceptance testing

  • Internal testing with team
  • Beta testing with select producers
  • Collect feedback
  • Fix critical bugs

  • Deploy to production

  • Execute deployment plan
  • Monitor error logs
  • Monitor performance metrics
  • Verify CDN delivery
  • Announce to users

Deliverable: - Production-ready knowledge base - Comprehensive documentation - Passing all tests and audits - Successfully deployed to production


6.2 Detailed Task Breakdown

Task Files Affected Estimated Hours Dependencies Priority
Phase 1: Foundation
Create Django app structure apps/api/knowledge/__init__.py, apps.py, settings.py 1 None Critical
Design and implement Category model apps/api/knowledge/models.py 3 App structure Critical
Design and implement Tag model apps/api/knowledge/models.py 2 App structure Critical
Design and implement Article model apps/api/knowledge/models.py 6 Category, Tag models Critical
Design and implement ArticleFeedback model apps/api/knowledge/models.py 2 Article model Critical
Configure admin for Category apps/api/knowledge/admin.py 2 Category model High
Configure admin for Tag apps/api/knowledge/admin.py 1 Tag model High
Configure admin for Article apps/api/knowledge/admin.py 4 Article model High
Configure admin for ArticleFeedback apps/api/knowledge/admin.py 2 Feedback model High
Create database migrations Migration files 1 All models Critical
Create sample data fixtures fixtures/sample_data.json 4 Migrations Medium
Write model unit tests tests/test_models.py 8 All models High
Phase 2: API
Create CategorySerializer serializers.py 2 Category model High
Create TagSerializer serializers.py 1 Tag model High
Create ArticleListSerializer serializers.py 3 Article model High
Create ArticleDetailSerializer serializers.py 4 Article model High
Create FeedbackSerializer serializers.py 2 Feedback model High
Implement CategoryViewSet views.py 3 CategorySerializer High
Implement TagViewSet views.py 2 TagSerializer High
Implement ArticleViewSet views.py 8 ArticleSerializers Critical
Implement SearchView views.py 6 Article model Critical
Configure article filters filters.py 3 Article model Medium
Configure URL routing urls.py, portal/urls.py 2 All ViewSets Critical
Write API integration tests tests/test_api.py 12 All ViewSets High
Phase 3: Frontend
Create TypeScript types src/types/knowledge.ts 2 API design High
Create API client functions src/lib/api/knowledge.ts 4 API endpoints Critical
Build knowledge base home page app/dashboard/knowledge/page.tsx 8 API client Critical
Build category page app/.../category/[slug]/page.tsx 6 API client High
Build article detail page app/.../article/[slug]/page.tsx 10 API client Critical
Build search results page app/.../search/page.tsx 6 Search API High
Create ArticleCard component components/knowledge/ArticleCard.tsx 3 Types Medium
Create CategoryCard component components/knowledge/CategoryCard.tsx 3 Types Medium
Create FeedbackWidget component components/knowledge/FeedbackWidget.tsx 4 Feedback API Medium
Create SearchBar component components/knowledge/SearchBar.tsx 4 Search API Medium
Create TableOfContents component components/knowledge/TableOfContents.tsx 4 None Low
Implement search hook hooks/useSearch.ts 3 Search API Medium
Add navigation menu link components/layout/Sidebar.tsx 1 None Medium
Phase 4: Images
Create image processing utilities utils/image_processing.py 6 Pillow High
Add image processing to Article save models.py 4 Utilities High
Configure image upload in admin admin.py 3 Model updates Medium
Implement lazy loading Frontend components 4 None Medium
Configure CDN headers S3 settings 2 None Medium
Create image optimization command management/commands/optimize_images.py 4 Utilities Low
Phase 5: Search & Analytics
Enhance search ranking views.py (SearchView) 6 Search implementation Medium
Implement autocomplete views.py (SearchSuggestionsView) 4 Search Medium
Create analytics models models.py 4 None Low
Build analytics dashboard admin.py 8 Analytics models Low
Add performance monitoring Multiple files 4 django-debug-toolbar Low
Phase 6: Testing & Deployment
Write view tests tests/test_views.py 10 All views High
Write serializer tests tests/test_serializers.py 6 All serializers High
Write search tests tests/test_search.py 6 Search implementation High
Write permission tests tests/test_permissions.py 4 Permissions High
Accessibility audit All frontend files 8 Frontend complete High
Performance testing N/A 6 Complete app High
Security audit N/A 6 Complete app Critical
Create documentation README.md, docs 8 Complete app Medium
Create sample content Admin interface 12 Deployment ready Medium
Deploy to staging Infrastructure 4 Tests passing High
User acceptance testing N/A 8 Staging deployment High
Production deployment Infrastructure 6 UAT passing Critical

Total Estimated Hours: 280-320 hours (approximately 6-8 weeks with 1 developer)

6.3 File Change Summary

New Files:

Backend (apps/api/knowledge/):

apps/api/knowledge/
├── __init__.py
├── apps.py
├── models.py                              # Category, Tag, Article, ArticleFeedback
├── admin.py                               # Unfold admin configuration
├── serializers.py                         # DRF serializers
├── views.py                               # ViewSets and custom views
├── urls.py                                # URL routing
├── filters.py                             # Django-filter configuration
├── permissions.py                         # Custom permissions
├── utils/
│   ├── __init__.py
│   ├── image_processing.py                # Image optimization utilities
│   └── search.py                          # Search utilities
├── management/
│   └── commands/
│       ├── __init__.py
│       ├── import_articles.py             # CSV import command
│       ├── generate_sample_knowledge.py   # Sample data generator
│       ├── update_read_times.py           # Batch update read times
│       ├── regenerate_thumbnails.py       # Batch image processing
│       └── clean_orphaned_media.py        # Media cleanup
├── migrations/
│   ├── __init__.py
│   └── 0001_initial.py                    # Initial models migration
├── fixtures/
│   └── sample_data.json                   # Sample categories and articles
└── tests/
    ├── __init__.py
    ├── test_models.py                     # Model unit tests
    ├── test_serializers.py                # Serializer tests
    ├── test_views.py                      # View/API tests
    ├── test_search.py                     # Search functionality tests
    └── test_permissions.py                # Permission tests

Frontend (apps/producer/src/):

apps/producer/src/
├── app/dashboard/knowledge/
│   ├── page.tsx                           # Knowledge base home
│   ├── layout.tsx                         # Knowledge base layout
│   ├── category/
│   │   └── [slug]/
│   │       └── page.tsx                   # Category article list
│   ├── article/
│   │   └── [slug]/
│   │       └── page.tsx                   # Article detail view
│   ├── tag/
│   │   └── [slug]/
│   │       └── page.tsx                   # Tag article list
│   └── search/
│       └── page.tsx                       # Search results
├── components/knowledge/
│   ├── ArticleCard.tsx                    # Article preview card
│   ├── CategoryCard.tsx                   # Category card with icon
│   ├── FeedbackWidget.tsx                 # Helpful/not helpful widget
│   ├── SearchBar.tsx                      # Search input with autocomplete
│   ├── TableOfContents.tsx                # Auto-generated TOC
│   ├── RelatedArticles.tsx                # Related articles sidebar
│   └── Breadcrumbs.tsx                    # Navigation breadcrumbs
├── lib/api/
│   └── knowledge.ts                       # API client functions
├── types/
│   └── knowledge.ts                       # TypeScript interfaces
├── hooks/
│   ├── useSearch.ts                       # Search with debounce
│   ├── useArticle.ts                      # Article fetching hook
│   └── useCategories.ts                   # Categories fetching hook
└── styles/knowledge/
    ├── article.css                        # Article-specific styles
    └── knowledge.css                      # General knowledge base styles

Modified Files:

Backend: - apps/api/brktickets/settings.py:84 - Add 'knowledge' to INSTALLED_APPS - apps/api/portal/urls.py - Include knowledge URLs under portal - apps/api/brktickets/settings.py - Add knowledge-specific settings (optional)

Frontend: - apps/producer/src/components/layout/Sidebar.tsx - Add knowledge base nav link - apps/producer/src/app/dashboard/layout.tsx - Update navigation (if needed)

Documentation: - apps/api/knowledge/README.md - Knowledge base documentation (new) - docs/knowledge-base-planning.md - This planning document (new) - @CLAUDE-architecture.md - Update with knowledge base info

Deleted Files: - None (greenfield implementation)


7. Testing Strategy

7.1 Test Coverage Plan

Unit Tests (Backend):

  1. Model Tests (apps/api/knowledge/tests/test_models.py):

    class CategoryModelTest(TestCase):
        def test_slug_generation_from_name()
        def test_hierarchical_category_relationship()
        def test_category_ordering()
        def test_active_inactive_status()
    
    class ArticleModelTest(TestCase):
        def test_slug_uniqueness()
        def test_estimated_read_time_calculation()
        def test_status_transitions()
        def test_view_count_increment()
        def test_soft_delete_behavior()
        def test_featured_image_processing()
        def test_published_articles_only_query()
    
    class ArticleFeedbackTest(TestCase):
        def test_feedback_submission()
        def test_user_can_only_submit_once()
        def test_helpful_count_update()
    

  2. Serializer Tests (tests/test_serializers.py):

    class ArticleSerializerTest(TestCase):
        def test_serialization_includes_all_fields()
        def test_nested_category_data()
        def test_nested_tag_data()
        def test_read_only_fields()
        def test_validation_for_required_fields()
    

  3. View Tests (tests/test_views.py):

    class ArticleViewSetTest(APITestCase):
        def test_list_articles_requires_authentication()
        def test_filter_by_category()
        def test_filter_by_tag()
        def test_pagination()
        def test_view_count_increment()
        def test_related_articles()
    
    class SearchViewTest(APITestCase):
        def test_search_by_title()
        def test_search_by_content()
        def test_search_ranking()
        def test_search_filters()
        def test_rate_limiting()
    

  4. Permission Tests (tests/test_permissions.py):

    class PermissionTest(APITestCase):
        def test_unauthenticated_user_denied()
        def test_authenticated_producer_allowed()
        def test_non_producer_denied()
        def test_draft_articles_not_visible()
    

Integration Tests (Backend):

  1. API Flow Tests:
  2. Complete user journey from home to article to feedback
  3. Search → filter → view article → submit feedback
  4. Category navigation → subcategory → article
  5. Image upload → processing → retrieval

  6. Database Tests:

  7. Foreign key constraints
  8. Cascade deletes
  9. Index performance
  10. Transaction rollbacks

Frontend Tests:

  1. Component Tests (Jest + React Testing Library):

    // ArticleCard.test.tsx
    describe('ArticleCard', () => {
      it('renders article title and excerpt')
      it('displays featured image with lazy loading')
      it('shows estimated read time')
      it('navigates to article on click')
    });
    
    // FeedbackWidget.test.tsx
    describe('FeedbackWidget', () => {
      it('renders helpful/not helpful buttons')
      it('submits feedback on button click')
      it('shows thank you message after submission')
      it('prevents duplicate submissions')
    });
    

  2. Integration Tests:

  3. API client function mocking
  4. Form submission flows
  5. Navigation between pages
  6. Search functionality

E2E Tests (Playwright):

  1. User Journeys:
    test('Producer can search and read article', async ({ page }) => {
      // Login as producer
      // Navigate to knowledge base
      // Search for "stripe setup"
      // Click first result
      // Verify article displays
      // Mark as helpful
      // Verify feedback submitted
    });
    
    test('Producer can browse by category', async ({ page }) => {
      // Login as producer
      // Navigate to knowledge base
      // Click "Getting Started" category
      // Verify articles display
      // Click article
      // Verify article detail shows
    });
    

Target Coverage: - Unit tests: >90% for models, >85% for serializers - Integration tests: >85% for views and API - Frontend tests: >80% for components - E2E tests: Critical user paths (5-10 scenarios)

7.2 Test Environment Requirements

Development Environment:

# Backend testing
cd apps/api
python manage.py test knowledge --settings=brktickets.test_settings

# With coverage
coverage run --source='knowledge' manage.py test knowledge
coverage report
coverage html

# Frontend testing
cd apps/producer
npm run test
npm run test:coverage

Test Database: - Separate test database (auto-created by Django) - In-memory SQLite for unit tests (fast) - PostgreSQL for integration tests (realistic)

Test Data: - Fixtures for consistent test data - Factory pattern for dynamic test objects (factory_boy) - Separate test media storage directory

Staging Environment: - Mirror of production configuration - Separate S3 bucket for test media - Full authentication flow testing

7.3 Acceptance Criteria

Definition of Done:

  • Functionality:
  • All models created with proper relationships
  • All API endpoints implemented and documented
  • All frontend pages functional and responsive
  • Search returns relevant results < 500ms
  • Image upload and optimization working
  • Feedback submission and display working
  • Category navigation and filtering working

  • Code Quality:

  • All unit tests passing (>90% model coverage)
  • All integration tests passing (>85% view coverage)
  • All E2E tests passing (critical paths)
  • Code reviewed by at least one team member
  • No linting errors (black, flake8)
  • TypeScript strict mode passing

  • Performance:

  • Page load time < 2 seconds (measured)
  • Search response < 500ms (measured)
  • Image file sizes reduced by 40-60%
  • Database query count < 10 per article page

  • Security:

  • All endpoints require authentication
  • CSRF protection on forms
  • XSS prevention verified
  • Rate limiting tested
  • Image upload validation working
  • No SQL injection vulnerabilities

  • Accessibility:

  • WCAG 2.1 AA compliance verified
  • Keyboard navigation working
  • Screen reader tested
  • All images have alt text
  • Color contrast ratios met
  • Automated accessibility tests passing

  • Documentation:

  • API documentation complete
  • README with setup instructions
  • Content management guide
  • Inline code comments for complex logic
  • Architecture documentation updated

  • Deployment:

  • Migrations run successfully on staging
  • All tests passing on staging
  • No breaking changes to existing features
  • Rollback plan documented
  • Monitoring and alerts configured
  • Sample content loaded

User Acceptance Criteria:

  1. As a producer, I can:
  2. Browse knowledge base categories
  3. Search for articles by keyword
  4. Read articles with images and formatting
  5. Mark articles as helpful/not helpful
  6. Navigate related articles
  7. Bookmark articles for later (should-have)
  8. Access knowledge base on mobile

  9. As an administrator, I can:

  10. Create/edit/delete articles via admin
  11. Upload and optimize images
  12. Organize articles into categories
  13. View analytics on article performance
  14. Publish/unpublish articles
  15. Manage hierarchical categories

  16. As a support team member, I can:

  17. Create articles with rich text editor
  18. Add tags for cross-referencing
  19. Set featured articles
  20. View which articles are most helpful
  21. See popular search terms

Performance Acceptance: - 95th percentile page load < 2.5 seconds - 99th percentile search response < 750ms - Support 100 concurrent users without degradation - Zero critical errors in first week

Business Acceptance: - 50% of active producers access knowledge base in first month - Average article helpfulness rating > 4.0/5.0 - 30% reduction in support tickets within 3 months - Positive user feedback in surveys


8. Risk Assessment & Mitigation

8.1 Technical Risks

Risk Probability Impact Mitigation Strategy
PostgreSQL full-text search insufficient for large scale Medium Medium Start with PostgreSQL, add django-watson if search quality degrades. Elasticsearch is fallback for >10K articles. Monitor search quality metrics.
Image processing performance bottleneck Low Medium Process images asynchronously with Celery. Use Pillow optimization settings. Consider external service (Cloudinary) if issues persist.
S3 costs exceed budget Low Medium Implement image compression. Monitor usage monthly. Add image size limits.
CKEditor5 XSS vulnerabilities Low High Use built-in CKEditor5 sanitization. Add DOMPurify on frontend. Regular security updates. Content Security Policy headers.
Database migration issues Medium High Test migrations on staging first. Create rollback scripts. Schedule maintenance window. Have database backup ready.
Authentication integration issues with NextAuth Low High Use existing JWT pattern from portal. Test thoroughly with producer accounts. Have fallback session auth.
Rich text rendering breaks frontend Medium Medium Sanitize HTML server-side and client-side. Test with malformed content. Add error boundaries. Limit content length.

8.2 Resource Risks

Risk Probability Impact Mitigation Strategy
Timeline delays due to complexity Medium Medium Build MVP first (Phase 1-3), defer nice-to-have features. Use existing patterns from codebase. Regular progress check-ins.
Developer availability/capacity Medium High Clear task breakdown. Prioritize critical features. Can pause after Phase 3 for MVP. Document decisions for handoff.
Content creation bottleneck High Medium Create 20-30 starter articles (not 1000+). Train support team on content creation. Use placeholder content for testing.
Design/UX resources unavailable Low Medium Use existing Shadcn UI components from producer portal. Follow established patterns. Iterate based on user feedback.
Testing resources limited Medium Medium Automate testing where possible. Focus on critical path E2E tests. Use fixtures for test data. Prioritize security testing.

8.3 Business Risks

Risk Probability Impact Mitigation Strategy
Low producer adoption Medium High Promote during onboarding. Add to producer dashboard prominently. Track usage metrics. Gather feedback and iterate.
Content becomes outdated High Medium Assign content owner. Set review schedule. Add "last updated" dates. Monitor feedback for accuracy issues.
Support team doesn't maintain content Medium High Provide training and documentation. Make admin interface intuitive. Show impact metrics. Recognize content contributors.
Feature creep beyond MVP Medium Medium Stick to phased approach. Document future enhancements separately. Get stakeholder buy-in on scope.

8.4 Rollback Strategy

Rollback Scenarios:

  1. Critical bug in production:
  2. Disable knowledge base routes in URL configuration
  3. Frontend: Hide navigation link, show "maintenance" message
  4. Backend: Return 503 for all knowledge endpoints
  5. Investigate and fix offline

  6. Database migration failure:

  7. Run prepared rollback migration
  8. Restore database from backup (if necessary)
  9. Remove 'knowledge' from INSTALLED_APPS
  10. Redeploy previous version

  11. Performance degradation:

  12. Disable expensive features (search autocomplete, analytics)
  13. Add rate limiting
  14. Scale database if needed

Rollback Steps:

# Backend rollback
cd apps/api

# 1. Revert code changes
git revert <commit-hash>

# 2. Rollback migrations (if needed)
python manage.py migrate knowledge zero

# 3. Remove from settings
# Edit settings.py, remove 'knowledge' from INSTALLED_APPS

# 4. Restart services
docker-compose restart api celery_worker

# Frontend rollback
cd apps/producer

# 1. Revert code changes
git revert <commit-hash>

# 2. Rebuild and deploy
npm run build
# Deploy to hosting

Feature Flags (Recommended):

# settings.py
KNOWLEDGE_BASE_ENABLED = os.getenv('KNOWLEDGE_BASE_ENABLED', 'true').lower() == 'true'

# views.py
if not settings.KNOWLEDGE_BASE_ENABLED:
    return Response({'error': 'Knowledge base temporarily unavailable'}, status=503)

This allows instant disable without code changes.


9. Deployment & Operations

9.1 Deployment Plan

Environment Progression:

Development → Staging → Production
   (local)    (staging)   (production)
     ↓           ↓             ↓
   SQLite    PostgreSQL   PostgreSQL
   FileSystem    S3           S3
   No CDN      CloudFront   CloudFront
   Debug=True  Debug=False  Debug=False

Pre-Deployment Checklist:

  • All tests passing on CI/CD
  • Code review approved
  • Database migrations tested on staging
  • S3 bucket permissions configured
  • Environment variables set
  • Documentation updated
  • Rollback plan documented
  • Monitoring configured
  • Sample content prepared
  • Team notified of deployment

Database Migration Steps:

# 1. Create backup
pg_dump -h $PGHOST -U $PGUSER -d $PGDATABASE > backup_$(date +%Y%m%d_%H%M%S).sql

# 2. Test migration on staging copy
python manage.py migrate --plan
python manage.py migrate knowledge

# 3. Verify tables created
python manage.py dbshell
\dt knowledge_*

# 4. Load sample data
python manage.py loaddata knowledge/fixtures/sample_data.json

# 5. Verify application starts
python manage.py check --deploy

# 6. Run smoke tests
python manage.py test knowledge.tests.test_smoke

Deployment Steps (Staging):

# Backend deployment
cd apps/api

# 1. Pull latest code
git checkout pique-506-producer-portal-knoweldge-base
git pull origin pique-506-producer-portal-knoweldge-base

# 2. Install dependencies
pip install -r requirements.txt

# 3. Collect static files
python manage.py collectstatic --noinput

# 4. Run migrations
python manage.py migrate

# 5. Restart services
docker-compose restart api celery_worker

# 6. Verify deployment
curl -H "Authorization: Bearer $JWT_TOKEN" \
  https://staging-api.piquetickets.com/api/v1/portal/knowledge/articles/

# Frontend deployment
cd apps/producer

# 1. Pull latest code
git pull origin pique-506-producer-portal-knoweldge-base

# 2. Install dependencies
npm install

# 3. Build production bundle
npm run build

# 4. Deploy to hosting (Railway/Vercel)
# (follows existing deployment process)

Production Deployment:

  1. Maintenance Window: Schedule 1-hour window during low traffic (3-4 AM)
  2. Feature Flag: Enable knowledge base behind flag initially
  3. Gradual Rollout:
  4. Day 1: 10% of producers
  5. Day 3: 50% of producers
  6. Day 7: 100% of producers
  7. Monitoring: Watch error rates, response times, database load
  8. Announcement: Email producers with link to knowledge base

9.2 Monitoring & Observability

Key Metrics to Monitor:

  1. Application Metrics:
  2. Request rate (requests/minute)
  3. Error rate (errors/minute)
  4. Response time (p50, p95, p99)
  5. Database query time

  6. Business Metrics:

  7. Daily active users
  8. Articles viewed per session
  9. Search queries per day
  10. Feedback submission rate
  11. Most viewed articles
  12. Most helpful articles
  13. Failed searches (no results)

  14. Infrastructure Metrics:

  15. Database connections (current/max)
  16. S3 bandwidth usage
  17. API response time distribution

Monitoring Implementation:

# Django middleware for metrics
class KnowledgeMetricsMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.path.startswith('/api/v1/portal/knowledge/'):
            start_time = time.time()
            response = self.get_response(request)
            duration = time.time() - start_time

            # Log metrics
            logger.info(f"knowledge_request", extra={
                'path': request.path,
                'method': request.method,
                'status': response.status_code,
                'duration_ms': duration * 1000,
                'user_id': request.user.id if request.user.is_authenticated else None
            })

            return response
        return self.get_response(request)

Logging Configuration:

# settings.py
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'json': {
            '()': 'pythonjsonlogger.jsonlogger.JsonFormatter',
            'format': '%(asctime)s %(name)s %(levelname)s %(message)s'
        }
    },
    'handlers': {
        'knowledge': {
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': 'logs/knowledge.log',
            'maxBytes': 15728640,  # 15MB
            'backupCount': 10,
            'formatter': 'json',
        },
    },
    'loggers': {
        'knowledge': {
            'handlers': ['knowledge'],
            'level': 'INFO',
            'propagate': False,
        },
    },
}

Alerting Rules:

# Example alerting configuration
alerts:
  - name: KnowledgeBaseHighErrorRate
    condition: error_rate > 5%
    duration: 5m
    severity: critical
    channels: [slack, email]

  - name: KnowledgeBaseSlowSearch
    condition: search_p95 > 1000ms
    duration: 10m
    severity: warning
    channels: [slack]

  - name: KnowledgeBaseDatabaseConnections
    condition: db_connections > 80% of max
    duration: 5m
    severity: critical
    channels: [slack, pagerduty]

  - name: KnowledgeBaseNoArticleViews
    condition: article_views = 0
    duration: 1h
    severity: warning
    channels: [slack]

Dashboard Configuration (Example - Grafana):

# Knowledge Base Overview Dashboard
panels:
  - title: "Requests per Minute"
    query: rate(knowledge_requests_total[5m])
    type: graph

  - title: "Response Time (p95)"
    query: histogram_quantile(0.95, knowledge_response_time)
    type: gauge

  - title: "Top Articles"
    query: topk(10, knowledge_article_views)
    type: table

  - title: "Search Success Rate"
    query: (knowledge_searches_with_results / knowledge_searches_total) * 100
    type: stat

9.3 Support & Maintenance

Ongoing Maintenance Tasks:

Task Frequency Owner Estimated Time
Review and update outdated articles Monthly Content Team 4 hours
Analyze search metrics for gaps Weekly Product Manager 1 hour
Review feedback comments Weekly Support Team 2 hours
Monitor performance metrics Daily Engineering 30 minutes
Update featured articles Monthly Content Team 1 hour
Cleanup orphaned images Quarterly Engineering 2 hours
Security dependency updates Monthly Engineering 2 hours
Database performance tuning Quarterly Engineering 4 hours

Training Requirements:

  1. Content Creators (Support Team):
  2. Django admin interface walkthrough
  3. CKEditor5 usage and best practices
  4. Image optimization guidelines
  5. Category and tag management
  6. Duration: 2-hour workshop

  7. Administrators:

  8. Article approval workflow
  9. Analytics dashboard interpretation
  10. User feedback management
  11. Content moderation
  12. Duration: 1-hour workshop

  13. Producers (End Users):

  14. Knowledge base tour (video)
  15. How to search effectively
  16. How to provide feedback
  17. Duration: 5-minute video tutorial

Documentation Requirements:

  1. User Documentation:
  2. Knowledge base user guide (producers)
  3. FAQ for common questions
  4. Video tutorials for key features

  5. Admin Documentation:

  6. Content management guide
  7. Article writing best practices
  8. Image optimization guide
  9. Analytics interpretation guide

  10. Technical Documentation:

  11. API documentation (auto-generated from DRF)
  12. Architecture overview
  13. Database schema
  14. Deployment procedures
  15. Troubleshooting guide

Troubleshooting Guide (Quick Reference):

Problem: Search returns no results
- Check article status (must be 'published')
- Verify search index is built
- Check for typos in search query
- Review search query logs

Problem: Images not displaying
- Check S3 bucket permissions
- Verify image path in database
- Check CORS configuration

Problem: Slow page loads
- Check database query count (use debug toolbar)
- Check image file sizes
- Review database indexes

Problem: Feedback not submitting
- Check user authentication
- Verify CSRF token
- Check database constraints
- Review error logs

Problem: Articles not publishing
- Verify all required fields filled
- Check user has publish permissions
- Review validation errors
- Check admin logs

10. Success Measurement

10.1 Success Metrics

Technical Metrics:

Metric Target Measurement Method Frequency
Page Load Time (p95) < 2 seconds Google Analytics, Lighthouse Daily
Search Response Time (p95) < 500ms Backend logging, APM Daily
Database Query Count per Page < 10 queries Django Debug Toolbar Weekly
Image File Size Reduction 40-60% Before/after comparison Once
Uptime > 99.9% Health check monitoring Continuous
Error Rate < 0.5% Error tracking (Sentry) Daily
API Response Success Rate > 99% API logging Daily

User Engagement Metrics:

Metric Target Measurement Method Frequency
Knowledge Base Monthly Active Users 80% of active producers Google Analytics Monthly
Average Articles Read per Session > 2 articles Backend analytics Weekly
Search Usage Rate > 60% of sessions include search Backend analytics Weekly
Feedback Submission Rate > 20% of articles read Backend analytics Weekly
Average Helpfulness Rating > 4.0/5.0 (80% helpful) Feedback aggregation Weekly
Bounce Rate < 40% Google Analytics Weekly
Time on Page > 2 minutes (article detail) Google Analytics Weekly
Return Visit Rate > 40% within 30 days User tracking Monthly

Business Metrics:

Metric Target Measurement Method Frequency
Support Ticket Reduction 50% reduction in basic questions Support ticket system Monthly
Producer Satisfaction Score +15% improvement Producer surveys Quarterly
Content Creation Velocity 10+ articles per month Content tracking Monthly
Onboarding Completion Rate +20% improvement Onboarding analytics Monthly
Producer Activation Rate +10% improvement User analytics Monthly

10.2 Review Schedule

Short-term Reviews:

  1. 1 Week Post-Launch:
  2. Metrics to Review:
    • Initial adoption rate (% of producers who accessed)
    • Critical errors or bugs
    • Page load performance
    • Search functionality
  3. Actions:
    • Fix critical bugs
    • Gather initial user feedback
  4. Attendees: Engineering, Product, Support

  5. 1 Month Post-Launch:

  6. Metrics to Review:
    • Monthly active users
    • Most viewed articles
    • Search success rate
    • Feedback ratings
    • Support ticket trends
  7. Actions:
    • Create content for gaps identified in searches
    • Update low-rated articles
    • Promote underutilized features
  8. Attendees: Engineering, Product, Support, Content Team

  9. 3 Months Post-Launch:

  10. Metrics to Review:
    • All success metrics
    • ROI on support time saved
    • Content gaps and opportunities
    • Technical performance trends
    • User satisfaction surveys
  11. Actions:
    • Full success evaluation
    • Identify Phase 2 features
    • Content strategy adjustment
    • Performance optimization priorities
  12. Attendees: Engineering, Product, Support, Content Team, Leadership

Ongoing Reviews:

  • Weekly: Quick metrics review (10 minutes in team standup)
  • Monthly: Detailed analytics review (1-hour meeting)
  • Quarterly: Strategic review and roadmap planning (2-hour meeting)

Success Criteria Evaluation:

After 3 months, the knowledge base is considered successful if:

Must Meet (Critical): - 60%+ of active producers have accessed knowledge base - 30%+ reduction in basic support tickets - Average helpfulness rating > 3.5/5.0 - No critical performance or security issues - Page load times < 2.5 seconds (p95)

Should Meet (High Priority): - 80%+ of active producers have accessed knowledge base - 50%+ reduction in basic support tickets - Average helpfulness rating > 4.0/5.0 - 100+ articles published - Search response times < 500ms

Could Meet (Stretch Goals): - 90%+ of active producers have accessed knowledge base - 60%+ reduction in basic support tickets - Average helpfulness rating > 4.5/5.0 - Return visit rate > 50% - Producer satisfaction increase > 20%


11. Appendices

Appendix A: Research References

Django Documentation: - Django Models - Model design patterns - Django REST Framework - API development - PostgreSQL Full-Text Search - Search implementation - Django Admin Customization - Admin interface

Third-Party Libraries: - CKEditor5 Documentation - Rich text editor - Django Unfold - Admin theme - Pillow Documentation - Image processing - python-slugify - Slug generation

Knowledge Base UX Research: - Knowledge Base Best Practices - Intercom - How to Build a Knowledge Base - Zendesk - Documentation System - Write the Docs

Accessibility: - WCAG 2.1 Guidelines - WebAIM Accessibility Resources

Performance: - Django Performance Optimization - Web.dev Performance Guide

Appendix B: Technical Diagrams

Database Schema (Detailed):

-- Category Table
CREATE TABLE knowledge_category (
    id BIGSERIAL PRIMARY KEY,
    name VARCHAR(100) UNIQUE NOT NULL,
    slug VARCHAR(50) UNIQUE NOT NULL,
    description TEXT,
    icon VARCHAR(50),
    "order" INTEGER DEFAULT 0,
    parent_id BIGINT REFERENCES knowledge_category(id) ON DELETE CASCADE,
    is_active BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX idx_category_slug ON knowledge_category(slug);
CREATE INDEX idx_category_parent ON knowledge_category(parent_id);
CREATE INDEX idx_category_active ON knowledge_category(is_active);

-- Tag Table
CREATE TABLE knowledge_tag (
    id BIGSERIAL PRIMARY KEY,
    name VARCHAR(50) UNIQUE NOT NULL,
    slug VARCHAR(50) UNIQUE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX idx_tag_slug ON knowledge_tag(slug);

-- Article Table
CREATE TABLE knowledge_article (
    id BIGSERIAL PRIMARY KEY,
    title VARCHAR(200) NOT NULL,
    slug VARCHAR(50) UNIQUE NOT NULL,
    content TEXT NOT NULL,
    excerpt VARCHAR(200),
    featured_image VARCHAR(255),
    featured_image_alt_text VARCHAR(255),
    category_id BIGINT NOT NULL REFERENCES knowledge_category(id) ON DELETE PROTECT,
    author_id INTEGER NOT NULL REFERENCES auth_user(id) ON DELETE PROTECT,
    status VARCHAR(10) DEFAULT 'draft',
    featured BOOLEAN DEFAULT FALSE,
    view_count INTEGER DEFAULT 0,
    helpful_count INTEGER DEFAULT 0,
    not_helpful_count INTEGER DEFAULT 0,
    published_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    meta_description VARCHAR(160),
    estimated_read_time INTEGER DEFAULT 1
);

CREATE INDEX idx_article_slug ON knowledge_article(slug);
CREATE INDEX idx_article_status_published ON knowledge_article(status, published_at);
CREATE INDEX idx_article_category_status ON knowledge_article(category_id, status);
CREATE INDEX idx_article_view_count ON knowledge_article(view_count DESC);
CREATE INDEX idx_article_helpful_count ON knowledge_article(helpful_count DESC);
CREATE INDEX idx_article_featured ON knowledge_article(featured) WHERE featured = TRUE;

-- Full-text search index
CREATE INDEX idx_article_search ON knowledge_article
    USING GIN (to_tsvector('english', title || ' ' || content));

-- Article-Tag Junction Table
CREATE TABLE knowledge_article_tags (
    id BIGSERIAL PRIMARY KEY,
    article_id BIGINT NOT NULL REFERENCES knowledge_article(id) ON DELETE CASCADE,
    tag_id BIGINT NOT NULL REFERENCES knowledge_tag(id) ON DELETE CASCADE,
    UNIQUE(article_id, tag_id)
);

CREATE INDEX idx_article_tags_article ON knowledge_article_tags(article_id);
CREATE INDEX idx_article_tags_tag ON knowledge_article_tags(tag_id);

-- ArticleFeedback Table
CREATE TABLE knowledge_articlefeedback (
    id BIGSERIAL PRIMARY KEY,
    article_id BIGINT NOT NULL REFERENCES knowledge_article(id) ON DELETE CASCADE,
    user_id INTEGER NOT NULL REFERENCES auth_user(id) ON DELETE CASCADE,
    is_helpful BOOLEAN NOT NULL,
    comment TEXT,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    UNIQUE(article_id, user_id)
);

CREATE INDEX idx_feedback_article ON knowledge_articlefeedback(article_id);
CREATE INDEX idx_feedback_user ON knowledge_articlefeedback(user_id);

Component Architecture (Frontend):

┌─────────────────────────────────────────────────────────────┐
│              Knowledge Base Page Hierarchy                   │
└─────────────────────────────────────────────────────────────┘

/dashboard/knowledge/layout.tsx
├── Header
│   ├── Breadcrumbs
│   └── SearchBar (global)
├── [Content Outlet]
│   ├── page.tsx (Home)
│   │   ├── CategoryGrid
│   │   │   └── CategoryCard (multiple)
│   │   ├── FeaturedArticles
│   │   │   └── ArticleCard (carousel)
│   │   ├── RecentArticles
│   │   │   └── ArticleCard (list)
│   │   └── QuickStats
│   │
│   ├── category/[slug]/page.tsx
│   │   ├── CategoryHeader
│   │   ├── FilterControls
│   │   │   ├── SortDropdown
│   │   │   └── ViewToggle
│   │   ├── SubcategoryList
│   │   └── ArticleGrid
│   │       └── ArticleCard (multiple)
│   │
│   ├── article/[slug]/page.tsx
│   │   ├── ArticleHero
│   │   │   └── FeaturedImage
│   │   ├── ArticleContent
│   │   │   ├── TableOfContents (sidebar)
│   │   │   └── RichTextRenderer
│   │   ├── FeedbackWidget
│   │   ├── RelatedArticles
│   │   │   └── ArticleCard (compact)
│   │   └── ShareButtons
│   │
│   └── search/page.tsx
│       ├── SearchFilters (sidebar)
│       ├── ResultsSummary
│       └── SearchResults
│           └── ArticleCard (with highlighting)
└── Footer

Appendix C: Code Examples

Example: Article Model with Full Implementation

# apps/api/knowledge/models.py
from django.db import models
from django.contrib.auth.models import User
from django.core.validators import FileExtensionValidator
from django.utils.text import slugify
from PIL import Image
from io import BytesIO
from django.core.files.base import ContentFile
import os

class Category(models.Model):
    """Knowledge base category for organizing articles."""
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(unique=True, blank=True)
    description = models.TextField(blank=True)
    icon = models.CharField(max_length=50, blank=True, help_text="FontAwesome icon class")
    order = models.IntegerField(default=0)
    parent = models.ForeignKey(
        'self',
        null=True,
        blank=True,
        on_delete=models.CASCADE,
        related_name='subcategories'
    )
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['order', 'name']
        verbose_name_plural = 'Categories'
        indexes = [
            models.Index(fields=['slug']),
            models.Index(fields=['parent', 'is_active']),
        ]

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        super().save(*args, **kwargs)

    @property
    def article_count(self):
        """Count of published articles in this category."""
        return self.article_set.filter(status='published').count()


class Tag(models.Model):
    """Tag for cross-referencing articles."""
    name = models.CharField(max_length=50, unique=True)
    slug = models.SlugField(unique=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        super().save(*args, **kwargs)


class Article(models.Model):
    """Knowledge base article."""

    STATUS_CHOICES = [
        ('draft', 'Draft'),
        ('published', 'Published'),
        ('archived', 'Archived'),
    ]

    title = models.CharField(max_length=200)
    slug = models.SlugField(unique=True, blank=True)
    content = models.TextField()
    excerpt = models.TextField(max_length=200, blank=True)
    featured_image = models.ImageField(
        upload_to='knowledge/articles/',
        blank=True,
        validators=[FileExtensionValidator(['jpg', 'jpeg', 'png', 'webp'])]
    )
    featured_image_alt_text = models.CharField(max_length=255, blank=True)

    category = models.ForeignKey(Category, on_delete=models.PROTECT)
    tags = models.ManyToManyField(Tag, blank=True)
    author = models.ForeignKey(User, on_delete=models.PROTECT)

    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
    featured = models.BooleanField(default=False)

    view_count = models.PositiveIntegerField(default=0)
    helpful_count = models.PositiveIntegerField(default=0)
    not_helpful_count = models.PositiveIntegerField(default=0)

    published_at = models.DateTimeField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    meta_description = models.CharField(max_length=160, blank=True)
    estimated_read_time = models.PositiveIntegerField(default=1)

    class Meta:
        ordering = ['-published_at', '-created_at']
        indexes = [
            models.Index(fields=['slug']),
            models.Index(fields=['status', 'published_at']),
            models.Index(fields=['category', 'status']),
            models.Index(fields=['-view_count']),
            models.Index(fields=['-helpful_count']),
        ]

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        # Generate slug
        if not self.slug:
            self.slug = self._generate_unique_slug()

        # Calculate read time
        self.estimated_read_time = self._calculate_read_time()

        # Auto-generate excerpt if not provided
        if not self.excerpt and self.content:
            self.excerpt = self._generate_excerpt()

        super().save(*args, **kwargs)

        # Process image after save (to have ID)
        if self.featured_image:
            self._process_featured_image()

    def _generate_unique_slug(self):
        """Generate unique slug from title."""
        slug = slugify(self.title)
        unique_slug = slug
        counter = 1

        while Article.objects.filter(slug=unique_slug).exists():
            unique_slug = f"{slug}-{counter}"
            counter += 1

        return unique_slug

    def _calculate_read_time(self):
        """Calculate estimated read time in minutes (200 words/minute)."""
        if not self.content:
            return 1
        word_count = len(self.content.split())
        return max(1, round(word_count / 200))

    def _generate_excerpt(self):
        """Generate excerpt from content (first 200 chars)."""
        from django.utils.html import strip_tags
        plain_text = strip_tags(self.content)
        return plain_text[:197] + '...' if len(plain_text) > 200 else plain_text

    def _process_featured_image(self):
        """Convert featured image to WebP and optimize."""
        if not self.featured_image or self.featured_image.name.endswith('.webp'):
            return

        try:
            img = Image.open(self.featured_image)

            # Convert to RGB if necessary
            if img.mode in ('RGBA', 'LA', 'P'):
                background = Image.new('RGB', img.size, (255, 255, 255))
                if img.mode == 'P':
                    img = img.convert('RGBA')
                background.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
                img = background

            # Save as WebP
            output = BytesIO()
            img.save(output, format='WEBP', quality=85, method=6)
            output.seek(0)

            # Generate new filename
            name_without_ext = os.path.splitext(self.featured_image.name)[0]
            webp_name = f"{name_without_ext}.webp"

            # Save optimized image
            self.featured_image.save(
                webp_name,
                ContentFile(output.read()),
                save=False
            )

            # Save model without triggering infinite recursion
            Article.objects.filter(pk=self.pk).update(featured_image=self.featured_image)

        except Exception as e:
            # Log error but don't fail save
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"Failed to process image for article {self.pk}: {str(e)}")

    def increment_view_count(self):
        """Atomically increment view count."""
        Article.objects.filter(pk=self.pk).update(view_count=models.F('view_count') + 1)
        self.refresh_from_db()

    @property
    def helpfulness_percentage(self):
        """Calculate percentage of helpful votes."""
        total = self.helpful_count + self.not_helpful_count
        if total == 0:
            return None
        return round((self.helpful_count / total) * 100, 1)


class ArticleFeedback(models.Model):
    """User feedback on article helpfulness."""
    article = models.ForeignKey(Article, on_delete=models.CASCADE)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    is_helpful = models.BooleanField()
    comment = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        unique_together = ['article', 'user']
        verbose_name = 'Article Feedback'
        verbose_name_plural = 'Article Feedback'

    def __str__(self):
        return f"Feedback on '{self.article.title}' by {self.user.username}"

    def save(self, *args, **kwargs):
        is_new = self.pk is None
        super().save(*args, **kwargs)

        # Update article counts
        if is_new:
            if self.is_helpful:
                Article.objects.filter(pk=self.article.pk).update(
                    helpful_count=models.F('helpful_count') + 1
                )
            else:
                Article.objects.filter(pk=self.article.pk).update(
                    not_helpful_count=models.F('not_helpful_count') + 1
                )

Example: Article ViewSet with Custom Actions

# apps/api/knowledge/views.py
from rest_framework import viewsets, filters, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django_filters.rest_framework import DjangoFilterBackend
from django.db.models import Q, F
from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank

from .models import Article, Category, Tag, ArticleFeedback
from .serializers import (
    ArticleListSerializer,
    ArticleDetailSerializer,
    CategorySerializer,
    TagSerializer,
    FeedbackSerializer
)
from .filters import ArticleFilter
from .permissions import IsProducerUser


class ArticleViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ViewSet for knowledge base articles.

    List and retrieve published articles.
    Supports filtering, searching, and custom actions.
    """
    permission_classes = [IsAuthenticated, IsProducerUser]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_class = ArticleFilter
    search_fields = ['title', 'content', 'excerpt']
    ordering_fields = ['published_at', 'view_count', 'helpful_count']
    ordering = ['-published_at']

    def get_queryset(self):
        """Return only published articles with optimized queries."""
        return Article.objects.filter(
            status='published'
        ).select_related(
            'category', 'author'
        ).prefetch_related(
            'tags'
        )

    def get_serializer_class(self):
        """Use detailed serializer for retrieve, list serializer for list."""
        if self.action == 'retrieve':
            return ArticleDetailSerializer
        return ArticleListSerializer

    def retrieve(self, request, *args, **kwargs):
        """Retrieve article and increment view count."""
        instance = self.get_object()
        instance.increment_view_count()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

    @action(detail=True, methods=['get'])
    def related(self, request, pk=None):
        """Get related articles based on category and tags."""
        article = self.get_object()

        # Get articles with same category or overlapping tags
        related = Article.objects.filter(
            status='published'
        ).exclude(
            pk=article.pk
        ).filter(
            Q(category=article.category) | Q(tags__in=article.tags.all())
        ).distinct().select_related(
            'category', 'author'
        ).prefetch_related(
            'tags'
        )[:5]

        serializer = ArticleListSerializer(related, many=True)

        return Response(serializer.data)

    @action(detail=True, methods=['post'])
    def feedback(self, request, pk=None):
        """Submit feedback on article helpfulness."""
        article = self.get_object()

        # Check if user already submitted feedback
        existing = ArticleFeedback.objects.filter(
            article=article,
            user=request.user
        ).first()

        if existing:
            return Response(
                {'error': 'You have already submitted feedback for this article'},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Create feedback
        serializer = FeedbackSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(article=article, user=request.user)
            return Response(serializer.data, status=status.HTTP_201_CREATED)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=False, methods=['get'])
    def featured(self, request):
        """Get featured articles."""
        featured = self.get_queryset().filter(featured=True)[:5]
        serializer = self.get_serializer(featured, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=['get'])
    def popular(self, request):
        """Get most viewed articles."""
        popular = self.get_queryset().order_by('-view_count')[:10]
        serializer = self.get_serializer(popular, many=True)
        return Response(serializer.data)


class CategoryViewSet(viewsets.ReadOnlyModelViewSet):
    """ViewSet for article categories."""
    queryset = Category.objects.filter(is_active=True)
    serializer_class = CategorySerializer
    permission_classes = [IsAuthenticated, IsProducerUser]
    lookup_field = 'slug'

    @action(detail=True, methods=['get'])
    def articles(self, request, slug=None):
        """Get all articles in this category."""
        category = self.get_object()
        articles = Article.objects.filter(
            category=category,
            status='published'
        ).select_related('category', 'author').prefetch_related('tags')

        # Apply pagination
        page = self.paginate_queryset(articles)
        if page is not None:
            serializer = ArticleListSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = ArticleListSerializer(articles, many=True)
        return Response(serializer.data)


class SearchView(viewsets.ViewSet):
    """Custom search view with PostgreSQL full-text search."""
    permission_classes = [IsAuthenticated, IsProducerUser]

    def list(self, request):
        """
        Search articles using full-text search.

        Query params:
        - q: search query (required)
        - category: filter by category slug
        - tag: filter by tag slug
        """
        query_text = request.query_params.get('q', '').strip()

        if not query_text:
            return Response(
                {'error': 'Search query parameter "q" is required'},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Build search vector and query
        vector = SearchVector('title', weight='A') + SearchVector('content', weight='B')
        query = SearchQuery(query_text)

        # Base queryset
        results = Article.objects.filter(
            status='published'
        ).annotate(
            rank=SearchRank(vector, query)
        ).filter(
            rank__gte=0.1
        ).select_related(
            'category', 'author'
        ).prefetch_related(
            'tags'
        ).order_by('-rank')

        # Apply filters
        category_slug = request.query_params.get('category')
        if category_slug:
            results = results.filter(category__slug=category_slug)

        tag_slug = request.query_params.get('tag')
        if tag_slug:
            results = results.filter(tags__slug=tag_slug)

        # Serialize and return
        serializer = ArticleListSerializer(results, many=True)
        return Response({
            'query': query_text,
            'count': results.count(),
            'results': serializer.data
        })

Appendix D: Meeting Notes & Decisions

Project Kickoff Meeting - 2025-10-10

Attendees: Product Manager, Engineering Lead, Support Team Lead

Key Decisions: 1. ✅ Approved MVP scope (Phases 1-3) 2. ✅ Start with PostgreSQL full-text search (not Elasticsearch) 3. ✅ Use CKEditor5 (already installed) instead of adding new editor 4. ✅ Target 6-week timeline for Phase 1-3 completion 5. ✅ Create 20-30 initial articles (not 100+) 6. ⏭️ Defer bookmarking, PDF export, and analytics to Phase 2

Action Items: - [ ] Engineering: Create knowledge app structure - [ ] Product: Draft initial article list - [ ] Support: Review article categories proposal - [ ] Design: Provide feedback on wireframes

Next Meeting: Weekly standup on Mondays at 10am


Quick Checklist for Document Completion

Research Phase

  • Analyzed existing codebase thoroughly
  • Researched industry best practices
  • Identified all stakeholders and requirements
  • Assessed technical constraints and dependencies

Planning Phase

  • Created detailed implementation plan (6 phases)
  • Defined clear acceptance criteria
  • Identified and mitigated risks
  • Planned testing strategy

Review Phase

  • Technical review completed (pending)
  • Stakeholder approval obtained (pending)
  • Resource allocation confirmed (pending)
  • Timeline approved by team (pending)

Documentation

  • All sections completed with specific details
  • File references are accurate and current
  • External links verified and accessible
  • Document reviewed for clarity and completeness

End of Planning Document

Next Steps: 1. Review this document with stakeholders 2. Get approval to proceed with Phase 1 3. Create Jira tickets for each task 4. Begin implementation following Phase 1 plan

Document Status: ✅ Ready for stakeholder review