Compare commits

...

14 Commits

Author SHA1 Message Date
72ec02306e 🚀 자동 배포 재테스트 - 2025-10-01 02:42:48
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
2025-10-01 02:42:48 +09:00
37c3b5af9d 🔧 웹훅 서버를 .cjs 확장자로 변경
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
2025-10-01 02:37:33 +09:00
1655006115 🔧 웹훅 서버를 ES 모듈 형식으로 수정
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
2025-10-01 02:36:00 +09:00
3cd7563c75 🧪 자동 배포 진단 테스트 - 2025-10-01 02:34:24
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
2025-10-01 02:34:24 +09:00
7a9a1fcbe8 로고삭제
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
2025-10-01 02:32:54 +09:00
6bd16ff68b 🎉 자동 배포 시스템 완성! - 2025-10-01 02:21:52
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
2025-10-01 02:21:52 +09:00
dc41178541 🔧 PM2 설정 파일을 CommonJS 형식으로 수정
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
2025-10-01 02:15:50 +09:00
0792e5d2bc 🧪 자동 배포 테스트 - 2025-10-01 02:14:48
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
2025-10-01 02:14:48 +09:00
cfd25ea1df 🔧 PM2 설정 파일을 .cjs 확장자로 변경
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
2025-10-01 02:07:49 +09:00
15603fad41 🔧 PM2 설정 파일을 ES 모듈 형식으로 수정
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
2025-10-01 02:06:41 +09:00
0a22b1bf04 🎨 코드 스타일 개선 및 Node.js 22 호환성 설정
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
2025-10-01 02:05:01 +09:00
0029f06774 🔧 Node.js 22 호환성 설정 추가
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
2025-10-01 02:03:46 +09:00
8edaa0e517 🧪 자동 배포 테스트 - 2025-10-01 02:00:24
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
2025-10-01 02:00:24 +09:00
a4bc12e1c4 🧪 자동 배포 테스트 - 2025-10-01 01:48:33
Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
2025-10-01 01:48:33 +09:00
11 changed files with 173 additions and 126 deletions

View File

@@ -1 +1 @@
{"id":"dev","timestamp":1759249355595}
{"id":"dev","timestamp":1759251838389}

View File

@@ -1 +1 @@
{"id":"dev","timestamp":1759249355595,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}
{"id":"dev","timestamp":1759251838389,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}

View File

