feat(ai-character): 관리자 웹 기반 구성

This commit is contained in:
Yu Sung
2026-07-26 03:28:09 +09:00
parent 1dcbf43320
commit 42027b9f0d
26 changed files with 4368 additions and 36 deletions

10
src/app/App.test.tsx Normal file
View File

@@ -0,0 +1,10 @@
import { render, screen } from "@testing-library/react";
import { App } from "./App";
test("renders Korean root shell with a main landmark", () => {
render(<App />);
expect(document.documentElement).toHaveAttribute("lang", "ko");
expect(screen.getByRole("main")).toHaveTextContent("AI 캐릭터 관리자");
});

13
src/app/App.tsx Normal file
View File

@@ -0,0 +1,13 @@
import { useEffect } from "react";
export function App() {
useEffect(() => {
document.documentElement.lang = "ko";
}, []);
return (
<main>
<h1>AI </h1>
</main>
);
}

19
src/main.tsx Normal file
View File

@@ -0,0 +1,19 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { App } from "@/app/App";
import { getRuntimeEnv } from "@/shared/config/env";
getRuntimeEnv();
const root = document.getElementById("root");
if (!root) {
throw new Error("Root element #root was not found");
}
createRoot(root).render(
<StrictMode>
<App />
</StrictMode>,
);

View File

@@ -0,0 +1,27 @@
import { afterEach, describe, expect, test, vi } from "vitest";
import { getRuntimeEnv } from "./env";
describe("getRuntimeEnv", () => {
afterEach(() => {
vi.unstubAllEnvs();
});
test("returns the configured API base URL", () => {
vi.stubEnv("VITE_API_BASE_URL", "https://api.example.com");
expect(getRuntimeEnv()).toEqual({ apiBaseUrl: "https://api.example.com" });
});
test("blocks startup when VITE_API_BASE_URL is missing", () => {
vi.stubEnv("VITE_API_BASE_URL", "");
expect(() => getRuntimeEnv()).toThrow("VITE_API_BASE_URL is required");
});
test("blocks startup when VITE_API_BASE_URL is not an http URL", () => {
vi.stubEnv("VITE_API_BASE_URL", "not-a-url");
expect(() => getRuntimeEnv()).toThrow("VITE_API_BASE_URL must be a valid http(s) URL");
});
});

23
src/shared/config/env.ts Normal file
View File

@@ -0,0 +1,23 @@
export type RuntimeEnv = {
apiBaseUrl: string;
};
export function getRuntimeEnv(): RuntimeEnv {
const apiBaseUrl = import.meta.env.VITE_API_BASE_URL;
if (!apiBaseUrl) {
throw new Error("VITE_API_BASE_URL is required");
}
let url: URL;
try {
url = new URL(apiBaseUrl);
} catch {
throw new Error("VITE_API_BASE_URL must be a valid http(s) URL");
}
if (url.protocol !== "http:" && url.protocol !== "https:") {
throw new Error("VITE_API_BASE_URL must be a valid http(s) URL");
}
return { apiBaseUrl };
}

10
src/shared/test/setup.ts Normal file
View File

@@ -0,0 +1,10 @@
import "@testing-library/jest-dom/vitest";
import { cleanup } from "@testing-library/react";
import { afterEach, vi } from "vitest";
afterEach(() => {
cleanup();
vi.clearAllMocks();
sessionStorage.clear();
localStorage.clear();
});