Skip to content

Service App

A case management module for tracking customer issues from creation through resolution — with configurable statuses, resolution types, and built-in Metadata API integration for customizable list views and detail pages.

Key Features

  • Case Tracking — Create and manage support cases with subject, description, status, and resolution fields
  • Configurable Statuses — Define case lifecycle stages (e.g., New → Working → Closed) via settings
  • Resolution Types — Track how cases are resolved (e.g., Done, Won't Do) with configurable options
  • Metadata API Integration — Register the Case model with the Metadata API for auto-generated list views, detail pages, and bulk actions
  • Ownership & Scoping — Every case has an owner field and a scoped manager inherited from BaseModel
  • Flexible Metadata — JSONField on every case allows storing custom fields without schema changes

Architecture

┌─────────────────────────────────────────────────────────────┐
│                      Your Application                       │
│                  (app/service/metadata.py)                   │
└─────────────────────────────────────────────────────────────┘
                    Metadata API Registration
┌─────────────────────────────────────────────────────────────┐
│                      Case Model                             │
│                  (grit/service/models.py)                    │
│                                                             │
│   ┌──────────┐   status    ┌────────────────────┐           │
│   │   New    │ ──────────▶ │     Working         │          │
│   └──────────┘             └────────────────────┘           │
│                                      │                      │
│                                   status                    │
│                                      │                      │
│                                      ▼                      │
│                              ┌───────────────┐              │
│                              │    Closed      │              │
│                              │  (resolution)  │              │
│                              └───────────────┘              │
└─────────────────────────────────────────────────────────────┘
                          inherits
┌─────────────────────────────────────────────────────────────┐
│                       BaseModel                             │
│   • UUID primary key    • metadata (JSON)                   │
│   • created_at / updated_at    • owner (FK to User)         │
│   • scoped manager                                          │
└─────────────────────────────────────────────────────────────┘

Quick Start

1. Register the Model with the Metadata API

In your app/service/metadata.py, register the Case model to enable auto-generated list and detail views:

from grit.core.metadata import metadata
from grit.service.models import Case


@metadata.register(Case)
class CaseMetadata(metadata.ModelMetadata):
    list_display = ('subject', 'status', 'resolution', 'owner', 'created_at')
    list_actions = [
        [{'label': 'New Case', 'action': 'new'}]
    ]
    fieldsets = (
        ('Case Information', {
            'fields': ('subject', 'description', 'status', 'resolution')
        }),
    )

2. Configure the Admin Panel

In your app/service/admin.py, register the model with Django admin for back-office management:

from django.contrib import admin
from grit.service.models import Case

@admin.register(Case)
class CaseAdmin(admin.ModelAdmin):
    list_display = ('subject', 'status', 'resolution', 'owner', 'created_at')
    list_filter = ('status', 'resolution')
    search_fields = ('subject', 'description')
    ordering = ('-created_at',)

3. Create Cases Programmatically

from grit.service.models import Case

case = Case.objects.create(
    subject="Cannot access dashboard",
    description="User reports 500 error when loading the dashboard page.",
    status="new",
    owner=request.user
)

Core Model

Case

Represents a customer issue or support request. Cases move through configurable status stages and are resolved with a resolution type.

Field Type Description
subject CharField(255) Case title (required)
description TextField Detailed description of the issue
status CharField Lifecycle stage — choices from settings (default: new)
resolution CharField How the case was resolved — choices from settings

Inherited from BaseModel:

Field Type Description
id UUIDField Auto-generated unique identifier
metadata JSONField Flexible JSON storage for custom fields
created_at DateTimeField Auto-set on creation
updated_at DateTimeField Auto-set on save
owner ForeignKey Record owner (links to user)

Configuration Reference

Case Statuses

Case statuses are configurable via APP_METADATA_SETTINGS in your Django settings. The is_closed flag indicates whether a status represents a terminal state:

# settings.py
APP_METADATA_SETTINGS = {
    'CHOICES': {
        'case_status': {
            'new': {'label': 'New', 'is_closed': False},
            'working': {'label': 'Working', 'is_closed': False},
            'closed': {'label': 'Closed', 'is_closed': True},
        }
    }
}

The first status in the dictionary is used as the default value for new cases.

Resolution Types

Resolution types indicate how a case was closed:

# settings.py
APP_METADATA_SETTINGS = {
    'CHOICES': {
        'resolutions': {
            'done': {'label': 'Done'},
            'wont_do': {'label': "Won't Do"},
        }
    }
}