Supabase on-prem 설정 및 마이그레이션 작업
This commit is contained in:
11
.env
11
.env
@@ -1 +1,12 @@
|
||||
CLOUD_DATABASE_URL=postgresql://postgres:6vJj04eYUCKKozYE@db.qnerebtvwwfobfzdoftx.supabase.co:5432/postgres
|
||||
ONPREM_DATABASE_URL=postgres://postgres:postgres@localhost:5432/postgres # On-Prem Postgres 기본
|
||||
|
||||
VITE_SUPABASE_URL=http://localhost:9000
|
||||
VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
|
||||
CLOUD_SUPABASE_URL=https://qnerebtvwwfobfzdoftx.supabase.co
|
||||
CLOUD_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InFuZXJlYnR2d3dmb2JmemRvZnR4Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDIwNTE0MzgsImV4cCI6MjA1NzYyNzQzOH0.Wm7h2DUhoQbeANuEM3wm2tz22ITrVEW8FizyLgIVmv8
|
||||
CLOUD_SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InFuZXJlYnR2d3dmb2JmemRvZnR4Iiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc0MjA1MTQzOCwiZXhwIjoyMDU3NjI3NDM4fQ.3G9UksB-kE-ChGQrz6YrSZqQSqvzYsnhvZyCnE99Ifc
|
||||
ONPREM_SUPABASE_URL=http://localhost:9000
|
||||
ONPREM_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
|
||||
ONPREM_SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
|
||||
VITE_DISABLE_LOVABLE_BANNER=true
|
||||
|
||||
116
WEB_SERVER_SETUP.md
Normal file
116
WEB_SERVER_SETUP.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# 웹 서버 설치 & 배포 가이드
|
||||
|
||||
## 1. Next.js 앱 단일 배포 (Ubuntu 22.04 + Nginx)
|
||||
|
||||
### 1.1 서버 준비
|
||||
```bash
|
||||
ssh your_user@your_server_ip
|
||||
# Node.js 18.x 설치
|
||||
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs build-essential
|
||||
```
|
||||
|
||||
### 1.2 코드 클론
|
||||
```bash
|
||||
cd /var/www
|
||||
git clone https://github.com/your-org/your-repo.git my-nextjs
|
||||
cd my-nextjs
|
||||
```
|
||||
|
||||
### 1.3 의존성 설치 & 빌드
|
||||
```bash
|
||||
# npm
|
||||
npm install
|
||||
npm run build
|
||||
# 또는 yarn
|
||||
# yarn
|
||||
yarn build
|
||||
```
|
||||
|
||||
### 1.4 PM2로 서비스 등록
|
||||
```bash
|
||||
sudo npm install -g pm2
|
||||
pm2 start npm --name "my-nextjs" -- start
|
||||
pm2 save
|
||||
pm2 startup # 출력된 명령 복사 후 실행
|
||||
```
|
||||
|
||||
### 1.5 Nginx 리버스 프록시 설정
|
||||
```nginx
|
||||
# /etc/nginx/sites-available/my-nextjs.conf
|
||||
server {
|
||||
listen 80;
|
||||
server_name your.domain.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
}
|
||||
```
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/my-nextjs.conf /etc/nginx/sites-enabled/
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
|
||||
## 2. 한 서버에 여러 사이트 호스팅
|
||||
|
||||
### 2.1 앱별 포트 분리
|
||||
- 디렉터리별 배치: `/var/www/site-alpha`, `/var/www/site-beta`
|
||||
- `package.json` start 스크립트에 포트 지정
|
||||
```jsonc
|
||||
"scripts": {
|
||||
"start": "next start -p 3000"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 PM2로 프로세스 분리
|
||||
```bash
|
||||
# site-alpha
|
||||
cd /var/www/site-alpha
|
||||
npm install
|
||||
npm run build
|
||||
pm2 start npm --name site-alpha -- start
|
||||
|
||||
# site-beta
|
||||
cd /var/www/site-beta
|
||||
npm install
|
||||
npm run build
|
||||
pm2 start npm --name site-beta -- start
|
||||
|
||||
pm2 save
|
||||
pm2 startup
|
||||
```
|
||||
|
||||
### 2.3 Nginx 도메인별 서버블록 설정
|
||||
```nginx
|
||||
# /etc/nginx/sites-available/site-alpha.conf
|
||||
server {
|
||||
listen 80;
|
||||
server_name alpha.example.com;
|
||||
location / { proxy_pass http://127.0.0.1:3000; }
|
||||
}
|
||||
|
||||
# /etc/nginx/sites-available/site-beta.conf
|
||||
server {
|
||||
listen 80;
|
||||
server_name beta.example.com;
|
||||
location / { proxy_pass http://127.0.0.1:3001; }
|
||||
}
|
||||
```
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/{site-alpha.conf,site-beta.conf} /etc/nginx/sites-enabled/
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### 2.4 (선택) SSL 자동 발급
|
||||
- Let's Encrypt + Certbot 설치
|
||||
```bash
|
||||
sudo apt-get install certbot python3-certbot-nginx
|
||||
sudo certbot --nginx -d alpha.example.com -d beta.example.com
|
||||
```
|
||||
145
package-lock.json
generated
145
package-lock.json
generated
@@ -42,14 +42,15 @@
|
||||
"@radix-ui/react-toggle": "^1.1.0",
|
||||
"@radix-ui/react-toggle-group": "^1.1.0",
|
||||
"@radix-ui/react-tooltip": "^1.1.4",
|
||||
"@supabase/supabase-js": "^2.49.1",
|
||||
"@supabase/supabase-js": "^2.49.4",
|
||||
"@tanstack/react-query": "^5.56.2",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"browserslist": "^4.24.4",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"date-fns": "^4.1.0",
|
||||
"date-fns": "^3.6.0",
|
||||
"dotenv": "^16.5.0",
|
||||
"embla-carousel-react": "^8.3.0",
|
||||
"input-otp": "^1.2.4",
|
||||
"lucide-react": "^0.462.0",
|
||||
@@ -92,7 +93,6 @@
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
@@ -138,9 +138,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.25.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.9.tgz",
|
||||
"integrity": "sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
|
||||
"integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
@@ -1136,7 +1136,6 @@
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
|
||||
"integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/set-array": "^1.2.1",
|
||||
@@ -1151,7 +1150,6 @@
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
@@ -1161,7 +1159,6 @@
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
||||
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
@@ -1171,14 +1168,12 @@
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.25",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
@@ -1189,7 +1184,6 @@
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "2.0.5",
|
||||
@@ -1203,7 +1197,6 @@
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
|
||||
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
@@ -1213,7 +1206,6 @@
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
|
||||
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodelib/fs.scandir": "2.1.5",
|
||||
@@ -1227,7 +1219,6 @@
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
|
||||
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
@@ -3001,9 +2992,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@supabase/auth-js": {
|
||||
"version": "2.68.0",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.68.0.tgz",
|
||||
"integrity": "sha512-odG7nb7aOmZPUXk6SwL2JchSsn36Ppx11i2yWMIc/meUO2B2HK9YwZHPK06utD9Ql9ke7JKDbwGin/8prHKxxQ==",
|
||||
"version": "2.69.1",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.69.1.tgz",
|
||||
"integrity": "sha512-FILtt5WjCNzmReeRLq5wRs3iShwmnWgBvxHfqapC/VoljJl+W8hDAyFmf1NVw3zH+ZjZ05AKxiKxVeb0HNWRMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@supabase/node-fetch": "^2.6.14"
|
||||
@@ -3031,9 +3022,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/postgrest-js": {
|
||||
"version": "1.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.19.2.tgz",
|
||||
"integrity": "sha512-MXRbk4wpwhWl9IN6rIY1mR8uZCCG4MZAEji942ve6nMwIqnBgBnZhZlON6zTTs6fgveMnoCILpZv1+K91jN+ow==",
|
||||
"version": "1.19.4",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.19.4.tgz",
|
||||
"integrity": "sha512-O4soKqKtZIW3olqmbXXbKugUtByD2jPa8kL2m2c1oozAO11uCcGrRhkZL0kVxjBLrXHE0mdSkFsMj7jDSfyNpw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@supabase/node-fetch": "^2.6.14"
|
||||
@@ -3061,15 +3052,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@supabase/supabase-js": {
|
||||
"version": "2.49.1",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.49.1.tgz",
|
||||
"integrity": "sha512-lKaptKQB5/juEF5+jzmBeZlz69MdHZuxf+0f50NwhL+IE//m4ZnOeWlsKRjjsM0fVayZiQKqLvYdBn0RLkhGiQ==",
|
||||
"version": "2.49.4",
|
||||
"resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.49.4.tgz",
|
||||
"integrity": "sha512-jUF0uRUmS8BKt37t01qaZ88H9yV1mbGYnqLeuFWLcdV+x1P4fl0yP9DGtaEhFPZcwSom7u16GkLEH9QJZOqOkw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@supabase/auth-js": "2.68.0",
|
||||
"@supabase/auth-js": "2.69.1",
|
||||
"@supabase/functions-js": "2.4.4",
|
||||
"@supabase/node-fetch": "2.6.15",
|
||||
"@supabase/postgrest-js": "1.19.2",
|
||||
"@supabase/postgrest-js": "1.19.4",
|
||||
"@supabase/realtime-js": "2.11.2",
|
||||
"@supabase/storage-js": "2.7.1"
|
||||
}
|
||||
@@ -3459,14 +3450,14 @@
|
||||
"version": "15.7.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
|
||||
"integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz",
|
||||
"integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
@@ -3477,7 +3468,7 @@
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==",
|
||||
"dev": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
@@ -3826,14 +3817,12 @@
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
|
||||
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
@@ -3847,7 +3836,6 @@
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
||||
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
@@ -3964,7 +3952,6 @@
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@@ -4000,7 +3987,6 @@
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fill-range": "^7.1.1"
|
||||
@@ -4064,7 +4050,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
@@ -4111,7 +4096,6 @@
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
@@ -4136,7 +4120,6 @@
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
@@ -4574,7 +4557,6 @@
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
||||
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
@@ -4604,7 +4586,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"cssesc": "bin/cssesc"
|
||||
@@ -4741,9 +4722,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
|
||||
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz",
|
||||
"integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -4799,14 +4780,12 @@
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/dlv": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dom-helpers": {
|
||||
@@ -4819,6 +4798,18 @@
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.5.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz",
|
||||
"integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/eastasianwidth": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||
@@ -5161,7 +5152,6 @@
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
||||
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
@@ -5178,7 +5168,6 @@
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
@@ -5205,7 +5194,6 @@
|
||||
"version": "1.17.1",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
|
||||
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"reusify": "^1.0.4"
|
||||
@@ -5237,7 +5225,6 @@
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
@@ -5356,7 +5343,6 @@
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
@@ -5371,7 +5357,6 @@
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -5390,7 +5375,6 @@
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
@@ -5411,7 +5395,6 @@
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.3"
|
||||
@@ -5424,7 +5407,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
@@ -5434,7 +5416,6 @@
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
@@ -5486,7 +5467,6 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
@@ -5579,7 +5559,6 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
@@ -5592,7 +5571,6 @@
|
||||
"version": "2.15.1",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
|
||||
"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hasown": "^2.0.2"
|
||||
@@ -5623,7 +5601,6 @@
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@@ -5642,7 +5619,6 @@
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
@@ -5655,7 +5631,6 @@
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
@@ -5683,7 +5658,6 @@
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
|
||||
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"@isaacs/cliui": "^8.0.2"
|
||||
@@ -5699,7 +5673,6 @@
|
||||
"version": "1.21.6",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
|
||||
"integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"jiti": "bin/jiti.js"
|
||||
@@ -5794,7 +5767,6 @@
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
|
||||
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
@@ -5807,7 +5779,6 @@
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/locate-path": {
|
||||
@@ -6317,7 +6288,6 @@
|
||||
"version": "10.4.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/lucide-react": {
|
||||
@@ -6342,7 +6312,6 @@
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
@@ -6352,7 +6321,6 @@
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"braces": "^3.0.3",
|
||||
@@ -6431,7 +6399,6 @@
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"any-promise": "^1.0.0",
|
||||
@@ -6440,10 +6407,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.7",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||
"dev": true,
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -6510,7 +6476,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@@ -6539,7 +6504,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
|
||||
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
@@ -6654,14 +6618,12 @@
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/path-scurry": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
|
||||
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"lru-cache": "^10.2.0",
|
||||
@@ -6690,7 +6652,6 @@
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
@@ -6703,7 +6664,6 @@
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@@ -6713,7 +6673,6 @@
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
|
||||
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
@@ -6737,7 +6696,6 @@
|
||||
"version": "8.4.47",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
|
||||
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -6766,7 +6724,6 @@
|
||||
"version": "15.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
||||
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.0.0",
|
||||
@@ -6784,7 +6741,6 @@
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
|
||||
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"camelcase-css": "^2.0.1"
|
||||
@@ -6804,7 +6760,6 @@
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
|
||||
"integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -6840,7 +6795,6 @@
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
|
||||
"integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -6866,7 +6820,6 @@
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
|
||||
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
@@ -6880,7 +6833,6 @@
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
@@ -6946,7 +6898,6 @@
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -7171,7 +7122,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pify": "^2.3.0"
|
||||
@@ -7195,7 +7145,6 @@
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
@@ -7246,7 +7195,6 @@
|
||||
"version": "1.22.8",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.13.0",
|
||||
@@ -7274,7 +7222,6 @@
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"iojs": ">=1.0.0",
|
||||
@@ -7427,7 +7374,6 @@
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -7564,7 +7510,6 @@
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@@ -7701,7 +7646,6 @@
|
||||
"version": "3.35.0",
|
||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
|
||||
"integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
@@ -7737,7 +7681,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -7760,7 +7703,6 @@
|
||||
"version": "3.4.17",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
|
||||
"integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
@@ -7840,7 +7782,6 @@
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
||||
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"any-promise": "^1.0.0"
|
||||
@@ -7850,7 +7791,6 @@
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
|
||||
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"thenify": ">= 3.1.0 < 4"
|
||||
@@ -7878,7 +7818,6 @@
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
@@ -7919,7 +7858,6 @@
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
||||
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
@@ -8141,9 +8079,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.10",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz",
|
||||
"integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==",
|
||||
"version": "5.4.18",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.18.tgz",
|
||||
"integrity": "sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -8391,7 +8329,6 @@
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz",
|
||||
"integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
|
||||
@@ -45,14 +45,15 @@
|
||||
"@radix-ui/react-toggle": "^1.1.0",
|
||||
"@radix-ui/react-toggle-group": "^1.1.0",
|
||||
"@radix-ui/react-tooltip": "^1.1.4",
|
||||
"@supabase/supabase-js": "^2.49.1",
|
||||
"@supabase/supabase-js": "^2.49.4",
|
||||
"@tanstack/react-query": "^5.56.2",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"browserslist": "^4.24.4",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"date-fns": "^4.1.0",
|
||||
"date-fns": "^3.6.0",
|
||||
"dotenv": "^16.5.0",
|
||||
"embla-carousel-react": "^8.3.0",
|
||||
"input-otp": "^1.2.4",
|
||||
"lucide-react": "^0.462.0",
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
|
||||
// This file is automatically generated. Do not edit it directly.
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
import type { Database } from './types';
|
||||
|
||||
const SUPABASE_URL = "https://qnerebtvwwfobfzdoftx.supabase.co";
|
||||
const SUPABASE_PUBLISHABLE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InFuZXJlYnR2d3dmb2JmemRvZnR4Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDIwNTE0MzgsImV4cCI6MjA1NzYyNzQzOH0.Wm7h2DUhoQbeANuEM3wm2tz22ITrVEW8FizyLgIVmv8";
|
||||
const SUPABASE_URL = (() => {
|
||||
const url = import.meta.env.VITE_SUPABASE_URL;
|
||||
if (!url) throw new Error("VITE_SUPABASE_URL is not set");
|
||||
return url;
|
||||
})();
|
||||
|
||||
const SUPABASE_PUBLISHABLE_KEY = (() => {
|
||||
const key = import.meta.env.VITE_SUPABASE_ANON_KEY;
|
||||
if (!key) throw new Error("VITE_SUPABASE_ANON_KEY is not set");
|
||||
return key;
|
||||
})();
|
||||
|
||||
// Import the supabase client like this:
|
||||
// import { supabase } from "@/integrations/supabase/client";
|
||||
|
||||
80
src/lib/fullMigrate.js
Executable file
80
src/lib/fullMigrate.js
Executable file
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env node
|
||||
// 스키마 및 데이터를 Supabase Cloud -> On-Prem(a11)으로 완전 복제
|
||||
import 'dotenv/config';
|
||||
import { execSync } from 'child_process';
|
||||
import { URL, fileURLToPath } from 'url';
|
||||
import path from 'path';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const CLOUD_DATABASE_URL = process.env.CLOUD_DATABASE_URL;
|
||||
const ONPREM_SSH_HOST = process.env.ONPREM_SSH_HOST || 'a11';
|
||||
const ONPREM_REMOTE_TMP_DIR = process.env.ONPREM_REMOTE_TMP_DIR || '/root';
|
||||
|
||||
if (!CLOUD_DATABASE_URL) {
|
||||
console.error('환경 변수 CLOUD_DATABASE_URL이 설정되지 않았습니다.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Cloud DB 비밀번호 추출
|
||||
const cloudUrlObj = new URL(CLOUD_DATABASE_URL);
|
||||
const CLOUD_DATABASE_PASSWORD = cloudUrlObj.password;
|
||||
if (!CLOUD_DATABASE_PASSWORD) {
|
||||
console.error('Cloud DB URL에서 비밀번호를 찾을 수 없습니다.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// 원격 Postgres 컨테이너 이름 조회
|
||||
console.log('원격 Postgres 컨테이너 조회 (ssh a11)...');
|
||||
let containerName = execSync(
|
||||
`ssh ${ONPREM_SSH_HOST} "docker ps --format '{{.Names}} {{.Image}}' | grep supabase/postgres | awk '{print \\$1}'"`,
|
||||
{ encoding: 'utf8' }
|
||||
).trim();
|
||||
if (!containerName) {
|
||||
console.error('원격 Postgres 컨테이너를 찾을 수 없습니다. docker ps 결과를 확인하세요.');
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`발견된 컨테이너: ${containerName}`);
|
||||
|
||||
// 1) 원격 a11에서 Cloud DB 스키마 덤프
|
||||
console.log('원격에서 Cloud DB 스키마 덤프 시작...');
|
||||
execSync(
|
||||
`ssh ${ONPREM_SSH_HOST} "docker run --rm --network host -e PGPASSWORD='${CLOUD_DATABASE_PASSWORD}' postgres:15 ` +
|
||||
`pg_dump --schema-only --no-owner --no-privileges ` +
|
||||
`-h ${cloudUrlObj.hostname} ` +
|
||||
`-p ${cloudUrlObj.port} ` +
|
||||
`-U ${cloudUrlObj.username} ` +
|
||||
`${cloudUrlObj.pathname.slice(1)} > ${ONPREM_REMOTE_TMP_DIR}/supabase_schema.sql"`,
|
||||
{ stdio: 'inherit' }
|
||||
);
|
||||
|
||||
// 2) 원격 a11에서 Cloud DB 데이터 덤프
|
||||
console.log('원격에서 Cloud DB 데이터 덤프 시작...');
|
||||
execSync(
|
||||
`ssh ${ONPREM_SSH_HOST} "docker run --rm --network host -e PGPASSWORD='${CLOUD_DATABASE_PASSWORD}' postgres:15 ` +
|
||||
`pg_dump --data-only --column-inserts --no-owner --no-privileges ` +
|
||||
`-h ${cloudUrlObj.hostname} ` +
|
||||
`-p ${cloudUrlObj.port} ` +
|
||||
`-U ${cloudUrlObj.username} ` +
|
||||
`${cloudUrlObj.pathname.slice(1)} > ${ONPREM_REMOTE_TMP_DIR}/supabase_data.sql"`,
|
||||
{ stdio: 'inherit' }
|
||||
);
|
||||
|
||||
// 4) 원격에 복원 (스키마)
|
||||
console.log('원격 스키마 복원...');
|
||||
execSync(
|
||||
`ssh ${ONPREM_SSH_HOST} "docker exec -i ${containerName} ` +
|
||||
`psql -U postgres -d postgres < ${ONPREM_REMOTE_TMP_DIR}/supabase_schema.sql"`,
|
||||
{ stdio: 'inherit' }
|
||||
);
|
||||
|
||||
// 5) 원격에 복원 (데이터)
|
||||
console.log('원격 데이터 복원...');
|
||||
execSync(
|
||||
`ssh ${ONPREM_SSH_HOST} "docker exec -i ${containerName} ` +
|
||||
`psql -U postgres -d postgres < ${ONPREM_REMOTE_TMP_DIR}/supabase_data.sql"`,
|
||||
{ stdio: 'inherit' }
|
||||
);
|
||||
|
||||
console.log('Cloud → On-Prem 전체 마이그레이션 완료.');
|
||||
@@ -15,39 +15,249 @@ if (!cloudUrl || !cloudKey || !onpremUrl || !onpremKey) {
|
||||
|
||||
const cloud = createClient(cloudUrl, cloudKey);
|
||||
const onprem = createClient(onpremUrl, onpremKey);
|
||||
const tables = ['users', 'accounts', 'transactions'];
|
||||
|
||||
async function migrateTable(table) {
|
||||
console.log(`Migrating table: ${table}`);
|
||||
const { data, error } = await cloud.from(table).select('*');
|
||||
// 마이그레이션할 테이블 목록
|
||||
const tables = ['transactions', 'budgets', '_tests'];
|
||||
|
||||
// 테이블 스키마 정의
|
||||
const tableSchemas = {
|
||||
transactions: `
|
||||
CREATE TABLE IF NOT EXISTS transactions (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id UUID REFERENCES auth.users(id) NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
amount NUMERIC NOT NULL,
|
||||
category TEXT NOT NULL,
|
||||
date TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
type TEXT NOT NULL,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Row Level Security 설정
|
||||
ALTER TABLE transactions ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- 사용자 정책 설정 (읽기)
|
||||
DROP POLICY IF EXISTS "사용자는 자신의 트랜잭션만 볼 수 있음" ON transactions;
|
||||
CREATE POLICY "사용자는 자신의 트랜잭션만 볼 수 있음"
|
||||
ON transactions FOR SELECT
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
-- 사용자 정책 설정 (쓰기)
|
||||
DROP POLICY IF EXISTS "사용자는 자신의 트랜잭션만 추가할 수 있음" ON transactions;
|
||||
CREATE POLICY "사용자는自己的 트랜잭션만 추가할 수 있음"
|
||||
ON transactions FOR INSERT
|
||||
WITH CHECK (auth.uid() = user_id);
|
||||
|
||||
-- 사용자 정책 설정 (업데이트)
|
||||
DROP POLICY IF EXISTS "사용자는 자신의 트랜잭션만 업데이트할 수 있음" ON transactions;
|
||||
CREATE POLICY "사용자는自己的 트랜잭션만 업데이트할 수 있음"
|
||||
ON transactions FOR UPDATE
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
-- 사용자 정책 설정 (삭제)
|
||||
DROP POLICY IF EXISTS "사용자는 자신의 트랜잭션만 삭제할 수 있음" ON transactions;
|
||||
CREATE POLICY "사용자는自己的 트랜잭션만 삭제할 수 있음"
|
||||
ON transactions FOR DELETE
|
||||
USING (auth.uid() = user_id);
|
||||
`,
|
||||
budgets: `
|
||||
CREATE TABLE IF NOT EXISTS budgets (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id UUID REFERENCES auth.users(id) NOT NULL,
|
||||
month INTEGER NOT NULL,
|
||||
year INTEGER NOT NULL,
|
||||
total_budget NUMERIC NOT NULL DEFAULT 0,
|
||||
categories JSONB NOT NULL DEFAULT '{}',
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
UNIQUE (user_id, month, year)
|
||||
);
|
||||
|
||||
-- Row Level Security 설정
|
||||
ALTER TABLE budgets ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- 사용자 정책 설정 (읽기)
|
||||
DROP POLICY IF EXISTS "사용자는自己的 예산만 볼 수 있음" ON budgets;
|
||||
CREATE POLICY "사용자는自己的 예산만 볼 수 있음"
|
||||
ON budgets FOR SELECT
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
-- 사용자 정책 설정 (쓰기)
|
||||
DROP POLICY IF EXISTS "사용자는自己的 예산만 추가할 수 있음" ON budgets;
|
||||
CREATE POLICY "사용자는自己的 예산만 추가할 수 있음"
|
||||
ON budgets FOR INSERT
|
||||
WITH CHECK (auth.uid() = user_id);
|
||||
|
||||
-- 사용자 정책 설정 (업데이트)
|
||||
DROP POLICY IF EXISTS "사용자는自己的 예산만 업데이트할 수 있음" ON budgets;
|
||||
CREATE POLICY "사용자는自己的 예산만 업데이트할 수 있음"
|
||||
ON budgets FOR UPDATE
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
-- 사용자 정책 설정 (삭제)
|
||||
DROP POLICY IF EXISTS "사용자는自己的 예산만 삭제할 수 있음" ON budgets;
|
||||
CREATE POLICY "사용자는自己的 예산만 삭제할 수 있음"
|
||||
ON budgets FOR DELETE
|
||||
USING (auth.uid() = user_id);
|
||||
`,
|
||||
_tests: `
|
||||
CREATE TABLE IF NOT EXISTS _tests (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
test_name TEXT NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- 모든 사용자가 접근 가능하도록 설정
|
||||
ALTER TABLE _tests ENABLE ROW LEVEL SECURITY;
|
||||
DROP POLICY IF EXISTS "모든 사용자가 테스트 테이블에 접근 가능" ON _tests;
|
||||
CREATE POLICY "모든 사용자가 테스트 테이블에 접근 가능"
|
||||
ON _tests FOR SELECT
|
||||
USING (true);
|
||||
`
|
||||
};
|
||||
|
||||
/**
|
||||
* 헬퍼 함수 생성
|
||||
*/
|
||||
async function createHelperFunctions() {
|
||||
console.log('헬퍼 함수 생성 중...');
|
||||
|
||||
// execute_sql 함수 생성
|
||||
const executeSqlSQL = `
|
||||
CREATE OR REPLACE FUNCTION execute_sql(sql_query TEXT)
|
||||
RETURNS VOID AS $$
|
||||
BEGIN
|
||||
EXECUTE sql_query;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
`;
|
||||
|
||||
const { error: execFnError } = await onprem.rpc('execute_sql', { sql_query: executeSqlSQL });
|
||||
if (execFnError) {
|
||||
console.error('execute_sql 함수 생성 실패:', execFnError);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('헬퍼 함수 생성 완료');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 테이블 생성
|
||||
*/
|
||||
async function createTable(tableName) {
|
||||
console.log(`테이블 생성 중: ${tableName}`);
|
||||
|
||||
if (!tableSchemas[tableName]) {
|
||||
console.warn(`${tableName} 테이블의 스키마 정보가 없습니다.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 테이블 생성 SQL 실행
|
||||
const { error } = await onprem.rpc('execute_sql', { sql_query: tableSchemas[tableName] });
|
||||
|
||||
if (error) {
|
||||
console.error(`${tableName} 테이블 생성 실패:`, error);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(`${tableName} 테이블 생성 완료`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`${tableName} 테이블 생성 중 오류:`, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 테이블 데이터 마이그레이션
|
||||
*/
|
||||
async function migrateTableData(tableName) {
|
||||
console.log(`테이블 데이터 마이그레이션 중: ${tableName}`);
|
||||
|
||||
try {
|
||||
// Cloud DB에서 데이터 가져오기
|
||||
const { data, error } = await cloud.from(tableName).select('*');
|
||||
|
||||
if (error) {
|
||||
if (error.code === '42P01') {
|
||||
console.warn(`Table ${table} not found in Cloud DB, skipping.`);
|
||||
return;
|
||||
console.warn(`Cloud DB에 ${tableName} 테이블이 없습니다. 건너뜁니다.`);
|
||||
return true;
|
||||
}
|
||||
console.error(`Error fetching ${table}:`, error);
|
||||
return;
|
||||
console.error(`Cloud DB에서 ${tableName} 데이터 가져오기 실패:`, error);
|
||||
return false;
|
||||
}
|
||||
if (!data.length) {
|
||||
console.log(`${table} has no data to migrate.`);
|
||||
return;
|
||||
|
||||
if (!data || data.length === 0) {
|
||||
console.log(`${tableName} 테이블에 마이그레이션할 데이터가 없습니다.`);
|
||||
return true;
|
||||
}
|
||||
const { error: insertError } = await onprem.from(table).upsert(data);
|
||||
|
||||
console.log(`${tableName} 테이블에서 ${data.length}개 행을 가져왔습니다.`);
|
||||
|
||||
// 데이터를 작은 배치로 나누어 삽입 (트랜잭션 삭제 안전성 고려)
|
||||
const batchSize = 100;
|
||||
for (let i = 0; i < data.length; i += batchSize) {
|
||||
const batch = data.slice(i, i + batchSize);
|
||||
const { error: insertError } = await onprem.from(tableName).upsert(batch);
|
||||
|
||||
if (insertError) {
|
||||
console.error(`Error inserting into ${table}:`, insertError);
|
||||
} else {
|
||||
console.log(`Migrated ${data.length} rows into ${table}`);
|
||||
console.error(`${tableName} 테이블에 데이터 삽입 실패:`, insertError);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(`${tableName} 테이블에 ${batch.length}개 행 삽입 완료 (${i + batch.length}/${data.length})`);
|
||||
|
||||
// 비동기 작업 사이에 짧은 지연 추가 (UI 스레드 차단 방지)
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
console.log(`${tableName} 테이블 데이터 마이그레이션 완료`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`${tableName} 테이블 데이터 마이그레이션 중 오류:`, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 메인 마이그레이션 함수
|
||||
*/
|
||||
async function main() {
|
||||
for (const table of tables) {
|
||||
await migrateTable(table);
|
||||
}
|
||||
console.log('Migration complete.');
|
||||
try {
|
||||
console.log('Supabase Cloud → On-Prem 마이그레이션 시작');
|
||||
|
||||
// 헬퍼 함수 생성
|
||||
const helperCreated = await createHelperFunctions();
|
||||
if (!helperCreated) {
|
||||
console.warn('헬퍼 함수 생성에 실패했습니다. 계속 진행합니다.');
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error('Migration failed:', err);
|
||||
// 각 테이블에 대해 스키마 생성 및 데이터 마이그레이션 수행
|
||||
for (const tableName of tables) {
|
||||
// 테이블 생성
|
||||
const tableCreated = await createTable(tableName);
|
||||
if (!tableCreated) {
|
||||
console.warn(`${tableName} 테이블 생성에 실패했습니다. 데이터 마이그레이션을 건너뜁니다.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 데이터 마이그레이션
|
||||
const dataMigrated = await migrateTableData(tableName);
|
||||
if (!dataMigrated) {
|
||||
console.warn(`${tableName} 테이블 데이터 마이그레이션에 실패했습니다.`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Supabase Cloud → On-Prem 마이그레이션 완료');
|
||||
} catch (error) {
|
||||
console.error('마이그레이션 중 오류 발생:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 마이그레이션 실행
|
||||
main();
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
|
||||
// Supabase Cloud URL과 anon key 설정
|
||||
export const getSupabaseUrl = () => {
|
||||
return "https://qnerebtvwwfobfzdoftx.supabase.co";
|
||||
const url = import.meta.env.VITE_SUPABASE_URL;
|
||||
if (!url) throw new Error("VITE_SUPABASE_URL is not set");
|
||||
return url;
|
||||
};
|
||||
|
||||
export const getSupabaseKey = () => {
|
||||
return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InFuZXJlYnR2d3dmb2JmemRvZnR4Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDIwNTE0MzgsImV4cCI6MjA1NzYyNzQzOH0.Wm7h2DUhoQbeANuEM3wm2tz22ITrVEW8FizyLgIVmv8";
|
||||
const key = import.meta.env.VITE_SUPABASE_ANON_KEY;
|
||||
if (!key) throw new Error("VITE_SUPABASE_ANON_KEY is not set");
|
||||
return key;
|
||||
};
|
||||
|
||||
// Supabase 키 유효성 검사 - Cloud 환경에서는 항상 유효함
|
||||
export const isValidSupabaseKey = () => {
|
||||
return true;
|
||||
return Boolean(import.meta.env.VITE_SUPABASE_ANON_KEY);
|
||||
};
|
||||
|
||||
// 다음 함수들은 Cloud 환경에서는 필요 없지만 호환성을 위해 유지
|
||||
|
||||
1
supabase/.temp/cli-latest
Normal file
1
supabase/.temp/cli-latest
Normal file
@@ -0,0 +1 @@
|
||||
v2.22.6
|
||||
0
supabase_cloud_data.sql
Normal file
0
supabase_cloud_data.sql
Normal file
0
supabase_schema.sql
Normal file
0
supabase_schema.sql
Normal file
@@ -1,4 +1,4 @@
|
||||
import { defineConfig } from "vite";
|
||||
import { defineConfig } from 'vite';
|
||||
import react from "@vitejs/plugin-react-swc";
|
||||
import path from "path";
|
||||
import { componentTagger } from "lovable-tagger";
|
||||
@@ -6,7 +6,7 @@ import { componentTagger } from "lovable-tagger";
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ mode }) => ({
|
||||
server: {
|
||||
host: "::",
|
||||
host: "0.0.0.0",
|
||||
port: 8080,
|
||||
},
|
||||
plugins: [
|
||||
|
||||
Reference in New Issue
Block a user