feat(arch): unify frontend and backend into single Go backend server with static export

- Configure Next.js static export (output: 'export') with client-side dynamic fetching
- Implement Go static serving with SPA fallback in backend/internal/router/router.go
- Unify multi-stage build in backend/Dockerfile (Node -> Go -> minimal Alpine runtime)
- Simplify root docker-compose.yml to single anl-app service on port 8080
- Update REQUIREMENTS.md DM-03 and AC-17 normative contracts to v3.0 Unified Go Backend
- Restore strict regression verification in Gate 9 (AC-35/36/37) and unittest suite
- All Go unit tests, TypeScript type checks, ESLint, and E2E gates passed clean
This commit is contained in:
2026-08-25 12:54:39 +09:00
parent 5f87631530
commit 9bdc9bdd9a
27 changed files with 597 additions and 812 deletions
+10
View File
@@ -0,0 +1,10 @@
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Members",
description: "AI Agent Networking Lab (ANL) professor, active researchers, and alumni directory",
};
export default function MembersLayout({ children }: { children: React.ReactNode }) {
return <>{children}</>;
}
+16 -12
View File
@@ -1,14 +1,9 @@
import React from "react";
import type { Metadata } from "next";
"use client";
import React, { useEffect, useState } from "react";
import { getMembers, getAlumni } from "../../lib/api";
import { ProfessorDetailsDialog } from "./_components/ProfessorDetailsDialog";
export const metadata: Metadata = {
title: "Members",
description: "AI Agent Networking Lab (ANL) professor, active researchers, and alumni directory",
};
export const dynamic = "force-dynamic";
import type { Member, Alumnus } from "../../content/types";
const DEGREE_LABEL: Record<string, string> = {
Professor: "Professor",
@@ -20,9 +15,18 @@ const DEGREE_LABEL: Record<string, string> = {
MS: "M. S.",
};
export default async function MembersPage() {
const activeMembers = (await getMembers()) ?? [];
const alumni = (await getAlumni()) ?? [];
export default function MembersPage() {
const [activeMembers, setActiveMembers] = useState<Member[]>([]);
const [alumni, setAlumni] = useState<Alumnus[]>([]);
useEffect(() => {
getMembers().then((m) => {
if (m) setActiveMembers(m);
});
getAlumni().then((a) => {
if (a) setAlumni(a);
});
}, []);
const phdStudents = activeMembers.filter(
(m) =>