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:
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@relink/analytics",
|
||||
"name": "@startover/analytics",
|
||||
"version": "0.0.1",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -19,7 +19,7 @@
|
||||
"clean": "rm -rf dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@relink/shared": "workspace:*"
|
||||
"@startover/shared": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tsup": "^8.3.5",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @relink/analytics - Event schemas and KPI calculations
|
||||
* @startover/analytics - Event schemas and KPI calculations
|
||||
*/
|
||||
|
||||
export type { AnalyticsEvent } from './event.js';
|
||||
|
||||
@@ -6,5 +6,5 @@ export default defineConfig({
|
||||
dts: true,
|
||||
clean: true,
|
||||
sourcemap: true,
|
||||
external: ['@relink/shared'],
|
||||
external: ['@startover/shared'],
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@relink/application",
|
||||
"name": "@startover/application",
|
||||
"version": "0.0.1",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -19,8 +19,8 @@
|
||||
"clean": "rm -rf dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@relink/domain": "workspace:*",
|
||||
"@relink/shared": "workspace:*"
|
||||
"@startover/domain": "workspace:*",
|
||||
"@startover/shared": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tsup": "^8.3.5",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @relink/application - Use cases and application services
|
||||
* @startover/application - Use cases and application services
|
||||
*
|
||||
* Orchestrates domain entities and defines application-level business rules.
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Result } from '@relink/shared';
|
||||
import type { Result } from '@startover/shared';
|
||||
|
||||
/**
|
||||
* Base use case interface. All application use cases implement this.
|
||||
|
||||
@@ -6,5 +6,5 @@ export default defineConfig({
|
||||
dts: true,
|
||||
clean: true,
|
||||
sourcemap: true,
|
||||
external: ['@relink/domain', '@relink/shared'],
|
||||
external: ['@startover/domain', '@startover/shared'],
|
||||
});
|
||||
|
||||
@@ -1 +1 @@
|
||||
DATABASE_URL="postgresql://relink:relink_dev@localhost:5432/relink_dev"
|
||||
DATABASE_URL="postgresql://startover:startover_dev@localhost:5432/startover_dev"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@relink/database",
|
||||
"name": "@startover/database",
|
||||
"version": "0.0.1",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// =============================================================================
|
||||
// Re:Link MVP - Prisma Schema
|
||||
// Startover MVP - Prisma Schema
|
||||
// =============================================================================
|
||||
// 설계 원칙:
|
||||
// - 내부 PK: BigInt @id @default(autoincrement())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @relink/database - Prisma client and database utilities
|
||||
* @startover/database - Prisma client and database utilities
|
||||
*/
|
||||
|
||||
export { createPrismaClient } from './client.js';
|
||||
|
||||
@@ -8,7 +8,7 @@ const SCHEMA_PATH = resolve(__dirname, '../prisma/schema.prisma');
|
||||
|
||||
const TEST_DATABASE_URL =
|
||||
process.env['DATABASE_TEST_URL'] ??
|
||||
'postgresql://relink:relink_test@localhost:5433/relink_test';
|
||||
'postgresql://startover:startover_test@localhost:5433/startover_test';
|
||||
|
||||
let testClient: PrismaClient | null = null;
|
||||
|
||||
@@ -26,10 +26,13 @@ export function getTestPrismaClient(): PrismaClient {
|
||||
}
|
||||
|
||||
export async function setupTestDatabase(): Promise<PrismaClient> {
|
||||
execSync(`DATABASE_URL="${TEST_DATABASE_URL}" npx prisma db push --schema="${SCHEMA_PATH}" --skip-generate --accept-data-loss`, {
|
||||
stdio: 'pipe',
|
||||
cwd: resolve(__dirname, '..'),
|
||||
});
|
||||
execSync(
|
||||
`DATABASE_URL="${TEST_DATABASE_URL}" npx prisma db push --schema="${SCHEMA_PATH}" --skip-generate --accept-data-loss`,
|
||||
{
|
||||
stdio: 'pipe',
|
||||
cwd: resolve(__dirname, '..'),
|
||||
},
|
||||
);
|
||||
|
||||
const client = getTestPrismaClient();
|
||||
await client.$connect();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@relink/domain",
|
||||
"name": "@startover/domain",
|
||||
"version": "0.0.1",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -19,7 +19,7 @@
|
||||
"clean": "rm -rf dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@relink/shared": "workspace:*"
|
||||
"@startover/shared": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tsup": "^8.3.5",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export interface CheckIdempotencyInput {
|
||||
readonly idempotencyKey: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export type ContractType = 'ACQUISITION' | 'DEMOLITION' | 'INTERIOR';
|
||||
|
||||
@@ -16,9 +16,7 @@ export interface ContractDraft {
|
||||
readonly policyVersionId: string;
|
||||
}
|
||||
|
||||
export function createContract(
|
||||
input: CreateContractInput,
|
||||
): Result<ContractDraft, AppError> {
|
||||
export function createContract(input: CreateContractInput): Result<ContractDraft, AppError> {
|
||||
// U021: 수락된 매칭만 계약 생성 가능
|
||||
if (input.matchRequestStatus !== 'ACCEPTED') {
|
||||
return failure(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export interface OpenDisputeInput {
|
||||
readonly currentEscrowStatus: string;
|
||||
@@ -17,9 +17,7 @@ const DISPUTABLE_CONTRACT_STATUSES = new Set(['ACTIVE', 'SIGNED']);
|
||||
const DISPUTABLE_ESCROW_STATUSES = new Set(['HOLDING', 'RELEASE_REVIEW']);
|
||||
|
||||
// U025: 분쟁이 열리면 에스크로는 DISPUTED로 전환
|
||||
export function openDispute(
|
||||
input: OpenDisputeInput,
|
||||
): Result<OpenDisputeResult, AppError> {
|
||||
export function openDispute(input: OpenDisputeInput): Result<OpenDisputeResult, AppError> {
|
||||
if (!DISPUTABLE_CONTRACT_STATUSES.has(input.contractStatus)) {
|
||||
return failure(
|
||||
appError('INVALID_CONTRACT_STATUS', '활성 상태의 계약만 분쟁을 열 수 있습니다.', {
|
||||
@@ -30,9 +28,13 @@ export function openDispute(
|
||||
|
||||
if (!DISPUTABLE_ESCROW_STATUSES.has(input.currentEscrowStatus)) {
|
||||
return failure(
|
||||
appError('INVALID_ESCROW_STATUS', 'HOLDING 또는 RELEASE_REVIEW 상태에서만 분쟁을 열 수 있습니다.', {
|
||||
currentEscrowStatus: input.currentEscrowStatus,
|
||||
}),
|
||||
appError(
|
||||
'INVALID_ESCROW_STATUS',
|
||||
'HOLDING 또는 RELEASE_REVIEW 상태에서만 분쟁을 열 수 있습니다.',
|
||||
{
|
||||
currentEscrowStatus: input.currentEscrowStatus,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export interface ReleaseEscrowInput {
|
||||
readonly currentEscrowStatus: string;
|
||||
@@ -10,9 +10,7 @@ export interface ReleaseEscrowResult {
|
||||
readonly escrowStatus: 'RELEASE_REVIEW';
|
||||
}
|
||||
|
||||
export function releaseEscrow(
|
||||
input: ReleaseEscrowInput,
|
||||
): Result<ReleaseEscrowResult, AppError> {
|
||||
export function releaseEscrow(input: ReleaseEscrowInput): Result<ReleaseEscrowResult, AppError> {
|
||||
// U023: HOLDING 상태에서만 정산 해제 가능
|
||||
if (input.currentEscrowStatus !== 'HOLDING') {
|
||||
return failure(
|
||||
@@ -31,9 +29,7 @@ export function releaseEscrow(
|
||||
|
||||
// U026: 분쟁이 열려있으면 정산 해제 차단
|
||||
if (input.hasOpenDispute) {
|
||||
return failure(
|
||||
appError('DISPUTE_OPEN', '열린 분쟁이 있어 정산 해제가 차단됩니다.'),
|
||||
);
|
||||
return failure(appError('DISPUTE_OPEN', '열린 분쟁이 있어 정산 해제가 차단됩니다.'));
|
||||
}
|
||||
|
||||
return success({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @relink/domain - Pure TypeScript domain layer
|
||||
* @startover/domain - Pure TypeScript domain layer
|
||||
*
|
||||
* Contains entities, value objects, and business rules.
|
||||
* No external dependencies allowed.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export type MatchRequestStatus =
|
||||
| 'OPEN'
|
||||
@@ -26,9 +26,13 @@ export function acceptMatchRequest(
|
||||
|
||||
if (!acceptableStatuses.includes(input.currentStatus)) {
|
||||
return failure(
|
||||
appError('INVALID_STATUS_TRANSITION', 'OPEN 또는 REVIEWING 상태의 요청만 수락할 수 있습니다.', {
|
||||
currentStatus: input.currentStatus,
|
||||
}),
|
||||
appError(
|
||||
'INVALID_STATUS_TRANSITION',
|
||||
'OPEN 또는 REVIEWING 상태의 요청만 수락할 수 있습니다.',
|
||||
{
|
||||
currentStatus: input.currentStatus,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export type MatchType = 'ACQUISITION' | 'DEMOLITION' | 'INTERIOR';
|
||||
export type MatchSourceType = 'USER_REQUEST' | 'OPERATOR_RECOMMENDATION' | 'SYSTEM_MATCH';
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
import { StoreLease, type StoreLeaseInput, type StoreLeaseProps } from './store-lease.js';
|
||||
import { StoreFacility, type StoreFacilityInput, type StoreFacilityProps } from './store-facility.js';
|
||||
import {
|
||||
StoreFacility,
|
||||
type StoreFacilityInput,
|
||||
type StoreFacilityProps,
|
||||
} from './store-facility.js';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Dependency interfaces (DIP)
|
||||
@@ -92,9 +96,7 @@ export function createStoreDraft(
|
||||
|
||||
if (fieldErrors.length === 1) {
|
||||
const err = fieldErrors[0]!;
|
||||
return failure(
|
||||
appError('VALIDATION_ERROR', err.message, { field: err.field }),
|
||||
);
|
||||
return failure(appError('VALIDATION_ERROR', err.message, { field: err.field }));
|
||||
}
|
||||
|
||||
if (fieldErrors.length > 1) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export interface PublishStoreInput {
|
||||
readonly currentReviewStatus: string;
|
||||
@@ -11,9 +11,7 @@ export interface PublishStoreResult {
|
||||
readonly policyVersionId: string;
|
||||
}
|
||||
|
||||
export function publishStore(
|
||||
input: PublishStoreInput,
|
||||
): Result<PublishStoreResult, AppError> {
|
||||
export function publishStore(input: PublishStoreInput): Result<PublishStoreResult, AppError> {
|
||||
if (input.currentReviewStatus !== 'APPROVED') {
|
||||
return failure(
|
||||
appError('NOT_APPROVED', '승인된 매장만 공개할 수 있습니다.', {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export type ReviewDecision = 'APPROVED' | 'REJECTED';
|
||||
export type ReviewableStatus = 'DRAFT' | 'SUBMITTED' | 'REVIEWING' | 'APPROVED' | 'REJECTED';
|
||||
@@ -17,9 +17,7 @@ export interface ReviewStoreResult {
|
||||
readonly memo?: string;
|
||||
}
|
||||
|
||||
export function reviewStore(
|
||||
input: ReviewStoreInput,
|
||||
): Result<ReviewStoreResult, AppError> {
|
||||
export function reviewStore(input: ReviewStoreInput): Result<ReviewStoreResult, AppError> {
|
||||
if (input.currentReviewStatus !== 'SUBMITTED') {
|
||||
return failure(
|
||||
appError('INVALID_STATUS_TRANSITION', 'SUBMITTED 상태의 매장만 검토할 수 있습니다.', {
|
||||
@@ -35,9 +33,7 @@ export function reviewStore(
|
||||
);
|
||||
}
|
||||
if (!input.memo?.trim()) {
|
||||
return failure(
|
||||
appError('VALIDATION_ERROR', '반려 시 메모는 필수입니다.', { field: 'memo' }),
|
||||
);
|
||||
return failure(appError('VALIDATION_ERROR', '반려 시 메모는 필수입니다.', { field: 'memo' }));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export interface StoreFacilityInput {
|
||||
readonly exclusiveAreaSqm: number;
|
||||
@@ -28,7 +28,9 @@ export const StoreFacility = {
|
||||
create(input: StoreFacilityInput): Result<StoreFacilityProps, AppError> {
|
||||
if (input.exclusiveAreaSqm <= 0) {
|
||||
return failure(
|
||||
appError('VALIDATION_ERROR', '전용면적은 0보다 커야 합니다.', { field: 'exclusiveAreaSqm' }),
|
||||
appError('VALIDATION_ERROR', '전용면적은 0보다 커야 합니다.', {
|
||||
field: 'exclusiveAreaSqm',
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export interface StoreLeaseInput {
|
||||
readonly depositAmount: number;
|
||||
@@ -42,7 +42,9 @@ export const StoreLease = {
|
||||
|
||||
if (input.maintenanceFeeAmount !== undefined && input.maintenanceFeeAmount < 0) {
|
||||
return failure(
|
||||
appError('VALIDATION_ERROR', '관리비는 0 이상이어야 합니다.', { field: 'maintenanceFeeAmount' }),
|
||||
appError('VALIDATION_ERROR', '관리비는 0 이상이어야 합니다.', {
|
||||
field: 'maintenanceFeeAmount',
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export type ChecklistItemStatus = 'PENDING' | 'CHECKED' | 'NOT_APPLICABLE';
|
||||
|
||||
@@ -25,9 +25,13 @@ export function advanceSubsidyToReady(
|
||||
// DOCUMENTS_PENDING 상태에서만 READY_TO_SUBMIT으로 전이 가능
|
||||
if (input.currentStatus !== 'DOCUMENTS_PENDING') {
|
||||
return failure(
|
||||
appError('INVALID_STATUS_TRANSITION', 'DOCUMENTS_PENDING 상태에서만 제출 준비로 전환할 수 있습니다.', {
|
||||
currentStatus: input.currentStatus,
|
||||
}),
|
||||
appError(
|
||||
'INVALID_STATUS_TRANSITION',
|
||||
'DOCUMENTS_PENDING 상태에서만 제출 준비로 전환할 수 있습니다.',
|
||||
{
|
||||
currentStatus: input.currentStatus,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export type SubsidyCaseStatus =
|
||||
| 'DRAFT'
|
||||
@@ -45,18 +45,20 @@ export function createSubsidyCase(
|
||||
|
||||
if (!isPublished && !isReviewable) {
|
||||
return failure(
|
||||
appError('STORE_NOT_ELIGIBLE', '공개되었거나 검토 가능한 매장만 지원금 케이스를 시작할 수 있습니다.', {
|
||||
reviewStatus: input.storeReviewStatus,
|
||||
publicationStatus: input.storePublicationStatus,
|
||||
}),
|
||||
appError(
|
||||
'STORE_NOT_ELIGIBLE',
|
||||
'공개되었거나 검토 가능한 매장만 지원금 케이스를 시작할 수 있습니다.',
|
||||
{
|
||||
reviewStatus: input.storeReviewStatus,
|
||||
publicationStatus: input.storePublicationStatus,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// U017: 체크리스트 항목이 없으면 케이스를 생성할 수 없다
|
||||
if (input.checklistItems.length === 0) {
|
||||
return failure(
|
||||
appError('EMPTY_CHECKLIST', '체크리스트 항목이 최소 1개 이상 있어야 합니다.'),
|
||||
);
|
||||
return failure(appError('EMPTY_CHECKLIST', '체크리스트 항목이 최소 1개 이상 있어야 합니다.'));
|
||||
}
|
||||
|
||||
return success({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export type SubsidyReviewDecision = 'APPROVED' | 'REJECTED';
|
||||
|
||||
@@ -22,9 +22,13 @@ export function reviewSubsidyCase(
|
||||
): Result<ReviewSubsidyCaseResult, AppError> {
|
||||
if (!REVIEWABLE_STATUSES.has(input.currentStatus)) {
|
||||
return failure(
|
||||
appError('INVALID_STATUS_TRANSITION', 'SUBMITTED 또는 REVIEWING 상태의 케이스만 검토할 수 있습니다.', {
|
||||
currentStatus: input.currentStatus,
|
||||
}),
|
||||
appError(
|
||||
'INVALID_STATUS_TRANSITION',
|
||||
'SUBMITTED 또는 REVIEWING 상태의 케이스만 검토할 수 있습니다.',
|
||||
{
|
||||
currentStatus: input.currentStatus,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
export type VendorCertificationStatus =
|
||||
| 'APPLIED'
|
||||
@@ -29,9 +29,7 @@ export function applyVendorCertification(
|
||||
input: ApplyVendorCertificationInput,
|
||||
): Result<VendorCertificationApplication, AppError> {
|
||||
if (!input.businessName.trim()) {
|
||||
return failure(
|
||||
appError('VALIDATION_ERROR', '업체명은 필수입니다.', { field: 'businessName' }),
|
||||
);
|
||||
return failure(appError('VALIDATION_ERROR', '업체명은 필수입니다.', { field: 'businessName' }));
|
||||
}
|
||||
|
||||
if (!input.contactName.trim()) {
|
||||
@@ -41,9 +39,7 @@ export function applyVendorCertification(
|
||||
}
|
||||
|
||||
if (!input.hasBusinessRegistration) {
|
||||
return failure(
|
||||
appError('MISSING_BUSINESS_REGISTRATION', '사업자등록증이 필요합니다.'),
|
||||
);
|
||||
return failure(appError('MISSING_BUSINESS_REGISTRATION', '사업자등록증이 필요합니다.'));
|
||||
}
|
||||
|
||||
if (input.coverageRegionCount === 0) {
|
||||
|
||||
+12
-5
@@ -1,4 +1,4 @@
|
||||
import { success, failure, appError, type Result, type AppError } from '@relink/shared';
|
||||
import { success, failure, appError, type Result, type AppError } from '@startover/shared';
|
||||
|
||||
import type { VendorCertificationStatus } from './apply-vendor-certification.js';
|
||||
|
||||
@@ -24,9 +24,13 @@ export function approveVendorCertification(
|
||||
): Result<ApproveVendorCertificationResult, AppError> {
|
||||
if (!REVIEWABLE_STATUSES.has(input.currentStatus)) {
|
||||
return failure(
|
||||
appError('INVALID_STATUS_TRANSITION', 'APPLIED 또는 REVIEWING 상태의 인증만 검토할 수 있습니다.', {
|
||||
currentStatus: input.currentStatus,
|
||||
}),
|
||||
appError(
|
||||
'INVALID_STATUS_TRANSITION',
|
||||
'APPLIED 또는 REVIEWING 상태의 인증만 검토할 수 있습니다.',
|
||||
{
|
||||
currentStatus: input.currentStatus,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -41,7 +45,10 @@ export function approveVendorCertification(
|
||||
// U018: 서비스 권역이 없으면 승인 불가
|
||||
if (input.coverageRegionCount === 0) {
|
||||
return failure(
|
||||
appError('MISSING_COVERAGE_REGION', '서비스 권역이 최소 1개 이상 있어야 승인할 수 있습니다.'),
|
||||
appError(
|
||||
'MISSING_COVERAGE_REGION',
|
||||
'서비스 권역이 최소 1개 이상 있어야 승인할 수 있습니다.',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@relink/infrastructure",
|
||||
"name": "@startover/infrastructure",
|
||||
"version": "0.0.1",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -20,10 +20,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^6.1.0",
|
||||
"@relink/application": "workspace:*",
|
||||
"@relink/database": "workspace:*",
|
||||
"@relink/domain": "workspace:*",
|
||||
"@relink/shared": "workspace:*"
|
||||
"@startover/application": "workspace:*",
|
||||
"@startover/database": "workspace:*",
|
||||
"@startover/domain": "workspace:*",
|
||||
"@startover/shared": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.2",
|
||||
|
||||
@@ -6,5 +6,5 @@ export default defineConfig({
|
||||
dts: true,
|
||||
clean: true,
|
||||
sourcemap: true,
|
||||
external: ['@relink/application', '@relink/domain', '@relink/shared'],
|
||||
external: ['@startover/application', '@startover/domain', '@startover/shared'],
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@relink/shared",
|
||||
"name": "@startover/shared",
|
||||
"version": "0.0.1",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const APP_NAME = 'Re:Link' as const;
|
||||
export const APP_NAME = 'Startover' as const;
|
||||
|
||||
export const PAGINATION = {
|
||||
DEFAULT_PAGE: 1,
|
||||
|
||||
@@ -25,7 +25,7 @@ export function expectFailure<T, E = AppError>(result: Result<T, E>): E {
|
||||
* Create a test database URL with a unique database name for isolation.
|
||||
*/
|
||||
export function createTestDatabaseUrl(baseUrl?: string): string {
|
||||
const base = baseUrl ?? 'postgresql://relink:relink_test@localhost:5433/relink_test';
|
||||
const base = baseUrl ?? 'postgresql://startover:startover_test@localhost:5433/startover_test';
|
||||
return base;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@relink/ui",
|
||||
"name": "@startover/ui",
|
||||
"version": "0.0.1",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @relink/ui - Shared UI components
|
||||
* @startover/ui - Shared UI components
|
||||
*/
|
||||
|
||||
export { Button } from './button.js';
|
||||
|
||||
Reference in New Issue
Block a user