@@ -1,5 +1,5 @@
{
"date": "2025-09-30T16:22:39.361Z",
"date": "2025-09-30T17:04:01.442Z",
"preset": "nitro-dev",
"framework": {
"name": "nuxt",
@@ -11,7 +11,7 @@
"dev": {
"pid": 77277,
"workerAddress": {
"socketPath": "/var/folders/qw/cvgxs3ls7x742rc9zgwbzkh80000gn/T/nitro-worker-77277-1-1-2519.sock"
"socketPath": "/var/folders/qw/cvgxs3ls7x742rc9zgwbzkh80000gn/T/nitro-worker-77277-3-3-8923.sock"
}
}
}

4
.nuxt/nuxt.d.ts vendored
View File

@@ -1,9 +1,9 @@
// Generated by nuxi
/// <reference types="@vueuse/nuxt" />
/// <reference types="@nuxtjs/device" />
/// <reference types="@nuxt/telemetry" />
/// <reference types="@pinia/nuxt" />
/// <reference types="@nuxt/devtools" />
/// <reference types="@nuxt/telemetry" />
/// <reference types="@vueuse/nuxt" />
/// <reference types="nuxt" />
/// <reference path="types/app-defaults.d.ts" />
/// <reference path="types/plugins.d.ts" />

View File

@@ -33,3 +33,9 @@ npm run dev
```sh
npm run build
```
# 🚀 자동 배포 테스트 - #오후
# 🚀 자동 배포 테스트 - 2025-10-01 02:00:14
# 🚀 자동 배포 테스트 - 2025-10-01 02:14:30
# 🎉 자동 배포 시스템 완성! - 2025-10-01 02:21:39
# 🧪 자동 배포 테스트 - 2025-10-01 02:34:11
# 🚀 자동 배포 재테스트 - 2025-10-01 02:42:33

24
ecosystem.config.cjs Normal file
View File

@@ -0,0 +1,24 @@
module.exports = {
apps: [
{
name: "music-admin",
script: ".output/server/index.mjs",
cwd: "/var/www/music/music-admin",
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: "1G",
env: {
NODE_ENV: "production",
PORT: 3000,
DATABASE_URL:
"postgresql://musicuser:Tjqjqhdks$321@localhost:5432/musicdb",
JWT_SECRET: "vTEq9OTvIFs3ZbDaszLRL/ZiAEXziemX1Wh1GIeb+DI=",
},
error_file: "/var/log/music-admin-error.log",
out_file: "/var/log/music-admin-out.log",
log_file: "/var/log/music-admin.log",
time: true,
},
],
};

View File

@@ -12,8 +12,8 @@ module.exports = {
NODE_ENV: "production",
PORT: 3000,
DATABASE_URL:
"postgresql://username:password@localhost:5432/music_admin?schema=public",
JWT_SECRET: "your-jwt-secret-key-here",
"postgresql://musicuser:Tjqjqhdks$321@localhost:5432/musicdb",
JWT_SECRET: "vTEq9OTvIFs3ZbDaszLRL/ZiAEXziemX1Wh1GIeb+DI=",
},
error_file: "/var/log/music-admin-error.log",
out_file: "/var/log/music-admin-out.log",

View File

@@ -1,19 +1,21 @@
import { fileURLToPath } from 'node:url'
import svgLoader from 'vite-svg-loader'
import vuetify from 'vite-plugin-vuetify'
import { fileURLToPath } from "node:url";
import svgLoader from "vite-svg-loader";
import vuetify from "vite-plugin-vuetify";
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
app: {
head: {
titleTemplate: '%s - NuxtJS Admin Template',
title: 'Sneat',
titleTemplate: "%s - NuxtJS Admin Template",
title: "Sneat",
link: [{
rel: 'icon',
type: 'image/x-icon',
href: '/favicon.ico',
}],
link: [
{
rel: "icon",
type: "image/x-icon",
href: "/favicon.ico",
},
],
},
},
@@ -22,29 +24,33 @@ export default defineNuxtConfig({
},
css: [
'@core/scss/template/index.scss',
'@styles/styles.scss',
'@/plugins/iconify/icons.css',
'@layouts/styles/index.scss',
"@core/scss/template/index.scss",
"@styles/styles.scss",
"@/plugins/iconify/icons.css",
"@layouts/styles/index.scss",
],
components: {
dirs: [{
path: '@/@core/components',
dirs: [
{
path: "@/@core/components",
pathPrefix: false,
}, {
path: '~/components/global',
},
{
path: "~/components/global",
global: true,
}, {
path: '~/components',
},
{
path: "~/components",
pathPrefix: false,
}],
},
],
},
plugins: ['@/plugins/vuetify/index.ts', '@/plugins/iconify/index.ts'],
plugins: ["@/plugins/vuetify/index.ts", "@/plugins/iconify/index.ts"],
imports: {
dirs: ['./@core/utils', './@core/composable/', './plugins/*/composables/*'],
dirs: ["./@core/utils", "./@core/composable/", "./plugins/*/composables/*"],
},
hooks: {},
@@ -53,17 +59,20 @@ export default defineNuxtConfig({
typedPages: true,
},
// Node.js 22 호환성 설정
compatibilityDate: "2024-10-01",
typescript: {
tsConfig: {
compilerOptions: {
paths: {
'@/*': ['../*'],
'@layouts/*': ['../@layouts/*'],
'@layouts': ['../@layouts'],
'@core/*': ['../@core/*'],
'@core': ['../@core'],
'@images/*': ['../assets/images/*'],
'@styles/*': ['../assets/styles/*'],
"@/*": ["../*"],
"@layouts/*": ["../@layouts/*"],
"@layouts": ["../@layouts"],
"@core/*": ["../@core/*"],
"@core": ["../@core"],
"@images/*": ["../assets/images/*"],
"@styles/*": ["../assets/styles/*"],
},
},
},
@@ -77,21 +86,24 @@ export default defineNuxtConfig({
vue: {
compilerOptions: {
isCustomElement: tag => tag === 'swiper-container' || tag === 'swiper-slide',
isCustomElement: (tag) =>
tag === "swiper-container" || tag === "swiper-slide",
},
},
vite: {
define: { 'process.env': {} },
define: { "process.env": {} },
resolve: {
alias: {
'@': fileURLToPath(new URL('.', import.meta.url)),
'@core': fileURLToPath(new URL('./@core', import.meta.url)),
'@layouts': fileURLToPath(new URL('./@layouts', import.meta.url)),
'@images': fileURLToPath(new URL('./assets/images/', import.meta.url)),
'@styles': fileURLToPath(new URL('./assets/styles/', import.meta.url)),
'@configured-variables': fileURLToPath(new URL('./assets/styles/variables/_template.scss', import.meta.url)),
"@": fileURLToPath(new URL(".", import.meta.url)),
"@core": fileURLToPath(new URL("./@core", import.meta.url)),
"@layouts": fileURLToPath(new URL("./@layouts", import.meta.url)),
"@images": fileURLToPath(new URL("./assets/images/", import.meta.url)),
"@styles": fileURLToPath(new URL("./assets/styles/", import.meta.url)),
"@configured-variables": fileURLToPath(
new URL("./assets/styles/variables/_template.scss", import.meta.url)
),
},
},
@@ -100,25 +112,23 @@ export default defineNuxtConfig({
},
optimizeDeps: {
exclude: ['vuetify'],
entries: [
'./**/*.vue',
],
exclude: ["vuetify"],
entries: ["./**/*.vue"],
},
plugins: [
svgLoader(),
vuetify({
styles: {
configFile: 'assets/styles/variables/_vuetify.scss',
configFile: "assets/styles/variables/_vuetify.scss",
},
}),
],
},
build: {
transpile: ['vuetify'],
transpile: ["vuetify"],
},
modules: ['@vueuse/nuxt', '@nuxtjs/device', '@pinia/nuxt'],
})
modules: ["@vueuse/nuxt", "@nuxtjs/device", "@pinia/nuxt"],
});

View File

@@ -1,87 +1,84 @@
<script setup lang="ts">
import AuthProvider from '@/views/pages/authentication/AuthProvider.vue'
import logo from '@images/logo.svg?raw'
import authV1BottomShape from '@images/svg/auth-v1-bottom-shape.svg?url'
import authV1TopShape from '@images/svg/auth-v1-top-shape.svg?url'
import AuthProvider from "@/views/pages/authentication/AuthProvider.vue";
import logo from "@images/logo.svg?raw";
import authV1BottomShape from "@images/svg/auth-v1-bottom-shape.svg?url";
import authV1TopShape from "@images/svg/auth-v1-top-shape.svg?url";
const form = ref({
user_id: '',
password: '',
user_id: "",
password: "",
remember: false,
})
});
const isPasswordVisible = ref(false)
const isLoading = ref(false)
const errorMessage = ref('')
const isPasswordVisible = ref(false);
const isLoading = ref(false);
const errorMessage = ref("");
const router = useRouter()
const router = useRouter();
// 컴포넌트 마운트 시 테스트
onMounted(() => {
})
onMounted(() => {});
const handleLogin = async () => {
if (!form.value.user_id || !form.value.password) {
errorMessage.value = '아이디와 비밀번호를 입력해주세요.'
return
errorMessage.value = "아이디와 비밀번호를 입력해주세요.";
return;
}
isLoading.value = true
errorMessage.value = ''
isLoading.value = true;
errorMessage.value = "";
try {
const response = await $fetch('/api/auth/login', {
method: 'POST',
const response = await $fetch("/api/auth/login", {
method: "POST",
body: {
user_id: form.value.user_id,
password: form.value.password
}
})
password: form.value.password,
},
});
if (response.success) {
// 토큰을 쿠키에 저장
const token = useCookie('auth-token', {
const token = useCookie("auth-token", {
maxAge: 60 * 60 * 24, // 24시간
secure: true,
sameSite: 'strict'
})
token.value = response.token
sameSite: "strict",
});
token.value = response.token;
// 사용자 정보를 쿠키에 저장
const user = useCookie('user-info', {
const user = useCookie("user-info", {
maxAge: 60 * 60 * 24,
secure: true,
sameSite: 'strict'
})
user.value = JSON.stringify(response.user)
sameSite: "strict",
});
user.value = JSON.stringify(response.user);
// 대시보드로 리다이렉션
await router.push('/dashboard')
await router.push("/dashboard");
} else {
errorMessage.value = response.message || '로그인에 실패했습니다.'
errorMessage.value = response.message || "로그인에 실패했습니다.";
}
} catch (error: any) {
console.error('Login error:', error)
console.error('Error details:', {
console.error("Login error:", error);
console.error("Error details:", {
statusCode: error.statusCode,
statusMessage: error.statusMessage,
data: error.data
})
errorMessage.value = error.data?.statusMessage || error.statusMessage || '로그인 중 오류가 발생했습니다.'
data: error.data,
});
errorMessage.value =
error.data?.statusMessage ||
error.statusMessage ||
"로그인 중 오류가 발생했습니다.";
} finally {
isLoading.value = false
}
isLoading.value = false;
}
};
definePageMeta({
layout: 'blank',
middleware: 'guest'
})
layout: "blank",
middleware: "guest",
});
</script>
<template>
@@ -106,38 +103,28 @@ definePageMeta({
:class="$vuetify.display.smAndUp ? 'pa-6' : 'pa-0'"
>
<VCardItem class="justify-center">
<NuxtLink
to="/"
class="app-logo"
>
<NuxtLink to="/" class="app-logo">
<!-- eslint-disable vue/no-v-html -->
<div
<!-- <div
class="d-flex"
v-html="logo"
/>
<h1 class="app-logo-title">
sneat
</h1>
</h1> -->
</NuxtLink>
</VCardItem>
<VCardText>
<h4 class="text-h4 mb-1">
음악 관리 시스템👋🏻
</h4>
<p class="mb-0">
계정에 로그인하여 관리 시스템을 시작하세요
</p>
<h4 class="text-h4 mb-1">음악 관리 시스템👋🏻</h4>
<p class="mb-0">계정에 로그인하여 관리 시스템을 시작하세요</p>
</VCardText>
<VCardText>
<VForm @submit.prevent="handleLogin">
<VRow>
<!-- 오류 메시지 -->
<VCol
v-if="errorMessage"
cols="12"
>
<VCol v-if="errorMessage" cols="12">
<VAlert
type="error"
variant="tonal"

View File

@@ -0,0 +1,20 @@
module.exports = {
apps: [
{
name: "music-admin-webhook",
script: "webhook-server.cjs",
cwd: "/var/www/music/music-admin",
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: "100M",
env: {
NODE_ENV: "production",
},
error_file: "/var/log/music-admin-webhook-error.log",
out_file: "/var/log/music-admin-webhook-out.log",
log_file: "/var/log/music-admin-webhook.log",
time: true,
},
],
};

View File

@@ -1,10 +1,10 @@
const express = require("express");
const { exec } = require("child_process");
const crypto = require("crypto");
import express from "express";
import { exec } from "child_process";
import crypto from "crypto";
const app = express();
const PORT = 9000;
const SECRET = "your-webhook-secret-key"; // 보안을 위해 변경하세요
const SECRET = "vTEq9OTvIFs3ZbDaszLRL/ZiAEXziemX1Wh1GIeb+DI="; // 보안을 위해 변경하세요
const PROJECT_DIR = "/var/www/music/music-admin";
// JSON 파싱 미들웨어