32 Commits
main ... manage

Author SHA1 Message Date
b10063a93f fix: hide zero shared allocation row in construction breakdown 2026-05-07 08:54:43 +09:00
930dc2d1de style: tone down management category selected state 2026-05-06 09:06:14 +09:00
039bc4c5a3 style: improve visibility of selected management category item 2026-05-06 09:03:39 +09:00
d7a322a6ca fix: hide project and transaction sections for shared allocation account modal 2026-05-04 17:41:28 +09:00
588d787d02 fix: disable project row click in account detail modal 2026-05-04 17:23:41 +09:00
5f4834de10 fix: aggregate allocation formula lines by year 2026-05-04 16:41:11 +09:00
bf7bf93179 feat: show shared allocation formula inline in shared project row 2026-05-04 16:36:54 +09:00
686ea738da chore: remove project amount detail-view button 2026-05-04 16:33:04 +09:00
f636d1c7f8 fix: remove duplicated account amount block in account detail modal 2026-05-04 16:31:04 +09:00
0bed3c489b fix: show allocation formula only for shared allocation group 2026-05-04 16:29:22 +09:00
d75a57cc97 Refine lifecycle detail modal totals and project detail popup layout 2026-05-04 14:32:15 +09:00
df25f04119 Always show allocation formula section for labor/admin detail modal 2026-05-04 14:19:34 +09:00
79b3fd646e Make lifecycle allocation formulas account-specific 2026-05-04 14:10:54 +09:00
b2134d7515 Refresh lifecycle breakdown panel after allocation mode change 2026-05-04 14:07:40 +09:00
9891ea0a32 Adjust lifecycle allocation UI and account-level shared cost breakdown 2026-05-04 13:55:41 +09:00
21ad66c8b4 feat(lifecycle): add selectable common allocation mode (expense/income ratio) 2026-05-04 10:21:21 +09:00
68eabcc228 fix(management): include linked non-management project codes in applied admin expense 2026-05-04 10:15:56 +09:00
fa8eaeef25 fix(management): resolve management overview SQL placeholder error 2026-05-04 10:12:46 +09:00
61e580b74a fix(management): classify applied/common admin expense by construction linkage 2026-05-04 10:10:54 +09:00
b3207b5ce0 fix(management): compute applied/common admin expense by monthly active project distribution 2026-05-04 10:05:38 +09:00
eab0a5bb3f feat(management): add yearly project-applied vs common admin expense split 2026-05-04 10:01:49 +09:00
c13f596453 feat(lifecycle): apply monthly shared allocation from project start month 2026-05-04 09:53:09 +09:00
7882d0cd05 feat(lifecycle): split unallocated sales/design cost into shared pool 2026-05-04 09:41:20 +09:00
4827d953d1 fix(lifecycle): classify account 724 labor cost as construction cost 2026-05-04 09:19:38 +09:00
868661426f feat(manage): refine lifecycle flow UI and direct/shared cost breakdown 2026-04-23 14:31:41 +09:00
90042a003a docs: rewrite manage branch README with detailed setup and lifecycle flow 2026-04-22 17:22:44 +09:00
bc611c3ff7 feat: improve lifecycle allocation popup flow and project cost visibility 2026-04-22 17:19:26 +09:00
6e8f606591 feat: update manage dashboard flows 2026-04-17 10:32:12 +09:00
01a6e197ce feat: add manage dashboard preview 2026-04-07 10:56:03 +09:00
d4498c356f Update PTC_ISSUES_LIST.md with dashboard and deployment features 2026-03-25 11:49:46 +09:00
47cd2bf5b2 Full dashboard implementation: API, UI, and sharing scripts 2026-03-25 11:35:54 +09:00
28709a3457 Update index.html with dashboard features from dashboard_preview.html 2026-03-25 11:35:28 +09:00
11 changed files with 18613 additions and 165 deletions

