chore: 合并为单仓库,统一部署流程
- 根目录加入 docker-compose、Caddyfile、文档等原本不在仓库里的文件 - 前后端两份 GitHub Actions 合并成根目录的一个 deploy workflow: 构建前端上传到 build/,再在服务器上 git pull 并重建容器 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
70983a12a5
commit
47d4679984
40 files changed
+13723
-34
No files matched your search
@@ -0,0 +1,208 @@
|
||||
# Showcase Management Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Add a Dashboard-based management page for awards and awarded submissions that controls the existing student-facing showcase.
|
||||
|
||||
**Architecture:** Keep the existing public showcase API unchanged. Add admin-only django-ninja management endpoints under `submission/api.py`, extend the TypeScript API client and shared types, then add a focused `ShowcaseManage.vue` Dashboard page wired into the existing router and sidebar.
|
||||
|
||||
**Tech Stack:** Django, django-ninja, Django TestCase, Vue 3 Composition API, TypeScript, Naive UI, Axios.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Backend Management API
|
||||
|
||||
**Files:**
|
||||
- Modify: `api/submission/schemas.py`
|
||||
- Modify: `api/submission/api.py`
|
||||
- Test: `api/submission/tests.py`
|
||||
|
||||
- [ ] **Step 1: Write failing API tests**
|
||||
|
||||
Append tests to `api/submission/tests.py` that create an admin user, a normal user, an award, and a submission. Cover forbidden normal-user access, award creation/update, adding the same submission twice, and student showcase visibility after removal/deactivation.
|
||||
|
||||
Run: `uv run manage.py test submission`
|
||||
|
||||
Expected: FAIL because `/api/submission/showcase/manage/awards` endpoints do not exist.
|
||||
|
||||
- [ ] **Step 2: Add schema classes**
|
||||
|
||||
Add management schemas in `api/submission/schemas.py`:
|
||||
|
||||
```python
|
||||
class AwardManageIn(Schema):
|
||||
name: str
|
||||
description: str = ""
|
||||
sort_order: int = 0
|
||||
is_active: bool = True
|
||||
item_ordering: str = "manual"
|
||||
|
||||
|
||||
class AwardManageOut(Schema):
|
||||
id: int
|
||||
name: str
|
||||
description: str
|
||||
sort_order: int
|
||||
is_active: bool
|
||||
item_ordering: str
|
||||
item_count: int
|
||||
|
||||
|
||||
class AwardItemIn(Schema):
|
||||
submission_id: UUID
|
||||
sort_order: int = 0
|
||||
|
||||
|
||||
class AwardItemUpdateIn(Schema):
|
||||
sort_order: int = 0
|
||||
|
||||
|
||||
class AwardItemManageOut(Schema):
|
||||
id: int
|
||||
submission_id: UUID
|
||||
username: str
|
||||
task_title: str
|
||||
task_display: int
|
||||
score: float
|
||||
view_count: int
|
||||
sort_order: int
|
||||
awarded_at: datetime
|
||||
has_prompt_chain: bool
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Add admin-only endpoints**
|
||||
|
||||
In `api/submission/api.py`, import `admin_required` and the new schemas. Add endpoints before `/showcase/{submission_id}/` so static `manage/...` paths resolve correctly:
|
||||
|
||||
- `GET /showcase/manage/awards`
|
||||
- `POST /showcase/manage/awards`
|
||||
- `PUT /showcase/manage/awards/{award_id}`
|
||||
- `DELETE /showcase/manage/awards/{award_id}`
|
||||
- `GET /showcase/manage/awards/{award_id}/items`
|
||||
- `POST /showcase/manage/awards/{award_id}/items`
|
||||
- `PUT /showcase/manage/items/{item_id}`
|
||||
- `DELETE /showcase/manage/items/{item_id}`
|
||||
|
||||
Use `admin_required`, `get_object_or_404`, `Count`, `Exists`, and `OuterRef`. Validate `item_ordering` against `ItemOrdering.values`.
|
||||
|
||||
- [ ] **Step 4: Run backend tests**
|
||||
|
||||
Run: `uv run manage.py test submission`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 2: Frontend API Types And Client
|
||||
|
||||
**Files:**
|
||||
- Modify: `client/src/utils/type.ts`
|
||||
- Modify: `client/src/api.ts`
|
||||
|
||||
- [ ] **Step 1: Add TypeScript types**
|
||||
|
||||
Add:
|
||||
|
||||
```ts
|
||||
export type ItemOrdering = "manual" | "awarded_at" | "score" | "view_count"
|
||||
|
||||
export interface AwardManageIn {
|
||||
name: string
|
||||
description: string
|
||||
sort_order: number
|
||||
is_active: boolean
|
||||
item_ordering: ItemOrdering
|
||||
}
|
||||
|
||||
export interface AwardManageOut extends AwardManageIn {
|
||||
id: number
|
||||
item_count: number
|
||||
}
|
||||
|
||||
export interface AwardItemIn {
|
||||
submission_id: string
|
||||
sort_order: number
|
||||
}
|
||||
|
||||
export interface AwardItemUpdateIn {
|
||||
sort_order: number
|
||||
}
|
||||
|
||||
export interface AwardItemManageOut {
|
||||
id: number
|
||||
submission_id: string
|
||||
username: string
|
||||
task_title: string
|
||||
task_display: number
|
||||
score: number
|
||||
view_count: number
|
||||
sort_order: number
|
||||
awarded_at: string
|
||||
has_prompt_chain: boolean
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Extend API client**
|
||||
|
||||
Import the new types in `client/src/api.ts` and add `Showcase` methods:
|
||||
|
||||
- `listManageAwards()`
|
||||
- `createAward(payload)`
|
||||
- `updateAward(id, payload)`
|
||||
- `deleteAward(id)`
|
||||
- `listAwardItems(id)`
|
||||
- `addAwardItem(id, payload)`
|
||||
- `updateAwardItem(itemId, payload)`
|
||||
- `deleteAwardItem(itemId)`
|
||||
|
||||
- [ ] **Step 3: Run type/build check**
|
||||
|
||||
Run: `npm run build` from `client/`.
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 3: Dashboard Route And Page
|
||||
|
||||
**Files:**
|
||||
- Modify: `client/src/router.ts`
|
||||
- Modify: `client/src/pages/Dashboard.vue`
|
||||
- Create: `client/src/pages/ShowcaseManage.vue`
|
||||
|
||||
- [ ] **Step 1: Add route and menu**
|
||||
|
||||
Add `/dashboard/showcase` child route named `showcase-manage`. Add a Dashboard sidebar item labelled `作品广场`, visible to `admin` and `super`.
|
||||
|
||||
- [ ] **Step 2: Create management page**
|
||||
|
||||
Build `ShowcaseManage.vue` with:
|
||||
|
||||
- Left award list and new award button.
|
||||
- Right award edit form.
|
||||
- Award items table with sortable numeric input and remove button.
|
||||
- Submission search table using existing `Submission.list()`.
|
||||
- Add-to-award button for each searched submission.
|
||||
|
||||
- [ ] **Step 3: Run frontend build**
|
||||
|
||||
Run: `npm run build` from `client/`.
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 4: End-To-End Verification
|
||||
|
||||
**Files:**
|
||||
- No production file edits expected.
|
||||
|
||||
- [ ] **Step 1: Run backend tests**
|
||||
|
||||
Run: `uv run manage.py test submission` from `api/`.
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 2: Run frontend build**
|
||||
|
||||
Run: `npm run build` from `client/`.
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 3: Manual smoke path**
|
||||
|
||||
Start the app with existing dev command if needed. Log in as an admin user, visit `/dashboard/showcase`, create an award, add a submission, then visit `/showcase` and confirm the awarded work appears.
|
||||
Reference in new issue
Block a user