임동욱 임동욱 08-21
feat: 포인트 기준관리 등록 팝업 추가 (기획 PTS10100001 ④)
앞선 커밋에서 "기획상 이벤트는 읽기 전용이라 등록이 없다"고 적었는데 틀렸다. 목록 기획(④)에
「+ 신규 등록」이 있고 등록 팝업 시안(PTS10100002_p)도 따로 있다. "읽기 전용"은 수정 팝업의
이벤트 칸에만 해당한다.

  등록  이벤트 = 셀렉트(기획 ① "등록된 코드중에서 선택")
  수정  이벤트 = 읽기 전용 입력 — 지금까지와 같다

팝업 하나가 두 모드를 겸한다. 제목·저장 버튼·완료 토스트가 갈리고, 이벤트 칸만 셀렉트/읽기
전용으로 바뀐다. 검증도 `isCreate`로 갈린다 — 등록은 대상 id가 없고(백엔드 채번) 이벤트를
골라야 하며, 수정은 그 반대다. 등록은 저장 직전에 코드표를 다시 조회해 화면이 보낸 이벤트
코드를 대조한다.

Repository에 `createPointStandard`(form POST)를 되살렸다. 등록은 form, 수정은 JSON으로
갈리는 규약은 콘텐츠·퀴즈와 같다.

「사이트」 열을 뺐다 — 기획 목록의 열은 번호·이벤트/구분·포인트·제한포인트·중복여부·설명·
사용여부·수정일시·관리뿐이고 사이트가 없다. 백엔드에도 담을 컬럼이 없어 늘 비어 있던 열이다.

확인: 「신규 등록」을 누르면 제목 「등록」, 항목이 이벤트*·포인트*·제한포인트*·중복 여부·
이벤트 설명*·사용여부, 저장 버튼 「등록」, 이벤트가 셀렉트(EVENT-1)로 뜨고 hidden id는 빈 값.

TODO: 이벤트 공통코드 그룹ID를 받지 못해 `CODE_GROUP.pointEvent`를 잠정값('EVENT_CD')으로
두었다. 실제 값이 확인되면 그 한 줄만 바꾼다.

Co-Authored-By: Claude Opus 5 
@1840bcbd9ff48eb5dbeda223999941e9844899d4
app/(protected)/(basic)/points/standards/_actions.ts
--- app/(protected)/(basic)/points/standards/_actions.ts
+++ app/(protected)/(basic)/points/standards/_actions.ts
@@ -2,10 +2,13 @@
 
 import { revalidatePath } from 'next/cache';
 import { verifySession } from '@/lib/auth/dal';
+import { fetchCommonCodes } from '@/lib/data/repositories/common-code-repository';
 import {
+  createPointStandard,
   deletePointStandard,
   updatePointStandard,
 } from '@/lib/data/repositories/point-standard-repository';
+import { CODE_GROUP } from '@/lib/domain/common-code';
 import {
   validatePointStandard,
   type PointStandardFormState,
@@ -25,30 +28,62 @@
   return trimmed === '' ? NaN : Number(trimmed);
 }
 