5130
PTC/dashboard_preview.html Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@
- [ ] UI 렌더링 완성 (PTC 데이터 선택 시 테이블 공백 문제 해결)
- [ ] PTC 고유 계정 체계(7xx, 8xx, 513) 분류 로직 고도화
- [ ] PTC 전용 실행 예산 보고서 양식 개발 및 출력 기능
- [ ] PTC 대시보드 고도화 (순유입/유출 잔액 합계 및 시각화 개선)
- [x] PTC 대시보드 고도화 (순유입/유출 잔액 합계 및 시각화 개선)
---
@@ -48,3 +48,15 @@
- PTC 순유입 및 유출 잔액 합계 산출 로직 개선
- 대시보드 상의 차트 및 요약 테이블에 실시간 데이터 반영
- 데이터 동기화 및 탭 전환 최적화
---
## 6. [PTC::Dashboard] 통합 대시보드 시각화 및 재무 상태 분석 기능 구현
**설명**: 프로젝트 전반의 재무 현황을 시각화하고, 공법 및 금액별로 자동 분류하여 상태를 진단하는 통합 대시보드 기능을 구현합니다.
### 주요 작업
- [x] 공법(Method) 및 제품군(Family)별 프로젝트 자동 분류 로직 구현
- [x] 입금/출금 기반 수익률(Margin Rate) 및 진행률(Progress Rate) 연동 시각화
- [x] 금액별 버킷(Buckets) 및 재무 상태(Status Bands: 정상, 선투입, 회수지연, 위험) 자동 판별 로직 적용
- [x] API 서버(`/api/dashboard-prototype`) 및 프론트엔드 반응형 레이아웃 최적화
- [x] Windows 사내망 공유용 PowerShell 자동화 스크립트(`start_ptc_share.ps1`) 개발

263
README.md
View File

