Rename project from Re:Link to Startover
Rebrand repository from "Re:Link" to "Startover" across the codebase. Updates include package names and scopes (@relink/* -> @startover/*), import paths, Next.js transpile settings, vitest name, UI text and docs, Dockerfile and CI/workflow names, deploy scripts and repo paths, and example/production env values. Also add auth-related env vars, an apps/web .env symlink, and small formatting/typing cleanups in several TSX/TS files and tests to accommodate the rename.
This commit is contained in:
Symlink
+1
@@ -0,0 +1 @@
|
||||
/Users/johngreen/Dev/Re_Link/.env
|
||||
@@ -2,7 +2,7 @@ import type { NextConfig } from 'next';
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: 'standalone',
|
||||
transpilePackages: ['@relink/ui', '@relink/shared'],
|
||||
transpilePackages: ['@startover/ui', '@startover/shared'],
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@relink/web",
|
||||
"name": "@startover/web",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
@@ -15,11 +15,11 @@
|
||||
"dependencies": {
|
||||
"@auth/prisma-adapter": "^2.11.1",
|
||||
"@prisma/client": "^6.1.0",
|
||||
"@relink/database": "workspace:*",
|
||||
"@relink/domain": "workspace:*",
|
||||
"@relink/infrastructure": "workspace:*",
|
||||
"@relink/shared": "workspace:*",
|
||||
"@relink/ui": "workspace:*",
|
||||
"@startover/database": "workspace:*",
|
||||
"@startover/domain": "workspace:*",
|
||||
"@startover/infrastructure": "workspace:*",
|
||||
"@startover/shared": "workspace:*",
|
||||
"@startover/ui": "workspace:*",
|
||||
"argon2": "^0.44.0",
|
||||
"next": "^15.1.0",
|
||||
"next-auth": "5.0.0-beta.30",
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
teardownTestDatabase,
|
||||
cleanAllTables,
|
||||
seedTestMasterData,
|
||||
} from '@relink/database';
|
||||
} from '@startover/database';
|
||||
import {
|
||||
createStoreDraftService,
|
||||
submitStoreService,
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
teardownTestDatabase,
|
||||
cleanAllTables,
|
||||
seedTestMasterData,
|
||||
} from '@relink/database';
|
||||
} from '@startover/database';
|
||||
import {
|
||||
createStoreDraftService,
|
||||
submitStoreService,
|
||||
@@ -71,7 +71,12 @@ describe('Match Request Service Integration Tests', () => {
|
||||
if (!createResult.ok) throw new Error('createStoreDraft failed');
|
||||
|
||||
await submitStoreService(prisma, createResult.value.publicId, ownerUserId.toString());
|
||||
await reviewStoreService(prisma, createResult.value.publicId, 'APPROVED', operatorUserId.toString());
|
||||
await reviewStoreService(
|
||||
prisma,
|
||||
createResult.value.publicId,
|
||||
'APPROVED',
|
||||
operatorUserId.toString(),
|
||||
);
|
||||
|
||||
const policyVersion = await prisma.policyVersion.create({
|
||||
data: {
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
teardownTestDatabase,
|
||||
cleanAllTables,
|
||||
seedTestMasterData,
|
||||
} from '@relink/database';
|
||||
} from '@startover/database';
|
||||
import {
|
||||
createStoreDraftService,
|
||||
submitStoreService,
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
teardownTestDatabase,
|
||||
cleanAllTables,
|
||||
seedTestMasterData,
|
||||
} from '@relink/database';
|
||||
} from '@startover/database';
|
||||
import {
|
||||
createStoreDraftService,
|
||||
submitStoreService,
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
teardownTestDatabase,
|
||||
cleanAllTables,
|
||||
seedTestMasterData,
|
||||
} from '@relink/database';
|
||||
} from '@startover/database';
|
||||
import {
|
||||
applyVendorCertificationService,
|
||||
reviewVendorCertificationService,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
import { releaseEscrowService } from '@/services/contract-service';
|
||||
import ContractActionButtons from './ContractActionButtons';
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ export default function AdminDashboardPage() {
|
||||
return (
|
||||
<main className="p-8">
|
||||
<h1 className="text-2xl font-bold text-gray-900">운영자 대시보드</h1>
|
||||
<p className="mt-1 text-sm text-gray-500">Re:Link 운영 현황을 한눈에 확인합니다</p>
|
||||
<p className="mt-1 text-sm text-gray-500">Startover 운영 현황을 한눈에 확인합니다</p>
|
||||
|
||||
{/* KPI 요약 */}
|
||||
<div className="mt-6 grid grid-cols-2 gap-4 md:grid-cols-4">
|
||||
@@ -75,10 +75,23 @@ export default function AdminDashboardPage() {
|
||||
{[
|
||||
{ action: '매장 승인', target: '강남역 카페 양도', actor: '김운영', time: '10분 전' },
|
||||
{ action: '업체 인증 승인', target: '(주)클린철거', actor: '이운영', time: '1시간 전' },
|
||||
{ action: '에스크로 입금 확인', target: '선릉역 한식당 계약', actor: 'SYSTEM', time: '2시간 전' },
|
||||
{ action: '매칭 요청 수락', target: '홍대 디저트카페', actor: '박운영', time: '3시간 전' },
|
||||
{
|
||||
action: '에스크로 입금 확인',
|
||||
target: '선릉역 한식당 계약',
|
||||
actor: 'SYSTEM',
|
||||
time: '2시간 전',
|
||||
},
|
||||
{
|
||||
action: '매칭 요청 수락',
|
||||
target: '홍대 디저트카페',
|
||||
actor: '박운영',
|
||||
time: '3시간 전',
|
||||
},
|
||||
].map((log, i) => (
|
||||
<div key={i} className="flex items-center justify-between border-b border-gray-50 py-2 last:border-0">
|
||||
<div
|
||||
key={i}
|
||||
className="flex items-center justify-between border-b border-gray-50 py-2 last:border-0"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-sm font-medium text-gray-900">{log.action}</span>
|
||||
<span className="text-sm text-gray-500">{log.target}</span>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { auth } from '@/lib/auth';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
import { InviteForm } from './invite-form';
|
||||
|
||||
const prisma = createPrismaClient();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
import { reviewStoreService } from '@/services/store-service';
|
||||
import StoreActionButtons from './StoreActionButtons';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
import { reviewSubsidyCaseService } from '@/services/subsidy-case-service';
|
||||
import SubsidyActionButtons from './SubsidyActionButtons';
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
import { reviewVendorCertificationService } from '@/services/vendor-certification-service';
|
||||
import VendorActionButtons from './VendorActionButtons';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { auth } from '@/lib/auth';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
|
||||
import type { ConsentType, ProfileType, UserRole } from '@prisma/client';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import argon2 from 'argon2';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
|
||||
const prisma = createPrismaClient();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { auth } from '@/lib/auth';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
|
||||
import type { UserRole } from '@prisma/client';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
|
||||
const prisma = createPrismaClient();
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import { NextResponse, type NextRequest } from 'next/server';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
import { submitStoreService } from '@/services/store-service';
|
||||
|
||||
const prisma = createPrismaClient();
|
||||
|
||||
export async function POST(
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string }> },
|
||||
) {
|
||||
export async function POST(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params;
|
||||
const body = await request.json().catch(() => ({}));
|
||||
const actorUserId = (body as Record<string, string>).actorUserId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextResponse, type NextRequest } from 'next/server';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
import { createStoreDraftService } from '@/services/store-service';
|
||||
import { z } from 'zod';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { z } from 'zod';
|
||||
import argon2 from 'argon2';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
|
||||
const prisma = createPrismaClient();
|
||||
import { randomBytes } from 'crypto';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { redirect } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
|
||||
const prisma = createPrismaClient();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Link from 'next/link';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
@@ -74,10 +74,19 @@ export default async function ContractsPage() {
|
||||
<p className="text-center text-sm text-gray-500">데이터가 없습니다</p>
|
||||
) : (
|
||||
contracts.map((contract) => {
|
||||
const statusInfo = STATUS_MAP[contract.status] ?? { label: contract.status, color: 'bg-gray-100 text-gray-700' };
|
||||
const escrowInfo = ESCROW_MAP[contract.escrowStatus] ?? { label: contract.escrowStatus, color: 'text-gray-500' };
|
||||
const statusInfo = STATUS_MAP[contract.status] ?? {
|
||||
label: contract.status,
|
||||
color: 'bg-gray-100 text-gray-700',
|
||||
};
|
||||
const escrowInfo = ESCROW_MAP[contract.escrowStatus] ?? {
|
||||
label: contract.escrowStatus,
|
||||
color: 'text-gray-500',
|
||||
};
|
||||
return (
|
||||
<div key={contract.publicId} className="rounded-lg border border-gray-200 bg-white p-5">
|
||||
<div
|
||||
key={contract.publicId}
|
||||
className="rounded-lg border border-gray-200 bg-white p-5"
|
||||
>
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -90,7 +99,9 @@ export default async function ContractsPage() {
|
||||
생성일: {new Date(contract.createdAt).toLocaleDateString('ko-KR')}
|
||||
</p>
|
||||
</div>
|
||||
<span className={`rounded-full px-2.5 py-0.5 text-xs font-medium ${statusInfo.color}`}>
|
||||
<span
|
||||
className={`rounded-full px-2.5 py-0.5 text-xs font-medium ${statusInfo.color}`}
|
||||
>
|
||||
{statusInfo.label}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -6,8 +6,8 @@ import { AuthButtons } from './auth-buttons';
|
||||
import './globals.css';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Re:Link',
|
||||
description: 'Re:Link - 폐업 · 양도 · 창업을 잇는 중개 플랫폼',
|
||||
title: 'Startover',
|
||||
description: 'Startover - 폐업 · 양도 · 창업을 잇는 중개 플랫폼',
|
||||
};
|
||||
|
||||
const OPERATOR_ROLES = [
|
||||
@@ -26,7 +26,7 @@ async function Navigation() {
|
||||
<nav className="border-b border-gray-200 bg-white">
|
||||
<div className="mx-auto flex h-16 max-w-7xl items-center justify-between px-4">
|
||||
<Link href="/" className="text-xl font-bold text-blue-600">
|
||||
Re:Link
|
||||
Startover
|
||||
</Link>
|
||||
<div className="flex items-center gap-6">
|
||||
<Link href="/stores" className="text-sm text-gray-700 hover:text-blue-600">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Link from 'next/link';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
@@ -42,7 +42,10 @@ export default async function MatchingPage() {
|
||||
<p className="text-center text-sm text-gray-500">데이터가 없습니다</p>
|
||||
) : (
|
||||
requests.map((req) => {
|
||||
const statusInfo = STATUS_LABELS[req.status] ?? { label: req.status, color: 'bg-gray-100 text-gray-700' };
|
||||
const statusInfo = STATUS_LABELS[req.status] ?? {
|
||||
label: req.status,
|
||||
color: 'bg-gray-100 text-gray-700',
|
||||
};
|
||||
return (
|
||||
<div key={req.publicId} className="rounded-lg border border-gray-200 bg-white p-5">
|
||||
<div className="flex items-start justify-between">
|
||||
@@ -53,14 +56,14 @@ export default async function MatchingPage() {
|
||||
{MATCH_TYPE_LABELS[req.matchType] ?? req.matchType}
|
||||
</span>
|
||||
</div>
|
||||
{req.message && (
|
||||
<p className="mt-1 text-sm text-gray-600">{req.message}</p>
|
||||
)}
|
||||
{req.message && <p className="mt-1 text-sm text-gray-600">{req.message}</p>}
|
||||
<p className="mt-2 text-xs text-gray-400">
|
||||
요청일: {new Date(req.createdAt).toLocaleDateString('ko-KR')}
|
||||
</p>
|
||||
</div>
|
||||
<span className={`rounded-full px-2.5 py-0.5 text-xs font-medium ${statusInfo.color}`}>
|
||||
<span
|
||||
className={`rounded-full px-2.5 py-0.5 text-xs font-medium ${statusInfo.color}`}
|
||||
>
|
||||
{statusInfo.label}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@ export default function HomePage() {
|
||||
return (
|
||||
<main className="mx-auto max-w-7xl px-4 py-16">
|
||||
<div className="text-center">
|
||||
<h1 className="text-5xl font-bold text-gray-900">Re:Link</h1>
|
||||
<h1 className="text-5xl font-bold text-gray-900">Startover</h1>
|
||||
<p className="mt-4 text-xl text-gray-600">폐업 · 양도 · 창업을 잇는 중개 플랫폼</p>
|
||||
<p className="mt-2 text-gray-500">
|
||||
매장 정보 1회 등록으로 창업자·철거업체·인테리어업체를 동시 연결합니다
|
||||
@@ -32,7 +32,10 @@ export default function HomePage() {
|
||||
<p className="mt-2 text-sm text-gray-600">
|
||||
매장 정보를 등록하면 철거비 절감, 시설 처분, 지원금 신청까지 한 번에 해결됩니다.
|
||||
</p>
|
||||
<Link href="/stores/new" className="mt-3 inline-block text-sm text-blue-600 hover:underline">
|
||||
<Link
|
||||
href="/stores/new"
|
||||
className="mt-3 inline-block text-sm text-blue-600 hover:underline"
|
||||
>
|
||||
매장 등록 →
|
||||
</Link>
|
||||
</div>
|
||||
@@ -66,7 +69,10 @@ export default function HomePage() {
|
||||
<p className="mt-2 text-sm text-gray-600">
|
||||
폐업 관련 정부 지원금 자격을 확인하고, 체크리스트와 서류 준비를 도와드립니다.
|
||||
</p>
|
||||
<Link href="/subsidies" className="mt-3 inline-block text-sm text-blue-600 hover:underline">
|
||||
<Link
|
||||
href="/subsidies"
|
||||
className="mt-3 inline-block text-sm text-blue-600 hover:underline"
|
||||
>
|
||||
지원금 확인 →
|
||||
</Link>
|
||||
</div>
|
||||
@@ -76,7 +82,10 @@ export default function HomePage() {
|
||||
<p className="mt-2 text-sm text-gray-600">
|
||||
표준 계약서, 에스크로 결제, 검수 승인 시스템으로 안전한 거래를 보장합니다.
|
||||
</p>
|
||||
<Link href="/contracts" className="mt-3 inline-block text-sm text-blue-600 hover:underline">
|
||||
<Link
|
||||
href="/contracts"
|
||||
className="mt-3 inline-block text-sm text-blue-600 hover:underline"
|
||||
>
|
||||
계약 관리 →
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Link from 'next/link';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Link from 'next/link';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Link from 'next/link';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Link from 'next/link';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
@@ -40,7 +40,7 @@ export default async function SubsidiesPage() {
|
||||
<div className="mt-6 rounded-lg border border-blue-200 bg-blue-50 p-4">
|
||||
<h3 className="text-sm font-semibold text-blue-800">가이드형 지원금 대행 서비스</h3>
|
||||
<p className="mt-1 text-sm text-blue-700">
|
||||
Re:Link은 지원금 신청 보조 파트너로서, 체크리스트·서류 업로드·진행 상태·운영자 피드백을
|
||||
Startover은 지원금 신청 보조 파트너로서, 체크리스트·서류 업로드·진행 상태·운영자 피드백을
|
||||
제공합니다.
|
||||
</p>
|
||||
</div>
|
||||
@@ -51,7 +51,10 @@ export default async function SubsidiesPage() {
|
||||
<p className="text-center text-sm text-gray-500">데이터가 없습니다</p>
|
||||
) : (
|
||||
cases.map((c) => {
|
||||
const statusInfo = STATUS_MAP[c.status] ?? { label: c.status, color: 'bg-gray-100 text-gray-700' };
|
||||
const statusInfo = STATUS_MAP[c.status] ?? {
|
||||
label: c.status,
|
||||
color: 'bg-gray-100 text-gray-700',
|
||||
};
|
||||
const total = c.checklistItems.length;
|
||||
const checked = c.checklistItems.filter((item) => item.status === 'CHECKED').length;
|
||||
return (
|
||||
@@ -63,7 +66,9 @@ export default async function SubsidiesPage() {
|
||||
신청일: {new Date(c.createdAt).toLocaleDateString('ko-KR')}
|
||||
</p>
|
||||
</div>
|
||||
<span className={`rounded-full px-2.5 py-0.5 text-xs font-medium ${statusInfo.color}`}>
|
||||
<span
|
||||
className={`rounded-full px-2.5 py-0.5 text-xs font-medium ${statusInfo.color}`}
|
||||
>
|
||||
{statusInfo.label}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
Vendored
+2
-2
@@ -1,9 +1,9 @@
|
||||
'use server';
|
||||
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
import { applyVendorCertificationService } from '@/services/vendor-certification-service';
|
||||
import type { VendorType } from '@relink/domain';
|
||||
import type { VendorType } from '@startover/domain';
|
||||
|
||||
const prisma = createPrismaClient();
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
import VendorApplicationForm from './vendor-application-form';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
|
||||
@@ -2,7 +2,7 @@ import NextAuth from 'next-auth';
|
||||
import type { NextAuthConfig } from 'next-auth';
|
||||
import Credentials from 'next-auth/providers/credentials';
|
||||
import Kakao from 'next-auth/providers/kakao';
|
||||
import { createPrismaClient } from '@relink/database';
|
||||
import { createPrismaClient } from '@startover/database';
|
||||
import argon2 from 'argon2';
|
||||
|
||||
import type { UserRole } from '@prisma/client';
|
||||
@@ -193,7 +193,7 @@ const fullConfig: NextAuthConfig = {
|
||||
return {
|
||||
id: String(profile.id),
|
||||
name: kakaoProfile?.nickname ?? null,
|
||||
email: (kakaoAccount?.email as string) || `kakao_${profile.id}@placeholder.relink`,
|
||||
email: (kakaoAccount?.email as string) || `kakao_${profile.id}@placeholder.startover`,
|
||||
image: kakaoProfile?.profile_image_url ?? null,
|
||||
};
|
||||
},
|
||||
@@ -239,11 +239,11 @@ const fullConfig: NextAuthConfig = {
|
||||
},
|
||||
async signIn({ user, account }) {
|
||||
if (account?.provider === 'kakao') {
|
||||
// placeholder 이메일(@placeholder.relink)은 비즈 앱 전환 전 임시 처리
|
||||
// placeholder 이메일(@placeholder.startover)은 비즈 앱 전환 전 임시 처리
|
||||
const email = user.email;
|
||||
if (!email) return false;
|
||||
|
||||
const isPlaceholder = email.endsWith('@placeholder.relink');
|
||||
const isPlaceholder = email.endsWith('@placeholder.startover');
|
||||
const existing = !isPlaceholder
|
||||
? await prisma.user.findFirst({
|
||||
where: { emailNormalized: email.toLowerCase().trim() },
|
||||
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
checkIdempotency,
|
||||
openDispute,
|
||||
type ContractType,
|
||||
} from '@relink/domain';
|
||||
import { createAuditLog, enqueueOutboxEvent } from '@relink/infrastructure';
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
} from '@startover/domain';
|
||||
import { createAuditLog, enqueueOutboxEvent } from '@startover/infrastructure';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// I012: 계약 생성 서비스
|
||||
|
||||
@@ -6,9 +6,9 @@ import {
|
||||
type MatchType,
|
||||
type MatchSourceType,
|
||||
type StoreSearchCriteria,
|
||||
} from '@relink/domain';
|
||||
import { createAuditLog, enqueueOutboxEvent } from '@relink/infrastructure';
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
} from '@startover/domain';
|
||||
import { createAuditLog, enqueueOutboxEvent } from '@startover/infrastructure';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export interface CreateMatchRequestServiceInput {
|
||||
readonly storePublicId: string;
|
||||
@@ -34,7 +34,9 @@ export async function createMatchRequestService(
|
||||
});
|
||||
|
||||
if (!store) {
|
||||
return failure(appError('NOT_FOUND', '매장을 찾을 수 없습니다.', { storePublicId: input.storePublicId }));
|
||||
return failure(
|
||||
appError('NOT_FOUND', '매장을 찾을 수 없습니다.', { storePublicId: input.storePublicId }),
|
||||
);
|
||||
}
|
||||
|
||||
const openRequest = await prisma.matchRequest.findFirst({
|
||||
@@ -118,7 +120,9 @@ export async function acceptMatchRequestService(
|
||||
});
|
||||
|
||||
if (!matchRequest) {
|
||||
return failure(appError('NOT_FOUND', '매칭 요청을 찾을 수 없습니다.', { matchRequestPublicId }));
|
||||
return failure(
|
||||
appError('NOT_FOUND', '매칭 요청을 찾을 수 없습니다.', { matchRequestPublicId }),
|
||||
);
|
||||
}
|
||||
|
||||
const domainResult = acceptMatchRequest({
|
||||
@@ -172,7 +176,17 @@ export async function acceptMatchRequestService(
|
||||
export async function searchStoresService(
|
||||
prisma: PrismaClient,
|
||||
criteria: StoreSearchCriteria,
|
||||
): Promise<Result<{ stores: Array<{ publicId: string; listingTitle: string; dealStatus: string }>; total: number; page: number; limit: number }, AppError>> {
|
||||
): Promise<
|
||||
Result<
|
||||
{
|
||||
stores: Array<{ publicId: string; listingTitle: string; dealStatus: string }>;
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
},
|
||||
AppError
|
||||
>
|
||||
> {
|
||||
const defaults = buildSearchDefaults(criteria);
|
||||
|
||||
const where: Record<string, unknown> = {
|
||||
|
||||
@@ -12,9 +12,9 @@ import {
|
||||
type StoreData,
|
||||
type ViewerContext,
|
||||
type FilteredStoreData,
|
||||
} from '@relink/domain';
|
||||
import { createAuditLog, enqueueOutboxEvent } from '@relink/infrastructure';
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
} from '@startover/domain';
|
||||
import { createAuditLog, enqueueOutboxEvent } from '@startover/infrastructure';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
function buildRegionChecker(regions: { code: string; isBetaEnabled: boolean }[]): RegionChecker {
|
||||
const betaCodes = new Set(regions.filter((r) => r.isBetaEnabled).map((r) => r.code));
|
||||
|
||||
@@ -4,9 +4,9 @@ import {
|
||||
reviewSubsidyCase,
|
||||
type ChecklistItemTemplate,
|
||||
type SubsidyReviewDecision,
|
||||
} from '@relink/domain';
|
||||
import { createAuditLog, enqueueOutboxEvent } from '@relink/infrastructure';
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
} from '@startover/domain';
|
||||
import { createAuditLog, enqueueOutboxEvent } from '@startover/infrastructure';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export interface CreateSubsidyCaseServiceInput {
|
||||
readonly storePublicId: string;
|
||||
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
approveVendorCertification,
|
||||
type VendorType,
|
||||
type VendorCertificationDecision,
|
||||
} from '@relink/domain';
|
||||
import { createAuditLog, enqueueOutboxEvent } from '@relink/infrastructure';
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
} from '@startover/domain';
|
||||
import { createAuditLog, enqueueOutboxEvent } from '@startover/infrastructure';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export interface ApplyVendorCertificationServiceInput {
|
||||
readonly ownerUserId: string;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { resolve } from 'path';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
name: '@relink/web',
|
||||
name: '@startover/web',
|
||||
globals: true,
|
||||
environment: 'node',
|
||||
testTimeout: 30000,
|
||||
|
||||
Reference in New Issue
Block a user