-/** 기획 PTS10100002_p — 이벤트는 읽기 전용이라 대상 id는 hidden 필드에서 읽는다. */
-export async function updatePointStandardAction(
-  _prevState: PointStandardFormState,
-  formData: FormData
-): Promise<PointStandardFormState> {
-  await verifySession();
-
-  const validation = validatePointStandard({
+function readFormValues(formData: FormData) {
+  return {
     id: readString(formData, 'id'),
+    eventCode: readString(formData, 'eventCode'),
     point: parseFormNumber(formData, 'point'),
     limitPoint: parseFormNumber(formData, 'limitPoint'),
     isDuplicable: readString(formData, 'isDuplicable') === 'Y',
     description: readString(formData, 'description'),
     isActive: readString(formData, 'isActive') === 'Y',
+  };
+}
+
+/** 기획 PTS10100002_p(등록) — 이벤트는 등록된 코드 중에서 고른다. */
+export async function createPointStandardAction(
+  _prevState: PointStandardFormState,
+  formData: FormData
+): Promise<PointStandardFormState> {
+  await verifySession();
+
+  const validation = validatePointStandard(readFormValues(formData), {
+    isCreate: true,
+    // 화면이 보낸 코드를 그대로 믿지 않는다 — 저장 직전에 코드표를 다시 조회해 대조한다.
+    allowedEventCodes: (
+      await fetchCommonCodes(CODE_GROUP.pointEvent)
+    ).map((code) => code.code),
   });
   if (!validation.ok) {
     return { status: 'error', errors: validation.errors };
   }
 
   try {
-    await updatePointStandard(
-      validation.values,
-      readString(formData, 'eventCode')
-    );
+    await createPointStandard(validation.values);
+  } catch {
+    return { status: 'error', message: SAVE_FAILED_MESSAGE };
+  }
+
+  revalidatePath(POINT_STANDARDS_PATH);
+  return { status: 'success' };
+}
+
+/** 기획 PTS10100002_p(수정) — 이벤트는 읽기 전용이라 hidden으로 실려 온다. */
+export async function updatePointStandardAction(
+  _prevState: PointStandardFormState,
+  formData: FormData
+): Promise<PointStandardFormState> {
+  await verifySession();
+
+  const validation = validatePointStandard(readFormValues(formData), {
+    isCreate: false,
+  });
+  if (!validation.ok) {
+    return { status: 'error', errors: validation.errors };
+  }
+
+  try {
+    await updatePointStandard(validation.values);
   } catch {
     return { status: 'error', message: SAVE_FAILED_MESSAGE };
   }
app/(protected)/(basic)/points/standards/_components/point-standard-form-modal.tsx
--- app/(protected)/(basic)/points/standards/_components/point-standard-form-modal.tsx
+++ app/(protected)/(basic)/points/standards/_components/point-standard-form-modal.tsx
@@ -8,6 +8,7 @@
 import { FoxModal } from '@fox/core/components/fox-modal';
 import { FoxRadio } from '@fox/core/components/fox-radio';
 import { FoxRadioGroup } from '@fox/core/components/fox-radio-group';
+import { FoxSelect } from '@fox/core/components/fox-select';
 import { FoxTextArea } from '@fox/core/components/fox-text-area';
 import { submitFormAction } from '@/app/_hooks/submit-form-action';
 import { useFeedback } from '@/app/_hooks/use-feedback';
@@ -16,34 +17,51 @@
   INITIAL_POINT_STANDARD_FORM_STATE,
 } from '@/lib/domain/point-standard-form';
 import type { PointStandard } from '@/lib/domain/point-standard';
-import { updatePointStandardAction } from '../_actions';
+import type { CommonCode } from '@/lib/domain/common-code';
+import {
+  createPointStandardAction,
+  updatePointStandardAction,
+} from '../_actions';
 import styles from './point-standard-form.module.scss';
 
 interface PointStandardFormModalProps {
-  standard: PointStandard;
+  /** 수정 대상. 없으면 등록이다. */
+  standard?: PointStandard;
+  /** 공통코드 `CODE_GROUP.pointEvent` — 등록의 이벤트 선택지(기획 ① "등록된 코드중에서 선택"). */
+  eventCodes: readonly CommonCode[];
   onClose: () => void;
 }
 
 export function PointStandardFormModal({
   standard,
+  eventCodes,
   onClose,
 }: PointStandardFormModalProps) {
+  const isCreate = standard === undefined;
   const { showToast } = useFeedback();
   const formRef = useRef<HTMLFormElement>(null);
   const [state, formAction, isPending] = useActionState(
-    updatePointStandardAction,
+    isCreate ? createPointStandardAction : updatePointStandardAction,
     INITIAL_POINT_STANDARD_FORM_STATE
   );
 
-  const [isDuplicable, setIsDuplicable] = useState(standard.isDuplicable);
-  const [isActive, setIsActive] = useState(standard.isActive);
+  const [eventCode, setEventCode] = useState(
+    standard?.eventCode ?? eventCodes[0]?.code ?? ''
+  );
+  const [isDuplicable, setIsDuplicable] = useState(standard?.isDuplicable ?? true);
+  const [isActive, setIsActive] = useState(standard?.isActive ?? true);
 
   useEffect(() => {
     if (state.status === 'success') {
-      showToast({ variant: 'success', message: '포인트 기준을 수정했습니다.' });
+      showToast({
+        variant: 'success',
+        message: isCreate
+          ? '포인트 기준을 등록했습니다.'
+          : '포인트 기준을 수정했습니다.',
+      });
       onClose();
     }
-  }, [state, showToast, onClose]);
+  }, [state, showToast, onClose, isCreate]);
 
   const errors = state.status === 'error' ? (state.errors ?? {}) : {};
 
@@ -51,7 +69,7 @@
     <FoxModal
       open
       size="md"
-      title="수정"
+      title={isCreate ? '등록' : '수정'}
       onClose={onClose}
       actions={
         <>
@@ -59,7 +77,7 @@
           <FoxButton
             type="primary"
             size="md"
-            label={isPending ? '저장 중...' : '수정'}
+            label={isPending ? '저장 중...' : isCreate ? '등록' : '수정'}
             disabled={isPending}
             onAction={() => formRef.current?.requestSubmit()}
           />
@@ -73,20 +91,38 @@
       >
         <p className={styles.required}>* 는 필수 항목입니다.</p>
 
-        <input type="hidden" name="id" value={standard.id} />
-        {/* 화면에서는 읽기 전용이지만 백엔드 UPDATE가 EVENT_CD를 덮어써서 그대로 돌려보낸다. */}
-        <input type="hidden" name="eventCode" value={standard.eventCode} />
+        <input type="hidden" name="id" value={standard?.id ?? ''} />
+        {/* 수정에서는 화면이 읽기 전용이지만 백엔드 UPDATE가 EVENT_CD를 덮어써서 그대로 돌려보낸다. */}
+        <input type="hidden" name="eventCode" value={eventCode} />
 
         <div className={styles.field}>
-          {/* 기획 ① 이벤트행은 수정불가(Read Only). 값은 hidden id가 갖는다. */}
-          <FoxInput
-            size="md"
-            label="이벤트"
-            requirement="required"
-            value={standard.eventCode}
-            readOnly
-            state="view"
-          />
+          {isCreate ? (
+            // 기획 ① 등록된 코드중에서 선택.
+            <FoxSelect
+              size="md"
+              label="이벤트"
+              requirement="required"
+              options={eventCodes.map((code) => ({
+                value: code.code,
+                label: code.label,
+              }))}
+              placeholder="이벤트를 선택하세요."
+              value={eventCode}
+              onValueChange={setEventCode}
+              error={Boolean(errors.eventCode)}
+              hint={errors.eventCode}
+            />
+          ) : (
+            // 기획 ① 이벤트행은 수정불가(Read Only).
+            <FoxInput
+              size="md"
+              label="이벤트"
+              requirement="required"
+              value={eventCode}
+              readOnly
+              state="view"
+            />
+          )}
         </div>
 
         <div className={styles.field}>
@@ -102,7 +138,7 @@
                 inputMode="numeric"
                 min={0}
                 aria-label="포인트"
-                defaultValue={String(standard.point)}
+                defaultValue={String(standard?.point ?? 0)}
                 invalid={Boolean(errors.point)}
               />
             </div>
@@ -124,7 +160,7 @@
                 inputMode="numeric"
                 min={0}
                 aria-label="제한포인트"
-                defaultValue={String(standard.limitPoint)}
+                defaultValue={String(standard?.limitPoint ?? 0)}
                 invalid={Boolean(errors.limitPoint)}
               />
             </div>
@@ -160,7 +196,7 @@
             name="description"
             label="이벤트 설명"
             requirement="required"
-            defaultValue={standard.description}
+            defaultValue={standard?.description ?? ''}
             placeholder="이벤트 설명을 입력하세요."
             rows={4}
             counter
app/(protected)/(basic)/points/standards/_components/point-standard-list.tsx
--- app/(protected)/(basic)/points/standards/_components/point-standard-list.tsx
+++ app/(protected)/(basic)/points/standards/_components/point-standard-list.tsx
@@ -1,7 +1,10 @@
 'use client';
 
+import { useState } from 'react';
+
 import { useRouter } from 'next/navigation';
 import { FoxButton } from '@fox/core/components/fox-button';
+import { FoxButtonGroup } from '@fox/core/components/fox-button-group';
 import {
   FoxListContainer,
   type FoxListColumn,
@@ -16,6 +19,7 @@
   formatPoint,
   type PointStandard,
 } from '@/lib/domain/point-standard';
+import type { CommonCode } from '@/lib/domain/common-code';
 import {
   POINT_STANDARDS_PATH,
   POINT_STANDARD_PAGE_SIZE_OPTIONS,
@@ -23,6 +27,7 @@
   type PointStandardPageSize,
   type PointStandardQuery,
 } from '@/lib/domain/point-standard-query';
+import { PointStandardFormModal } from './point-standard-form-modal';
 import { PointStandardRowActions } from './point-standard-row-actions';
 
 interface PointStandardListProps {
@@ -31,6 +36,8 @@
   currentPage: number;
   totalPages: number;
   totalCount: number;
+  /** 공통코드 `CODE_GROUP.pointEvent` — 등록 팝업의 이벤트 선택지. */
+  eventCodes: readonly CommonCode[];
 }
 
 export function PointStandardList({
@@ -39,8 +46,10 @@
   currentPage,
   totalPages,
   totalCount,
+  eventCodes,
 }: PointStandardListProps) {
   const router = useRouter();
+  const [isCreateOpen, setIsCreateOpen] = useState(false);
 
   function go(patch: Partial<PointStandardQuery>) {
     router.replace(buildPointStandardHref(query, { ...patch, page: 1 }));
@@ -79,12 +88,6 @@
         />
       ),
     },
-    {
-      key: 'siteCode',
-      header: '사이트',
-      width: 140,
-      render: (row) => formatOptionalValue(row.siteCode),
-    },
     { key: 'description', header: '설명', width: 320 },
     {
       key: 'isActive',
@@ -107,12 +110,13 @@
       key: 'actions',
       header: '관리',
       width: 120,
-      render: (row) => <PointStandardRowActions standard={row} />,
+      render: (row) => <PointStandardRowActions standard={row} eventCodes={eventCodes} />,
     },
   ];
 
   return (
-    <FoxListContainer<PointStandard>
+    <>
+      <FoxListContainer<PointStandard>
       title="포인트 기준관리 목록"
       breadcrumb={[
         { label: '홈', href: '/' },
@@ -143,12 +147,21 @@
       keyword={query.keyword}
       searchPlaceholder="검색어를 입력하세요."
       toolbarActions={
-        <FoxButton
-          type="default"
-          size="md"
-          label="초기화"
-          onAction={() => router.replace(POINT_STANDARDS_PATH)}
-        />
+        <FoxButtonGroup size="md">
+          <FoxButton
+            type="default"
+            size="md"
+            label="초기화"
+            onAction={() => router.replace(POINT_STANDARDS_PATH)}
+          />
+          <FoxButton
+            type="primary"
+            size="md"
+            leadingIcon={<i className="fox-ico fox-ico-Plus" aria-hidden="true" />}
+            label="신규 등록"
+            onAction={() => setIsCreateOpen(true)}
+          />
+        </FoxButtonGroup>
       }
       page={currentPage}
       totalPages={totalPages}
@@ -161,5 +174,13 @@
         }
       }}
     />
+
+      {isCreateOpen && (
+        <PointStandardFormModal
+          eventCodes={eventCodes}
+          onClose={() => setIsCreateOpen(false)}
+        />
+      )}
+    </>
   );
 }
