Skip to content

feat: admin-api-and-dashboard-transcript-management#13

Open
VivekSingla20 wants to merge 1 commit into
mainfrom
feat/admin-api-and-dashboard-transcript-management
Open

feat: admin-api-and-dashboard-transcript-management#13
VivekSingla20 wants to merge 1 commit into
mainfrom
feat/admin-api-and-dashboard-transcript-management

Conversation

@VivekSingla20
Copy link
Copy Markdown
Collaborator

  • Implement EditTranscriptModal for editing transcript details.
  • Create ChannelsPage and VideosPage for channel and video management.
  • Add DashboardPage to display transcript statistics and recent activity.
  • Introduce HealthPage to monitor API and database health.
  • Develop LoginPage for admin authentication.
  • Create TranscriptsPage for listing and managing transcripts with search and pagination.
  • Update About page to dynamically display transcript statistics.
  • Adjust TypeScript configuration files for improved module resolution.
    -Overall made a basic admin panel

- Implement EditTranscriptModal for editing transcript details.
- Create ChannelsPage and VideosPage for channel and video management.
- Add DashboardPage to display transcript statistics and recent activity.
- Introduce HealthPage to monitor API and database health.
- Develop LoginPage for admin authentication.
- Create TranscriptsPage for listing and managing transcripts with search and pagination.
- Update About page to dynamically display transcript statistics.
- Adjust TypeScript configuration files for improved module resolution.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an admin panel and supporting backend admin API for transcript management, plus updates the public About page to display dynamic transcript statistics.