@@ -1,25 +1,258 @@
# PTC Project Management System
# PTC Manage (manage 브랜치)
이 프로젝트는 `PTC(2023-2026.02).xlsx` 데이터를 기반으로 한 프로젝트 관리 및 집행 분석 시스템입니다.
PTC 실행 원장 기반의 사내 프로젝트 관리/원가 분석 웹앱입니다.
`manage` 브랜치는 **프로젝트 관리 + 프로젝트 생애주기 원가 + 관리 대시보드** 운영 기능을 중심으로 유지됩니다.
## 주요 구성
- 기본 실행 주소: `http://localhost:4000/PTC/`
- 관리 실험 화면: `http://localhost:4000/PTC-lab-manage/`
- 단일 Python 서버가 API + 프론트를 함께 제공합니다.
- **Frontend (`/PTC/index.html`)**: React 기반의 단일 페이지 애플리케이션 (SPA)으로 프로젝트 대시보드 및 예산 관리를 담당합니다.
- **Backend (`/server/ptc_api_server.py`)**: Python 기반의 API 서버로 SQLite DB를 통해 데이터를 제공합니다.
- **Database (`/db/`)**: PostgreSQL 스키마 및 로컬 SQLite DB 관련 스크립트가 포함되어 있습니다.
- **Windows Scripts (`/windows/`)**: 로컬 환경에서 서버를 실행하고 공유하기 위한 배치 파일들입니다.
## 1. 현재 브랜치 핵심 기능
## 실행 방법
- 프로젝트 마스터 관리
- 프로젝트명/구분/공법/기간/메모 수정
- 프로젝트 간 연관 코드 관리
- 프로젝트 관리 탭에서는 거래내역 표를 제거하고, 거래는 `거래내역확인` 탭에서만 조회
- 프로젝트 생애주기 원가
- 연관 프로젝트(영업/설계/시공) 흐름을 3열 고정 레이아웃으로 조회
- 영업/설계 카드 클릭 시 배분 팝업에서 `해당프로젝트/총프로젝트` 저장
- 배분값 저장/삭제 후 반영 매출 자동 재계산
- 시공 컬럼에 공정률 표시(숫자 강조)
- 영업/설계 연결 프로젝트가 없을 때 톤다운된 비어있음 상태 표시
- 계정별 금액/항목 목록을 박스형 카드가 아닌 라인형 리스트로 표시
- 프로젝트 생애주기 원가 분해
- `시공비/인건비/관리비` 상세 모달 제공
- 인건비/관리비에 `직접분/공통배분분` 분리 표시
- 현재는 연결 프로젝트 비용을 직접분으로 처리(공통배분분은 향후 공통배분 기능 추가 시 반영)
- 배분 로직
- 예: 설계 프로젝트에 `1/3` 저장 시, 생애주기 화면 반영금액은 해당 프로젝트 금액의 `1/3`
- 저장은 `project_lifecycle_allocations` 테이블에 영구 반영
- 계정 표시 정책(프로젝트 화면)
- `기타 수지/자산` 계정(예: `194 전도금`)은 프로젝트/생애주기 집계 및 상세에서 숨김
- 계정 재매핑
- 프로젝트별 계정코드 재분류(허용 계정 범위 검증 포함)
## 2. 기술 스택
- Backend: Python 3 표준 라이브러리 (`http.server`, `sqlite3` 등)
- DB: SQLite (`db/ptc_local.sqlite3`)
- Frontend: 정적 HTML 대시보드 페이지 (`PTC/*.html`)
- 운영 보조: Windows 배치 스크립트 (`windows/*.bat`)
별도 백엔드 프레임워크(FastAPI/Flask) 없이 단일 서버 스크립트로 동작합니다.
## 3. 디렉터리 구조
```text
/home/hyein/project
├─ PTC/
│ ├─ index.html # 메인 화면
│ ├─ dashboard_preview.html # 실험 대시보드
│ ├─ admin_dashboard.html # 관리자 화면
│ └─ management_dashboard_preview.html # 관리/생애주기 핵심 화면
├─ server/
│ ├─ ptc_api_server.py # API + 프론트 서빙 서버
│ └─ ptc_source_path.txt # 사용할 원본 xlsx 경로 설정값
├─ db/
│ ├─ ptc_local.sqlite3 # 로컬 DB 파일
│ ├─ import_ptc_xlsx.py # xlsx -> staging csv 변환 스크립트
│ ├─ schema.sql / seed.sql # (별도 Postgres 실험용)
│ └─ README.md
├─ windows/
│ ├─ start_ptc_share.bat # 사내 공유 실행
│ ├─ set_ptc_source.bat # 원본 xlsx 선택/저장
│ └─ README.txt
└─ README.md
```
## 4. 빠른 시작
### 4.1 요구사항
- Python 3.10+ 권장
- 로컬 파일 접근 권한
- 원본 엑셀 파일 존재
- 기본: `PTC 입출금내역(2015~).xlsx`
### 4.2 서버 실행
프로젝트 루트에서:
### 1. 서버 실행
```bash
python3 server/ptc_api_server.py
```
서버는 기본적으로 4000 포트에서 실행되며, API와 프론트엔드(`/PTC/`)를 함께 제공합니다.
### 2. 프론트엔드 접속
브라우저에서 `http://localhost:4000/PTC/` 로 접속합니다.
필요하면 `index.html``apiBase` 쿼리 파라미터로 API 주소를 덮어쓸 수 있습니다.
실행 후:
## 데이터 업데이트
`db/import_ptc_xlsx.py` 스크립트를 사용하여 엑셀 데이터를 DB로 변환할 수 있습니다. 자세한 내용은 `db/README.md`를 참조하세요.
- API Health: `http://localhost:4000/api/health`
- 메인 UI: `http://localhost:4000/PTC/`
- 관리 UI: `http://localhost:4000/PTC-lab-manage/`
## 5. 데이터 로딩 방식
서버 시작 시 `init_db()`가 아래 순서로 동작합니다.
1. SQLite 스키마/인덱스/마이그레이션 보정
2. 원본 xlsx 경로 확인
- `server/ptc_source_path.txt` 값이 있으면 우선 사용
- 없으면 기본 파일(`PTC 입출금내역(2015~).xlsx`) 사용
3. `xlsx_source_signature(경로+mtime)` 비교
4. 원본이 바뀐 경우 `ptc_transactions` 전체 재적재
5. `project_master` 초기값(프로젝트코드 기준) 자동 보강
즉, 원본 파일 갱신 시 서버 재시작만으로 로컬 DB가 다시 동기화됩니다.
## 6. 화면별 URL
- `/PTC/` : 메인 대시보드
- `/PTC-lab/` : 대시보드 실험 화면
- `/PTC-admin/` : 관리자 화면
- `/PTC-lab-manage/` : 프로젝트 관리/생애주기 원가 화면
## 7. 프로젝트 생애주기 배분(중요)
### 7.1 사용 방법
1. `/PTC-lab-manage/` 접속
2. 대상 시공 프로젝트 선택
3. `관련 프로젝트 흐름`에서 영업/설계 카드 클릭
4. 팝업에서 `해당 프로젝트수``총 프로젝트수` 입력
- 예: `1 / 3`
5. 저장 시 반영금액 = 원금액 × `(1/3)`
### 7.2 저장/삭제 API
- 저장: `POST /api/lifecycle-allocation/upsert`
- 삭제: `POST /api/lifecycle-allocation/delete`
저장 데이터는 `project_lifecycle_allocations` 테이블에 유지되며, 페이지 재진입 후에도 반영됩니다.
### 7.3 관련 프로젝트 흐름(영업/설계/시공)
- 컬럼은 항상 `영업/설계/시공` 3개를 고정 표시합니다.
- 영업/설계가 없으면 `연결 프로젝트 없음`을 톤다운 텍스트로 보여줍니다.
- 시공 컬럼은 현재 프로젝트 기준으로 표시되며, 공정률(`x.x%`)이 헤더에 노출됩니다.
- 영업/설계만 배분 팝업 클릭 대상이고, 시공은 읽기 전용입니다.
### 7.4 프로젝트 생애주기 원가(분해 기준)
- 상단 요약: `총 입금 / 총 지출 / 총 수익 / 수익률`.
- 하단 분해: `시공비 / 인건비 / 관리비` 클릭 시 상세 모달.
- 인건비/관리비 상세는 `직접분 / 공통배분분`을 함께 보여줍니다.
- 현재 구현 기준:
- 연결 프로젝트에 귀속된 비용은 직접분으로 집계
- 공통배분분은 0원(향후 공통비 배분 로직 추가 예정)
## 8. 프로젝트 화면 숨김 계정 정책
프로젝트/생애주기 관점에서는 특정 계정을 집계에서 완전히 제외합니다.
- 기준 상수: `PROJECT_VIEW_EXCLUDED_ACCOUNT_CODES`
- 포함 예시: `194(전도금)`, `191(출자금)`, `259(선수금)`, `901~904`, `961`, `962`, `999`
의도:
- 프로젝트 실적(입금/지출/수익) 화면에 불필요한 자산/영업외 항목 노출 방지
- 카드 합계와 상세 내역의 해석 일관성 유지
## 9. 주요 DB 테이블
- `ptc_transactions`
- 원본 거래 행(정규화 포함) 저장
- `project_master`
- 프로젝트 마스터(명칭/구분/공법/기간/메모)
- `project_relations`
- 프로젝트 간 연관 관계
- `project_lifecycle_allocations`
- 생애주기 배분값(`분자/분모`) 저장
- `project_budget_lines`, `project_budget_account_lines`
- 프로젝트 예산 라인
- `project_progress`, `project_pile_progress_entries`
- 공정/말뚝 진행 데이터
- `meta`
- 원본 시그니처 등 시스템 메타
## 10. 주요 API
### 10.1 GET
- `GET /api/health` : 서버/적재건수
- `GET /api/summary` : 전체 요약
- `GET /api/project-types` : 프로젝트 구분 목록
- `GET /api/projects` : 프로젝트 목록/검색
- `GET /api/project-detail` : 프로젝트 상세
- `GET /api/project-budget-actual-detail` : 예산 vs 실적 상세
- `GET /api/lifecycle-account-detail` : 생애주기 계정 상세
- `GET /api/management-overview` : 관리 화면 요약
- `GET /api/management-overview-accounts` : 관리 화면 계정집계
- `GET /api/transactions` : 원장 행 미리보기
`GET /api/project-detail` 응답의 `related_projects` 항목에는 시공 공정률(`progress_rate`)이 포함됩니다.
### 10.2 POST
- `POST /api/project-master/upsert` : 프로젝트 마스터 저장
- `POST /api/lifecycle-allocation/upsert` : 생애주기 배분 저장
- `POST /api/lifecycle-allocation/delete` : 생애주기 배분 삭제
- `POST /api/project-master/batch-update-method` : 공법 일괄 업데이트
- `POST /api/project-account-remap` : 프로젝트 계정 재매핑
- `POST /api/project-account-remap-rows` : 행 단위 재매핑
- `POST /api/project-budget/upsert` : 프로젝트 예산 저장
- `POST /api/project-pile-progress/upsert` : 말뚝 진행 저장
## 11. 운영 스크립트 (Windows)
`windows/README.txt` 기준 요약:
- `set_ptc_source.bat` : 사용할 원본 `.xlsx` 선택 + 서버 재시작
- `start_ptc_share.bat` : WSL 서버 시작/방화벽/공유 주소 안내
- `check_ptc_share.bat` : 공유 상태 확인
- `stop_ptc_share.bat` : 공유 중지
- `install_ptc_share_autostart.bat` : 로그인 시 자동 실행 등록
## 12. 트러블슈팅
### 12.1 화면에 "PTC 화면을 준비하는 중입니다"만 보일 때
- 프론트 스크립트 에러 가능성이 큽니다.
- 최근 이슈 예: nullish 연산자(`??`) + 논리연산자 혼용 시 괄호 누락
- 대응:
1. 브라우저 새로고침(강력 새로고침)
2. 서버 재시작
3. 콘솔 에러 라인 확인 후 `PTC/management_dashboard_preview.html` 수정
### 12.2 배분값 저장 후 다시 1/1로 보일 때
- 저장 API 호출 실패 또는 validation 실패 가능성
- 확인:
- `allocation_numerator <= allocation_denominator`
- `allocation_denominator > 0`
- `base_project_code`, `source_project_code` 누락 여부
### 12.3 카드 금액과 상세 내역이 다르게 느껴질 때
- 프로젝트 화면에서는 숨김 계정 정책이 적용됩니다.
- `기타 수지/자산` 계정은 의도적으로 상세/집계에서 제외됩니다.
### 12.4 코드 수정 후 화면이 이전 동작으로 보일 때
- 서버 프로세스가 이전 코드를 계속 실행 중일 수 있습니다.
- `server/ptc_api_server.py` 수정 후에는 서버를 재시작해 최신 로직(배분/공정률/직접분-공통배분분 집계)이 반영되었는지 확인하세요.
## 13. 개발 시 참고
- 현재 서버는 단일 파일(`server/ptc_api_server.py`) 중심 구조입니다.
- 스키마 변경 시 `init_db()``pragma table_info` 기반 보정 로직을 같이 업데이트하세요.
- UI 변경 시 관리 화면 파일:
- `PTC/management_dashboard_preview.html`
## 14. 커밋/브랜치 운영 권장
- 운영 브랜치: `manage`
- 기능 단위로 커밋 분리
- 예: `feat(lifecycle): ...`, `fix(project-view): ...`
- 데이터 파일(`.xlsx`, `.sqlite3`)은 가급적 직접 커밋하지 않고 경로/절차 중심으로 관리
---
문의/개선 시에는 **재현 경로(화면 URL + 프로젝트코드 + 계정코드 + 날짜 범위)**를 함께 남기면 원인 분석이 훨씬 빨라집니다.

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1 @@
/home/hyein/project/PTC(2023-2026.02).xlsx
/home/hyein/project/PTC 입출금내역(2015~).xlsx