app/(protected)/(basic)/points/standards/_components/point-standard-row-actions.tsx
--- app/(protected)/(basic)/points/standards/_components/point-standard-row-actions.tsx
+++ app/(protected)/(basic)/points/standards/_components/point-standard-row-actions.tsx
@@ -6,15 +6,18 @@
 import { FoxIconButton } from '@fox/core/components/fox-icon-button';
 import { useFeedback } from '@/app/_hooks/use-feedback';
 import type { PointStandard } from '@/lib/domain/point-standard';
+import type { CommonCode } from '@/lib/domain/common-code';
 import { deletePointStandardAction } from '../_actions';
 import { PointStandardFormModal } from './point-standard-form-modal';
 
 interface PointStandardRowActionsProps {
   standard: PointStandard;
+  eventCodes: readonly CommonCode[];
 }
 
 export function PointStandardRowActions({
   standard,
+  eventCodes,
 }: PointStandardRowActionsProps) {
   const { showAlert, hideAlert, showToast } = useFeedback();
   const [isEditOpen, setIsEditOpen] = useState(false);
@@ -67,6 +70,7 @@
       {isEditOpen && (
         <PointStandardFormModal
           standard={standard}
+          eventCodes={eventCodes}
           onClose={() => setIsEditOpen(false)}
         />
       )}
app/(protected)/(basic)/points/standards/page.tsx
--- app/(protected)/(basic)/points/standards/page.tsx
+++ app/(protected)/(basic)/points/standards/page.tsx
@@ -1,4 +1,6 @@
 import { verifySession } from '@/lib/auth/dal';
+import { fetchCommonCodes } from '@/lib/data/repositories/common-code-repository';
+import { CODE_GROUP } from '@/lib/domain/common-code';
 import { fetchPointStandards } from '@/lib/data/repositories/point-standard-repository';
 import { parsePointStandardQuery } from '@/lib/domain/point-standard-query';
 import { PointStandardList } from './_components/point-standard-list';
@@ -14,6 +16,7 @@
 
   const query = parsePointStandardQuery(await searchParams);
   const { items, totalCount } = await fetchPointStandards(query);
+  const eventCodes = await fetchCommonCodes(CODE_GROUP.pointEvent);
 
   const totalPages = Math.max(1, Math.ceil(totalCount / query.pageSize));
   const currentPage = Math.min(query.page, totalPages);
@@ -25,6 +28,7 @@
       currentPage={currentPage}
       totalPages={totalPages}
       totalCount={totalCount}
+      eventCodes={eventCodes}
     />
   );
 }