Changes:

  • Added admin UI (login, dashboard, transcripts CRUD, health monitor, placeholder channels/videos pages) and wired /admin/* routes in the frontend.
  • Introduced backend admin namespace (/api/v1/admin) with JWT-based auth, rate limiting, transcript CRUD endpoints, and admin health endpoints.
  • Improved DB pooling/timeout configuration and made About page stats dynamic via transcript meta.

Reviewed changes

Copilot reviewed 32 out of 34 changed files in this pull request and generated 18 comments.

Show a summary per file
File Description
tsconfig.node.tsbuildinfo Adds TS build info artifact (should be ignored, not committed).
tsconfig.json Alters TS path alias configuration (currently removes baseUrl).
tsconfig.app.tsbuildinfo Adds TS build info artifact (should be ignored, not committed).
tsconfig.app.json Alters app TS path alias configuration (currently removes baseUrl).
src/pages/About.tsx Replaces static stats with dynamic meta-derived stats and adjusts CTA.
src/admin/pages/VideosPage.tsx Adds placeholder admin videos page.
src/admin/pages/TranscriptsPage.tsx Adds admin transcript listing with search, pagination, edit/delete flows.
src/admin/pages/LoginPage.tsx Adds admin login page using password → token flow.
src/admin/pages/HealthPage.tsx Adds admin health monitor UI consuming admin health endpoints.
src/admin/pages/DashboardPage.tsx Adds admin dashboard summary + recent activity list.
src/admin/pages/ChannelsPage.tsx Adds placeholder admin channels page.
src/admin/components/EditTranscriptModal.tsx Adds modal to edit transcript metadata and text fields.
src/admin/api.ts Adds admin API client wrapper (login, transcripts CRUD, health).
src/admin/AuthContext.tsx Adds auth context for token storage and auth state.
src/admin/AdminLayout.tsx Adds authenticated admin shell with sidebar navigation + logout.
src/App.tsx Wires admin routes and wraps app in AuthProvider; introduces PublicLayout/Outlet.
backend/src/services/supabaseService.js Makes pool settings configurable and adds retry/timeouts behavior to DB queries.
backend/src/services/admin/transcriptService.js Adds admin transcript list/get/update/delete service logic.
backend/src/services/admin/authService.js Adds admin password validation and JWT issuance.
backend/src/routes/index.js Mounts /admin routes under /api/v1.
backend/src/routes/adminRoutes.js Defines admin route grouping with auth + rate limiting.
backend/src/routes/admin/transcriptRoutes.js Adds admin transcript endpoints with validation + permissions.
backend/src/routes/admin/healthRoutes.js Adds admin health endpoints (basic + detailed).
backend/src/routes/admin/authRoutes.js Adds admin login endpoint with validation + auth rate limiter.
backend/src/middleware/validation.js Adds validation rules for admin login and transcript list/update.
backend/src/middleware/index.js Re-exports new admin auth + admin rate limiter middleware.
backend/src/middleware/adminRateLimiter.js Adds admin and admin-auth rate limiters.
backend/src/middleware/adminAuth.js Adds JWT verification middleware and permission guard.
backend/src/controllers/admin/transcriptController.js Adds admin transcript controller actions.
backend/src/controllers/admin/authController.js Adds admin login controller action.
backend/src/config/index.js Adds DB pool/timeout config + admin config + production env validation.
backend/package.json Adds jsonwebtoken dependency.
backend/package-lock.json Locks jsonwebtoken and its transitive deps.
backend/.env.example Documents new DB tuning and admin env vars.
Files not reviewed (1)
  • backend/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tsconfig.node.tsbuildinfo
@@ -0,0 +1 @@
{"root":["./vite.config.ts"],"version":"5.9.3"} No newline at end of file
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This .tsbuildinfo file is a build artifact and should not be committed. Add a *.tsbuildinfo (or the specific filename) entry to .gitignore and remove this file from the repo to avoid noisy diffs and merge conflicts.

Copilot uses AI. Check for mistakes.
Comment thread src/admin/api.ts
Comment on lines +184 to +188
try {
return await request<HealthResponse>("/api/v1/admin/health/detailed");
} catch {
return await request<HealthResponse>("/api/v1/admin/health");
}
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getHealth() falls back to the basic health endpoint for any error from /health/detailed. If /health/detailed returns 503 in production to indicate degraded health, this fallback will hide the detailed dependency status. Consider only falling back on network/parse failures, or handling 503 responses by still consuming the detailed JSON payload.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +26
api.getTranscripts(1, 100)
.then((res) => {
const all = res.transcripts || [];
setTranscripts(all);
const known = all.filter((t) => t.status === "pending" || t.status === "processing" || t.status === "done").length;
setStats({
total: res.total || all.length,
withKnownStatus: known,
unknownStatus: all.length - known,
});
})
.catch((error) => {
toast.error(getErrorMessage(error, "Failed to load dashboard data"));
})
.finally(() => setLoading(false));
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dashboard stats are computed from api.getTranscripts(1, 100), so withKnownStatus/unknownStatus only reflect the first 100 transcripts, not the whole dataset (while total uses res.total). This will report incorrect counts when there are more than 100 transcripts. Consider adding a dedicated stats endpoint (or a query that returns aggregated status counts) instead of sampling the first page.

Suggested change
api.getTranscripts(1, 100)
.then((res) => {
const all = res.transcripts || [];
setTranscripts(all);
const known = all.filter((t) => t.status === "pending" || t.status === "processing" || t.status === "done").length;
setStats({
total: res.total || all.length,
withKnownStatus: known,
unknownStatus: all.length - known,
});
})
.catch((error) => {
toast.error(getErrorMessage(error, "Failed to load dashboard data"));
})
.finally(() => setLoading(false));
let cancelled = false;
const loadDashboardData = async () => {
const pageSize = 100;
let page = 1;
let total = 0;
let all: Transcript[] = [];
try {
while (true) {
const res = await api.getTranscripts(page, pageSize);
const batch = res.transcripts || [];
if (page === 1) {
total = res.total || batch.length;
}
all = all.concat(batch);
if (batch.length === 0 || all.length >= total || batch.length < pageSize) {
break;
}
page += 1;
}
if (cancelled) return;
const known = all.filter(
(t) => t.status === "pending" || t.status === "processing" || t.status === "done"
).length;
setTranscripts(all);
setStats({
total: total || all.length,
withKnownStatus: known,
unknownStatus: all.length - known,
});
} catch (error) {
if (cancelled) return;
toast.error(getErrorMessage(error, "Failed to load dashboard data"));
} finally {
if (!cancelled) {
setLoading(false);
}
}
};
loadDashboardData();
return () => {
cancelled = true;
};

Copilot uses AI. Check for mistakes.
Comment thread src/App.tsx
Comment on lines +24 to +25
import ChannelsPage from "./admin/pages/ChannelsPage.tsx";
import VideosPage from "./admin/pages/VideosPage.tsx";
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These imports include the .tsx extension, while other imports in the same file omit it (e.g., ./admin/pages/LoginPage on lines 20-23). For consistency and to avoid tooling edge-cases, prefer extensionless imports (e.g. ./admin/pages/ChannelsPage).

Suggested change
import ChannelsPage from "./admin/pages/ChannelsPage.tsx";
import VideosPage from "./admin/pages/VideosPage.tsx";
import ChannelsPage from "./admin/pages/ChannelsPage";
import VideosPage from "./admin/pages/VideosPage";

Copilot uses AI. Check for mistakes.
Comment on lines +130 to +133
<button onClick={() => setEditingId(t.id)} className="p-1.5 rounded hover:bg-secondary transition-colors text-muted-foreground hover:text-foreground">
<Pencil className="w-3.5 h-3.5" />
</button>
<button onClick={() => setDeletingId(t.id)} className="p-1.5 rounded hover:bg-destructive/10 transition-colors text-muted-foreground hover:text-destructive">
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These icon-only edit/delete buttons are missing accessible names. Add aria-label values (and consider type="button") so they’re usable with screen readers and don’t accidentally act as submit buttons if placed inside a form later.

Suggested change
<button onClick={() => setEditingId(t.id)} className="p-1.5 rounded hover:bg-secondary transition-colors text-muted-foreground hover:text-foreground">
<Pencil className="w-3.5 h-3.5" />
</button>
<button onClick={() => setDeletingId(t.id)} className="p-1.5 rounded hover:bg-destructive/10 transition-colors text-muted-foreground hover:text-destructive">
<button
type="button"
aria-label={`Edit transcript ${t.title}`}
onClick={() => setEditingId(t.id)}
className="p-1.5 rounded hover:bg-secondary transition-colors text-muted-foreground hover:text-foreground"
>
<Pencil className="w-3.5 h-3.5" />
</button>
<button
type="button"
aria-label={`Delete transcript ${t.title}`}
onClick={() => setDeletingId(t.id)}
className="p-1.5 rounded hover:bg-destructive/10 transition-colors text-muted-foreground hover:text-destructive"
>

Copilot uses AI. Check for mistakes.
Comment thread tsconfig.app.json
Comment on lines 24 to 27

"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

paths is configured but baseUrl was removed. TypeScript requires baseUrl when using paths, otherwise alias imports like @/… will fail to typecheck/compile. Reintroduce baseUrl (typically ".") or drop paths if aliases aren’t intended.

Copilot uses AI. Check for mistakes.
Comment thread src/admin/api.ts
Comment on lines +104 to +108
if (!res.ok) {
let message = `Request failed (${res.status})`;

try {
const json = (await res.json()) as ApiErrorEnvelope;
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On non-2xx responses, request() only attempts to read error.message and otherwise throws away the body. For health endpoints it’s common to return 503 while still returning useful data about which dependency is unhealthy. Consider parsing and surfacing that data (or special-casing health calls) so the UI can show degraded state instead of a generic failure.

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +67
placeholder="Search by title..."
value={search}
onChange={(e) => { setSearch(e.target.value); setPage(1); }}
className="w-full pl-8 pr-3 py-2 rounded-md border border-input bg-background text-sm focus:outline-none focus:ring-2 focus:ring-primary"
/>
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because search is part of fetchData’s dependencies, typing in this input will trigger a fetch on every keystroke via the effect. Add a debounce (or a submit button) to reduce API load and improve responsiveness.

Copilot uses AI. Check for mistakes.
Comment on lines +148 to +154
<button onClick={() => setPage((p) => Math.max(1, p - 1))} disabled={page === 1}
className="p-1.5 rounded hover:bg-secondary disabled:opacity-30 transition-colors">
<ChevronLeft className="w-4 h-4" />
</button>
<span className="text-sm text-muted-foreground">Page {page} of {totalPages}</span>
<button onClick={() => setPage((p) => Math.min(totalPages, p + 1))} disabled={page === totalPages}
className="p-1.5 rounded hover:bg-secondary disabled:opacity-30 transition-colors">
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pagination controls are icon-only buttons without accessible names. Add aria-label text (e.g., “Previous page” / “Next page”) so assistive tech can identify them.

Suggested change
<button onClick={() => setPage((p) => Math.max(1, p - 1))} disabled={page === 1}
className="p-1.5 rounded hover:bg-secondary disabled:opacity-30 transition-colors">
<ChevronLeft className="w-4 h-4" />
</button>
<span className="text-sm text-muted-foreground">Page {page} of {totalPages}</span>
<button onClick={() => setPage((p) => Math.min(totalPages, p + 1))} disabled={page === totalPages}
className="p-1.5 rounded hover:bg-secondary disabled:opacity-30 transition-colors">
<button
onClick={() => setPage((p) => Math.max(1, p - 1))}
disabled={page === 1}
aria-label="Previous page"
className="p-1.5 rounded hover:bg-secondary disabled:opacity-30 transition-colors"
>
<ChevronLeft className="w-4 h-4" />
</button>
<span className="text-sm text-muted-foreground">Page {page} of {totalPages}</span>
<button
onClick={() => setPage((p) => Math.min(totalPages, p + 1))}
disabled={page === totalPages}
aria-label="Next page"
className="p-1.5 rounded hover:bg-secondary disabled:opacity-30 transition-colors"
>

Copilot uses AI. Check for mistakes.
Comment thread src/admin/AdminLayout.tsx
</span>
)}
<button
onClick={() => setSidebarOpen(!sidebarOpen)}
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sidebar toggle is an icon-only button without an accessible name. Add an aria-label (e.g., “Collapse sidebar” / “Expand sidebar”) so it’s usable with screen readers.

Suggested change
onClick={() => setSidebarOpen(!sidebarOpen)}
onClick={() => setSidebarOpen(!sidebarOpen)}
aria-label={sidebarOpen ? "Collapse sidebar" : "Expand sidebar"}

Copilot uses AI. Check for mistakes.
@Sansh2356
Copy link
Copy Markdown

@cubic-dev-ai review this pull request

@cubic-dev-ai
Copy link
Copy Markdown

cubic-dev-ai Bot commented May 3, 2026

@cubic-dev-ai review this pull request

@Sansh2356 I have started the AI code review. It will take a few minutes to complete.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 34 files

@Sansh2356
Copy link
Copy Markdown

@CodeRabbit-ai review .

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 3, 2026

Tip

For best results, initiate chat on the files or code changes.

@Sansh2356 Sure! I'll review the pull request now.

[review]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants