공용 상수 backend/constants.js로 추출

DIFFICULTIES(난이도 enum), PARTY_SIZE(1~6), SYMBOL_MASTER_LEVEL(2~99),
UPLOAD_FILE_SIZE_LIMIT(10MB)를 backend/constants.js로 추출하고 admin.js,
boss-crystal.js, symbol.js, BossDifficulty 모델에서 참조.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
caadiq 2026-04-21 20:31:43 +09:00
parent 1ee3f19f4f
commit b3907ec48f
5 changed files with 26 additions and 8 deletions

11
backend/constants.js Normal file
View file

@ -0,0 +1,11 @@
// 난이도 ENUM — 모델과 validation 에서 공용
export const DIFFICULTIES = ['easy', 'normal', 'hard', 'chaos', 'extreme'];
// 파티 인원수 범위
export const PARTY_SIZE = { min: 1, max: 6 };
// 심볼 마스터 레벨 범위
export const SYMBOL_MASTER_LEVEL = { min: 2, max: 99 };
// 업로드 파일 크기 상한 (10MB)
export const UPLOAD_FILE_SIZE_LIMIT = 10 * 1024 * 1024;

View file

@ -1,11 +1,12 @@
import { DataTypes } from 'sequelize';
import { sequelize } from '../../lib/db.js';
import { DIFFICULTIES } from '../../constants.js';
export const BossCrystalBossDifficulty = sequelize.define('BossCrystalBossDifficulty', {
id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
boss_id: { type: DataTypes.INTEGER, allowNull: false },
difficulty: {
type: DataTypes.ENUM('easy', 'normal', 'hard', 'chaos', 'extreme'),
type: DataTypes.ENUM(...DIFFICULTIES),
allowNull: false,
},
crystal_price: { type: DataTypes.BIGINT, allowNull: false },

View file

@ -6,11 +6,12 @@ import { getPublicUrl } from '../lib/s3.js';
import { sequelize } from '../lib/db.js';
import bossCrystalRouter from './admin/boss-crystal.js';
import symbolRouter from './admin/symbol.js';
import { UPLOAD_FILE_SIZE_LIMIT } from '../constants.js';
const router = Router();
const upload = multer({
storage: multer.memoryStorage(),
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB
limits: { fileSize: UPLOAD_FILE_SIZE_LIMIT },
});
// 관리자 인증 미들웨어

View file

@ -4,11 +4,12 @@ import { BossCrystalBoss, BossCrystalBossDifficulty } from '../../models/index.j
import { uploadBossImage, deleteBossImage } from '../../services/boss-crystal/image.js';
import { getPublicUrl } from '../../lib/s3.js';
import { sequelize } from '../../lib/db.js';
import { UPLOAD_FILE_SIZE_LIMIT, PARTY_SIZE, DIFFICULTIES } from '../../constants.js';
const router = Router();
const upload = multer({
storage: multer.memoryStorage(),
limits: { fileSize: 10 * 1024 * 1024 },
limits: { fileSize: UPLOAD_FILE_SIZE_LIMIT },
});
function serialize(boss) {
@ -39,9 +40,8 @@ function parseDifficulties(raw) {
if (!Array.isArray(arr) || arr.length === 0) {
throw new Error('하나 이상의 난이도가 필요합니다');
}
const valid = ['easy', 'normal', 'hard', 'chaos', 'extreme'];
return arr.map((d) => {
if (!valid.includes(d.difficulty)) throw new Error(`잘못된 난이도: ${d.difficulty}`);
if (!DIFFICULTIES.includes(d.difficulty)) throw new Error(`잘못된 난이도: ${d.difficulty}`);
const price = Number(d.crystal_price);
if (isNaN(price) || price <= 0) throw new Error(`잘못된 가격: ${d.difficulty}`);
return { difficulty: d.difficulty, crystal_price: price };
@ -50,7 +50,9 @@ function parseDifficulties(raw) {
function parseMaxParty(raw) {
const n = Number(raw);
if (isNaN(n) || n < 1 || n > 6) throw new Error('인원수는 1~6이어야 합니다');
if (isNaN(n) || n < PARTY_SIZE.min || n > PARTY_SIZE.max) {
throw new Error(`인원수는 ${PARTY_SIZE.min}~${PARTY_SIZE.max}이어야 합니다`);
}
return n;
}

View file

@ -4,11 +4,12 @@ import { Symbol, SymbolLevel } from '../../models/index.js';
import { convertAndUploadTo, deleteFromS3 } from '../../services/image.js';
import { getPublicUrl } from '../../lib/s3.js';
import { sequelize } from '../../lib/db.js';
import { UPLOAD_FILE_SIZE_LIMIT, SYMBOL_MASTER_LEVEL } from '../../constants.js';
const router = Router();
const upload = multer({
storage: multer.memoryStorage(),
limits: { fileSize: 10 * 1024 * 1024 },
limits: { fileSize: UPLOAD_FILE_SIZE_LIMIT },
});
const VALID_TYPES = ['아케인', '어센틱', '그랜드 어센틱'];
@ -70,7 +71,9 @@ function validateBasic({ type, region, max_level }) {
const r = String(region || '').trim();
if (!r) throw new Error('지역 이름을 입력해주세요');
const ml = Number(max_level);
if (!ml || ml < 2 || ml > 99) throw new Error('만렙은 2~99 사이여야 합니다');
if (!ml || ml < SYMBOL_MASTER_LEVEL.min || ml > SYMBOL_MASTER_LEVEL.max) {
throw new Error(`만렙은 ${SYMBOL_MASTER_LEVEL.min}~${SYMBOL_MASTER_LEVEL.max} 사이여야 합니다`);
}
return { type, region: r, max_level: ml };
}