Index: src/app/admin/layout.tsx
===================================================================
--- src/app/admin/layout.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ src/app/admin/layout.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -0,0 +1,27 @@
+import type { Metadata } from "next";
+import { Geist, Geist_Mono } from "next/font/google";
+import "../globals.css";
+import "@fortawesome/fontawesome-svg-core/styles.css";
+import { config } from "@fortawesome/fontawesome-svg-core";
+import Header from "@/components/header";
+import AdminNavbar from "@/components/admin-navbar";
+
+config.autoAddCss = false;
+
+const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"] });
+const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"] });
+
+export const metadata: Metadata = {
+  title: "IKnow - Admin Portal",
+  description: "Administration of subjects, semesters and teaching assignments",
+};
+
+export default function AdminLayout({ children }: Readonly<{ children: React.ReactNode }>) {
+  return (
+    <div className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
+      <Header />
+      <AdminNavbar />
+      {children}
+    </div>
+  );
+}
Index: src/app/admin/page.tsx
===================================================================
--- src/app/admin/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ src/app/admin/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -0,0 +1,5 @@
+import { redirect } from "next/navigation";
+
+export default function AdminIndex() {
+  redirect("/admin/subjects");
+}
Index: src/app/admin/schedule/page.tsx
===================================================================
--- src/app/admin/schedule/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ src/app/admin/schedule/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -0,0 +1,224 @@
+"use client";
+
+import { useCallback, useEffect, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { adminGet, adminSend, type AdminSemester, type Schedule } from "@/lib/admin-api";
+
+export default function AdminSchedulePage() {
+  const { t } = useTranslation();
+
+  const [semesters, setSemesters] = useState<AdminSemester[]>([]);
+  const [semesterId, setSemesterId] = useState<number | null>(null);
+  const [schedule, setSchedule] = useState<Schedule | null>(null);
+
+  const [loading, setLoading] = useState(true);
+  const [busy, setBusy] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+  const [notice, setNotice] = useState<string | null>(null);
+
+  const [subjectId, setSubjectId] = useState<number | "">("");
+  const [professorId, setProfessorId] = useState<number | "">("");
+
+  useEffect(() => {
+    (async () => {
+      try {
+        const list = await adminGet<AdminSemester[]>("/api/admin/semesters");
+        setSemesters(list);
+        setSemesterId(list[0]?.id ?? null);
+      } catch (e) {
+        setError(e instanceof Error ? e.message : String(e));
+      } finally {
+        setLoading(false);
+      }
+    })();
+  }, []);
+
+  const loadSchedule = useCallback(async (id: number) => {
+    setLoading(true);
+    setError(null);
+    try {
+      setSchedule(await adminGet<Schedule>(`/api/admin/schedule/${id}`));
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setLoading(false);
+    }
+  }, []);
+
+  useEffect(() => {
+    if (semesterId !== null) void loadSchedule(semesterId);
+  }, [semesterId, loadSchedule]);
+
+  async function run(action: () => Promise<{ message?: string }>) {
+    setBusy(true);
+    setError(null);
+    setNotice(null);
+    try {
+      const result = await action();
+      setNotice(result.message ?? null);
+      if (semesterId !== null) await loadSchedule(semesterId);
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setBusy(false);
+    }
+  }
+
+  return (
+    <div className="min-h-screen pb-8">
+      <div className="bg-primary text-white rounded-xl p-8 mb-8">
+        <h1 className="text-3xl font-bold mb-2">{t("admin_schedule")}</h1>
+        <p className="text-lg opacity-90">{t("admin_schedule_intro")}</p>
+      </div>
+
+      {error && (
+        <div className="mb-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">{error}</div>
+      )}
+      {notice && (
+        <div className="mb-4 rounded-lg border border-green-200 bg-green-50 px-4 py-3 text-sm text-green-800">{notice}</div>
+      )}
+
+      <div className="bg-card rounded-xl shadow-sm border border-border p-6 mb-6">
+        <div className="flex flex-wrap items-end gap-4">
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("semester")}</span>
+            <select
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={semesterId ?? ""}
+              onChange={(e) => setSemesterId(Number(e.target.value))}
+            >
+              {semesters.map((s) => (
+                <option key={s.id} value={s.id}>{s.name}</option>
+              ))}
+            </select>
+          </label>
+
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("subject")}</span>
+            <select
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={subjectId}
+              onChange={(e) => setSubjectId(e.target.value === "" ? "" : Number(e.target.value))}
+            >
+              <option value="">{t("admin_pick_subject")}</option>
+              {schedule?.allSubjects.map((s) => (
+                <option key={s.id} value={s.id}>{s.code} — {s.name}</option>
+              ))}
+            </select>
+          </label>
+
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_professor")}</span>
+            <select
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={professorId}
+              onChange={(e) => setProfessorId(e.target.value === "" ? "" : Number(e.target.value))}
+            >
+              <option value="">{t("admin_pick_professor")}</option>
+              {schedule?.professors.map((p) => (
+                <option key={p.id} value={p.id}>{p.name}</option>
+              ))}
+            </select>
+          </label>
+
+          <button
+            className="rounded-lg bg-green-600 px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
+            disabled={busy || subjectId === "" || professorId === "" || semesterId === null}
+            onClick={() =>
+              void run(() =>
+                adminSend("/api/admin/schedule", "POST", {
+                  ProfessorId: professorId,
+                  SemesterId: semesterId,
+                  SubjectId: subjectId,
+                }),
+              )
+            }
+          >
+            {t("admin_assign")}
+          </button>
+        </div>
+      </div>
+
+      {schedule && schedule.uncoveredSubjects.length > 0 && (
+        <div className="mb-6 rounded-lg border border-yellow-200 bg-yellow-50 px-4 py-3 text-sm text-yellow-900">
+          <strong>{t("admin_uncovered_count", { count: schedule.uncoveredSubjects.length })}</strong>
+          <span className="ml-2">{t("admin_uncovered_hint")}</span>
+          <div className="mt-2 font-mono text-xs">
+            {schedule.uncoveredSubjects.map((u) => u.code).join(", ")}
+          </div>
+        </div>
+      )}
+
+      <div className="grid gap-6 lg:grid-cols-3">
+        <div className="lg:col-span-2 bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+          <div className="bg-primary text-white px-6 py-4">
+            <h2 className="text-xl font-bold">
+              {t("admin_assignments")} {schedule ? `— ${schedule.semesterName}` : ""}
+            </h2>
+          </div>
+          <div className="overflow-x-auto">
+            <table className="w-full">
+              <thead className="bg-accent">
+                <tr>
+                  <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_subject_code")}</th>
+                  <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("subject")}</th>
+                  <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_professor")}</th>
+                  <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("actions")}</th>
+                </tr>
+              </thead>
+              <tbody>
+                {loading ? (
+                  <tr><td className="px-4 py-4 text-muted-foreground" colSpan={4}>{t("loading")}</td></tr>
+                ) : !schedule || schedule.assignments.length === 0 ? (
+                  <tr><td className="px-4 py-4 text-muted-foreground" colSpan={4}>{t("admin_no_assignments")}</td></tr>
+                ) : (
+                  schedule.assignments.map((a) => (
+                    <tr key={`${a.subjectId}-${a.professorId}`} className="hover:bg-accent">
+                      <td className="px-4 py-3 border-b font-mono text-card-foreground">{a.subjectCode}</td>
+                      <td className="px-4 py-3 border-b text-card-foreground">{a.subjectName}</td>
+                      <td className="px-4 py-3 border-b text-card-foreground">{a.professorName}</td>
+                      <td className="px-4 py-3 border-b">
+                        <button
+                          className="rounded-lg bg-gray-800 px-3 py-1.5 text-sm text-white disabled:opacity-50"
+                          disabled={busy}
+                          onClick={() =>
+                            void run(() =>
+                              adminSend("/api/admin/schedule", "DELETE", {
+                                ProfessorId: a.professorId,
+                                SemesterId: schedule.semesterId,
+                                SubjectId: a.subjectId,
+                              }),
+                            )
+                          }
+                        >
+                          {t("admin_remove")}
+                        </button>
+                      </td>
+                    </tr>
+                  ))
+                )}
+              </tbody>
+            </table>
+          </div>
+        </div>
+
+        <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+          <div className="bg-primary text-white px-6 py-4">
+            <h2 className="text-xl font-bold">{t("admin_load")}</h2>
+          </div>
+          <ul className="divide-y divide-border">
+            {schedule?.load.map((l) => (
+              <li key={l.professorId} className="flex items-center justify-between px-4 py-3">
+                <span className="text-card-foreground">{l.professorName}</span>
+                <span className="rounded-full bg-accent px-2 py-0.5 text-sm text-muted-foreground">{l.subjects}</span>
+              </li>
+            ))}
+            {!schedule?.load.length && (
+              <li className="px-4 py-3 text-muted-foreground">{t("admin_no_professors")}</li>
+            )}
+          </ul>
+        </div>
+      </div>
+    </div>
+  );
+}
Index: src/app/admin/semesters/page.tsx
===================================================================
--- src/app/admin/semesters/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ src/app/admin/semesters/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -0,0 +1,173 @@
+"use client";
+
+import { useCallback, useEffect, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { adminGet, adminSend, type AdminSemester } from "@/lib/admin-api";
+
+export default function AdminSemestersPage() {
+  const { t } = useTranslation();
+
+  const [semesters, setSemesters] = useState<AdminSemester[]>([]);
+  const [loading, setLoading] = useState(true);
+  const [busy, setBusy] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+  const [notice, setNotice] = useState<string | null>(null);
+
+  const [year, setYear] = useState(new Date().getFullYear());
+  const [type, setType] = useState<"winter" | "summer">("winter");
+  const [expandedId, setExpandedId] = useState<number | null>(null);
+
+  const refresh = useCallback(async () => {
+    setLoading(true);
+    setError(null);
+    try {
+      setSemesters(await adminGet<AdminSemester[]>("/api/admin/semesters"));
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setLoading(false);
+    }
+  }, []);
+
+  useEffect(() => {
+    void refresh();
+  }, [refresh]);
+
+  async function create() {
+    setBusy(true);
+    setError(null);
+    setNotice(null);
+    try {
+      const result = await adminSend("/api/admin/semesters", "POST", { Year: year, Type: type });
+      setNotice(result.message ?? null);
+      await refresh();
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setBusy(false);
+    }
+  }
+
+  return (
+    <div className="min-h-screen pb-8">
+      <div className="bg-primary text-white rounded-xl p-8 mb-8">
+        <h1 className="text-3xl font-bold mb-2">{t("admin_semesters")}</h1>
+        <p className="text-lg opacity-90">{t("admin_semesters_intro")}</p>
+      </div>
+
+      {error && (
+        <div className="mb-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">{error}</div>
+      )}
+      {notice && (
+        <div className="mb-4 rounded-lg border border-green-200 bg-green-50 px-4 py-3 text-sm text-green-800">{notice}</div>
+      )}
+
+      <div className="bg-card rounded-xl shadow-sm border border-border p-6 mb-6">
+        <h2 className="text-xl font-semibold mb-4 text-card-foreground">{t("admin_new_semester")}</h2>
+        <div className="flex flex-wrap items-end gap-4">
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_year")}</span>
+            <input
+              type="number"
+              min={2000}
+              max={2100}
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={year}
+              onChange={(e) => setYear(Number(e.target.value))}
+            />
+          </label>
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_type")}</span>
+            <select
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={type}
+              onChange={(e) => setType(e.target.value as "winter" | "summer")}
+            >
+              <option value="winter">{t("admin_winter")}</option>
+              <option value="summer">{t("admin_summer")}</option>
+            </select>
+          </label>
+          <button
+            disabled={busy}
+            className="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
+            onClick={() => void create()}
+          >
+            {t("admin_open_semester")}
+          </button>
+        </div>
+      </div>
+
+      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+        <div className="bg-primary text-white px-6 py-4">
+          <h2 className="text-xl font-bold">{t("admin_open_semesters")}</h2>
+        </div>
+        <div className="overflow-x-auto">
+          <table className="w-full">
+            <thead className="bg-accent">
+              <tr>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("semester")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_enrolments")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_coverage")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("actions")}</th>
+              </tr>
+            </thead>
+            <tbody>
+              {loading ? (
+                <tr><td className="px-4 py-4 text-muted-foreground" colSpan={4}>{t("loading")}</td></tr>
+              ) : semesters.length === 0 ? (
+                <tr><td className="px-4 py-4 text-muted-foreground" colSpan={4}>{t("admin_no_semesters")}</td></tr>
+              ) : (
+                semesters.map((s) => {
+                  const uncovered = s.uncoveredSubjects.length;
+                  return (
+                    <>
+                      <tr key={s.id} className="hover:bg-accent">
+                        <td className="px-4 py-3 border-b text-card-foreground">{s.name}</td>
+                        <td className="px-4 py-3 border-b text-card-foreground">{s.enrolmentCount}</td>
+                        <td className="px-4 py-3 border-b">
+                          {uncovered === 0 ? (
+                            <span className="rounded-full bg-green-100 px-2 py-0.5 text-xs text-green-800">
+                              {t("admin_fully_covered")}
+                            </span>
+                          ) : (
+                            <span className="rounded-full bg-yellow-100 px-2 py-0.5 text-xs text-yellow-900">
+                              {t("admin_uncovered_count", { count: uncovered })}
+                            </span>
+                          )}
+                        </td>
+                        <td className="px-4 py-3 border-b">
+                          {uncovered > 0 && (
+                            <button
+                              className="rounded-lg border border-border px-3 py-1.5 text-sm"
+                              onClick={() => setExpandedId(expandedId === s.id ? null : s.id)}
+                            >
+                              {expandedId === s.id ? t("admin_close") : t("admin_show_uncovered")}
+                            </button>
+                          )}
+                        </td>
+                      </tr>
+                      {expandedId === s.id && uncovered > 0 && (
+                        <tr key={`${s.id}-detail`}>
+                          <td colSpan={4} className="border-b bg-accent/40 px-4 py-4 text-sm">
+                            <p className="mb-2 text-muted-foreground">{t("admin_uncovered_hint")}</p>
+                            <ul className="grid gap-1 sm:grid-cols-2 lg:grid-cols-3">
+                              {s.uncoveredSubjects.map((u) => (
+                                <li key={u.id} className="text-card-foreground">
+                                  <span className="font-mono">{u.code}</span> — {u.name}
+                                </li>
+                              ))}
+                            </ul>
+                          </td>
+                        </tr>
+                      )}
+                    </>
+                  );
+                })
+              )}
+            </tbody>
+          </table>
+        </div>
+      </div>
+    </div>
+  );
+}
Index: src/app/admin/subjects/page.tsx
===================================================================
--- src/app/admin/subjects/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ src/app/admin/subjects/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -0,0 +1,409 @@
+"use client";
+
+import { useCallback, useEffect, useMemo, useState } from "react";
+import { useTranslation } from "react-i18next";
+import {
+  adminGet,
+  adminSend,
+  type AdminSubject,
+  type SubjectRef,
+} from "@/lib/admin-api";
+
+const EMPTY_FORM = { name: "", code: "", awardedCredits: 6, dependencyCredit: 0 };
+
+export default function AdminSubjectsPage() {
+  const { t } = useTranslation();
+
+  const [subjects, setSubjects] = useState<AdminSubject[]>([]);
+  const [majors, setMajors] = useState<SubjectRef[]>([]);
+  const [loading, setLoading] = useState(true);
+  const [busy, setBusy] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+  const [notice, setNotice] = useState<string | null>(null);
+
+  const [form, setForm] = useState(EMPTY_FORM);
+  const [editingId, setEditingId] = useState<number | null>(null);
+  const [expandedId, setExpandedId] = useState<number | null>(null);
+  const [query, setQuery] = useState("");
+
+  const refresh = useCallback(async () => {
+    setLoading(true);
+    setError(null);
+    try {
+      const [s, m] = await Promise.all([
+        adminGet<AdminSubject[]>("/api/admin/subjects"),
+        adminGet<SubjectRef[]>("/api/admin/majors"),
+      ]);
+      setSubjects(s);
+      setMajors(m);
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setLoading(false);
+    }
+  }, []);
+
+  useEffect(() => {
+    void refresh();
+  }, [refresh]);
+
+  async function run(action: () => Promise<{ message?: string }>) {
+    setBusy(true);
+    setError(null);
+    setNotice(null);
+    try {
+      const result = await action();
+      setNotice(result.message ?? null);
+      await refresh();
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setBusy(false);
+    }
+  }
+
+  const filtered = useMemo(() => {
+    const q = query.trim().toLowerCase();
+    if (!q) return subjects;
+    return subjects.filter(
+      (s) =>
+        (s.name ?? "").toLowerCase().includes(q) ||
+        (s.code ?? "").toLowerCase().includes(q),
+    );
+  }, [subjects, query]);
+
+  function startEdit(s: AdminSubject) {
+    setEditingId(s.id);
+    setForm({
+      name: s.name ?? "",
+      code: s.code ?? "",
+      awardedCredits: s.awardedCredits,
+      dependencyCredit: s.dependencyCredit ?? 0,
+    });
+    window.scrollTo({ top: 0, behavior: "smooth" });
+  }
+
+  function cancelEdit() {
+    setEditingId(null);
+    setForm(EMPTY_FORM);
+  }
+
+  return (
+    <div className="min-h-screen pb-8">
+      <div className="bg-primary text-white rounded-xl p-8 mb-8">
+        <h1 className="text-3xl font-bold mb-2">{t("admin_subjects")}</h1>
+        <p className="text-lg opacity-90">{t("admin_subjects_intro")}</p>
+      </div>
+
+      {error && (
+        <div className="mb-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">
+          {error}
+        </div>
+      )}
+      {notice && (
+        <div className="mb-4 rounded-lg border border-green-200 bg-green-50 px-4 py-3 text-sm text-green-800">
+          {notice}
+        </div>
+      )}
+
+      {/* create / edit */}
+      <div className="bg-card rounded-xl shadow-sm border border-border p-6 mb-6">
+        <h2 className="text-xl font-semibold mb-4 text-card-foreground">
+          {editingId === null ? t("admin_new_subject") : t("admin_edit_subject")}
+        </h2>
+        <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_subject_name")}</span>
+            <input
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={form.name}
+              onChange={(e) => setForm({ ...form, name: e.target.value })}
+            />
+          </label>
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_subject_code")}</span>
+            <input
+              className="rounded-lg border border-border bg-background px-3 py-2 font-mono"
+              value={form.code}
+              onChange={(e) => setForm({ ...form, code: e.target.value })}
+            />
+          </label>
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_credits")}</span>
+            <input
+              type="number"
+              min={1}
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={form.awardedCredits}
+              onChange={(e) => setForm({ ...form, awardedCredits: Number(e.target.value) })}
+            />
+          </label>
+          <label className="flex flex-col">
+            <span className="text-sm text-muted-foreground">{t("admin_dependency_credit")}</span>
+            <input
+              type="number"
+              min={0}
+              className="rounded-lg border border-border bg-background px-3 py-2"
+              value={form.dependencyCredit}
+              onChange={(e) => setForm({ ...form, dependencyCredit: Number(e.target.value) })}
+            />
+          </label>
+        </div>
+        <div className="mt-4 flex gap-3">
+          <button
+            disabled={busy}
+            className="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
+            onClick={() =>
+              void run(async () => {
+                const body = {
+                  Name: form.name,
+                  Code: form.code,
+                  AwardedCredits: form.awardedCredits,
+                  DependencyCredit: form.dependencyCredit,
+                };
+                const result =
+                  editingId === null
+                    ? await adminSend("/api/admin/subjects", "POST", body)
+                    : await adminSend(`/api/admin/subjects/${editingId}`, "PUT", body);
+                cancelEdit();
+                return result;
+              })
+            }
+          >
+            {editingId === null ? t("admin_create") : t("admin_save")}
+          </button>
+          {editingId !== null && (
+            <button
+              className="rounded-lg border border-border px-4 py-2 text-sm font-medium"
+              onClick={cancelEdit}
+              disabled={busy}
+            >
+              {t("cancel")}
+            </button>
+          )}
+        </div>
+      </div>
+
+      {/* list */}
+      <div className="bg-card rounded-xl shadow-sm border border-border overflow-hidden">
+        <div className="flex items-center justify-between gap-4 bg-primary text-white px-6 py-4">
+          <h2 className="text-xl font-bold">
+            {t("admin_subjects")} ({filtered.length})
+          </h2>
+          <input
+            className="rounded-lg px-3 py-2 text-card-foreground bg-background"
+            placeholder={t("admin_search_subject")}
+            value={query}
+            onChange={(e) => setQuery(e.target.value)}
+          />
+        </div>
+
+        <div className="overflow-x-auto">
+          <table className="w-full">
+            <thead className="bg-accent">
+              <tr>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_subject_code")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_subject_name")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_credits")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_majors")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("admin_prerequisites")}</th>
+                <th className="px-4 py-3 text-left text-xs font-medium uppercase text-muted-foreground">{t("actions")}</th>
+              </tr>
+            </thead>
+            <tbody>
+              {loading ? (
+                <tr><td className="px-4 py-4 text-muted-foreground" colSpan={6}>{t("loading")}</td></tr>
+              ) : filtered.length === 0 ? (
+                <tr><td className="px-4 py-4 text-muted-foreground" colSpan={6}>{t("admin_no_subjects")}</td></tr>
+              ) : (
+                filtered.map((s) => (
+                  <ExpandableRow
+                    key={s.id}
+                    subject={s}
+                    majors={majors}
+                    subjects={subjects}
+                    busy={busy}
+                    expanded={expandedId === s.id}
+                    onToggle={() => setExpandedId(expandedId === s.id ? null : s.id)}
+                    onEdit={() => startEdit(s)}
+                    run={run}
+                  />
+                ))
+              )}
+            </tbody>
+          </table>
+        </div>
+      </div>
+    </div>
+  );
+}
+
+function ExpandableRow({
+  subject,
+  majors,
+  subjects,
+  busy,
+  expanded,
+  onToggle,
+  onEdit,
+  run,
+}: {
+  subject: AdminSubject;
+  majors: SubjectRef[];
+  subjects: AdminSubject[];
+  busy: boolean;
+  expanded: boolean;
+  onToggle: () => void;
+  onEdit: () => void;
+  run: (action: () => Promise<{ message?: string }>) => Promise<void>;
+}) {
+  const { t } = useTranslation();
+  const [majorId, setMajorId] = useState<number | "">("");
+  const [semester, setSemester] = useState(1);
+  const [prereqId, setPrereqId] = useState<number | "">("");
+
+  // A subject already taken by students cannot be deleted; the FK forbids it.
+  const deletable = subject.enrolledCount === 0;
+
+  return (
+    <>
+      <tr className="hover:bg-accent">
+        <td className="px-4 py-3 border-b font-mono text-card-foreground">{subject.code}</td>
+        <td className="px-4 py-3 border-b text-card-foreground">{subject.name}</td>
+        <td className="px-4 py-3 border-b text-card-foreground">{subject.awardedCredits}</td>
+        <td className="px-4 py-3 border-b text-sm text-muted-foreground">
+          {subject.majors.length === 0 ? "—" : subject.majors.map((m) => `${m.majorName} (${m.mandatorySemester})`).join(", ")}
+        </td>
+        <td className="px-4 py-3 border-b text-sm text-muted-foreground">
+          {subject.prerequisites.length === 0 ? "—" : subject.prerequisites.map((p) => p.code).join(", ")}
+        </td>
+        <td className="px-4 py-3 border-b">
+          <div className="flex flex-wrap gap-2">
+            <button className="rounded-lg border border-border px-3 py-1.5 text-sm" onClick={onToggle}>
+              {expanded ? t("admin_close") : t("admin_manage")}
+            </button>
+            <button className="rounded-lg bg-blue-600 px-3 py-1.5 text-sm text-white disabled:opacity-50" onClick={onEdit} disabled={busy}>
+              {t("edit_grade") === "Измени оценка" ? "Измени" : "Edit"}
+            </button>
+            <button
+              className="rounded-lg bg-gray-800 px-3 py-1.5 text-sm text-white disabled:opacity-40"
+              disabled={busy || !deletable}
+              title={deletable ? undefined : t("admin_delete_blocked", { count: subject.enrolledCount })}
+              onClick={() => void run(() => adminSend(`/api/admin/subjects/${subject.id}`, "DELETE"))}
+            >
+              {t("admin_delete")}
+            </button>
+          </div>
+        </td>
+      </tr>
+
+      {expanded && (
+        <tr>
+          <td colSpan={6} className="border-b bg-accent/40 px-4 py-4">
+            <div className="grid gap-6 lg:grid-cols-2">
+              {/* majors */}
+              <div>
+                <h3 className="font-semibold text-card-foreground mb-2">{t("admin_majors")}</h3>
+                <ul className="mb-3 space-y-1 text-sm">
+                  {subject.majors.map((m) => (
+                    <li key={m.majorId} className="flex items-center justify-between gap-2">
+                      <span>{m.majorName} — {t("enroll_semester_short")} {m.mandatorySemester}</span>
+                      <button
+                        className="text-red-700 hover:underline"
+                        disabled={busy}
+                        onClick={() => void run(() => adminSend(`/api/admin/subjects/${subject.id}/majors/${m.majorId}`, "DELETE"))}
+                      >
+                        {t("admin_remove")}
+                      </button>
+                    </li>
+                  ))}
+                  {subject.majors.length === 0 && <li className="text-muted-foreground">—</li>}
+                </ul>
+                <div className="flex flex-wrap gap-2">
+                  <select
+                    className="rounded-lg border border-border bg-background px-3 py-2 text-sm"
+                    value={majorId}
+                    onChange={(e) => setMajorId(e.target.value === "" ? "" : Number(e.target.value))}
+                  >
+                    <option value="">{t("admin_pick_major")}</option>
+                    {majors.map((m) => (
+                      <option key={m.id} value={m.id}>{m.name}</option>
+                    ))}
+                  </select>
+                  <input
+                    type="number"
+                    min={1}
+                    className="w-24 rounded-lg border border-border bg-background px-3 py-2 text-sm"
+                    value={semester}
+                    onChange={(e) => setSemester(Number(e.target.value))}
+                  />
+                  <button
+                    className="rounded-lg bg-green-600 px-3 py-2 text-sm text-white disabled:opacity-50"
+                    disabled={busy || majorId === ""}
+                    onClick={() =>
+                      void run(() =>
+                        adminSend(`/api/admin/subjects/${subject.id}/majors`, "POST", {
+                          MajorId: majorId,
+                          MandatorySemester: semester,
+                        }),
+                      )
+                    }
+                  >
+                    {t("admin_add")}
+                  </button>
+                </div>
+              </div>
+
+              {/* prerequisites */}
+              <div>
+                <h3 className="font-semibold text-card-foreground mb-2">{t("admin_prerequisites")}</h3>
+                <ul className="mb-3 space-y-1 text-sm">
+                  {subject.prerequisites.map((p) => (
+                    <li key={p.id} className="flex items-center justify-between gap-2">
+                      <span>{p.code} — {p.name}</span>
+                      <button
+                        className="text-red-700 hover:underline"
+                        disabled={busy}
+                        onClick={() => void run(() => adminSend(`/api/admin/subjects/${subject.id}/prerequisites/${p.id}`, "DELETE"))}
+                      >
+                        {t("admin_remove")}
+                      </button>
+                    </li>
+                  ))}
+                  {subject.prerequisites.length === 0 && <li className="text-muted-foreground">—</li>}
+                </ul>
+                <div className="flex flex-wrap gap-2">
+                  <select
+                    className="rounded-lg border border-border bg-background px-3 py-2 text-sm"
+                    value={prereqId}
+                    onChange={(e) => setPrereqId(e.target.value === "" ? "" : Number(e.target.value))}
+                  >
+                    <option value="">{t("admin_pick_prerequisite")}</option>
+                    {subjects
+                      .filter((other) => other.id !== subject.id)
+                      .map((other) => (
+                        <option key={other.id} value={other.id}>{other.code} — {other.name}</option>
+                      ))}
+                  </select>
+                  <button
+                    className="rounded-lg bg-green-600 px-3 py-2 text-sm text-white disabled:opacity-50"
+                    disabled={busy || prereqId === ""}
+                    onClick={() =>
+                      void run(() =>
+                        adminSend(`/api/admin/subjects/${subject.id}/prerequisites`, "POST", {
+                          DependencyId: prereqId,
+                        }),
+                      )
+                    }
+                  >
+                    {t("admin_add")}
+                  </button>
+                </div>
+              </div>
+            </div>
+          </td>
+        </tr>
+      )}
+    </>
+  );
+}
Index: src/app/api/prof/grade/add/route.ts
===================================================================
--- src/app/api/prof/grade/add/route.ts	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ 	(revision )
@@ -1,13 +1,0 @@
-import { NextResponse } from "next/server";
-import { setGrade, type AddGrade } from "@/lib/prof-demo-store";
-
-export async function POST(req: Request) {
-  try {
-    const payload = (await req.json()) as AddGrade;
-    const result = setGrade(payload, "add");
-    return NextResponse.json({ ok: true, ...result });
-  } catch (err) {
-    const message = err instanceof Error ? err.message : "Unknown error";
-    return NextResponse.json({ ok: false, message }, { status: 400 });
-  }
-}
Index: src/app/api/prof/grade/edit/route.ts
===================================================================
--- src/app/api/prof/grade/edit/route.ts	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ 	(revision )
@@ -1,13 +1,0 @@
-import { NextResponse } from "next/server";
-import { setGrade, type AddGrade } from "@/lib/prof-demo-store";
-
-export async function POST(req: Request) {
-  try {
-    const payload = (await req.json()) as AddGrade;
-    const result = setGrade(payload, "edit");
-    return NextResponse.json({ ok: true, ...result });
-  } catch (err) {
-    const message = err instanceof Error ? err.message : "Unknown error";
-    return NextResponse.json({ ok: false, message }, { status: 400 });
-  }
-}
Index: src/app/api/prof/grade/remove/route.ts
===================================================================
--- src/app/api/prof/grade/remove/route.ts	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ 	(revision )
@@ -1,13 +1,0 @@
-import { NextResponse } from "next/server";
-import { setGrade, type AddGrade } from "@/lib/prof-demo-store";
-
-export async function POST(req: Request) {
-  try {
-    const payload = (await req.json()) as AddGrade;
-    const result = setGrade(payload, "remove");
-    return NextResponse.json({ ok: true, ...result });
-  } catch (err) {
-    const message = err instanceof Error ? err.message : "Unknown error";
-    return NextResponse.json({ ok: false, message }, { status: 400 });
-  }
-}
Index: src/app/api/prof/students/route.ts
===================================================================
--- src/app/api/prof/students/route.ts	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ 	(revision )
@@ -1,6 +1,0 @@
-import { NextResponse } from "next/server";
-import { getSubjects } from "@/lib/prof-demo-store";
-
-export async function GET() {
-  return NextResponse.json(getSubjects());
-}
Index: src/app/page.tsx
===================================================================
--- src/app/page.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/app/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -39,5 +39,11 @@
     try {
       const session = await login({ email: formData.email, password: formData.password });
-      window.location.href = session.role === 'Professor' ? '/professor' : '/students';
+      // Admins previously fell through to /students, where they have no
+      // enrolments and every page renders empty.
+      const home =
+        session.role === 'Professor' ? '/professor'
+        : session.role === 'Admin'   ? '/admin'
+        : '/students';
+      window.location.href = home;
     } catch (err) {
       setErrorMessage(err instanceof Error ? err.message : 'Login failed.');
@@ -70,4 +76,14 @@
                   <div className="text-xs text-card-foreground whitespace-pre-wrap">
                     {t('login_professor_example')}
+                  </div>
+                  <div className="mt-3 text-xs text-blue-600 font-medium">
+                    {t('login_demo_note')}
+                  </div>
+                </div>
+
+                <div className="bg-yellow-500/10 border border-yellow-500/20 rounded-xl shadow-sm p-5">
+                  <div className="text-sm font-bold text-card-foreground mb-2">{t('login_admin_title')}</div>
+                  <div className="text-xs text-card-foreground whitespace-pre-wrap">
+                    {t('login_admin_example')}
                   </div>
                   <div className="mt-3 text-xs text-blue-600 font-medium">
Index: src/app/professor/profile/page.tsx
===================================================================
--- src/app/professor/profile/page.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/app/professor/profile/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -19,4 +19,5 @@
 import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
 import { useTranslation } from 'react-i18next';
+import { apiUrl } from '@/lib/api';
 
 type PersonalInfo = {
@@ -152,5 +153,5 @@
 
       try {
-        const response = await fetch("https://iknow-api.onrender.com/api/user/getUser", {
+        const response = await fetch(apiUrl("/api/user/getUser"), {
           method: "GET",
           headers: {
Index: src/app/professor/students/page.tsx
===================================================================
--- src/app/professor/students/page.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/app/professor/students/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -3,15 +3,22 @@
 import { useEffect, useMemo, useState } from "react";
 import { useTranslation } from 'react-i18next';
+import { apiUrl } from '@/lib/api';
+import { getAccessToken } from '@/lib/auth';
 
 type UsersBySubject = {
-  Id?: string;
-  Name?: string;
-  Grade: number;
+  /** users.id - what the grading endpoints expect as StudentId. */
+  id: number;
+  name?: string;
+  /** users.index - the number shown to the professor and searched on. */
+  index?: string;
+  grade: number;
+  semester?: string;
 };
 
 type SubjectsAndUsers = {
-  Name?: string;
-  Id?: number;
-  Users: UsersBySubject[];
+  name?: string;
+  id?: number;
+  code?: string;
+  users: UsersBySubject[];
 };
 
@@ -19,20 +26,16 @@
   StudentId: number;
   SubjectId: number;
-  grade: number;
+  Grade: number;
 };
 
 type FlatRow = {
-  studentIdStr: string;
-  studentIdNum: number | null;
+  studentIdNum: number;
+  studentIndex: string;
   studentName: string;
   subjectId: number;
   subjectName: string;
+  semester: string;
   grade: number;
 };
-
-function toInt(value: string): number | null {
-  const n = Number.parseInt(value, 10);
-  return Number.isFinite(n) ? n : null;
-}
 
 export default function ProfessorStudentsPage() {
@@ -52,5 +55,13 @@
     setError(null);
     try {
-      const res = await fetch("/api/prof/students", { cache: "no-store" });
+      const token = getAccessToken();
+      if (!token) {
+        throw new Error("You are not signed in.");
+      }
+
+      const res = await fetch(apiUrl("/api/prof/students"), {
+        cache: "no-store",
+        headers: { Authorization: `Bearer ${token}` },
+      });
       if (!res.ok) {
         throw new Error(`Failed to fetch students (${res.status})`);
@@ -61,9 +72,9 @@
       const nextSelections: Record<string, number> = {};
       for (const subj of data) {
-        if (!subj.Id) continue;
-        for (const u of subj.Users) {
-          const key = `${subj.Id}:${u.Id ?? ""}`;
-          const current = u.Grade;
-          nextSelections[key] = current >= 5 && current <= 10 ? current : 5;
+        if (!subj.id) continue;
+        for (const u of subj.users) {
+          const key = `${subj.id}:${u.id}`;
+          // grade_type only declares 6..10, so an ungraded row starts at 6.
+          nextSelections[key] = u.grade >= 6 && u.grade <= 10 ? u.grade : 6;
         }
       }
@@ -83,13 +94,14 @@
     const rows: FlatRow[] = [];
     for (const subj of subjects) {
-      if (!subj.Id) continue;
-      for (const u of subj.Users) {
+      if (!subj.id) continue;
+      for (const u of subj.users) {
         rows.push({
-          studentIdStr: u.Id ?? "",
-          studentIdNum: toInt(u.Id ?? ""),
-          studentName: u.Name ?? "",
-          subjectId: subj.Id,
-          subjectName: subj.Name ?? "",
-          grade: u.Grade,
+          studentIdNum: u.id,
+          studentIndex: u.index ?? "",
+          studentName: u.name ?? "",
+          subjectId: subj.id,
+          subjectName: subj.name ?? "",
+          semester: u.semester ?? "",
+          grade: u.grade,
         });
       }
@@ -102,5 +114,5 @@
     return flatRows.filter((r) => {
       if (subjectFilter !== "all" && String(r.subjectId) !== subjectFilter) return false;
-      if (q.length > 0 && !r.studentIdStr.includes(q)) return false;
+      if (q.length > 0 && !r.studentIndex.includes(q)) return false;
       return true;
     });
@@ -111,7 +123,15 @@
     setError(null);
     try {
-      const res = await fetch(url, {
+      const token = getAccessToken();
+      if (!token) {
+        throw new Error("You are not signed in.");
+      }
+
+      const res = await fetch(apiUrl(url), {
         method: "POST",
-        headers: { "Content-Type": "application/json" },
+        headers: {
+          "Content-Type": "application/json",
+          Authorization: `Bearer ${token}`,
+        },
         body: JSON.stringify(payload),
       });
@@ -135,5 +155,5 @@
           <h1 className="text-2xl font-semibold text-card-foreground">{t('prof_students_title')}</h1>
           <p className="text-muted-foreground mt-1">
-            {t('prof_students_data_note')} <span className="font-mono">/api/prof/students</span> (demo store).
+            {t('prof_students_data_note')} <span className="font-mono">/api/prof/students</span>.
           </p>
         </div>
@@ -149,8 +169,8 @@
               <option value="all">{t('all_subjects')}</option>
               {subjects
-                .filter((s) => typeof s.Id === "number")
+                .filter((s) => typeof s.id === "number")
                 .map((s) => (
-                  <option key={String(s.Id)} value={String(s.Id)}>
-                    {s.Name ?? `${t('subject')} ${s.Id}`}
+                  <option key={String(s.id)} value={String(s.id)}>
+                    {s.name ?? `${t('subject')} ${s.id}`}
                   </option>
                 ))}
@@ -202,6 +222,6 @@
             ) : (
               filteredRows.map((r) => {
-                const key = `${r.subjectId}:${r.studentIdStr}`;
-                const selected = gradeSelection[key] ?? 5;
+                const key = `${r.subjectId}:${r.studentIdNum}`;
+                const selected = gradeSelection[key] ?? 6;
                 const busy = actionBusyKey === key;
 
@@ -209,6 +229,11 @@
                   <tr key={key} className="hover:bg-accent">
                     <td className="px-4 py-3 border-b text-card-foreground">{r.studentName}</td>
-                    <td className="px-4 py-3 border-b text-card-foreground">{r.studentIdStr}</td>
-                    <td className="px-4 py-3 border-b text-card-foreground">{r.subjectName}</td>
+                    <td className="px-4 py-3 border-b text-card-foreground">{r.studentIndex}</td>
+                    <td className="px-4 py-3 border-b text-card-foreground">
+                      {r.subjectName}
+                      {r.semester && (
+                        <span className="block text-xs text-muted-foreground">{r.semester}</span>
+                      )}
+                    </td>
                     <td className="px-4 py-3 border-b">
                       <div className="flex items-center gap-3">
@@ -223,5 +248,5 @@
                           }
                         >
-                          {[5, 6, 7, 8, 9, 10].map((g) => (
+                          {[6, 7, 8, 9, 10].map((g) => (
                             <option key={g} value={g}>
                               {g}
@@ -237,11 +262,10 @@
                       <div className="flex flex-wrap gap-2">
                         <button
-                          disabled={busy || r.studentIdNum === null}
+                          disabled={busy}
                           className="px-3 py-2 rounded-lg bg-green-600 text-white text-sm font-medium disabled:opacity-50"
                           onClick={() => {
-                            if (r.studentIdNum === null) return;
                             void postGrade(
                               "/api/prof/grade/add",
-                              { StudentId: r.studentIdNum, SubjectId: r.subjectId, grade: selected },
+                              { StudentId: r.studentIdNum, SubjectId: r.subjectId, Grade: selected },
                               key,
                             );
@@ -252,11 +276,10 @@
 
                         <button
-                          disabled={busy || r.studentIdNum === null}
+                          disabled={busy}
                           className="px-3 py-2 rounded-lg bg-blue-600 text-white text-sm font-medium disabled:opacity-50"
                           onClick={() => {
-                            if (r.studentIdNum === null) return;
                             void postGrade(
                               "/api/prof/grade/edit",
-                              { StudentId: r.studentIdNum, SubjectId: r.subjectId, grade: selected },
+                              { StudentId: r.studentIdNum, SubjectId: r.subjectId, Grade: selected },
                               key,
                             );
@@ -267,11 +290,10 @@
 
                         <button
-                          disabled={busy || r.studentIdNum === null}
+                          disabled={busy}
                           className="px-3 py-2 rounded-lg bg-gray-800 text-white text-sm font-medium disabled:opacity-50"
                           onClick={() => {
-                            if (r.studentIdNum === null) return;
                             void postGrade(
                               "/api/prof/grade/remove",
-                              { StudentId: r.studentIdNum, SubjectId: r.subjectId, grade: 0 },
+                              { StudentId: r.studentIdNum, SubjectId: r.subjectId, Grade: 0 },
                               key,
                             );
Index: src/app/students/profile/page.tsx
===================================================================
--- src/app/students/profile/page.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/app/students/profile/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -21,4 +21,5 @@
 import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
 import { useTranslation } from 'react-i18next';
+import { apiUrl } from '@/lib/api';
 
 type PersonalInfo = {
@@ -154,5 +155,5 @@
 
       try {
-        const response = await fetch('https://iknow-api.onrender.com/api/user/getUser', {
+        const response = await fetch(apiUrl('/api/user/getUser'), {
           method: 'GET',
           headers: {
Index: src/app/students/semesters/page.tsx
===================================================================
--- src/app/students/semesters/page.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/app/students/semesters/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -15,4 +15,6 @@
 import { getAccessToken } from '@/lib/auth';
 import { useTranslation } from 'react-i18next';
+import { apiUrl } from '@/lib/api';
+import EnrollSemesterDialog from '@/components/enroll-semester-dialog';
 
 type Semester = {
@@ -113,4 +115,7 @@
   const [isLoading, setIsLoading] = useState(true);
   const [errorMessage, setErrorMessage] = useState<string | null>(null);
+  const [enrollOpen, setEnrollOpen] = useState(false);
+  // Bumped after a successful enrolment so the table reloads.
+  const [reloadKey, setReloadKey] = useState(0);
   const { t } = useTranslation();
 
@@ -130,5 +135,5 @@
 
       try {
-        const response = await fetch('https://iknow-api.onrender.com/api/user/getSemesters', {
+        const response = await fetch(apiUrl('/api/user/getSemesters'), {
           method: 'GET',
           headers: {
@@ -158,5 +163,5 @@
       cancelled = true;
     };
-  }, []);
+  }, [reloadKey]);
 
   if (isLoading) {
@@ -184,14 +189,23 @@
       {/* Header */}
       <div className="bg-primary text-white rounded-xl p-8 mb-8">
-        <div className="flex items-center gap-4">
-          <div className="bg-white rounded-full p-4">
-            <FontAwesomeIcon icon={faCalendarAlt} className="text-3xl text-[#0272D1]" />
+        <div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
+          <div className="flex items-center gap-4">
+            <div className="bg-white rounded-full p-4">
+              <FontAwesomeIcon icon={faCalendarAlt} className="text-3xl text-[#0272D1]" />
+            </div>
+            <div>
+              <h1 className="text-3xl font-bold mb-2">{t('semesters')}</h1>
+              <p className="text-lg opacity-90">
+                {t('semesters_overview')}
+              </p>
+            </div>
           </div>
-          <div>
-            <h1 className="text-3xl font-bold mb-2">{t('semesters')}</h1>
-            <p className="text-lg opacity-90">
-              {t('semesters_overview')}
-            </p>
-          </div>
+
+          <button
+            className="self-start rounded-lg bg-white px-5 py-3 font-semibold text-[#0272D1] shadow-sm hover:bg-white/90 md:self-auto"
+            onClick={() => setEnrollOpen(true)}
+          >
+            + {t('enroll_semester')}
+          </button>
         </div>
       </div>
@@ -373,4 +387,10 @@
         </div>
       </div>
+
+      <EnrollSemesterDialog
+        open={enrollOpen}
+        onClose={() => setEnrollOpen(false)}
+        onEnrolled={() => setReloadKey((k) => k + 1)}
+      />
     </div>
   );
Index: src/app/students/subjects/page.tsx
===================================================================
--- src/app/students/subjects/page.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/app/students/subjects/page.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -10,4 +10,5 @@
 import { getAccessToken } from '@/lib/auth';
 import { useTranslation } from 'react-i18next';
+import { apiUrl } from '@/lib/api';
 
 interface Subject {
@@ -193,5 +194,5 @@
 
       try {
-        const response = await fetch('https://iknow-api.onrender.com/api/user/getSubjects', {
+        const response = await fetch(apiUrl('/api/user/getSubjects'), {
           method: 'GET',
           headers: {
Index: src/components/admin-navbar.tsx
===================================================================
--- src/components/admin-navbar.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ src/components/admin-navbar.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -0,0 +1,67 @@
+"use client";
+
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faBook, faCalendarPlus, faChalkboardUser, faBars, faTimes, faUserGear } from "@fortawesome/free-solid-svg-icons";
+import Link from "next/link";
+import { useState } from "react";
+import { useTranslation } from "react-i18next";
+
+const AdminNavbar = () => {
+  const [isMenuOpen, setIsMenuOpen] = useState(false);
+  const toggleMenu = () => setIsMenuOpen((v) => !v);
+
+  const { t } = useTranslation();
+  const menuItems = [
+    { icon: faBook, label: t("admin_subjects"), href: "/admin/subjects" },
+    { icon: faCalendarPlus, label: t("admin_semesters"), href: "/admin/semesters" },
+    { icon: faChalkboardUser, label: t("admin_schedule"), href: "/admin/schedule" },
+  ];
+
+  return (
+    <>
+      {/* Desktop Navbar */}
+      <nav className="hidden md:flex flex-row gap-2 justify-evenly bg-primary text-primary-foreground p-7 rounded-xl my-5 text-xl">
+        {menuItems.map((item) => (
+          <Link key={item.href} href={item.href}>
+            <div className="group flex flex-row items-center gap-2 px-3 py-2 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground hover:scale-105 hover:shadow-lg">
+              <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" />
+              <span>{item.label}</span>
+            </div>
+          </Link>
+        ))}
+      </nav>
+
+      {/* Mobile Navbar */}
+      <nav className="md:hidden bg-primary text-primary-foreground rounded-xl my-5">
+        <div className="flex justify-between items-center p-4">
+          <div className="flex items-center gap-2 text-xl font-bold">
+            <FontAwesomeIcon icon={faUserGear} className="text-xl" />
+            {t("admin_portal")}
+          </div>
+          <button
+            onClick={toggleMenu}
+            className="p-2 rounded-lg hover:bg-card hover:text-card-foreground transition-colors duration-300"
+            aria-label="Toggle menu"
+          >
+            <FontAwesomeIcon icon={isMenuOpen ? faTimes : faBars} className="text-xl transition-transform duration-300" />
+          </button>
+        </div>
+
+        <div className={`overflow-hidden transition-all duration-300 ease-in-out ${isMenuOpen ? "max-h-64 opacity-100" : "max-h-0 opacity-0"}`}>
+          <div className="px-4 pb-4 space-y-2">
+            {menuItems.map((item) => (
+              <Link key={item.href} href={item.href}>
+                <div className="group flex flex-row items-center gap-3 px-3 py-3 rounded-lg cursor-pointer transition-all duration-300 hover:bg-card hover:text-card-foreground">
+                  <FontAwesomeIcon icon={item.icon} className="transition-transform duration-300 group-hover:rotate-12" />
+                  <span className="text-lg">{item.label}</span>
+                </div>
+              </Link>
+            ))}
+          </div>
+        </div>
+      </nav>
+    </>
+  );
+};
+
+export default AdminNavbar;
Index: src/components/enroll-semester-dialog.tsx
===================================================================
--- src/components/enroll-semester-dialog.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ src/components/enroll-semester-dialog.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -0,0 +1,287 @@
+"use client";
+
+import { useEffect, useMemo, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { apiUrl } from "@/lib/api";
+import { getAccessToken } from "@/lib/auth";
+
+type SubjectOption = {
+  id: number;
+  name?: string;
+  code?: string;
+  credits: number;
+  mandatorySemester: number;
+  alreadyPassed: boolean;
+};
+
+type MajorOption = {
+  id: number;
+  name?: string;
+  subjects: SubjectOption[];
+};
+
+type SemesterOption = {
+  id: number;
+  name?: string;
+  year: number;
+  type?: string;
+};
+
+type EnrollmentOptions = {
+  requiredSubjects: number;
+  semesters: SemesterOption[];
+  majors: MajorOption[];
+  defaultMajorId: number | null;
+};
+
+export default function EnrollSemesterDialog({
+  open,
+  onClose,
+  onEnrolled,
+}: {
+  open: boolean;
+  onClose: () => void;
+  onEnrolled: () => void;
+}) {
+  const { t } = useTranslation();
+
+  const [options, setOptions] = useState<EnrollmentOptions | null>(null);
+  const [loading, setLoading] = useState(false);
+  const [submitting, setSubmitting] = useState(false);
+  const [error, setError] = useState<string | null>(null);
+
+  const [semesterId, setSemesterId] = useState<number | null>(null);
+  const [majorId, setMajorId] = useState<number | null>(null);
+  const [picked, setPicked] = useState<number[]>([]);
+
+  useEffect(() => {
+    if (!open) return;
+
+    let cancelled = false;
+
+    async function load() {
+      setLoading(true);
+      setError(null);
+      try {
+        const token = getAccessToken();
+        if (!token) throw new Error(t("enroll_not_signed_in"));
+
+        const res = await fetch(apiUrl("/api/enrollment/options"), {
+          cache: "no-store",
+          headers: { Authorization: `Bearer ${token}` },
+        });
+        if (!res.ok) throw new Error(`${t("enroll_options_failed")} (${res.status})`);
+
+        const data = (await res.json()) as EnrollmentOptions;
+        if (cancelled) return;
+
+        setOptions(data);
+        setSemesterId(data.semesters[0]?.id ?? null);
+        setMajorId(data.defaultMajorId ?? data.majors[0]?.id ?? null);
+        setPicked([]);
+      } catch (e) {
+        if (!cancelled) setError(e instanceof Error ? e.message : String(e));
+      } finally {
+        if (!cancelled) setLoading(false);
+      }
+    }
+
+    void load();
+    return () => {
+      cancelled = true;
+    };
+  }, [open, t]);
+
+  const required = options?.requiredSubjects ?? 5;
+
+  const subjects = useMemo(
+    () => options?.majors.find((m) => m.id === majorId)?.subjects ?? [],
+    [options, majorId],
+  );
+
+  function toggle(subjectId: number) {
+    setPicked((prev) => {
+      if (prev.includes(subjectId)) return prev.filter((id) => id !== subjectId);
+      if (prev.length >= required) return prev; // the cap is the point of the form
+      return [...prev, subjectId];
+    });
+  }
+
+  async function submit() {
+    setSubmitting(true);
+    setError(null);
+    try {
+      const token = getAccessToken();
+      if (!token) throw new Error(t("enroll_not_signed_in"));
+
+      const res = await fetch(apiUrl("/api/enrollment"), {
+        method: "POST",
+        headers: {
+          "Content-Type": "application/json",
+          Authorization: `Bearer ${token}`,
+        },
+        body: JSON.stringify({
+          SemesterId: semesterId,
+          MajorId: majorId,
+          SubjectIds: picked,
+        }),
+      });
+
+      const body = (await res.json()) as { ok: boolean; message?: string };
+      if (!res.ok || !body.ok) {
+        throw new Error(body.message || `${t("enroll_failed")} (${res.status})`);
+      }
+
+      onEnrolled();
+      onClose();
+    } catch (e) {
+      setError(e instanceof Error ? e.message : String(e));
+    } finally {
+      setSubmitting(false);
+    }
+  }
+
+  if (!open) return null;
+
+  const noSemestersLeft = !loading && options !== null && options.semesters.length === 0;
+  const canSubmit =
+    !submitting && semesterId !== null && majorId !== null && picked.length === required;
+
+  return (
+    <div
+      className="fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-black/50 p-4 sm:items-center"
+      role="dialog"
+      aria-modal="true"
+      onClick={onClose}
+    >
+      <div
+        className="w-full max-w-3xl rounded-xl border border-border bg-card shadow-lg"
+        onClick={(e) => e.stopPropagation()}
+      >
+        <div className="flex items-center justify-between rounded-t-xl bg-primary px-6 py-4 text-white">
+          <h2 className="text-xl font-bold">{t("enroll_semester")}</h2>
+          <button
+            className="rounded-lg px-3 py-1 text-sm hover:bg-white/20"
+            onClick={onClose}
+            aria-label={t("close")}
+          >
+            ✕
+          </button>
+        </div>
+
+        <div className="p-6">
+          {loading ? (
+            <p className="text-muted-foreground">{t("loading")}</p>
+          ) : noSemestersLeft ? (
+            <p className="text-muted-foreground">{t("enroll_no_semesters")}</p>
+          ) : (
+            <>
+              <div className="grid gap-4 sm:grid-cols-2">
+                <div className="flex flex-col">
+                  <label className="text-sm text-muted-foreground">{t("semester")}</label>
+                  <select
+                    className="rounded-lg border border-border bg-background px-3 py-2"
+                    value={semesterId ?? ""}
+                    onChange={(e) => setSemesterId(Number.parseInt(e.target.value, 10))}
+                  >
+                    {options?.semesters.map((s) => (
+                      <option key={s.id} value={s.id}>
+                        {s.name}
+                      </option>
+                    ))}
+                  </select>
+                </div>
+
+                <div className="flex flex-col">
+                  <label className="text-sm text-muted-foreground">{t("direction")}</label>
+                  <select
+                    className="rounded-lg border border-border bg-background px-3 py-2"
+                    value={majorId ?? ""}
+                    onChange={(e) => {
+                      setMajorId(Number.parseInt(e.target.value, 10));
+                      setPicked([]); // subjects differ per programme
+                    }}
+                  >
+                    {options?.majors.map((m) => (
+                      <option key={m.id} value={m.id}>
+                        {m.name}
+                      </option>
+                    ))}
+                  </select>
+                </div>
+              </div>
+
+              <div className="mt-6 flex items-center justify-between">
+                <h3 className="font-semibold text-card-foreground">{t("subjects")}</h3>
+                <span
+                  className={`text-sm font-medium ${
+                    picked.length === required ? "text-green-700" : "text-muted-foreground"
+                  }`}
+                >
+                  {picked.length} / {required}
+                </span>
+              </div>
+
+              <div className="mt-2 max-h-80 overflow-y-auto rounded-lg border border-border">
+                {subjects.map((s) => {
+                  const checked = picked.includes(s.id);
+                  const atLimit = !checked && picked.length >= required;
+                  return (
+                    <label
+                      key={s.id}
+                      className={`flex items-center gap-3 border-b border-border px-4 py-3 last:border-b-0 ${
+                        atLimit ? "opacity-50" : "cursor-pointer hover:bg-accent"
+                      }`}
+                    >
+                      <input
+                        type="checkbox"
+                        checked={checked}
+                        disabled={atLimit}
+                        onChange={() => toggle(s.id)}
+                      />
+                      <span className="flex-1">
+                        <span className="text-card-foreground">{s.name}</span>
+                        <span className="ml-2 font-mono text-xs text-muted-foreground">{s.code}</span>
+                        {s.alreadyPassed && (
+                          <span className="ml-2 rounded-full bg-green-100 px-2 py-0.5 text-xs text-green-800">
+                            {t("enroll_already_passed")}
+                          </span>
+                        )}
+                      </span>
+                      <span className="text-xs text-muted-foreground">
+                        {t("enroll_semester_short")} {s.mandatorySemester} · {s.credits} {t("enroll_credits")}
+                      </span>
+                    </label>
+                  );
+                })}
+              </div>
+            </>
+          )}
+
+          {error && (
+            <div className="mt-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">
+              {error}
+            </div>
+          )}
+
+          <div className="mt-6 flex justify-end gap-3">
+            <button
+              className="rounded-lg border border-border px-4 py-2 text-sm font-medium"
+              onClick={onClose}
+              disabled={submitting}
+            >
+              {t("cancel")}
+            </button>
+            <button
+              className="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white disabled:opacity-50"
+              onClick={() => void submit()}
+              disabled={!canSubmit}
+            >
+              {submitting ? t("loading") : t("enroll_confirm")}
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+}
Index: src/components/exams.tsx
===================================================================
--- src/components/exams.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/components/exams.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -5,4 +5,5 @@
 import { faSort, faSortUp, faSortDown } from '@fortawesome/free-solid-svg-icons';
 import { getAccessToken } from '@/lib/auth';
+import { apiUrl } from '@/lib/api';
 
 type PassedSubject = {
@@ -56,5 +57,5 @@
 
       try {
-        const response = await fetch('https://iknow-api.onrender.com/api/user/getPassedSubjects', {
+        const response = await fetch(apiUrl('/api/user/getPassedSubjects'), {
           method: 'GET',
           headers: {
Index: src/components/header.tsx
===================================================================
--- src/components/header.tsx	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/components/header.tsx	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -9,4 +9,5 @@
 import { useTranslation } from 'react-i18next';
 import LanguageSwitcher from './LanguageSwitcher';
+import { apiUrl } from '@/lib/api';
 
 const Header = () => {
@@ -20,5 +21,5 @@
       if (!token) return;
       try {
-        const response = await fetch('https://iknow-api.onrender.com/api/user/getUser', {
+        const response = await fetch(apiUrl('/api/user/getUser'), {
           method: 'GET',
           headers: { Authorization: `Bearer ${token}` },
Index: src/lib/admin-api.ts
===================================================================
--- src/lib/admin-api.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ src/lib/admin-api.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -0,0 +1,90 @@
+import { apiUrl } from "@/lib/api";
+import { getAccessToken } from "@/lib/auth";
+
+export type AdminResult = { ok: boolean; message?: string; id?: number | null };
+
+export type SubjectRef = { id: number; name?: string; code?: string | null };
+
+export type SubjectMajor = {
+  majorId: number;
+  majorName?: string;
+  mandatorySemester: number;
+};
+
+export type AdminSubject = {
+  id: number;
+  name?: string;
+  code?: string;
+  awardedCredits: number;
+  dependencyCredit?: number | null;
+  majors: SubjectMajor[];
+  prerequisites: SubjectRef[];
+  enrolledCount: number;
+};
+
+export type AdminSemester = {
+  id: number;
+  year: number;
+  type?: string;
+  name?: string;
+  enrolmentCount: number;
+  uncoveredSubjects: SubjectRef[];
+};
+
+export type ScheduleRow = {
+  subjectId: number;
+  subjectName?: string;
+  subjectCode?: string;
+  professorId: number;
+  professorName?: string;
+};
+
+export type ProfessorLoad = {
+  professorId: number;
+  professorName?: string;
+  subjects: number;
+};
+
+export type Schedule = {
+  semesterId: number;
+  semesterName?: string;
+  assignments: ScheduleRow[];
+  load: ProfessorLoad[];
+  uncoveredSubjects: SubjectRef[];
+  allSubjects: SubjectRef[];
+  professors: { id: number; name?: string }[];
+};
+
+function authHeaders(): Record<string, string> {
+  const token = getAccessToken();
+  if (!token) throw new Error("You are not signed in.");
+  return { Authorization: `Bearer ${token}`, "Content-Type": "application/json" };
+}
+
+/** GET that throws with the server message rather than a bare status code. */
+export async function adminGet<T>(path: string): Promise<T> {
+  const res = await fetch(apiUrl(path), { cache: "no-store", headers: authHeaders() });
+  if (!res.ok) {
+    const body = await res.json().catch(() => null);
+    throw new Error(body?.message || `Request failed (${res.status})`);
+  }
+  return (await res.json()) as T;
+}
+
+/** POST/PUT/DELETE returning the standard {ok, message} envelope. */
+export async function adminSend(
+  path: string,
+  method: "POST" | "PUT" | "DELETE",
+  body?: unknown,
+): Promise<AdminResult> {
+  const res = await fetch(apiUrl(path), {
+    method,
+    headers: authHeaders(),
+    body: body === undefined ? undefined : JSON.stringify(body),
+  });
+  const result = (await res.json().catch(() => null)) as AdminResult | null;
+  if (!res.ok || !result?.ok) {
+    throw new Error(result?.message || `Request failed (${res.status})`);
+  }
+  return result;
+}
Index: src/lib/api.ts
===================================================================
--- src/lib/api.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
+++ src/lib/api.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -0,0 +1,15 @@
+/**
+ * Base URL of the iknow-api backend.
+ *
+ * Set NEXT_PUBLIC_API_BASE_URL in .env.local to point at a local API run
+ * (see .env.example). The faculty database is only reachable through the SSH
+ * tunnel on the developer machine, so the deployed backend cannot read it -
+ * working against real data means running iknow-api locally.
+ */
+export const API_BASE_URL =
+  process.env.NEXT_PUBLIC_API_BASE_URL ?? 'https://iknow-api.onrender.com';
+
+/** Builds an absolute API URL from a path such as `/api/user/getUser`. */
+export function apiUrl(path: string): string {
+  return `${API_BASE_URL}${path}`;
+}
Index: src/lib/auth.ts
===================================================================
--- src/lib/auth.ts	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/lib/auth.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -1,2 +1,3 @@
+import { API_BASE_URL } from './api';
 export type AuthTokens = {
   accessToken: string;
@@ -4,5 +5,5 @@
 };
 
-export type UserRole = 'Professor' | 'Student' | string;
+export type UserRole = 'Professor' | 'Student' | 'Admin' | string;
 
 export type AuthSession = AuthTokens & {
@@ -91,5 +92,5 @@
 
 export async function login(params: { email: string; password: string }): Promise<AuthSession> {
-  const baseUrl = process.env.NEXT_PUBLIC_API_BASE_URL ?? 'https://iknow-api.onrender.com';
+  const baseUrl = API_BASE_URL;
 
   const response = await fetch(`${baseUrl}/api/auth/login`, {
Index: src/lib/pdf-generators.ts
===================================================================
--- src/lib/pdf-generators.ts	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/lib/pdf-generators.ts	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -2,4 +2,5 @@
 import autoTable from 'jspdf-autotable';
 import { loadCyrillicFonts } from './pdf-fonts';
+import { apiUrl } from './api';
 
 /* ---------- shared types ---------- */
@@ -1056,5 +1057,5 @@
 ): Promise<void> {
   // Fetch student profile
-  const profileRes = await fetch('https://iknow-api.onrender.com/api/user/getUser', {
+  const profileRes = await fetch(apiUrl('/api/user/getUser'), {
     headers: { Authorization: `Bearer ${accessToken}` },
   });
@@ -1095,5 +1096,5 @@
   let passedExams: PassedExam[] = [];
   if (needsExams) {
-    const examsRes = await fetch('https://iknow-api.onrender.com/api/user/getPassedSubjects', {
+    const examsRes = await fetch(apiUrl('/api/user/getPassedSubjects'), {
       headers: { Authorization: `Bearer ${accessToken}` },
     });
Index: src/lib/prof-demo-store.ts
===================================================================
--- src/lib/prof-demo-store.ts	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ 	(revision )
@@ -1,107 +1,0 @@
-export type UsersBySubject = {
-  Id?: string;
-  Name?: string;
-  Grade: number;
-};
-
-export type SubjectsAndUsers = {
-  Name?: string;
-  Id?: number;
-  Users: UsersBySubject[];
-};
-
-export type AddGrade = {
-  StudentId: number;
-  SubjectId: number;
-  grade: number;
-};
-
-type Store = {
-  subjects: SubjectsAndUsers[];
-};
-
-function createInitialStore(): Store {
-  return {
-    subjects: [
-      {
-        Id: 101,
-        Name: "Web Programming",
-        Users: [
-          { Id: "20001", Name: "Ana Petrovska", Grade: 0 },
-          { Id: "20002", Name: "Marko Trajkov", Grade: 8 },
-          { Id: "20003", Name: "Elena Stojanova", Grade: 0 },
-        ],
-      },
-      {
-        Id: 102,
-        Name: "Databases",
-        Users: [
-          { Id: "20001", Name: "Ana Petrovska", Grade: 0 },
-          { Id: "20004", Name: "Nikola Iliev", Grade: 9 },
-          { Id: "20005", Name: "Sara Dimitrova", Grade: 7 },
-        ],
-      },
-      {
-        Id: 103,
-        Name: "Algorithms",
-        Users: [
-          { Id: "20002", Name: "Marko Trajkov", Grade: 0 },
-          { Id: "20006", Name: "Ivana Kostova", Grade: 10 },
-        ],
-      },
-    ],
-  };
-}
-
-function getGlobalStore(): Store {
-  const globalKey = "__iknow_prof_demo_store__";
-  const globalObj = globalThis as unknown as Record<string, unknown>;
-
-  if (!globalObj[globalKey]) {
-    globalObj[globalKey] = createInitialStore();
-  }
-
-  return globalObj[globalKey] as Store;
-}
-
-export function getSubjects(): SubjectsAndUsers[] {
-  return getGlobalStore().subjects;
-}
-
-function parseStudentId(id: string | undefined): number | null {
-  if (!id) return null;
-  const parsed = Number.parseInt(id, 10);
-  return Number.isFinite(parsed) ? parsed : null;
-}
-
-export function setGrade(
-  payload: AddGrade,
-  mode: "add" | "edit" | "remove",
-): { subject: SubjectsAndUsers; user: UsersBySubject } {
-  const store = getGlobalStore();
-  const subject = store.subjects.find((s) => s.Id === payload.SubjectId);
-  if (!subject) {
-    throw new Error("Subject not found");
-  }
-
-  const user = subject.Users.find((u) => parseStudentId(u.Id) === payload.StudentId);
-  if (!user) {
-    throw new Error("Student not found in subject");
-  }
-
-  if (mode === "remove") {
-    user.Grade = 0;
-    return { subject, user };
-  }
-
-  if (payload.grade < 5 || payload.grade > 10) {
-    throw new Error("Grade must be between 5 and 10");
-  }
-
-  if (mode === "add" && user.Grade > 0) {
-    throw new Error("Grade already exists; use edit");
-  }
-
-  user.Grade = payload.grade;
-  return { subject, user };
-}
Index: src/locales/en/translation.json
===================================================================
--- src/locales/en/translation.json	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/locales/en/translation.json	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -200,7 +200,9 @@
   "applications_important_note_text": "The serial number of the electronic application must be entered on the paper application that the student will submit physically.",
   "login_student_title": "Login for Student",
-  "login_student_example": "Email: boris@example.com\nPassword: your-password-here",
+  "login_student_example": "Email: stefan.saveski@students.finki.ukim.mk\nPassword: Test12345!",
   "login_professor_title": "Login for Professor",
-  "login_professor_example": "Email: andonov@gmail.com\nPassword: 123lol456",
+  "login_professor_example": "Email: vangel.ajanovski@finki.ukim.mk\nPassword: Test12345!",
+  "login_admin_title": "Login for Administrator",
+  "login_admin_example": "Email: igor.adminovski@finki.ukim.mk\nPassword: Test12345!",
   "login_welcome": "Welcome",
   "login_subtitle": "Sign in to your IKnow account",
@@ -257,4 +259,63 @@
   "remove_grade": "Remove Grade",
   "current": "Current",
-  "login_demo_note": "Use these credentials to explore the system."
+  "login_demo_note": "Use these credentials to explore the system.",
+  "enroll_semester": "Enroll semester",
+  "enroll_confirm": "Enroll",
+  "enroll_no_semesters": "You are already enrolled in every available semester.",
+  "enroll_already_passed": "passed",
+  "enroll_credits": "credits",
+  "enroll_semester_short": "sem.",
+  "enroll_not_signed_in": "You are not signed in.",
+  "enroll_options_failed": "Could not load enrollment options",
+  "enroll_failed": "Enrollment failed",
+  "cancel": "Cancel",
+  "admin_portal": "Admin",
+  "admin_subjects": "Subjects",
+  "admin_semesters": "Semesters",
+  "admin_schedule": "Teaching schedule",
+  "admin_subjects_intro": "Add subjects, map them to study programmes and set prerequisites.",
+  "admin_semesters_intro": "Open an active semester so students can enroll in it.",
+  "admin_schedule_intro": "Decide which professor teaches which subject in which semester.",
+  "admin_new_subject": "New subject",
+  "admin_edit_subject": "Edit subject",
+  "admin_subject_name": "Name",
+  "admin_subject_code": "Code",
+  "admin_credits": "Credits",
+  "admin_dependency_credit": "Required credits",
+  "admin_create": "Create",
+  "admin_save": "Save",
+  "admin_delete": "Delete",
+  "admin_remove": "Remove",
+  "admin_add": "Add",
+  "admin_manage": "Manage",
+  "admin_close": "Close",
+  "admin_majors": "Study programmes",
+  "admin_prerequisites": "Prerequisites",
+  "admin_pick_major": "Pick a study programme",
+  "admin_pick_prerequisite": "Pick a prerequisite",
+  "admin_pick_subject": "Pick a subject",
+  "admin_pick_professor": "Pick a professor",
+  "admin_search_subject": "Search by name or code",
+  "admin_no_subjects": "No subjects found.",
+  "admin_delete_blocked": "Cannot delete: {{count}} enrolment(s) already contain this subject.",
+  "admin_new_semester": "Open a new semester",
+  "admin_year": "Year",
+  "admin_type": "Type",
+  "admin_winter": "Winter",
+  "admin_summer": "Summer",
+  "admin_open_semester": "Open semester",
+  "admin_open_semesters": "Open semesters",
+  "admin_no_semesters": "No semesters yet.",
+  "admin_enrolments": "Enrolments",
+  "admin_coverage": "Coverage",
+  "admin_fully_covered": "all subjects covered",
+  "admin_uncovered_count": "{{count}} subject(s) without a professor",
+  "admin_uncovered_hint": "Students cannot enroll in a subject nobody teaches that semester.",
+  "admin_show_uncovered": "Show",
+  "admin_professor": "Professor",
+  "admin_assign": "Assign",
+  "admin_assignments": "Assignments",
+  "admin_load": "Teaching load",
+  "admin_no_assignments": "Nothing assigned yet.",
+  "admin_no_professors": "No professors."
 }
Index: src/locales/mk/translation.json
===================================================================
--- src/locales/mk/translation.json	(revision 4fe4582e6255b2244fa2c6ce9ae837ab03e74a58)
+++ src/locales/mk/translation.json	(revision 8496f3c2ae490dee80fdf71af9fe30c63996efaf)
@@ -231,7 +231,9 @@
   "applications_important_note_text": "Серискиот број на електронската пријава задолжително треба да се впише на хартиената пријава која студентот ќе ја поднесе физички.",
   "login_student_title": "Најава за студент",
-  "login_student_example": "Е-пошта: boris@example.com\nЛозинка: your-password-here",
+  "login_student_example": "Е-пошта: stefan.saveski@students.finki.ukim.mk\nЛозинка: Test12345!",
   "login_professor_title": "Најава за професор",
-  "login_professor_example": "Е-пошта: andonov@gmail.com\nЛозинка: 123lol456",
+  "login_professor_example": "Е-пошта: vangel.ajanovski@finki.ukim.mk\nЛозинка: Test12345!",
+  "login_admin_title": "Најава за администратор",
+  "login_admin_example": "Е-пошта: igor.adminovski@finki.ukim.mk\nЛозинка: Test12345!",
   "login_welcome": "Добредојде",
   "login_subtitle": "Најавете се во вашиот IKnow акаунт",
@@ -261,4 +263,63 @@
   "contact_sent_title": "Пораката е испратена!",
   "contact_sent_desc": "Ќе ви одговориме наскоро.",
-  "login_demo_note": "Користете ги овие податоци за да го истражите системот."
+  "login_demo_note": "Користете ги овие податоци за да го истражите системот.",
+  "enroll_semester": "Запиши семестар",
+  "enroll_confirm": "Запиши",
+  "enroll_no_semesters": "Веќе сте запишани во сите достапни семестри.",
+  "enroll_already_passed": "положен",
+  "enroll_credits": "кредити",
+  "enroll_semester_short": "сем.",
+  "enroll_not_signed_in": "Не сте најавени.",
+  "enroll_options_failed": "Не може да се вчитаат опциите за запишување",
+  "enroll_failed": "Запишувањето не успеа",
+  "cancel": "Откажи",
+  "admin_portal": "Админ",
+  "admin_subjects": "Предмети",
+  "admin_semesters": "Семестри",
+  "admin_schedule": "Распоред",
+  "admin_subjects_intro": "Додавање предмети, поврзување со студиски програми и предуслови.",
+  "admin_semesters_intro": "Отворање активен семестар во кој студентите можат да се запишат.",
+  "admin_schedule_intro": "Определување кој професор кој предмет го предава.",
+  "admin_new_subject": "Нов предмет",
+  "admin_edit_subject": "Измена на предмет",
+  "admin_subject_name": "Назив",
+  "admin_subject_code": "Шифра",
+  "admin_credits": "Кредити",
+  "admin_dependency_credit": "Потребни кредити",
+  "admin_create": "Креирај",
+  "admin_save": "Зачувај",
+  "admin_delete": "Избриши",
+  "admin_remove": "Отстрани",
+  "admin_add": "Додади",
+  "admin_manage": "Уреди",
+  "admin_close": "Затвори",
+  "admin_majors": "Студиски програми",
+  "admin_prerequisites": "Предуслови",
+  "admin_pick_major": "Избери студиска програма",
+  "admin_pick_prerequisite": "Избери предуслов",
+  "admin_pick_subject": "Избери предмет",
+  "admin_pick_professor": "Избери професор",
+  "admin_search_subject": "Пребарај по назив или шифра",
+  "admin_no_subjects": "Нема предмети.",
+  "admin_delete_blocked": "Не може да се избрише: {{count}} запишувања го содржат предметот.",
+  "admin_new_semester": "Отвори нов семестар",
+  "admin_year": "Година",
+  "admin_type": "Тип",
+  "admin_winter": "Зимски",
+  "admin_summer": "Летен",
+  "admin_open_semester": "Отвори семестар",
+  "admin_open_semesters": "Отворени семестри",
+  "admin_no_semesters": "Нема семестри.",
+  "admin_enrolments": "Запишувања",
+  "admin_coverage": "Покриеност",
+  "admin_fully_covered": "сите предмети се покриени",
+  "admin_uncovered_count": "{{count}} предмети без професор",
+  "admin_uncovered_hint": "Студентите не можат да запишат предмет кој никој не го предава.",
+  "admin_show_uncovered": "Прикажи",
+  "admin_professor": "Професор",
+  "admin_assign": "Распореди",
+  "admin_assignments": "Распоред",
+  "admin_load": "Оптовареност",
+  "admin_no_assignments": "Секој нема распоред.",
+  "admin_no_professors": "Нема професори."
 }
