Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .tech/03-next-development-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Examora Next Development Plan

## Current Source of Truth

The current high-level product and architecture roadmap is:

- `docs/superpowers/specs/2026-05-17-examora-industry-exam-system-roadmap-design.md`

The staged implementation index is:

- `docs/superpowers/plans/2026-05-17-examora-module-batches.md`

This file keeps the internal engineering route aligned with those documents and records the admin route baseline that future work should build on.

## Admin Route Baseline

Use the new admin information architecture only:

- `/overview/dashboard`
- `/content/library/questions`
- `/content/library/programming`
- `/content/papers`
- `/examination/exams`
- `/examination/submissions`
- `/examination/judge-tasks`
- `/examination/events`
- `/system/settings/users`
- `/system/settings/user-groups`

Legacy routes stay removed and should resolve through the 404 fallback:

- `/admin/questions` -> `/content/library/questions`
- `/admin/papers` -> `/content/papers`
- `/admin/exams` -> `/examination/exams`
- `/assessment/results/submissions` -> `/examination/submissions`
- `/assessment/results/judge-tasks` -> `/examination/judge-tasks`
- `/monitoring/proctoring/events` -> `/examination/events`
- `/examination/candidates` has no replacement until assignment management is implemented.

## Batch Execution Route

1. Admin Baseline
- Stabilize route migration, paper pre-publish checks, real audit events page, and theme behavior.
- Verify admin tests, lint, build, Go tests, and Chrome route checks.
2. Publish Safety
- Enforce paper and exam publish readiness in backend services.
- Direct API calls must not publish empty papers, zero-score papers, draft-question papers, or invalid exams.
3. Content Asset Center
- Harden question lifecycle, dependency checks, programming test-case requirements, and paper preview.
4. Exam Operations Center
- Make exam detail the operational console for snapshots, assignments, sessions, submissions, judge tasks, and events.
5. Candidate Desktop Flow
- Complete assigned exam list, start/resume, safe snapshot loading, autosave, and final submission.
6. Scoring and Judge Visibility
- Complete objective scoring visibility and programming judge result state.
7. Audit and Risk Review
- Normalize client events into searchable admin audit data without treating audit signals as automatic cheating conclusions.
8. Reports, Operations, and Docs
- Add lightweight reports, operational scripts, and public documentation updates.

## Guardrails

- Keep admin DTOs and candidate DTOs separate.
- Candidate APIs must not expose answer keys, hidden test cases, or internal scoring data.
- Source questions and papers remain mutable library assets; published exams must use frozen snapshots.
- Every batch should leave a working vertical slice and pass its declared verification commands.
32 changes: 32 additions & 0 deletions apps/admin/config/routes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import routes from './routes';

const flattenPaths = (items: any[]): string[] =>
items.flatMap((item) => [
item.path,
...(item.routes ? flattenPaths(item.routes) : []),
]);

describe('admin routes', () => {
test('does not keep legacy redirect routes after full migration', () => {
const paths = flattenPaths(routes).filter(Boolean);

expect(paths).not.toContain('/admin/exams');
expect(paths).not.toContain('/admin/exam/:id/publish');
expect(paths).not.toContain('/admin/exam/create');
expect(paths).not.toContain('/monitoring');
expect(paths).not.toContain('/monitoring/proctoring');
expect(paths).not.toContain('/monitoring/proctoring/events');
expect(paths).not.toContain('/assessment');
expect(paths).not.toContain('/assessment/results');
expect(paths).not.toContain('/assessment/results/submissions');
expect(paths).not.toContain('/assessment/results/judge-tasks');
expect(paths).not.toContain('/examination/candidates');
});

test('keeps an explicit not found fallback route', () => {
const paths = flattenPaths(routes).filter(Boolean);

expect(paths).toContain('*');
expect(paths).not.toContain('./*');
});
});
76 changes: 1 addition & 75 deletions apps/admin/config/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,43 +168,6 @@ export default [
component: './Examination/ExamPublish',
access: 'canAdmin',
},
// Legacy monitoring redirects
{
path: '/monitoring',
hideInMenu: true,
redirect: '/examination/events',
},
{
path: '/monitoring/proctoring',
hideInMenu: true,
redirect: '/examination/events',
},
{
path: '/monitoring/proctoring/events',
hideInMenu: true,
redirect: '/examination/events',
},
// Legacy assessment redirects
{
path: '/assessment',
hideInMenu: true,
redirect: '/examination/submissions',
},
{
path: '/assessment/results',
hideInMenu: true,
redirect: '/examination/submissions',
},
{
path: '/assessment/results/submissions',
hideInMenu: true,
redirect: '/examination/submissions',
},
{
path: '/assessment/results/judge-tasks',
hideInMenu: true,
redirect: '/examination/judge-tasks',
},
// System section
{
path: '/system',
Expand Down Expand Up @@ -242,46 +205,9 @@ export default [
},
],
},
// Legacy redirects
{
path: '/examination/candidates',
redirect: '/system/settings/user-groups',
},
{
path: '/admin/exams',
redirect: '/examination/exams',
},
{
path: '/admin/exam/:id/publish',
redirect: '/examination/exams/:id/publish',
},
{
path: '/admin/exam/create',
redirect: '/examination/exams/create',
},
{
path: '/admin',
redirect: '/system/settings/users',
},
{
path: '/welcome',
redirect: '/overview/dashboard',
},
{
path: '/exams',
redirect: '/examination/exams',
},
{
path: '/exams/create',
redirect: '/examination/exams/create',
},
{
path: '/exams/:id/publish',
redirect: '/examination/exams/:id/publish',
},
{
component: './404',
layout: false,
path: './*',
path: '*',
},
];
8 changes: 2 additions & 6 deletions apps/admin/src/components/RightContent/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { createStyles } from 'antd-style';
import React, { useEffect, useState } from 'react';
import {
getEffectiveThemeMode,
getSystemPrefersDark,
loadThemePreference,
SYSTEM_DARK_QUERY,
saveThemePreference,
Expand Down Expand Up @@ -66,11 +67,6 @@ export const SelectLang: React.FC = () => {
);
};

function getSystemPrefersDark(): boolean {
if (typeof window === 'undefined' || !window.matchMedia) return false;
return window.matchMedia(SYSTEM_DARK_QUERY).matches;
}