lib/data/repositories/point-standard-repository.ts
--- lib/data/repositories/point-standard-repository.ts
+++ lib/data/repositories/point-standard-repository.ts
@@ -10,12 +10,12 @@
  *
  * ```
  * GET    /api/v1/mngr/point/pagination      목록
+ * POST   /api/v1/mngr/point                 어노테이션 없음 → form
  * PUT    /api/v1/mngr/point/{eventPtSn}     @RequestBody(JSON)
  * DELETE /api/v1/mngr/point/{eventPtSn}     soft delete(DEL_YN)
  * ```
  *
- * `POST /api/v1/mngr/point`(등록)도 있지만 쓰지 않는다 — 기획상 이벤트는 읽기 전용이라 화면에
- * 신규 등록이 없다. 등록 화면이 생기면 콘텐츠·퀴즈와 같은 form 규약으로 붙이면 된다.
+ * 등록은 form, 수정은 JSON으로 갈린다 — 콘텐츠·퀴즈와 같은 규약이다.
  *
  * ⚠️ 백엔드 결함(보고함, 미수정)
  * 1. **`MngrPointPolicyVo`에 `eventPtSn` 말고는 필드가 없다.** 목록 SQL은 EVENT_CD·
@@ -69,8 +69,6 @@
     point: readNumber(raw, 'grantPointAmt'),
     limitPoint: readNumber(raw, 'dayLmtPointAmt'),
     isDuplicable: readString(raw, 'duplYn') !== 'N',