View File

@@ -1,5 +1,7 @@
사용 파일
- start_ptc_share.bat : 공유용 실행 파일. 관리자 권한으로 다시 실행되어 WSL 서버 시작, IP 공유 설정, 방화벽 허용, 공유 주소 복사까지 처리합니다.
- install_ptc_share_autostart.bat : Windows 로그인 시 자동으로 공유가 시작되도록 작업 스케줄러에 등록합니다.
- remove_ptc_share_autostart.bat : 자동 실행 등록을 해제합니다.
- set_ptc_source.bat : 사용할 PTC 원본 `.xlsx` 파일을 선택하고 저장한 뒤 서버를 다시 시작합니다.
- stop_ptc_share.bat : 공유 중지
- check_ptc_share.bat : 현재 공유 상태 확인

View File

@@ -1,12 +1,6 @@
@echo off
setlocal EnableExtensions
set "HOST_IP="
for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "$ip = Get-NetIPAddress -AddressFamily IPv4 ^| Where-Object { $_.IPAddress -notlike '127.*' -and $_.IPAddress -notlike '169.254.*' -and $_.PrefixOrigin -ne 'WellKnown' } ^| Sort-Object InterfaceMetric, SkipAsSource ^| Select-Object -ExpandProperty IPAddress -First 1; if ($ip) { $ip }"`) do (
set "HOST_IP=%%i"
)
if "%HOST_IP%"=="" set "HOST_IP=localhost"
set "HOST_IP=172.16.40.36"
echo [Windows portproxy]
netsh interface portproxy show v4tov4
@@ -15,10 +9,13 @@ echo [WSL api]
wsl.exe bash -lc "curl -s http://127.0.0.1:4000/api/health"
echo.
echo [WSL web]
wsl.exe bash -lc "curl -I -s http://127.0.0.1:4000/PTC/ | head -n 1"
wsl.exe bash -lc "curl -I -s http://127.0.0.1:4000/PTC-lab/ | head -n 1"
echo.
echo [WSL manage web]
wsl.exe bash -lc "curl -I -s http://127.0.0.1:4000/PTC-lab-manage/ | head -n 1"
echo.
echo [Office LAN web]
powershell -NoProfile -Command "try { (Invoke-WebRequest -Uri 'http://%HOST_IP%:4000/PTC/' -UseBasicParsing -TimeoutSec 5).StatusCode } catch { $_.Exception.Message }"
powershell -NoProfile -Command "try { (Invoke-WebRequest -Uri 'http://%HOST_IP%:4000/PTC-lab-manage/' -UseBasicParsing -TimeoutSec 5).StatusCode } catch { $_.Exception.Message }"
echo.
echo [Office LAN api]
powershell -NoProfile -Command "try { (Invoke-WebRequest -Uri 'http://%HOST_IP%:4000/api/health' -UseBasicParsing -TimeoutSec 5).Content } catch { $_.Exception.Message }"

View File

@@ -1,77 +1,7 @@
@echo off
setlocal EnableExtensions
set "PROJECT_DIR=/home/hyein/project"
set "API_PORT=4000"
set "LOCAL_URL=http://localhost:4000/PTC/"
set "SHARE_URL="
set "LAN_IP="
set "CURRENT_SOURCE="
net session >nul 2>&1
if not "%errorlevel%"=="0" (
echo 관리자 권한으로 다시 실행해 공유 설정까지 적용합니다...
powershell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
exit /b
)
for /f "usebackq delims=" %%i in (`wsl.exe bash -lc "if [ -f /home/hyein/project/server/ptc_source_path.txt ]; then cat /home/hyein/project/server/ptc_source_path.txt; else echo /home/hyein/project/PTC(2023-2026.02).xlsx; fi"`) do (
set "CURRENT_SOURCE=%%i"
)
echo PTC 서버 시작 중...
echo 원본 파일: %CURRENT_SOURCE%
wsl.exe bash -lc "pkill -f '/home/hyein/project/server/ptc_api_server.py' >/dev/null 2>&1 || true; nohup python3 /home/hyein/project/server/ptc_api_server.py >/tmp/ptc_api.log 2>&1 & sleep 3"
if errorlevel 1 (
echo WSL에서 서버 시작 명령 실행에 실패했습니다.
echo WSL이 실행 가능한지 확인해 주세요.
pause
exit /b 1
)
echo 로컬 서버 상태 확인 중...
wsl.exe bash -lc "curl -fsS http://127.0.0.1:4000/api/health >/tmp/ptc_api_health.json && curl -fsSI http://127.0.0.1:4000/PTC/ >/tmp/ptc_web_health.txt"
if errorlevel 1 (
echo 로컬 서버 확인에 실패했습니다.
echo 아래 로그를 확인해 주세요.
wsl.exe bash -lc "tail -n 80 /tmp/ptc_api.log"
pause
exit /b 1
)
echo 브라우저를 엽니다...
start "" "%LOCAL_URL%"
echo.
echo 로컬 실행 완료
echo 메인 화면: %LOCAL_URL%
echo.
echo 사내망 공유용 Windows IP 확인 중...
for /f "usebackq delims=" %%i in (`powershell -NoProfile -Command "$ip = Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -notlike '127.*' -and $_.IPAddress -notlike '169.254.*' -and $_.PrefixOrigin -ne 'WellKnown' } | Select-Object -ExpandProperty IPAddress -First 1; if ($ip) { $ip }"`) do (
set "LAN_IP=%%i"
)
echo WSL IP 확인 중...
for /f "usebackq delims=" %%i in (`wsl.exe bash -lc "hostname -I | awk '{print $1}'"`) do (
set "WSL_IP=%%i"
)
if "%LAN_IP%"=="" goto :share_done
if "%WSL_IP%"=="" goto :share_done
echo 사내망 공유 설정 중...
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=%API_PORT% >nul 2>&1
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=%API_PORT% connectaddress=%WSL_IP% connectport=%API_PORT% >nul 2>&1
netsh advfirewall firewall delete rule name="PTC 4000" >nul 2>&1
netsh advfirewall firewall add rule name="PTC 4000" dir=in action=allow protocol=TCP localport=%API_PORT% >nul 2>&1
:share_done
if not "%LAN_IP%"=="" (
set "SHARE_URL=http://%LAN_IP%:%API_PORT%/PTC/"
echo 사내망 접속 주소: %SHARE_URL%
echo %SHARE_URL%| clip
echo 공유 주소를 클립보드에 복사했습니다.
)
pause
setlocal
pushd "%~dp0" >nul 2>&1
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0start_ptc_share.ps1"
set "EXIT_CODE=%ERRORLEVEL%"
popd >nul 2>&1
exit /b %EXIT_CODE%

135
windows/start_ptc_share.ps1 Normal file
View File

@@ -0,0 +1,135 @@
param(
[switch]$NoBrowser,
[switch]$NoPause
)
$ErrorActionPreference = "Stop"
function Test-IsAdmin {
$currentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($currentIdentity)
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
if (-not (Test-IsAdmin)) {
$childArgs = @(
"-NoProfile",
"-ExecutionPolicy", "Bypass",
"-File", "`"$PSCommandPath`""
)
if ($NoBrowser) { $childArgs += "-NoBrowser" }
if ($NoPause) { $childArgs += "-NoPause" }
Start-Process -FilePath "powershell.exe" -Verb RunAs -ArgumentList @(
$childArgs
)
exit 0
}
$projectDir = "/home/hyein/project"
$apiPort = 4000
$localUrl = "http://localhost:$apiPort/PTC-lab-manage/"
$preferredLanIp = "172.16.40.36"
$defaultSource = "/home/hyein/project/PTC(2023-2026.02).xlsx"
$sourceConfigPath = "/home/hyein/project/server/ptc_source_path.txt"
function Invoke-WslBash([string]$command) {
$output = & wsl.exe bash -lc $command 2>&1
$exitCode = $LASTEXITCODE
return [PSCustomObject]@{
Output = @($output)
ExitCode = $exitCode
}
}
$currentSourceResult = Invoke-WslBash "cat '$sourceConfigPath' 2>/dev/null || printf '%s\n' '$defaultSource'"
$currentSource = ($currentSourceResult.Output | Select-Object -First 1).Trim()
if ([string]::IsNullOrWhiteSpace($currentSource)) {
$currentSource = $defaultSource
}
Write-Host "Starting PTC server..."
Write-Host "Source file: $currentSource"
$startResult = Invoke-WslBash "pkill -f '/home/hyein/project/server/ptc_api_server.py' >/dev/null 2>&1 || true; nohup python3 /home/hyein/project/server/ptc_api_server.py >/tmp/ptc_api.log 2>&1 & sleep 3"
if ($startResult.ExitCode -ne 0) {
Write-Host "Failed to start the server in WSL." -ForegroundColor Red
if (-not $NoPause) {
Read-Host "Press Enter to exit"
}
exit 1
}
$healthResult = Invoke-WslBash "curl -fsS http://127.0.0.1:$apiPort/api/health >/tmp/ptc_api_health.json && curl -fsSI http://127.0.0.1:$apiPort/PTC-lab/ >/tmp/ptc_web_health.txt && curl -fsSI http://127.0.0.1:$apiPort/PTC-lab-manage/ >/tmp/ptc_manage_web_health.txt"
if ($healthResult.ExitCode -ne 0) {
Write-Host "Local server check failed. Recent server log:" -ForegroundColor Red
$logResult = Invoke-WslBash "tail -n 80 /tmp/ptc_api.log"
$logResult.Output | ForEach-Object { Write-Host $_ }
if (-not $NoPause) {
Read-Host "Press Enter to exit"
}
exit 1
}
if (-not $NoBrowser) {
Start-Process $localUrl
}
Write-Host ""
Write-Host "Local URL: $localUrl"
$lanIps = @(Get-NetIPAddress -AddressFamily IPv4 |
Where-Object {
$_.IPAddress -notlike '127.*' -and
$_.IPAddress -notlike '169.254.*' -and
$_.PrefixOrigin -ne 'WellKnown'
} |
Sort-Object InterfaceMetric, SkipAsSource |
Select-Object -ExpandProperty IPAddress)
$lanIp = $lanIps | Select-Object -First 1
$wslIpResult = Invoke-WslBash "hostname -I | awk '{print \$1}'"
$wslIp = ($wslIpResult.Output | Select-Object -First 1).Trim()
if (-not [string]::IsNullOrWhiteSpace($lanIp) -and -not [string]::IsNullOrWhiteSpace($wslIp)) {
Write-Host "Configuring LAN sharing..."
& netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=$apiPort | Out-Null
& netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=$apiPort connectaddress=$wslIp connectport=$apiPort | Out-Null
& netsh advfirewall firewall delete rule name="PTC 4000" | Out-Null
& netsh advfirewall firewall add rule name="PTC 4000" dir=in action=allow protocol=TCP localport=$apiPort | Out-Null
if (-not ($lanIps -contains $preferredLanIp)) {
Write-Host "Preferred share IP $preferredLanIp is not assigned on this PC." -ForegroundColor Red
Write-Host "Detected Windows IPs: $($lanIps -join ', ')" -ForegroundColor Yellow
if (-not $NoPause) {
Read-Host "Press Enter to exit"
}
exit 1
}
$shareIp = $preferredLanIp
$shareUrl = "http://$shareIp:$apiPort/PTC-lab-manage/"
Write-Host "Windows IP: $lanIp"
Write-Host "Preferred share IP in use: $shareIp"
Write-Host "WSL IP: $wslIp"
Write-Host "LAN URL: $shareUrl"
Set-Clipboard -Value $shareUrl
Write-Host "The share URL has been copied to the clipboard."
try {
$lanWebStatus = (Invoke-WebRequest -Uri $shareUrl -UseBasicParsing -TimeoutSec 5).StatusCode
$lanApiStatus = (Invoke-WebRequest -Uri "http://$shareIp:$apiPort/api/health" -UseBasicParsing -TimeoutSec 5).StatusCode
Write-Host "LAN web check: $lanWebStatus"
Write-Host "LAN api check: $lanApiStatus"
}
catch {
Write-Host "LAN check failed for $shareIp:$apiPort" -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Yellow
}
}
else {
Write-Host "LAN sharing was skipped because Windows IP or WSL IP could not be detected."
}
if (-not $NoPause) {
Read-Host "Press Enter to close"
}