const themeModeIcons: Record<ThemeMode, React.ReactNode> = {
light: <SunOutlined />,
dark: <MoonOutlined />,
Expand Down Expand Up @@ -114,7 +110,7 @@ export const ThemeSwitcher: React.FC = () => {
...state,
settings: {
...state?.settings,
...toLayoutSettings(next),
...toLayoutSettings(next, systemPrefersDark),
},
}));
};
Expand Down
8 changes: 0 additions & 8 deletions apps/admin/src/locales/en-US/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ export default {
'menu.overview.dashboard': 'Dashboard',
'menu.content': 'Library',
'menu.examination': 'Exams',
'menu.monitoring': 'MONITORING',
'menu.assessment': 'ASSESSMENT',
'menu.system': 'System',
'menu.home': 'Home',
'menu.login': 'Login',
Expand All @@ -30,12 +28,6 @@ export default {
'menu.examEdit': 'Edit Exam',
'menu.examPublish': 'Publish',
'menu.examination.examDetail': 'Exam Detail',
'menu.examination.candidates': 'User Groups',
'menu.proctoring': 'Proctoring',
'menu.monitoring.events': 'Events',
'menu.results': 'Results',
'menu.assessment.submissions': 'Submissions',
'menu.assessment.judgeTasks': 'Judge Tasks',
'menu.settings': 'Settings',
'menu.system.users': 'Users',
'menu.system.userGroups': 'User Groups',
Expand Down
55 changes: 20 additions & 35 deletions apps/admin/src/locales/en-US/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,16 @@ export default {
'pages.papers.detail.saveSuccess': 'Paper saved',
'pages.papers.detail.saveError': 'Failed to save paper',
'pages.papers.detail.loadError': 'Failed to load paper',
'pages.papers.detail.publishBlockedTitle': 'Paper cannot be published',
'pages.papers.detail.publishBlockedContent':
'A paper cannot be published without questions. Add at least 1 published question, then confirm the total score is greater than 0 and no question has 0 score. Current questions: {questions}; unpublished: {unpublished}; zero-score: {zeroScore}.',
'pages.papers.detail.basicInfo': 'Basic Info',
'pages.papers.detail.summary': 'Paper Summary',
'pages.papers.detail.publishReadyShort': 'Ready',
'pages.papers.detail.publishNoQuestionsShort': 'No questions',
'pages.papers.detail.publishNotReadyShort': 'Needs work',
'pages.papers.detail.publishInlineSummary':
'{questions} questions / {score} pts · {unpublished} unpublished · {zeroScore} zero-score',
'pages.papers.detail.paperStructure': 'Paper Content',
'pages.papers.detail.defaultSectionTitle': 'Section 1',
'pages.papers.detail.sectionTitleTemplate': 'Section {index}',
Expand Down Expand Up @@ -544,41 +552,18 @@ export default {
'pages.dashboard.shortcuts.questions': 'Question Bank',
'pages.dashboard.shortcuts.programming': 'Programming Bank',
'pages.dashboard.shortcuts.submissions': 'Submissions',
// Coming soon
'pages.comingSoon.title': 'Module Under Construction',
'pages.comingSoon.description':
'This admin module is reserved in the navigation and will be connected in a future iteration.',
'pages.comingSoon.shortTitle': 'Coming Soon',
'pages.comingSoon.shortDescription':
'This feature is under development. Please check back later.',
'pages.comingSoon.backDashboard': 'Back to Dashboard',
'pages.comingSoon.viewExams': 'View Exam Management',
'pages.comingSoon.note':
'This entry keeps the admin information architecture stable while business pages are added.',
'pages.comingSoon.questions.title': 'Question Bank',
'pages.comingSoon.questions.description':
'Question lists, type settings, answers, and explanations will be connected here.',
'pages.comingSoon.programming.title': 'Programming Questions and Test Cases',
'pages.comingSoon.programming.description':
'Programming templates, sample cases, hidden cases, and execution limits will be managed here.',
'pages.comingSoon.papers.title': 'Paper Management',
'pages.comingSoon.papers.description':
'Paper composition, question ordering, score settings, and status flow will be connected here.',
'pages.comingSoon.examCreate.title': 'Create Exam',
'pages.comingSoon.examCreate.description':
'Exam details, paper binding, and pre-publish configuration will be connected here.',
'pages.comingSoon.candidates.title': 'Candidate Management',
'pages.comingSoon.candidates.description':
'Candidate accounts, exam authorization, groups, and import/export will be connected here.',
'pages.comingSoon.events.title': 'Proctoring Audit',
'pages.comingSoon.events.description':
'Desktop events, device binding, and abnormal behavior records will be viewed here.',
'pages.comingSoon.submissions.title': 'Submission Records',
'pages.comingSoon.submissions.description':
'Candidate papers, programming submissions, and scoring status will be summarized here.',
'pages.comingSoon.judgeTasks.title': 'Judge Tasks',
'pages.comingSoon.judgeTasks.description':
'Async judge tasks, retry status, and sandbox results will be tracked here.',
// Events
'pages.events.description':
'View desktop audit events and device information by exam.',
'pages.events.examsLoadError': 'Failed to load exams',
'pages.events.fetchError': 'Failed to load audit events',
'pages.events.columns.user': 'User ID',
'pages.events.columns.device': 'Device',
'pages.events.columns.type': 'Event Type',
'pages.events.columns.createdAt': 'Time',
'pages.events.examPlaceholder': 'Select exam',
'pages.events.emptyExam': 'Select an exam to view audit events',
'pages.events.detailTitle': 'Event Detail',
// Exam form
'pages.exams.createTitle': 'Create Exam',
'pages.exams.editTitle': 'Edit Exam',
Expand Down
8 changes: 0 additions & 8 deletions apps/admin/src/locales/zh-CN/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ export default {
'menu.overview.dashboard': '工作台',
'menu.content': '资源库',
'menu.examination': '考试',
'menu.monitoring': 'MONITORING',
'menu.assessment': 'ASSESSMENT',
'menu.system': '系统',
'menu.home': '首页',
'menu.login': '登录',
Expand All @@ -30,12 +28,6 @@ export default {
'menu.examEdit': '编辑考试',
'menu.examPublish': '发布考试',
'menu.examination.examDetail': '考试详情',
'menu.examination.candidates': '用户组',
'menu.proctoring': '监考',
'menu.monitoring.events': '事件',
'menu.results': '评测',
'menu.assessment.submissions': '答卷',
'menu.assessment.judgeTasks': '判题',
'menu.settings': '设置',
'menu.system.users': '用户',
'menu.system.userGroups': '用户组',
Expand Down
Loading
Loading