-    // 이슈: 사이트 구분 컬럼이 백엔드에 없다. 화면은 기획대로 열을 두고 값은 비워 둔다.
-    siteCode: '',
     description: readString(raw, 'eventExpln'),
     isActive: readString(raw, 'useYn') !== 'N',
     updatedAt:
@@ -154,12 +152,9 @@
   useYn: string;
 };
 
-function buildPayload(
-  values: PointStandardValues,
-  eventCode: string
-): PointStandardPayload {
+function buildPayload(values: PointStandardValues): PointStandardPayload {
   return {
-    eventCd: eventCode,
+    eventCd: values.eventCode,
     grantPointAmt: String(values.point),
     dayLmtPointAmt: String(values.limitPoint),
     duplYn: values.isDuplicable ? 'Y' : 'N',
@@ -170,14 +165,16 @@
 
 async function sendWrite(
   path: string,
-  method: 'PUT' | 'DELETE',
-  body?: unknown
+  method: 'POST' | 'PUT' | 'DELETE',
+  body?: unknown,
+  form?: Record<string, string | number | undefined>
 ): Promise<void> {
   const accessToken = await getSessionAccessToken();
 
   const result = await backendFetch<unknown>(path, {
     method,
     ...(body === undefined ? {} : { body }),
+    ...(form === undefined ? {} : { form }),
     accessToken: accessToken ?? undefined,
     cache: 'no-store',
     canHaveNullData: true,
@@ -189,14 +186,25 @@
   }
 }
 
+/**
+ * 등록은 `@RequestBody`가 없어 form으로 간다.
+ *
+ * TODO: 백엔드가 `insert`에 `@RequestBody`를 붙이면 수정과 같은 JSON으로 통일한다. 반영 여부는
+ * `/v3/api-docs`에서 이 경로의 POST에 `requestBody`가 생겼는지로 확인한다.
+ */
+export async function createPointStandard(
+  values: PointStandardValues
+): Promise<void> {
+  await sendWrite(POINT_PATH, 'POST', undefined, { ...buildPayload(values) });
+}
+
 export async function updatePointStandard(
-  values: PointStandardValues,
-  eventCode: string
+  values: PointStandardValues
 ): Promise<void> {
   await sendWrite(
     `${POINT_PATH}/${encodeURIComponent(values.id)}`,
     'PUT',
-    buildPayload(values, eventCode)
+    buildPayload(values)
   );
 }
 
lib/domain/common-code.ts
--- lib/domain/common-code.ts
+++ lib/domain/common-code.ts
@@ -25,6 +25,9 @@
   inquiryAnswerStatus: 'BBS_ANS_CD',
   /** FAQ 유형. */
   faqType: 'BBS_FAQ_CD',
+  // TODO: 포인트 지급기준의 「이벤트」 — 기획이 "등록된 코드중에서 선택"이라 코드관리와 엮인다.
+  // 실제 그룹ID를 받지 못해 잠정값이다. 모르는 그룹은 빈 목록으로 와서 선택지가 비어 보인다.
+  pointEvent: 'EVENT_CD',
   /** 학교(학교급). */
   school: 'COM_SCHUL_CD',
   /** 학년. 학교마다 다르므로 `atrbNm`에 학교 코드를 넣어 조회한다. */
lib/domain/point-standard-form.ts
--- lib/domain/point-standard-form.ts
+++ lib/domain/point-standard-form.ts
@@ -2,7 +2,10 @@
 export const DESCRIPTION_MAX_LENGTH = 200;
 
 export interface PointStandardValues {
+  /** 수정은 기존 값, 등록은 비어 있다(백엔드가 채번). */
   id: string;
+  /** 공통코드 `CODE_GROUP.pointEvent`. 등록은 선택, 수정은 읽기 전용으로 그대로 돌려보낸다. */
+  eventCode: string;
   point: number;
   limitPoint: number;
   isDuplicable: boolean;
@@ -11,7 +14,7 @@
 }
 
 export type PointStandardFormErrors = Partial<
-  Record<'id' | 'point' | 'limitPoint' | 'description', string>
+  Record<'id' | 'eventCode' | 'point' | 'limitPoint' | 'description', string>
 >;
 
 export type PointStandardFormState =
@@ -45,13 +48,32 @@
   return {};
 }
 
+/**
+ * 등록·수정 공통 검증.
+ *
+ * `isCreate`로 갈린다 — 등록은 대상 id가 없고(백엔드가 채번) 이벤트를 골라야 하며, 수정은 그
+ * 반대다(이벤트는 읽기 전용이라 화면이 그대로 돌려보낸다).
+ */
 export function validatePointStandard(
-  values: PointStandardValues
+  values: PointStandardValues,
+  options: { isCreate: boolean; allowedEventCodes?: readonly string[] }
 ): ValidationResult {
   const errors: PointStandardFormErrors = {};
 
-  if (!values.id.trim()) {
+  if (!options.isCreate && !values.id.trim()) {
     errors.id = '수정할 대상을 찾을 수 없습니다.';
+  }
+
+  const eventCode = values.eventCode.trim();
+  if (!eventCode) {
+    errors.eventCode = '이벤트를 선택해 주세요.';
+  } else if (
+    options.isCreate &&
+    options.allowedEventCodes &&
+    options.allowedEventCodes.length > 0 &&
+    !options.allowedEventCodes.includes(eventCode)
+  ) {
+    errors.eventCode = '이벤트를 다시 선택해 주세요.';
   }
 
   const point = validatePointNumber(values.point, '포인트');
@@ -79,6 +101,7 @@
     ok: true,
     values: {
       id: values.id.trim(),
+      eventCode,
       point: values.point,
       limitPoint: values.limitPoint,
       isDuplicable: values.isDuplicable,
lib/domain/point-standard.ts
--- lib/domain/point-standard.ts
+++ lib/domain/point-standard.ts
@@ -4,7 +4,6 @@
   point: number;
   limitPoint: number;
   isDuplicable: boolean;
-  siteCode: string;
   description: string;
   isActive: boolean;
   updatedAt: string;
Add a comment
List