diff --git a/client/package.json b/client/package.json
index 491bf0b..5611ba8 100644
--- a/client/package.json
+++ b/client/package.json
@@ -14,8 +14,8 @@
"@mui/icons-material": "^5.14.12",
"@mui/material": "^5.14.9",
"@mui/styles": "^5.15.13",
- "@pvi/core": "workspace:^",
- "@pvi/react": "workspace:^",
+ "@policy-maker/core": "workspace:^",
+ "@policy-maker/next": "workspace:^",
"@tanstack/react-query": "^5.4.3",
"@types/node": "20.6.0",
"@types/react": "18.2.21",
diff --git a/client/src/app/article/[articleId]/ArticleDetail.css b/client/src/app/article/[articleId]/ArticleDetail.css
new file mode 100644
index 0000000..8251129
--- /dev/null
+++ b/client/src/app/article/[articleId]/ArticleDetail.css
@@ -0,0 +1,13 @@
+.page {
+ background-color: black;
+}
+
+.header {
+ margin: 0 0 var(--primitives_spacing-4) 0;
+}
+
+.body {
+ color: white;
+ padding: 0 24%;
+ margin-bottom: var(--primitives_spacing-10);
+}
diff --git a/client/src/app/article/[articleId]/page.tsx b/client/src/app/article/[articleId]/page.tsx
new file mode 100644
index 0000000..3384509
--- /dev/null
+++ b/client/src/app/article/[articleId]/page.tsx
@@ -0,0 +1,109 @@
+"use client";
+
+import "./ArticleDetail.css";
+import Header from "@components/Header";
+
+import Footer from "@components/Footer";
+import { useEffect, useState } from "react";
+import { z } from "zod";
+import typography from "@styles/typography.module.css";
+
+type ArticleDetailProps = {
+ params: {
+ articleId: number;
+ };
+};
+
+export default function ArticleDetail(props: ArticleDetailProps) {
+ const id = props.params.articleId;
+ const [result, setResult] = useState("");
+
+ useEffect(() => {
+ fetch("http://localhost:8080/articles/" + id)
+ .then((res) => res.json())
+ .then(z.object({ content: z.string() }).parse)
+ .then(({ content }) => setResult(content));
+ }, []);
+
+ return (
+
+ );
+}
+
+// 서버 데이터로 대체 예정입니다.
+const samplePostData = {
+ id: 1,
+ title: "지원 사업 관련 질문 있습니다!",
+ content:
+ "나무들이 서로 속삭이는 듯한 소리가 숲속을 가득 채우고 있었다. 간간히 부는 바람이 나뭇잎을 흔들며, 그 소리는 마치 오래된 이야기를 들려주는 것 같았다. 이 숲의 한가운데서, 한 소년이 고개를 들어 하늘을 바라보았다. 햇빛이 나뭇가지 사이로 비치며, 그의 얼굴에 따스한 빛을 더했다. 소년은 숲이 주는 평화로움 속에서 잠시의 여유를 즐기며, 모험을 꿈꾸었다. 이 순간, 그는 어떠한 걱정도, 두려움도 잊고 오직 순수한 기쁨을 느끼며, 자연과 하나가 되었다.",
+ postType: "INFORMATION" as const,
+ likesCount: 20,
+ viewsCount: 100,
+ commentsCount: 5,
+ createdTime: new Date("2021-08-01"),
+ lastModifiedTime: new Date("2021-08-01"),
+ createdUser: {
+ id: 1,
+ name: "날아오르는 고라파덕",
+ thumbnailImage: null,
+ },
+ tags: [
+ {
+ id: 1,
+ name: "정보",
+ },
+ {
+ id: 2,
+ name: "월간Best",
+ },
+ ],
+};
+
+const sampleCommentData = [
+ {
+ id: 1,
+ content: "너무 좋은 글이네요! 감사합니다.",
+ likesCount: 20,
+ createdTime: new Date("2021-08-01"),
+ lastModifiedTime: new Date("2021-08-01"),
+ createdUser: {
+ id: 1,
+ name: "날아오르는 고라파덕",
+ thumbnailImage: null,
+ },
+ },
+ {
+ id: 2,
+ content: "너무 좋은 글이네요! 감사합니다.",
+ likesCount: 20,
+ createdTime: new Date("2021-08-01"),
+ lastModifiedTime: new Date("2021-08-01"),
+ createdUser: {
+ id: 1,
+ name: "날아오르는 고라파덕",
+ thumbnailImage: null,
+ },
+ },
+ {
+ id: 3,
+ content: "너무 좋은 글이네요! 감사합니다.",
+ likesCount: 20,
+ createdTime: new Date("2021-08-01"),
+ lastModifiedTime: new Date("2021-08-01"),
+ createdUser: {
+ id: 1,
+ name: "날아오르는 고라파덕",
+ thumbnailImage: null,
+ },
+ },
+];
diff --git a/client/src/app/article/write/ArticleWrite.css b/client/src/app/article/write/ArticleWrite.css
new file mode 100644
index 0000000..8c2ef0a
--- /dev/null
+++ b/client/src/app/article/write/ArticleWrite.css
@@ -0,0 +1,32 @@
+.page {
+ background-color: black;
+}
+
+.header {
+ margin: 0 0 var(--primitives_spacing-4) 0;
+}
+
+.body {
+ color: white;
+ padding: 0 24%;
+ margin-bottom: var(--primitives_spacing-10);
+}
+
+.body input {
+ border: none;
+ outline: none;
+ background-color: var(--surface-primary);
+ padding: 0;
+ height: 50px;
+ margin-right: var(--primitives_spacing-4);
+}
+
+.body button {
+ border: none;
+ outline: none;
+ cursor: pointer;
+ background-color: var(--surface-primary);
+ color: var(--text-secondary);
+ text-align: left;
+ padding: 10px;
+}
diff --git a/client/src/app/article/write/page.tsx b/client/src/app/article/write/page.tsx
new file mode 100644
index 0000000..0c09522
--- /dev/null
+++ b/client/src/app/article/write/page.tsx
@@ -0,0 +1,50 @@
+"use client";
+
+import "./ArticleWrite.css";
+import Header from "@components/Header";
+
+import Footer from "@components/Footer";
+import { useCallback, useState } from "react";
+import { useRouter } from "next/navigation";
+import { z } from "zod";
+
+import typography from "@styles/typography.module.css";
+
+export default function ArticleWrite() {
+ const [data, setData] = useState("");
+ const router = useRouter();
+
+ const onSubmit = useCallback(() => {
+ fetch("http://localhost:8080/articles", {
+ method: "POST",
+ body: JSON.stringify({ content: data }),
+ headers: {
+ "Content-Type": "application/json",
+ },
+ })
+ .then((res) => res.json())
+ .then(
+ z.object({
+ insertedId: z.number(),
+ }).parse,
+ )
+ .then(({ insertedId }) => router.push(`/article/${insertedId}`));
+ }, [data, router]);
+
+ return (
+
+
+
+
+
+
+ setData(e.target.value)} />
+
+
+
+
+
+
+
+ );
+}
diff --git a/client/src/app/dev/page.tsx b/client/src/app/dev/page.tsx
index da830e9..f877a92 100644
--- a/client/src/app/dev/page.tsx
+++ b/client/src/app/dev/page.tsx
@@ -11,8 +11,17 @@ import styled from "@emotion/styled";
import Lottie from "lottie-react";
import logoAnimation from "../../../public/logo_animation.json";
import layout from "../../styles/layout";
+import { useView } from "library/policy-maker/next";
+import viewPolicy from "@core/policy/view";
+import { UserRepository } from "@core/repository/user";
export default function Dev() {
+ const { view } = useView({
+ policy: viewPolicy.user.user(1),
+ from: () => UserRepository.getUser(1),
+ });
+
+ console.log(view);
return (
COMPONENTS
diff --git a/client/src/app/error.tsx b/client/src/app/error.tsx
new file mode 100644
index 0000000..b0c13c4
--- /dev/null
+++ b/client/src/app/error.tsx
@@ -0,0 +1,30 @@
+"use client";
+
+import { useEffect } from "react";
+
+export default function Error({
+ error,
+ reset,
+}: {
+ error: Error & { digest?: string };
+ reset: () => void;
+}) {
+ useEffect(() => {
+ // Log the error to an error reporting service
+ console.error(error);
+ }, [error]);
+
+ return (
+
+
Something went wrong!
+
+
+ );
+}
diff --git a/client/src/app/layout.tsx b/client/src/app/layout.tsx
index 6fb5f88..f1e1963 100644
--- a/client/src/app/layout.tsx
+++ b/client/src/app/layout.tsx
@@ -1,7 +1,7 @@
import type { Metadata } from "next";
-import Providers from "@/utils/next-query-resolver/Providers";
import "./globals.css";
import "./fonts.css";
+import { Provider } from "@policy-maker/next";
export const metadata: Metadata = {
title: "Create Next App",
@@ -14,10 +14,10 @@ export default function RootLayout({
children: React.ReactNode;
}) {
return (
-
+
{children}
-
+
);
}
diff --git a/client/src/app/loading.tsx b/client/src/app/loading.tsx
new file mode 100644
index 0000000..fc80ef0
--- /dev/null
+++ b/client/src/app/loading.tsx
@@ -0,0 +1,3 @@
+export default function Loading() {
+ return Loading...
;
+}
diff --git a/client/src/app/login/page.tsx b/client/src/app/login/page.tsx
index 2398624..250e3c7 100644
--- a/client/src/app/login/page.tsx
+++ b/client/src/app/login/page.tsx
@@ -8,25 +8,39 @@ import {
Snackbar,
} from "@mui/material";
import "./Login.css";
-import { UserApi } from "@core/api/user";
-import { useView } from "library/policy-maker-2/react";
-import { VPMe } from "@core/policy/user/view/me";
+
+import { useIntentInput, useIntentSubmit } from "library/policy-maker/next";
+import intentPolicy from "@core/policy/intent";
+import { UserRepository } from "@core/repository/user";
+import { useRouter } from "next/navigation";
function Login() {
- const [email, setEmail] = useState("");
- const [password, setPassword] = useState("");
+ const { submit, isValid } = useIntentSubmit({
+ policy: intentPolicy.user.login(),
+ to: UserRepository.postLogin,
+ });
+
+ const {
+ set,
+ values: { email, password },
+ } = useIntentInput({
+ policy: intentPolicy.user.login(),
+ initialValue: () => ({ email: "", password: "" }),
+ });
+
+ // const [email, setEmail] = useState("");
+ // const [password, setPassword] = useState("");
const [error, setError] = useState(null);
const [openSnackbar, setOpenSnackbar] = useState(false);
- const { view } = useView({
- policy: VPMe(),
- from: () => UserApi.getMe.client({}).catch(() => null),
- });
+ const router = useRouter();
const handleLogin = () => {
- UserApi.postSignIn
- .client({ body: { email, password } })
- .then((data) => {
- localStorage.setItem("xctoken", data.token);
+ if (!isValid) alert("이메일 또는 비밀번호를 확인해주세요");
+
+ submit()
+ .then(({ token }) => {
+ localStorage.setItem("xctoken", token);
+ router.push("/");
})
.catch((e) => {
setError(e.message);
@@ -51,8 +65,8 @@ function Login() {
fullWidth
variant="outlined"
margin="normal"
- value={email}
- onChange={(e) => setEmail(e.target.value)}
+ value={email.value}
+ onChange={(e) => set({ email: e.target.value })}
/>
setPassword(e.target.value)}
+ value={password.value}
+ onChange={(e) => set({ password: e.target.value })}
/>
diff --git a/client/src/app/page.tsx b/client/src/app/page.tsx
index 15da1a8..0527424 100644
--- a/client/src/app/page.tsx
+++ b/client/src/app/page.tsx
@@ -1,95 +1,11 @@
-import Image from "next/image";
-import styles from "./page.module.css";
+import Link from "next/link";
+import MeTest from "@/modules/home/MeTest/MeTest";
export default function Home() {
return (
-
-
-
- Get started by editing
- src/app/page.tsx
-
-
-
-
-
-
-
-
-
+
+
+ 로그인
);
}
diff --git a/client/src/app/register/page.tsx b/client/src/app/register/page.tsx
index 862a392..e4942ea 100644
--- a/client/src/app/register/page.tsx
+++ b/client/src/app/register/page.tsx
@@ -19,7 +19,7 @@ function Register() {
//const navigate = useNavigate()
const handleJoin = () => {
- fetch("../api/mock/user/register/route", {
+ fetch("http://localhost:8080/users/register", {
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -28,8 +28,10 @@ function Register() {
})
.then((response) => {
if (response.ok) {
+ alert(`회원가입 성공`);
return response.json();
} else {
+ alert(`회원가입 실패`);
throw new Error("Register fail");
}
})
diff --git a/client/src/app/serverTest/error.tsx b/client/src/app/serverTest/error.tsx
new file mode 100644
index 0000000..6f4f3f1
--- /dev/null
+++ b/client/src/app/serverTest/error.tsx
@@ -0,0 +1,30 @@
+"use client";
+
+import { useEffect } from "react";
+
+export default function Error({
+ error,
+ reset,
+}: {
+ error: Error & { digest?: string };
+ reset: () => void;
+}) {
+ useEffect(() => {
+ // Log the error to an error reporting service
+ console.error(error);
+ }, [error]);
+
+ return (
+
+
Something went wrong2
+
+
+ );
+}
diff --git a/client/src/app/serverTest/page.tsx b/client/src/app/serverTest/page.tsx
index 3087230..bbc37b2 100644
--- a/client/src/app/serverTest/page.tsx
+++ b/client/src/app/serverTest/page.tsx
@@ -1,11 +1,15 @@
"use client";
-import { api } from "@/api";
-import { PostApi } from "@core/api/post";
-import { useEffect } from "react";
+import viewPolicy from "@core/policy/view";
+import { UserRepository } from "@core/repository/user";
+import { delay, error } from "library/fetch";
+import { useView } from "library/policy-maker/next";
+
export default function ServerTest() {
- useEffect(() => {
- api.get("/posts").then(console.log);
- }, []);
- return ;
+ const { view } = useView({
+ policy: viewPolicy.user.user(1),
+ from: () => UserRepository.getUser(1).then(delay(1000)).then(error(50)),
+ });
+
+ return {view.name}
;
}
diff --git a/client/src/modules/home/MeTest/MeTest.tsx b/client/src/modules/home/MeTest/MeTest.tsx
new file mode 100644
index 0000000..0a6471b
--- /dev/null
+++ b/client/src/modules/home/MeTest/MeTest.tsx
@@ -0,0 +1,16 @@
+"use client";
+
+import viewPolicy from "@core/policy/view";
+import { UserRepository } from "@core/repository/user";
+import { useViewMaybe } from "library/policy-maker/next";
+
+export default function MeTest() {
+ const { view } = useViewMaybe({
+ policy: viewPolicy.user.me(),
+ from: UserRepository.getMe,
+ });
+
+ if (!view) return 로그인을 해주세요
;
+
+ return {view.name}로 로그인 되었습니다
;
+}
diff --git a/core/constant/post/text.ts b/core/constant/post/text.ts
index 407e96a..d770fe6 100644
--- a/core/constant/post/text.ts
+++ b/core/constant/post/text.ts
@@ -3,7 +3,6 @@ import { z } from "zod";
export const POST_TEXT = {
TITLE: z.string().min(1).max(100),
CONTENT: z.string().min(1),
- COMMENT_CONTENT: z.string().min(1),
};
export type POST_TEXT = {
[key in keyof typeof POST_TEXT]: z.infer<(typeof POST_TEXT)[key]>;
@@ -12,3 +11,8 @@ export type POST_TEXT = {
export const POST_COMMENT_TEXT = {
content: z.string().min(1),
};
+export type POST_COMMENT_TEXT = {
+ [key in keyof typeof POST_COMMENT_TEXT]: z.infer<
+ (typeof POST_COMMENT_TEXT)[key]
+ >;
+};
diff --git a/core/constant/user/text.ts b/core/constant/user/text.ts
new file mode 100644
index 0000000..62586e6
--- /dev/null
+++ b/core/constant/user/text.ts
@@ -0,0 +1,6 @@
+import { z } from "zod";
+
+export const USER_TEXT = {
+ NAME: z.string().min(1).max(30),
+ BIO: z.string().max(500),
+};
diff --git a/core/constant/user/userEmail.ts b/core/constant/user/userEmail.ts
new file mode 100644
index 0000000..6979a94
--- /dev/null
+++ b/core/constant/user/userEmail.ts
@@ -0,0 +1,3 @@
+import { z } from "zod";
+
+export const USER_EMAIL = z.string().email().max(255);
diff --git a/core/constant/user/userPassword.ts b/core/constant/user/userPassword.ts
new file mode 100644
index 0000000..8947b12
--- /dev/null
+++ b/core/constant/user/userPassword.ts
@@ -0,0 +1,3 @@
+import { z } from "zod";
+
+export const USER_PASSWORD = z.string().min(8).max(45);
diff --git a/core/dto/user/index.ts b/core/dto/user/index.ts
new file mode 100644
index 0000000..ec96c41
--- /dev/null
+++ b/core/dto/user/index.ts
@@ -0,0 +1,5 @@
+import { z } from "zod";
+import { User } from "@core/entity/user";
+
+export const UserDto = User;
+export type UserDto = z.infer;
diff --git a/core/dto/user/request.ts b/core/dto/user/request.ts
new file mode 100644
index 0000000..e51f942
--- /dev/null
+++ b/core/dto/user/request.ts
@@ -0,0 +1,15 @@
+import { USER_TEXT } from "@core/constant/user/text";
+import { z } from "zod";
+
+export const PostRegisterBody = z.object({
+ email: z.string().email(),
+ password: z.string().min(8),
+ name: USER_TEXT.NAME,
+});
+export type PostRegisterBody = z.infer;
+
+export const PostLoginBody = z.object({
+ email: z.string().email(),
+ password: z.string().min(8),
+});
+export type PostLoginBody = z.infer;
diff --git a/core/entity/post/index.ts b/core/entity/post/index.ts
index 7480e7f..5f6000f 100644
--- a/core/entity/post/index.ts
+++ b/core/entity/post/index.ts
@@ -15,10 +15,10 @@ export const Post = z
postType: POST_TYPE,
title: POST_TEXT.TITLE,
content: POST_TEXT.CONTENT,
- tags: Tag.array(),
- likesCount: z.number().int().nonnegative(),
- viewsCount: z.number().int().nonnegative(),
- commentsCount: z.number().int().nonnegative(),
+ tags: Tag.array().default([]),
+ likesCount: z.number().default(0),
+ viewsCount: z.number().default(0),
+ commentsCount: z.number().default(0),
})
.extend(Creatable.shape);
export type Post = z.infer;
diff --git a/core/entity/post/summary.ts b/core/entity/post/summary.ts
index 3c6e1af..9e1b3d5 100644
--- a/core/entity/post/summary.ts
+++ b/core/entity/post/summary.ts
@@ -1,9 +1,13 @@
-import { Post } from ".";
+import { z } from "zod";
+import { ID } from "@core/constant/common/id";
+import { POST_TEXT } from "@core/constant/post/text";
+import { Creatable } from "../utility/creatable";
+
+export const PostSummary = z
+ .object({
+ id: ID.POST,
+ title: POST_TEXT.TITLE,
+ })
+ .extend(Creatable.shape);
-export const PostSummary = Post.pick({
- id: true,
- title: true,
- content: true,
- createdUser: true,
-});
export type PostSummary = typeof PostSummary;
diff --git a/core/entity/user/index.ts b/core/entity/user/index.ts
index 8086147..9b43768 100644
--- a/core/entity/user/index.ts
+++ b/core/entity/user/index.ts
@@ -1,18 +1,7 @@
import { z } from "zod";
-import { Authorization } from "../../utility/Authorization";
-import { PublicId } from "../../utility/Id";
import { ID } from "@core/constant/common/id";
import { USER_TYPE } from "@core/constant/user/userType";
-
-/*
- * Old
- */
-export type UserEntity = {
- id: PublicId;
- name: string; // required
- email: string; // required
- authorization: Authorization;
-};
+import { USER_TEXT } from "@core/constant/user/text";
/**
* @entity User
@@ -22,11 +11,10 @@ export const User = z.object({
id: ID.USER,
type: USER_TYPE.default("USER"),
email: z.string().email(),
- name: z.string().min(1).max(30),
- bio: z.string().nullable(),
+ name: USER_TEXT.NAME,
+ bio: USER_TEXT.BIO.nullable(),
// image
thumbnailImage: z.string().nullable(),
- backgroundImage: z.string().nullable(),
});
export type User = z.infer;
diff --git a/core/entity/user/summary.ts b/core/entity/user/summary.ts
index 14de969..dbfd4ae 100644
--- a/core/entity/user/summary.ts
+++ b/core/entity/user/summary.ts
@@ -1,13 +1,20 @@
+import { ID } from "@core/constant/common/id";
+import { USER_TEXT } from "@core/constant/user/text";
import { z } from "zod";
-import { User } from ".";
/**
* @entity User Summary
* @description 사용자의 요약 정보입니다.
*/
-export const UserSummary = User.pick({
- id: true,
- name: true,
- thumbnailImage: true,
+export const UserSummary = z.object({
+ id: ID.USER,
+ name: USER_TEXT.NAME,
+ thumbnailImage: z.string().nullable(),
});
export type UserSummary = z.infer;
+
+export const UnknownUserSummary: UserSummary = {
+ id: -1,
+ name: "알 수 없는 사용자",
+ thumbnailImage: null,
+};
diff --git a/core/entity/utility/creatable.ts b/core/entity/utility/creatable.ts
index 1603e73..3aee805 100644
--- a/core/entity/utility/creatable.ts
+++ b/core/entity/utility/creatable.ts
@@ -1,9 +1,8 @@
import { z } from "zod";
-import { UserSummary } from "../user/summary";
-import { UNKNOWN_USER_SUMMARY } from "../../constant/user/unknownUser";
+import { UnknownUserSummary, UserSummary } from "../user/summary";
export const Creatable = z.object({
- createdUser: UserSummary.default(UNKNOWN_USER_SUMMARY),
+ createdUser: UserSummary.default(UnknownUserSummary),
createdTime: z.instanceof(Date),
lastModifiedTime: z.instanceof(Date).nullable(),
});
diff --git a/core/package.json b/core/package.json
index bc3d433..4828f99 100644
--- a/core/package.json
+++ b/core/package.json
@@ -3,8 +3,7 @@
"version": "0.0.0",
"private": true,
"dependencies": {
- "@policy-maker-2/core": "workspace:^",
- "@pvi/core": "workspace:^",
+ "@policy-maker/core": "workspace:^",
"fetch": "workspace:^",
"qs": "^6.12.1",
"zod": "^3.23.8"
diff --git a/core/policy/intent.ts b/core/policy/intent.ts
index d740afa..1dc442d 100644
--- a/core/policy/intent.ts
+++ b/core/policy/intent.ts
@@ -1,13 +1,9 @@
-import { IPLikePost } from "./post/intent/likePost";
-import { IPLikePostComment } from "./post/intent/likePostComment";
-import { IPWritePost } from "./post/intent/writePost";
-import { IPWritePostComment } from "./post/intent/writePostComment";
+import { IPLogin } from "./user/intent/login";
-export const intentPolicy = {
- post: {
- writePost: IPWritePost,
- writePostComment: IPWritePostComment,
- likePost: IPLikePost,
- likePostComment: IPLikePostComment,
+const intentPolicy = {
+ user: {
+ login: IPLogin,
},
};
+
+export default intentPolicy;
diff --git a/core/policy/post/intent/likePost.ts b/core/policy/post/intent/likePost.ts
deleted file mode 100644
index 9c4a44f..0000000
--- a/core/policy/post/intent/likePost.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { ID } from "@core/constant/common/id";
-import { IntentPolicy } from "@policy-maker-2/core";
-import { z } from "zod";
-
-export const IPLikePost = IntentPolicy((postId: ID["POST"]) => ({
- key: { name: "likePost", postId },
- model: { input: z.never(), output: z.unknown() },
- next: () => [],
-}));
diff --git a/core/policy/post/intent/likePostComment.ts b/core/policy/post/intent/likePostComment.ts
deleted file mode 100644
index f79e090..0000000
--- a/core/policy/post/intent/likePostComment.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { ID } from "@core/constant/common/id";
-import { IntentPolicy } from "@policy-maker-2/core";
-import { z } from "zod";
-
-export const IPLikePostComment = IntentPolicy(
- (postCommentId: ID["POST_COMMENT"]) => ({
- key: { name: "likePost", postCommentId },
- model: { input: z.never(), output: z.unknown() },
- next: () => [],
- }),
-);
diff --git a/core/policy/post/intent/writePost.ts b/core/policy/post/intent/writePost.ts
deleted file mode 100644
index 8429636..0000000
--- a/core/policy/post/intent/writePost.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { ID } from "@core/constant/common/id";
-import { POST_TYPE } from "@core/constant/post/postType";
-import { POST_TEXT } from "@core/constant/post/text";
-import { Post } from "@core/entity/post";
-import { IntentPolicy } from "@policy-maker-2/core";
-import { z } from "zod";
-
-const input = z.object({
- type: POST_TYPE,
- title: POST_TEXT.TITLE,
- content: POST_TEXT.CONTENT,
-});
-
-export const IPWritePost = IntentPolicy((postId: ID["POST"]) => ({
- key: { name: "writePost", postId },
- model: { input, output: Post },
- next: () => [],
-}));
diff --git a/core/policy/post/intent/writePostComment.ts b/core/policy/post/intent/writePostComment.ts
deleted file mode 100644
index 873435c..0000000
--- a/core/policy/post/intent/writePostComment.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { ID } from "@core/constant/common/id";
-import { POST_TEXT } from "@core/constant/post/text";
-import { PostComment } from "@core/entity/comment/post";
-import { IntentPolicy } from "@policy-maker-2/core";
-import { z } from "zod";
-
-const input = z.object({
- content: POST_TEXT.COMMENT_CONTENT,
-});
-
-export const IPWritePostComment = IntentPolicy((postId: ID["POST"]) => ({
- key: { name: "writePost", postId },
- model: { input, output: PostComment },
- next: () => [],
-}));
diff --git a/core/policy/post/view/posts.ts b/core/policy/post/view/posts.ts
deleted file mode 100644
index 75d0175..0000000
--- a/core/policy/post/view/posts.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { Paginated } from "@core/api/util";
-import { Post } from "@core/entity/post";
-import { ViewPolicy } from "@policy-maker-2/core";
-
-export const VPPosts = ViewPolicy((page: number) => ({
- key: ["posts"],
- model: Paginated(Post),
-}));
diff --git a/core/policy/post/view/trendingPosts.ts b/core/policy/post/view/trendingPosts.ts
deleted file mode 100644
index 4eacb97..0000000
--- a/core/policy/post/view/trendingPosts.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { PostTrending } from "@core/entity/post/trending";
-import { ViewPolicy } from "@policy-maker-2/core";
-
-export const VPTrendingPosts = ViewPolicy((page: number) => ({
- key: { name: "posts", page },
- model: PostTrending.array(),
-}));
diff --git a/core/policy/user/intent/login.ts b/core/policy/user/intent/login.ts
new file mode 100644
index 0000000..c025f5e
--- /dev/null
+++ b/core/policy/user/intent/login.ts
@@ -0,0 +1,15 @@
+import { USER_EMAIL } from "@core/constant/user/userEmail";
+import { USER_PASSWORD } from "@core/constant/user/userPassword";
+import { User } from "@core/entity/user";
+import { IntentPolicy } from "@policy-maker/core";
+import { z } from "zod";
+
+export const LoginInput = z.object({
+ email: USER_EMAIL,
+ password: USER_PASSWORD,
+});
+
+export const IPLogin = IntentPolicy(() => ({
+ key: ["login"],
+ model: { input: LoginInput, output: z.object({ token: z.string() }) },
+}));
diff --git a/core/policy/user/intent/signIn.ts b/core/policy/user/intent/signIn.ts
deleted file mode 100644
index ee4ee49..0000000
--- a/core/policy/user/intent/signIn.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { IntentPolicy } from "library/policy-maker-2/core";
-import { z } from "zod";
-import { VPMe } from "../view/me";
-
-export const IPSignin = IntentPolicy(() => ({
- key: ["signIn"],
- model: {
- input: z.object({ email: z.string(), password: z.string() }),
- output: z.unknown(),
- },
- next: () => [VPMe().invalidate()],
-}));
diff --git a/core/policy/user/view/me.ts b/core/policy/user/view/me.ts
index 2899e54..9623f67 100644
--- a/core/policy/user/view/me.ts
+++ b/core/policy/user/view/me.ts
@@ -1,8 +1,7 @@
import { User } from "@core/entity/user";
-import { ViewPolicy } from "library/policy-maker-2/core";
-import { z } from "zod";
+import { ViewPolicy } from "@policy-maker/core";
export const VPMe = ViewPolicy(() => ({
key: ["me"],
- model: User.extend({ token: z.string() }).nullable(),
+ model: User,
}));
diff --git a/core/policy/user/view/user.ts b/core/policy/user/view/user.ts
index e69de29..e8cf755 100644
--- a/core/policy/user/view/user.ts
+++ b/core/policy/user/view/user.ts
@@ -0,0 +1,8 @@
+import { ID } from "@core/constant/common/id";
+import { User } from "@core/entity/user";
+import { ViewPolicy } from "@policy-maker/core";
+
+export const VPUser = ViewPolicy((id: ID["USER"]) => ({
+ key: ["user", { user: id }],
+ model: User,
+}));
diff --git a/core/policy/view.ts b/core/policy/view.ts
index 54a4b17..f0892c4 100644
--- a/core/policy/view.ts
+++ b/core/policy/view.ts
@@ -1,9 +1,11 @@
-import { VPPosts } from "./post/view/posts";
-import { VPTrendingPosts } from "./post/view/trendingPosts";
+import { VPMe } from "./user/view/me";
+import { VPUser } from "./user/view/user";
-export const viewPolicy = {
- post: {
- posts: VPPosts,
- trendingPosts: VPTrendingPosts,
+const viewPolicy = {
+ user: {
+ me: VPMe,
+ user: VPUser,
},
};
+
+export default viewPolicy;
diff --git a/core/repository/user/index.ts b/core/repository/user/index.ts
new file mode 100644
index 0000000..275b84e
--- /dev/null
+++ b/core/repository/user/index.ts
@@ -0,0 +1,18 @@
+import { api, authApi } from "@core/api";
+import { ID } from "@core/constant/common/id";
+import { PostLoginBody } from "@core/dto/user/request";
+import { User } from "@core/entity/user";
+import { z } from "zod";
+
+const getMe = () => authApi.get("/users/me").then(User.parse);
+
+const getUser = (id: ID["USER"]) => api.get(`/users/${id}`).then(User.parse);
+
+const postLogin = (body: PostLoginBody) =>
+ api.post("/users/login", body).then(z.object({ token: z.string() }).parse);
+
+export const UserRepository = {
+ getMe,
+ getUser,
+ postLogin,
+};
diff --git a/library/policy-maker-2/core/example/sample.ts b/library/policy-maker-2/core/example/sample.ts
deleted file mode 100644
index 0ca775f..0000000
--- a/library/policy-maker-2/core/example/sample.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { z } from "zod";
-import { IntentPolicy } from "../src/intent";
-import { ViewPolicy } from "../src/view";
-
-const VPMe = ViewPolicy(() => ({
- key: { name: "me" },
- model: z.object({
- id: z.number(),
- name: z.string(),
- }),
-}));
-
-const IPEditMe = IntentPolicy(() => ({
- key: { name: "me" },
- model: {
- input: z.object({
- id: z.number(),
- name: z.string(),
- }),
- output: z.object({
- id: z.number(),
- name: z.string(),
- }),
- },
- next: ({ output }) => [
- VPMe().set(() => output),
- VPMe().invalidate(),
- VPMe().reset(),
- ],
-}));
diff --git a/library/policy-maker-2/core/index.ts b/library/policy-maker-2/core/index.ts
deleted file mode 100644
index e6170ae..0000000
--- a/library/policy-maker-2/core/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from "./src/store";
-export * from "./src/intent";
-export * from "./src/view";
diff --git a/library/policy-maker-2/core/package.json b/library/policy-maker-2/core/package.json
deleted file mode 100644
index 60d4556..0000000
--- a/library/policy-maker-2/core/package.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "@policy-maker-2/core",
- "version:": "0.0.1",
- "type": "module",
- "main": "index.ts",
- "peerDependencies": {
- "zod": "^3.23.0"
- },
- "dependencies": {
- "nanoid": "^5.0.7"
- }
-}
diff --git a/library/policy-maker-2/core/tsconfig.json b/library/policy-maker-2/core/tsconfig.json
deleted file mode 100644
index 834098d..0000000
--- a/library/policy-maker-2/core/tsconfig.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "extends": "../../../tsconfig.base.json",
- "compilerOptions": {
- "target": "ES2020",
- "useDefineForClassFields": true,
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
- "module": "ESNext",
- "skipLibCheck": true,
-
- /* Bundler mode */
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "resolveJsonModule": true,
- "isolatedModules": true,
- "noEmit": true,
-
- /* Linting */
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true
- },
- "include": ["index.ts", "**/*.ts"]
-}
diff --git a/library/policy-maker/README.md b/library/policy-maker/README.md
deleted file mode 100644
index e69de29..0000000
diff --git a/library/policy-maker/core/README.md b/library/policy-maker/core/README.md
deleted file mode 100644
index 3f008d3..0000000
--- a/library/policy-maker/core/README.md
+++ /dev/null
@@ -1,33 +0,0 @@
-```ts
-export const useView = (policy, repository) => {
- const store = useStore();
- const data = useMemo(() => store.get(policy.key, repository), [policy.key]);
- return { data: repository };
-};
-```
-
-```tsx
-import styles from "./TodoList.module.css";
-
-export default function TodoList() {
- const { data } = useView(view.todo.todos(), TodoRepository.getTodos());
-
- return (
-
- {data.map((todo) => (
-
- ))}
-
- );
-}
-```
-
-```tsx
-export default function TodoDetail() {
- const todoDomain = useTodoDomain();
- const { data } = useView({
- policy: viewPolicy.todo.todo(todoDomain),
- from: () => TodoRepository.getTodo(todoDomain),
- });
-}
-```
diff --git a/library/policy-maker/core/function/common.ts b/library/policy-maker/core/function/common.ts
deleted file mode 100644
index 5837166..0000000
--- a/library/policy-maker/core/function/common.ts
+++ /dev/null
@@ -1 +0,0 @@
-export type PolicyKey = readonly unknown[];
diff --git a/library/policy-maker/core/function/intent.ts b/library/policy-maker/core/function/intent.ts
deleted file mode 100644
index 917a4d5..0000000
--- a/library/policy-maker/core/function/intent.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { TypeOf, ZodObject, ZodRawShape, ZodType } from "zod";
-import { PolicyKey } from "./common";
-import { ViewConnectionInterface } from "./view";
-
-type ZodAnyObject = ZodObject;
-
-export type IntentModel = { input: ZodAnyObject; output: ZodType };
-
-type Result = {
- input: TypeOf;
- output: TypeOf;
-};
-
-export type IntentPolicy = (
- ...deps: Deps
-) => {
- key: PolicyKey;
- model: Model;
- connect: (
- result: Result,
- ) => (ViewConnectionInterface | null | undefined | false)[];
-};
-
-export const IP = (
- input: IntentPolicy,
-) => input;
-
-export type ImplementedIntentPolicy = ReturnType<
- IntentPolicy
->;
diff --git a/library/policy-maker/core/function/view.ts b/library/policy-maker/core/function/view.ts
deleted file mode 100644
index a5e82b6..0000000
--- a/library/policy-maker/core/function/view.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import { TypeOf, ZodType } from "zod";
-import { PolicyKey } from "./common";
-
-export type ViewModel = ZodType;
-
-type ViewMapFn = (
- prev: TypeOf,
-) => TypeOf;
-type ViewInvalidateInterface = {
- type: "invalidate";
- key: PolicyKey;
-};
-type ViewMapInterface = {
- type: "map";
- key: PolicyKey;
- mapFn: (prev: unknown) => unknown;
-};
-type ViewSetInterface = {
- type: "set";
- key: PolicyKey;
- data: unknown;
-};
-type ViewResetInterface = {
- type: "reset";
- key: PolicyKey;
-};
-
-export type ViewConnectionInterface =
- | ViewInvalidateInterface
- | ViewMapInterface
- | ViewResetInterface
- | ViewSetInterface;
-
-type ViewPolicyParam = (
- ...args: Deps
-) => {
- key: PolicyKey;
- model: Model;
-};
-
-export type ViewPolicy = (
- ...deps: Deps
-) => {
- key: PolicyKey;
- model: Model;
- invalidate: () => ViewInvalidateInterface;
- map: (mapFn: ViewMapFn) => ViewMapInterface;
- set: (data: TypeOf) => ViewSetInterface;
- reset: () => ViewResetInterface;
-};
-
-export const VP =
- (
- policy: ViewPolicyParam,
- ): ViewPolicy =>
- (...deps: Deps) => {
- const injected = policy(...deps);
- const invalidate = () =>
- ({ type: "invalidate", key: injected.key }) as const;
- const map = (mapFn: ViewMapFn) =>
- ({
- type: "map",
- key: injected.key,
- mapFn,
- }) as const;
- const set = (data: TypeOf) =>
- ({ type: "set", key: injected.key, data }) as const;
- const reset = () => ({ type: "reset", key: injected.key }) as const;
- return { ...injected, invalidate, map, set, reset };
- };
-
-export type ImplementedViewPolicy = ReturnType<
- ViewPolicy
->;
diff --git a/library/policy-maker/core/index.ts b/library/policy-maker/core/index.ts
index 937d7b9..e6170ae 100644
--- a/library/policy-maker/core/index.ts
+++ b/library/policy-maker/core/index.ts
@@ -1,32 +1,3 @@
-import { PolicyKey } from "./function/common";
-import {
- IP,
- IntentPolicy,
- IntentModel,
- ImplementedIntentPolicy,
-} from "./function/intent";
-import {
- VP,
- ViewPolicy,
- ViewModel,
- ImplementedViewPolicy,
-} from "./function/view";
-import { ViewConnectionInterface } from "./function/view";
-/**
- * functions
- */
-export { VP, IP };
-
-/**
- * types
- */
-export type {
- ViewPolicy,
- ImplementedViewPolicy,
- IntentPolicy,
- ImplementedIntentPolicy,
- PolicyKey,
- ViewModel,
- IntentModel,
- ViewConnectionInterface,
-};
+export * from "./src/store";
+export * from "./src/intent";
+export * from "./src/view";
diff --git a/library/policy-maker/core/package.json b/library/policy-maker/core/package.json
index a2b2941..0d0d1c3 100644
--- a/library/policy-maker/core/package.json
+++ b/library/policy-maker/core/package.json
@@ -1,9 +1,12 @@
{
"name": "@policy-maker/core",
- "version": "0.0.1",
- "private": true,
- "main": "./index.ts",
+ "version:": "0.0.1",
+ "type": "module",
+ "main": "index.ts",
"peerDependencies": {
- "zod": "^3.23.5"
+ "zod": "^3.23.0"
+ },
+ "dependencies": {
+ "nanoid": "^5.0.7"
}
}
diff --git a/library/policy-maker-2/core/src/intent.ts b/library/policy-maker/core/src/intent.ts
similarity index 58%
rename from library/policy-maker-2/core/src/intent.ts
rename to library/policy-maker/core/src/intent.ts
index 4d5e71c..e02276d 100644
--- a/library/policy-maker-2/core/src/intent.ts
+++ b/library/policy-maker/core/src/intent.ts
@@ -19,26 +19,43 @@ type Reset = {
predicate: Predicate;
};
-export type IntentNext = Set | Invalidate | Reset | undefined | null | false;
+type Execute = {
+ type: "EXECUTE";
+ callback: () => void;
+};
+
+export type IntentNext =
+ | Set
+ | Invalidate
+ | Reset
+ | Execute
+ | undefined /* = Falsy */
+ | null /* = Falsy */
+ | false; /* = Falsy */
export const IntentPolicy =
(
init: (...args: Args) => {
key: Key[];
model: { input: Input; output: Output };
- next: (result: {
+ next?: (result: {
input: TypeOf;
output: TypeOf