Checkpoint React frontend migration
This commit is contained in:
365
ADMIN_TRYOUT_RESTRUCTURE_PLAN.md
Normal file
365
ADMIN_TRYOUT_RESTRUCTURE_PLAN.md
Normal file
@@ -0,0 +1,365 @@
|
||||
# Admin UI Redesign - Implementation Plan
|
||||
|
||||
## Overview
|
||||
|
||||
This plan outlines the migration from the current scattered admin structure to a clean, hierarchy-driven navigation centered on **Tryouts**.
|
||||
|
||||
### Guiding Principles
|
||||
1. **One main page per domain** - Features live under their parent, not as separate menu items
|
||||
2. **URL reflects depth** - Path structure shows relationship (`/admin/tryout/{id}/questions`)
|
||||
3. **Tree as map** - Hierarchy tree shows structure; drill-down shows details
|
||||
4. **Consistent naming** - Use "Tryout" instead of "Exam" throughout
|
||||
|
||||
---
|
||||
|
||||
## 1. URL Structure
|
||||
|
||||
### New URL Scheme
|
||||
|
||||
| Old Route | New Route | Description |
|
||||
|-----------|-----------|-------------|
|
||||
| `/admin/exams` | `/admin/tryouts` | Hierarchy tree (main entry) |
|
||||
| `/admin/student-attempts` | `/admin/tryout/{tryout_id}/attempts` | Attempts filtered by tryout |
|
||||
| - | `/admin/tryout/{tryout_id}/questions` | Questions filtered by tryout |
|
||||
| - | `/admin/tryout/{tryout_id}/questions/{question_id}/workspace` | Question workspace |
|
||||
| - | `/admin/tryout/{tryout_id}/questions/{question_id}/workspace/{tab}` | Workspace tabs |
|
||||
| - | `/admin/tryout/{tryout_id}/normalization` | Normalization settings for this tryout |
|
||||
| `/admin/questions` | `/admin/questions` | Global question list (kept) |
|
||||
| (none) | `/admin/import-tryout` | Import tryout modal/page |
|
||||
|
||||
> **Note:** Import is tryout-level, not question-level. Import button lives on `/admin/tryouts` page header.
|
||||
|
||||
### Hierarchy Depth Convention
|
||||
|
||||
```
|
||||
/admin/tryouts → Level 0: Root
|
||||
/admin/tryout/{tryout_id} → Level 1: Entity
|
||||
/admin/tryout/{tryout_id}/attempts → Level 2: Related data
|
||||
/admin/tryout/{tryout_id}/questions → Level 2: Related data
|
||||
/admin/tryout/{tryout_id}/questions/{id} → Level 3: Specific item
|
||||
/admin/tryout/{tryout_id}/questions/{id}/workspace → Level 4: Detail view
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Navigation Structure
|
||||
|
||||
### Proposed Navigation
|
||||
|
||||
```
|
||||
Questions
|
||||
├── /admin/questions # Global question list
|
||||
└── /admin/tryout/*/questions/*/workspace # Direct link from tree
|
||||
|
||||
Tryouts
|
||||
├── /admin/tryouts # Tree: Website → Tryout → Stat → Actions + Import button
|
||||
├── /admin/tryout/*/attempts # Filtered attempts
|
||||
├── /admin/tryout/*/questions # Questions in this tryout
|
||||
├── /admin/tryout/*/normalization # Normalization settings
|
||||
└── /admin/import-tryout # Import modal/page
|
||||
|
||||
Reports
|
||||
├── /admin/reports # Dashboard
|
||||
├── /admin/item-statistics
|
||||
└── /admin/calibration-status
|
||||
|
||||
Settings
|
||||
├── /admin/settings
|
||||
├── /admin/websites
|
||||
└── /admin/password
|
||||
```
|
||||
|
||||
### Navigation Item Definition
|
||||
|
||||
```python
|
||||
ADMIN_NAV_ITEMS = (
|
||||
("Dashboard", "/admin/dashboard", ("/admin/dashboard",)),
|
||||
("Questions", "/admin/questions", (
|
||||
"/admin/questions",
|
||||
"/admin/tryout/*/questions/*/workspace", # Pattern for direct links
|
||||
)),
|
||||
("Tryouts", "/admin/tryouts", (
|
||||
"/admin/tryouts",
|
||||
"/admin/tryout/*/attempts",
|
||||
"/admin/tryout/*/questions",
|
||||
"/admin/tryout/*/normalization",
|
||||
"/admin/import-tryout",
|
||||
)),
|
||||
("Reports", "/admin/reports", (
|
||||
"/admin/reports",
|
||||
"/admin/item-statistics",
|
||||
"/admin/calibration-status",
|
||||
)),
|
||||
("Settings", "/admin/settings", (
|
||||
"/admin/settings",
|
||||
"/admin/websites",
|
||||
"/admin/password",
|
||||
)),
|
||||
("Logout", "/admin/logout", ("/admin/logout",)),
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Tryouts Tree Structure
|
||||
|
||||
### Visual Design
|
||||
|
||||
```
|
||||
┌─ Tryouts ───────────────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ [+ Import Tryout] │
|
||||
│ │
|
||||
│ 🌐 Website A │
|
||||
│ │ │
|
||||
│ ├─ 📋 132380 - UTBK 2024 [●] │
|
||||
│ │ └─ [Expanded on click] │
|
||||
│ │ │
|
||||
│ ├─ 📋 132381 - SIMAK UI [✓] │
|
||||
│ │ │
|
||||
│ └─ 📋 132382 - PAS Semester 1 [○] │
|
||||
│ │
|
||||
│ 🌐 Website B │
|
||||
│ └─ ... │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Expanded Tryout View:
|
||||
┌─ 📋 132380 - UTBK 2024 ─────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
│ ┌─ Stat Card ─────────────────────────────────────────────────────────┐ │
|
||||
│ │ 👥 150 participants │ NM: 672 avg │ NN: 505 avg │ │
|
||||
│ │ ✓ 98% completion │ 📐 Calibration: ████████░░ 85% (17/20) │ │
|
||||
│ └────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [📝 Questions (20)] [👥 Attempts (150)] [📐 Normalization] [⚙ Settings]│
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Legend:
|
||||
[●] Partial (50-89% calibrated)
|
||||
[✓] Ready (≥90% calibrated)
|
||||
[○] Needs Data (<50% calibrated)
|
||||
```
|
||||
|
||||
### Import Button Location
|
||||
|
||||
- **Location:** Header of `/admin/tryouts` page
|
||||
- **Label:** "[+ Import Tryout]" or "[Import Tryout JSON]"
|
||||
- **Behavior:** Opens import modal/page
|
||||
- **Why:** Import is tryout-level operation (imports questions WITH tryout context)
|
||||
|
||||
### Stat Card Components
|
||||
|
||||
| Field | Source | Display |
|
||||
|-------|--------|---------|
|
||||
| Participants | `TryoutStats.participant_count` | 👥 {count} |
|
||||
| Avg NM | `AVG(Session.NM)` where completed | 📊 {value} avg |
|
||||
| Avg NN | `AVG(Session.NN)` where completed | 📈 {value} avg |
|
||||
| Completion Rate | `completed / participants * 100` | ✓ {percentage}% |
|
||||
| Calibration | `calibrated_items / total_items` | 📐 Progress bar + {count}/{total} |
|
||||
|
||||
### Action Buttons
|
||||
|
||||
| Action | Target URL | Icon |
|
||||
|--------|------------|------|
|
||||
| Questions | `/admin/tryout/{id}/questions` | 📝 |
|
||||
| Attempts | `/admin/tryout/{id}/attempts` | 👥 |
|
||||
| Normalization | `/admin/tryout/{id}/normalization` | 📐 |
|
||||
| Settings | `/admin/tryout/{id}/settings` (or modal) | ⚙ |
|
||||
|
||||
---
|
||||
|
||||
## 4. Page Specifications
|
||||
|
||||
### 4.1 `/admin/tryouts` (Main Tree)
|
||||
|
||||
**Purpose:** Primary navigation entry, shows structure at a glance
|
||||
|
||||
**Default State:**
|
||||
- Websites expanded
|
||||
- Tryouts collapsed
|
||||
- Shows calibration indicator dot next to each tryout
|
||||
|
||||
**Interactions:**
|
||||
- Click tryout → expand/collapse
|
||||
- Expanded tryout shows stat card + action buttons
|
||||
- Actions navigate to filtered views
|
||||
|
||||
### 4.2 `/admin/tryout/{tryout_id}/questions`
|
||||
|
||||
**Purpose:** View all questions in a specific tryout
|
||||
|
||||
**Behavior:**
|
||||
- Shows only original/imported questions (basis items)
|
||||
- Pre-filtered by `tryout_id`
|
||||
- Links to workspace for AI variant generation
|
||||
|
||||
**Table Columns:**
|
||||
|
||||
| Column | Description |
|
||||
|--------|-------------|
|
||||
| ID | Question internal ID |
|
||||
| Stem Preview | First 100 chars of question text |
|
||||
| Difficulty | Current difficulty level |
|
||||
| Calibration | P-value or IRT-b indicator |
|
||||
| Variants | Count of generated variants |
|
||||
| Actions | [View] [Workspace] |
|
||||
|
||||
### 4.3 `/admin/tryout/{tryout_id}/questions/{question_id}/workspace`
|
||||
|
||||
**Purpose:** Generate and manage question variants
|
||||
|
||||
**Tabs:**
|
||||
|
||||
| Tab | Purpose |
|
||||
|-----|---------|
|
||||
| Generate | AI variant generation interface |
|
||||
| Review | Review generated variants |
|
||||
| Batch | Batch generation options |
|
||||
|
||||
**Access Pattern:**
|
||||
- Opens from question list or tree direct link
|
||||
- Context: knows parent tryout, parent question
|
||||
|
||||
### 4.4 `/admin/tryout/{tryout_id}/attempts`
|
||||
|
||||
**Purpose:** View student attempts for specific tryout
|
||||
|
||||
**Current Implementation:** Already exists at `/admin/student-attempts` → migrate URL
|
||||
|
||||
**Enhancements:**
|
||||
- Pre-filtered by `tryout_id` (no dropdown needed on this page)
|
||||
- Stat card from parent tryout shown at top
|
||||
|
||||
### 4.5 `/admin/tryout/{tryout_id}/normalization`
|
||||
|
||||
**Purpose:** Configure normalization settings for a specific tryout
|
||||
|
||||
**Settings (per-tryout):**
|
||||
|
||||
| Setting | Type | Default | Description |
|
||||
|---------|------|---------|-------------|
|
||||
| Mode | Select | Auto | Auto (calculate from data) or Manual (fixed values) |
|
||||
| Rataan | Number | 500 | Target mean for normalization |
|
||||
| SB | Number | 100 | Target standard deviation |
|
||||
| Recalculate | Button | - | Re-run normalization on existing sessions |
|
||||
|
||||
**Formula:** `NN = 500 + 100 × ((NM - Rataan) / SB)`
|
||||
|
||||
**UI:**
|
||||
- Simple form with current values
|
||||
- "Recalculate" button triggers normalization job
|
||||
- Shows last normalization timestamp
|
||||
|
||||
### 4.6 `/admin/import-tryout`
|
||||
|
||||
**Purpose:** Import tryout data (questions + metadata) from JSON
|
||||
|
||||
**Access:** Via "[+ Import Tryout]" button on `/admin/tryouts` page
|
||||
|
||||
**Behavior:**
|
||||
- Opens modal or dedicated page
|
||||
- Upload JSON file or paste JSON content
|
||||
- Preview import before confirming
|
||||
- Creates new tryout with questions
|
||||
|
||||
**URL Convention:** Not under specific tryout (it's creating a new one)
|
||||
|
||||
---
|
||||
|
||||
## 5. Deprecations
|
||||
|
||||
### Routes to Remove
|
||||
|
||||
| Route | Reason |
|
||||
|-------|--------|
|
||||
| `/admin/exams` | Renamed to `/admin/tryouts` |
|
||||
| `/admin/student-attempts` | URL changed to `/admin/tryout/{id}/attempts` |
|
||||
| `/admin/templates` | AI uses basis items directly |
|
||||
| `/admin/basis-items` | Merge into question workspace |
|
||||
| `/admin/hierarchy` | Tree IS the hierarchy |
|
||||
| `/admin/question-quality` | Merged into tryout stat card |
|
||||
|
||||
### Legacy Redirects
|
||||
|
||||
```python
|
||||
LEGACY_URL_MAP = {
|
||||
"/admin/exams": "/admin/tryouts",
|
||||
"/admin/student-attempts": "/admin/tryouts", # Or redirect to tryouts with guidance
|
||||
"/admin/hierarchy": "/admin/tryouts",
|
||||
"/admin/question-quality": "/admin/tryouts",
|
||||
# Templates and basis-items: 404 (removed)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Implementation Phases
|
||||
|
||||
### Phase 1: Foundation
|
||||
- [ ] Rename `/admin/exams` → `/admin/tryouts` (keep old route for now)
|
||||
- [ ] Implement tree structure in `/admin/tryouts`
|
||||
- [ ] Move `TryoutStats` info into tree stat cards
|
||||
- [ ] Add calibration indicator dots
|
||||
|
||||
### Phase 2: URL Migration
|
||||
- [ ] Create `/admin/tryout/{id}/attempts` (redirect from old route)
|
||||
- [ ] Create `/admin/tryout/{id}/questions`
|
||||
- [ ] Update navigation items
|
||||
|
||||
### Phase 3: Workspace Integration
|
||||
- [ ] Create question workspace route
|
||||
- [ ] Implement workspace tabs
|
||||
- [ ] Connect workspace to tree and question list
|
||||
|
||||
### Phase 4: Cleanup
|
||||
- [ ] Add legacy redirects
|
||||
- [ ] Remove deprecated routes
|
||||
- [ ] Update all hardcoded links in views
|
||||
|
||||
### Phase 5: Polish
|
||||
- [ ] Review all pages for consistency
|
||||
- [ ] Update documentation
|
||||
- [ ] Test all navigation paths
|
||||
|
||||
---
|
||||
|
||||
## 7. Open Questions
|
||||
|
||||
1. ~~Normalization settings~~ - **RESOLVED**: Move under tryout context as `/admin/tryout/{id}/normalization`
|
||||
|
||||
2. ~~Import questions page~~ - **RESOLVED**: Import is tryout-level. Button on `/admin/tryouts` header, not a separate page.
|
||||
|
||||
3. **Tryout settings** - What settings are actually needed? (Scoring mode, time limits, selection criteria?)
|
||||
|
||||
4. **Global questions page** - Is `/admin/questions` (unfiltered) still useful, or should every question access go through tryout context?
|
||||
|
||||
5. **Templates deprecation** - Confirm that `/admin/templates` is truly unused and can be safely removed?
|
||||
|
||||
6. **Legacy routes for deleted pages** - Should `/admin/templates` and `/admin/basis-items` redirect somewhere or return 404?
|
||||
|
||||
---
|
||||
|
||||
## 8. Files to Modify
|
||||
|
||||
### Primary Changes
|
||||
- `app/admin_web.py` - Major route restructuring
|
||||
- Navigation definition in `admin_web.py`
|
||||
- Legacy URL map
|
||||
|
||||
### Likely Additions
|
||||
- Static assets for tree expansion/collapse (if not using existing)
|
||||
|
||||
### Documentation Updates
|
||||
- `ADMIN_UI_REDESIGN_PLAN.md` - Update to reflect final structure
|
||||
- `PROJECT_UNDERSTANDING.md` - Update route documentation
|
||||
|
||||
---
|
||||
|
||||
## 9. Changelog
|
||||
|
||||
| Version | Date | Changes |
|
||||
|---------|------|---------|
|
||||
| 1.0 | 2026-06-17 | Initial draft based on discussion |
|
||||
| 1.1 | 2026-06-17 | - Move normalization to `/admin/tryout/{id}/normalization`<br>- Move import button to `/admin/tryouts` header<br>- Add normalization page spec (4.5)<br>- Rename import page spec (4.6)<br>- Update navigation and action buttons |
|
||||
Reference in New Issue
Block a user