Compare commits
8
Commits
f55e673cb5
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
823292cbb6 | ||
|
|
acb6cefbcc | ||
|
|
5cb7d74efa | ||
|
|
996f1c853e | ||
|
|
526f4e4545 | ||
|
|
8a7df11d9c | ||
|
|
9c064615a9 | ||
|
|
ea1fd350da |
Generated
+1
-1
@@ -485,7 +485,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "codeassist-tauri"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"png 0.17.16",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "codeassist-tauri"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
description = "CodeAssist 표준 Rust/Tauri 데스크톱 앱"
|
||||
authors = ["justdodev"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<!-- 맥 전용. macOS 는 앱 안 http(비암호화) 요청을 기본 차단(ATS)하는데, 우리 서버·고객사 서버가
|
||||
http 라 앱이 로그인조차 못 함. Tauri 가 이 파일을 번들 Info.plist 에 합쳐 넣음. Windows 는 무관. -->
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "CodeAssist",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.4",
|
||||
"identifier": "com.codeassist.app",
|
||||
"build": {
|
||||
"beforeDevCommand": { "cwd": "../../2_frontend", "script": "npm run dev" },
|
||||
|
||||
@@ -13,3 +13,5 @@ deploy/langfuse/docker-compose.override.yml
|
||||
|
||||
# render_opencode.py 가 환경마다 만드는 파일 — 서버마다 다름
|
||||
opencode/opencode.json
|
||||
deploy/docker/.env
|
||||
deploy/phoenix/.env
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
export PYTHONUTF8=1
|
||||
# git 안이면 최신으로(고객사: /www/abap-ito). 로컬 수정이 있어 못 당기면 멈춤 — 렌더 산출물은 git 밖이라 안 걸림
|
||||
if git rev-parse --show-toplevel >/dev/null 2>&1; then git -C "$(git rev-parse --show-toplevel)" pull --ff-only; fi
|
||||
# 필수 키 비어 있으면 여기서 멈춤 — 비어 있는 채로 띄우면 채팅 때 "누락" 에러가 나서 원인 찾기 어려움
|
||||
for k in AAF_FABRIX_BASE_URL AAF_FABRIX_CLIENT_KEY AAF_FABRIX_OPENAPI_TOKEN DB_HOST; do
|
||||
grep -qE "^$k=.+" .env || { echo "!! .env 에 $k 가 비어 있음 — 채우고 다시"; exit 1; }
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# CodeAssist 도커 배포 .env — 이 폴더에 .env 로 복사해서 채움. be 컨테이너 환경변수로 그대로 들어감.
|
||||
|
||||
# 바깥 포트 (앱이 http://<서버>:<BE_PORT>/api/v1 로 붙음)
|
||||
BE_PORT=8080
|
||||
|
||||
# LLM — 우리 환경은 OpenRouter 직접(고객사 FabriX 키 AAF_* 는 비움 → 렌더러가 OpenRouter 템플릿을 고름)
|
||||
OPENROUTER_API_KEY=
|
||||
OPENCODE_VISION_MODEL=openrouter/google/gemma-4-31b-it
|
||||
|
||||
# 토큰 서명 키 (비우면 data/.auth_secret 자동 생성)
|
||||
AUTH_SECRET=
|
||||
|
||||
# DB — 비우면 SQLite(be_data 볼륨). 팀 PostgreSQL 쓰려면 채움
|
||||
DB_HOST=
|
||||
DB_PORT=5432
|
||||
DB_USER=
|
||||
DB_PASSWORD=
|
||||
DB_NAME=
|
||||
DB_SCHEMA=codeassist
|
||||
DB_SSLMODE=prefer
|
||||
|
||||
# 앱(Tauri)에서 오는 요청 허용 origin
|
||||
CORS_ORIGINS=http://tauri.localhost,tauri://localhost,http://localhost:15173
|
||||
|
||||
# 채팅 타임아웃(초)
|
||||
STREAM_FIRST_EVENT_TIMEOUT_S=300
|
||||
STREAM_TURN_TIMEOUT_S=600
|
||||
|
||||
# SAP 조회 MCP — 같은 서버의 abap-opencode compose 에 mcp 컨테이너가 있으면 그 주소. 비우면 끔
|
||||
MCP_HOST=mcp
|
||||
MCP_PORT=3200
|
||||
MCP_API_KEY=
|
||||
|
||||
# 관측(Phoenix) — deploy/phoenix 로 띄운 주소. 비우면 안 보냄
|
||||
PHOENIX_HOST=http://host.docker.internal:6006 # 같은 서버 Phoenix. 다른 서버면 그 사설 IP
|
||||
TRACE_PROJECT=codeassist
|
||||
PHOENIX_UI_PASSWORD=
|
||||
@@ -0,0 +1,12 @@
|
||||
# CodeAssist 백엔드 — Django(ASGI/uvicorn). 기동 때 migrate → OpenCode 설정 렌더 → 서버.
|
||||
FROM python:3.12-slim
|
||||
WORKDIR /app
|
||||
ENV PYTHONUTF8=1 PYTHONUNBUFFERED=1 DJANGO_SETTINGS_MODULE=config.settings
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY manage.py ./
|
||||
COPY config ./config
|
||||
COPY apps ./apps
|
||||
COPY common ./common
|
||||
# opencode/ 는 compose 가 bind 로 끼움(/app/opencode) — 렌더 결과 opencode.json 을 opencode 컨테이너도 같은 폴더로 봄
|
||||
CMD ["sh", "-c", "python manage.py migrate --noinput && ([ -f seed/snippets.db ] && python manage.py import_snippets seed/snippets.db || true) && python opencode/render_opencode.py && uvicorn config.asgi:application --host 0.0.0.0 --port 8080"]
|
||||
@@ -0,0 +1,9 @@
|
||||
# OpenCode 헤드리스 서버 — 고객사 opencode-bin 과 같은 1.18.6 으로 고정
|
||||
FROM node:22-bookworm-slim
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl git ripgrep \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
RUN npm install -g --no-audit --no-fund opencode-ai@1.18.6
|
||||
WORKDIR /workspace
|
||||
EXPOSE 4096
|
||||
# .opencode/tools 의 커스텀 도구가 @opencode-ai/plugin 을 씀 — bind 된 workspace 라 기동 때 설치(있으면 건너뜀)
|
||||
CMD ["sh", "-c", "cd /workspace/.opencode && npm install --no-audit --no-fund --silent >/dev/null 2>&1; cd /workspace && opencode serve --hostname 0.0.0.0 --port 4096"]
|
||||
@@ -0,0 +1,35 @@
|
||||
# CodeAssist 백엔드 — 도커 배포 (우리 환경용)
|
||||
|
||||
고객사(도커 없음)는 `5_django_backend/deploy.sh`(bare) 를 씀. 여긴 도커 되는 서버(20.200.170.37 등)용.
|
||||
둘 다 같은 저장소 구조를 쓰고, 배포 스크립트만 다름:
|
||||
|
||||
| 환경 | 스크립트 | 하는 일 |
|
||||
|---|---|---|
|
||||
| 우리(도커) | `deploy/docker/deploy.sh [up\|update\|stop\|logs\|status]` | (update 면 git pull) → 이미지 빌드 → be·opencode 기동 → 헬스 확인 |
|
||||
| 고객사(bare) | `deploy.sh` | git pull → .env 키 보정 → migrate → 렌더 → opencode-bin·uvicorn 재기동 → 헬스 |
|
||||
|
||||
## 처음 한 번
|
||||
|
||||
```bash
|
||||
cd <저장소>/code-assistant/5_django_backend/deploy/docker # 고객사 repo 구조 기준. 우리 git 이면 5_django_backend/deploy/docker
|
||||
cp .env.example .env && vi .env # OPENROUTER_API_KEY, PHOENIX_HOST 정도만 채우면 됨
|
||||
./deploy.sh
|
||||
```
|
||||
컨테이너 2개: `be`(Django, 바깥 `BE_PORT`=8080) + `opencode`(OpenCode 1.18.6). 저장소의 `opencode/` 폴더를 둘 다 bind 로 봐서
|
||||
AGENTS.md·위키·커스텀 도구가 그대로 먹고, be 가 렌더한 `opencode.json` 을 opencode 가 바로 읽음.
|
||||
|
||||
## 이후
|
||||
|
||||
```bash
|
||||
./deploy.sh update # 최신 코드로 갱신
|
||||
./deploy.sh status # 상태 + 헬스
|
||||
./deploy.sh logs
|
||||
```
|
||||
|
||||
## 알아둘 것
|
||||
|
||||
- LLM: `.env` 에 `AAF_FABRIX_*` 가 없으면 렌더러가 OpenRouter 템플릿(`opencode/opencode.openrouter.json.tmpl`)을 고름. 고객사는 FabriX 템플릿.
|
||||
- DB: `DB_HOST` 비우면 SQLite(`be_data` 볼륨). 팀 PostgreSQL 쓰려면 DB_* 채움(스키마 `codeassist`).
|
||||
- SAP 조회(MCP): 같은 서버에 abap-opencode compose 가 떠 있으면 그 `mcp` 컨테이너를 쓸 수 있음 — 두 compose 를 같은 네트워크로 묶어야 함(아직 안 함). 비우면 꺼짐.
|
||||
- 관측: `PHOENIX_HOST=http://host.docker.internal:6006`(같은 서버; 공인 IP 는 컨테이너 안에서 안 닿음) (`deploy/phoenix/docker-compose.yml` 로 띄운 것). 프로젝트 `codeassist`.
|
||||
- 앱(Tauri) 쪽은 `2_frontend/.env.production` 의 `VITE_API_BASE_URL` 을 이 서버로 바꿔 빌드해야 붙음.
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
# CodeAssist 도커 배포 — 우리 환경용. 이거 하나면 됨. (ABAP_OPENCODE web/deploy/deploy.sh 와 같은 명령 모양)
|
||||
#
|
||||
# ./deploy.sh 빌드 + 기동 (떠 있으면 갱신)
|
||||
# ./deploy.sh update git pull 까지 하고 갱신
|
||||
# ./deploy.sh stop 종료 (데이터 볼륨은 남음)
|
||||
# ./deploy.sh logs 로그
|
||||
# ./deploy.sh status 상태
|
||||
#
|
||||
# 전제: 이 폴더에 .env (cp .env.example .env 후 채움)
|
||||
set -euo pipefail
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"; cd "$HERE"
|
||||
CMD="${1:-up}"
|
||||
|
||||
command -v docker >/dev/null || { echo "docker 없음"; exit 1; }
|
||||
docker compose version >/dev/null 2>&1 || { echo "docker compose v2 없음"; exit 1; }
|
||||
[ -f .env ] || { echo ".env 없음 — cp .env.example .env 후 채워"; exit 1; }
|
||||
set -a; . ./.env; set +a
|
||||
PORT="${BE_PORT:-8080}"; BASE="http://localhost:${PORT}/api/v1"
|
||||
|
||||
case "$CMD" in
|
||||
stop) docker compose down; echo "종료(볼륨 유지)"; exit 0 ;;
|
||||
logs) docker compose logs -f --tail=100; exit 0 ;;
|
||||
status) docker compose ps; curl -fsS -m 5 "$BASE/health" && echo || echo "헬스 응답 없음"; exit 0 ;;
|
||||
update) git -C "$HERE/../../.." pull --ff-only || { echo "git pull 실패 — 로컬 변경 확인"; exit 1; } ;;
|
||||
up) ;;
|
||||
*) echo "모르는 명령: $CMD (up|update|stop|logs|status)"; exit 1 ;;
|
||||
esac
|
||||
|
||||
[ -n "${OPENROUTER_API_KEY:-}${AAF_FABRIX_BASE_URL:-}" ] || { echo ".env 에 OPENROUTER_API_KEY(또는 AAF_FABRIX_*) 가 비어 있음"; exit 1; }
|
||||
|
||||
echo "-- 이미지 빌드 + 기동"
|
||||
docker compose up -d --build
|
||||
echo "-- 기동 확인(최대 2분)"
|
||||
for _ in $(seq 1 60); do curl -fsS -m 3 "$BASE/health" >/dev/null 2>&1 && break; sleep 2; done
|
||||
curl -fsS -m 5 "$BASE/health" || { echo "안 떴음 → ./deploy.sh logs"; docker compose ps; exit 1; }
|
||||
echo
|
||||
echo "-- OpenCode 설정(렌더 결과) 모델:"; grep -oE '"model": *"[^"]+"' ../../opencode/opencode.json || true
|
||||
echo "-- 앱 주소: http://$(hostname -I 2>/dev/null | awk '{print $1}'):${PORT}/api/v1"
|
||||
@@ -0,0 +1,37 @@
|
||||
# CodeAssist 백엔드 — 우리 환경(도커)용. 고객사(도커 없음)는 5_django_backend/deploy.sh.
|
||||
# 사용: 이 폴더에서 cp .env.example .env 채우고 ./deploy.sh
|
||||
# 밖으로 여는 건 be(:8080 → BE_PORT) 하나. 앱(Tauri)이 http://<서버>:<BE_PORT>/api/v1 로 붙음.
|
||||
name: codeassist
|
||||
|
||||
services:
|
||||
be:
|
||||
build: { context: ../.., dockerfile: deploy/docker/Dockerfile.be }
|
||||
ports:
|
||||
- "${BE_PORT:-8080}:8080"
|
||||
env_file: .env
|
||||
environment:
|
||||
OPENCODE_BASE_URL: http://opencode:4096
|
||||
OPENCODE_DIRECTORY: /workspace # OpenCode 컨테이너가 보는 workspace 경로 — 세션이 여기 생김
|
||||
BACKEND_HOST: be # 렌더된 opencode.json 의 게이트웨이 주소(고객사 모드일 때)
|
||||
BACKEND_PORT: "8080"
|
||||
MCP_HOST: ${MCP_HOST:-mcp}
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway" # 같은 서버의 Phoenix(:6006) 를 host.docker.internal 로 — 공인 IP 는 컨테이너 안에서 안 닿음(Azure)
|
||||
volumes:
|
||||
- ../../opencode:/app/opencode # AGENTS.md·.opencode·wiki·렌더 결과(opencode.json)
|
||||
- be_data:/app/data # SQLite(DB_HOST 비울 때)·auth secret
|
||||
depends_on: [opencode]
|
||||
restart: unless-stopped
|
||||
|
||||
opencode:
|
||||
build: { context: ../.., dockerfile: deploy/docker/Dockerfile.opencode }
|
||||
environment:
|
||||
OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-}
|
||||
volumes:
|
||||
- ../../opencode:/workspace
|
||||
- oc_data:/root/.local/share/opencode # 세션·메시지 저장
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
be_data:
|
||||
oc_data:
|
||||
@@ -0,0 +1,22 @@
|
||||
# Phoenix — 우리 환경(도커)용. 한 대에 하나 띄우고 CodeAssist·ABAP_OPENCODE 둘 다 여기로 보냄(프로젝트로 나뉨).
|
||||
# 고객사(도커 없음)는 같은 폴더의 run.sh(pip 방식).
|
||||
# docker compose up -d → http://<서버>:6006
|
||||
name: phoenix
|
||||
|
||||
services:
|
||||
phoenix:
|
||||
image: arizephoenix/phoenix:latest
|
||||
ports:
|
||||
- "${PHOENIX_PORT:-6006}:6006"
|
||||
environment:
|
||||
PHOENIX_WORKING_DIR: /data
|
||||
PHOENIX_TELEMETRY_ENABLED: "false"
|
||||
# 로그인 켜려면 둘 다 채움(첫 관리자 admin@localhost / PHOENIX_DEFAULT_ADMIN_INITIAL_PASSWORD). 켜면 수신에도 API 키 필요 — 모듈 헤더 한 줄 추가해야 함
|
||||
# PHOENIX_ENABLE_AUTH: "true"
|
||||
# PHOENIX_SECRET: ${PHOENIX_SECRET}
|
||||
volumes:
|
||||
- phoenix_data:/data
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
phoenix_data:
|
||||
@@ -6,7 +6,7 @@
|
||||
"npm": "@ai-sdk/openai-compatible",
|
||||
"name": "FabriX",
|
||||
"options": {
|
||||
"baseURL": "http://127.0.0.1:${BACKEND_PORT}/api/ito",
|
||||
"baseURL": "http://${BACKEND_HOST}:${BACKEND_PORT}/api/ito",
|
||||
"apiKey": "${AAF_GATEWAY_KEY}"
|
||||
},
|
||||
"models": ${AAF_FABRIX_MODELS_JSON}
|
||||
@@ -18,7 +18,7 @@
|
||||
"mcp": {
|
||||
"sap-icf": {
|
||||
"type": "remote",
|
||||
"url": "http://127.0.0.1:${MCP_PORT}/mcp",
|
||||
"url": "http://${MCP_HOST}:${MCP_PORT}/mcp",
|
||||
"headers": { "Authorization": "Bearer ${MCP_API_KEY}" },
|
||||
"enabled": ${SAP_MCP_ENABLED}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"provider": {
|
||||
"openrouter": {
|
||||
"options": { "apiKey": "{env:OPENROUTER_API_KEY}" },
|
||||
"models": {
|
||||
"z-ai/glm-5.2": { "name": "GLM 5.2" },
|
||||
"google/gemma-4-31b-it": { "name": "Gemma4", "attachment": true, "modalities": { "input": ["text", "image"], "output": ["text"] } }
|
||||
}
|
||||
}
|
||||
},
|
||||
"model": "openrouter/z-ai/glm-5.2",
|
||||
"tools": { "question": false },
|
||||
"permission": { "external_directory": "allow" },
|
||||
"mcp": {
|
||||
"sap-icf": {
|
||||
"type": "remote",
|
||||
"url": "http://${MCP_HOST}:${MCP_PORT}/mcp",
|
||||
"headers": { "Authorization": "Bearer ${MCP_API_KEY}" },
|
||||
"enabled": ${SAP_MCP_ENABLED}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""고객사(FabriX)용 opencode.json 만들기 — 템플릿의 ${이름} 을 .env 값으로 채움.
|
||||
"""opencode.json 만들기 — 템플릿의 ${이름} 을 .env 값으로 채움.
|
||||
|
||||
python opencode/render_opencode.py # ../.env 읽어서 opencode/opencode.json 덮어씀
|
||||
python opencode/render_opencode.py --check # 쓰진 않고 결과만 출력
|
||||
|
||||
개발(OpenRouter)로 돌아가려면 `git checkout opencode/opencode.json`.
|
||||
템플릿 고르기: AAF_FABRIX_BASE_URL 이 있으면 고객사(FabriX 게이트웨이), 없으면 OpenRouter(우리 환경·로컬).
|
||||
호스트: BACKEND_HOST/MCP_HOST 기본 127.0.0.1, 도커 compose 에선 be / mcp 컨테이너 이름.
|
||||
ABAP_OPENCODE web/deploy/bare/render-opencode.py 와 같은 규칙:
|
||||
AAF_FABRIX_MODELS="605:Gemma4,339:GaussO Flash,581:GaussO Think" → 모델 목록. 키가 곧 x-llm-model-id.
|
||||
비어 있으면 AAF_FABRIX_MODEL_ID 하나(이름 FabriX). 기본 모델은 목록의 첫 번째.
|
||||
@@ -34,7 +35,7 @@ def load_env(path: Path) -> dict[str, str]:
|
||||
k, v = line.split("=", 1)
|
||||
v = v.split(" #", 1)[0].strip().strip("\"'") # 줄 끝 주석은 두 칸 띄고 #
|
||||
out[k.strip()] = v
|
||||
out.update({k: v for k, v in os.environ.items() if k.startswith(("AAF_", "BACKEND_PORT", "MCP_", "OPENCODE_"))})
|
||||
out.update({k: v for k, v in os.environ.items() if k.startswith(("AAF_", "BACKEND_", "MCP_", "OPENCODE_", "OPENROUTER_"))})
|
||||
return out
|
||||
|
||||
|
||||
@@ -53,7 +54,9 @@ def render(env: dict[str, str]) -> str:
|
||||
return m
|
||||
values["AAF_FABRIX_MODELS_JSON"] = json.dumps({mid: _model(mid, name) for mid, name in models.items()}, ensure_ascii=False)
|
||||
values["AAF_FABRIX_DEFAULT_MODEL"] = next(iter(models))
|
||||
values.setdefault("BACKEND_HOST", "127.0.0.1")
|
||||
values.setdefault("BACKEND_PORT", "8001")
|
||||
values.setdefault("MCP_HOST", "127.0.0.1")
|
||||
values.setdefault("MCP_PORT", "8888")
|
||||
# SAP MCP: MCP_API_KEY 가 있으면 켬. 없으면 끔(로컬 개발)
|
||||
values["SAP_MCP_ENABLED"] = "true" if values.get("MCP_API_KEY") else "false"
|
||||
@@ -67,7 +70,8 @@ def render(env: dict[str, str]) -> str:
|
||||
missing.append(m.group(1))
|
||||
return v
|
||||
|
||||
text = re.sub(r"\$\{(\w+)\}", fill, (HERE / "opencode.fabrix.json.tmpl").read_text(encoding="utf-8"))
|
||||
tmpl = "opencode.fabrix.json.tmpl" if env.get("AAF_FABRIX_BASE_URL") else "opencode.openrouter.json.tmpl"
|
||||
text = re.sub(r"\$\{(\w+)\}", fill, (HERE / tmpl).read_text(encoding="utf-8"))
|
||||
if missing:
|
||||
print("경고: 비어 있는 값 —", ", ".join(sorted(set(missing))), file=sys.stderr)
|
||||
return text
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# 2026-09-22 — 한 것 / 다음에 이어서
|
||||
|
||||
## 오늘 한 것
|
||||
|
||||
- **고객사 repo 정리**: GHE 단일 repo 를 `abap-specgen/`(ABAP_OPENCODE) + `code-assistant/`(CODE_ASSISTANT) 두 폴더로. -13 bare 런타임 이동, -12 는 clone 으로 전환. → `docs/tech/customer-repo-layout.md`
|
||||
- **채팅 UI**: 생각 과정(추론·도구 스텝) 접이식 + "생각하는 중/작성 중 · N초" 상태줄 하나. 앱 0.1.3.
|
||||
- **위키 우선 규칙**: `opencode/wiki/`(팀원 인덱싱 결과) 먼저 읽고, SAP(MCP)은 빠진 부분만. 도구가 workspace 밖 파일 읽다 멈추던 것(`external_directory: allow`) 고침.
|
||||
- **LLM 관측**: Langfuse 는 고객사(컨테이너 안, docker 불가)라 접고 **Phoenix**. 전송 모듈(`apps/gateway/langfuse.py` = ABAP_OPENCODE `common/langfuse.py`) OTLP protobuf. 한 줄 = 질문(답·토큰·시간), 트리 = 도구 호출. → `docs/tech/observability-phoenix.md`
|
||||
- 고객사 -12: Phoenix pip 로 8915, 화면은 `http://10.196.81.34:8914/phoenix/`(비번 codeassist2026). -13 은 8914 경유로 전송. 둘 다 확인됨.
|
||||
- 우리 서버 20.200.170.37: Phoenix 도커(:6006) + CodeAssist 도커(:8080) + ABAP_OPENCODE 갱신. 컨테이너→Phoenix 는 `host.docker.internal`.
|
||||
- **배포 스크립트 환경별 하나씩**: 도커 `deploy/docker/deploy.sh`(CodeAssist) / `web/deploy/deploy.sh`(ABAP_OPENCODE), bare `deploy.sh`(git pull 포함) / `web/deploy/bare/deploy.sh`. 렌더러가 FabriX/OpenRouter 템플릿 자동 선택.
|
||||
- 양쪽 git(sqnotes) 전부 push 됨. 고객사 GHE 에도 code-assistant 최신 반영됨(Phoenix 중계까지).
|
||||
|
||||
## 다음에 이어서
|
||||
|
||||
1. **Azure NSG 8080·6006 인바운드** — 인프라 개발자에게 요청해둠. 열리면:
|
||||
- `curl http://20.200.170.37:8080/api/v1/health`, 브라우저 `http://20.200.170.37:6006`
|
||||
- 앱을 우리 서버용으로 빌드: `2_frontend/.env.production` → `VITE_API_BASE_URL=http://20.200.170.37:8080/api/v1`, Tauri 빌드(버전 올려서)
|
||||
- 테스트 계정 `t@x.com / pw1234` 는 지우거나 바꿀 것
|
||||
2. 우리 서버 CodeAssist 의 SAP MCP 는 꺼져 있음(`MCP_API_KEY` 비움). 쓰려면 abap-opencode compose 의 `mcp` 컨테이너와 네트워크 묶기.
|
||||
3. 고객사: `abap_index` 도구 켜기(팀원 인덱스 서버 :8100 뜨면 `tools.off → tools`). 위키 `index.md` 는 팀원이 새로 뽑아주면 교체.
|
||||
4. 로컬 정리: Langfuse 도커 6개(`5_django_backend/deploy/langfuse` 에서 `docker compose down -v`), `phoenix-test` 컨테이너, `codeassist` compose — 안 쓰면 내리기.
|
||||
5. 밀린 것: 옛 Tauri 로컬 SQLite 스니펫 명령 제거, 이미지 재진입 표시, 자동 업데이트(tauri-plugin-updater), WBS 잔여(스니펫 검색 규칙·에러로그·매뉴얼).
|
||||
|
||||
## 접속 메모
|
||||
- 우리 서버: `ssh pwc-rnd-aide-lab`(edge_user, pem 은 `z_pem_key/`). 클론 `~/codeassist`, `~/abap-opencode`.
|
||||
- 고객사: -12 `ssh -p 8912`, -13 `ssh -p 8916` @10.196.81.34. repo `/www/abap-ito`.
|
||||
@@ -23,12 +23,16 @@
|
||||
- `.env` 는 폴더마다 따로. 둘 다 gitignore. **커밋 전 `git status --short | grep '\.env$'` 가 비어야 함.**
|
||||
- `-12`(code-assistant) 와 `-13`(abap-specgen) 은 서로 통신 안 함. 각자 GHE 만 봄.
|
||||
|
||||
## 배포 루틴
|
||||
## 배포 루틴 — 환경별 스크립트 하나씩
|
||||
|
||||
| VM | 명령 |
|
||||
|---|---|
|
||||
| -12 (code-assistant, 포트 8914→8080) | `cd /www/abap-ito && git pull && cd code-assistant/5_django_backend && bash deploy.sh` |
|
||||
| -13 (abap-specgen, 포트 8918) | `cd /www/abap-ito && git pull && bash abap-specgen/web/deploy/bare/run.sh restart` |
|
||||
| | 고객사(도커 없음, bare) | 우리 환경 20.200.170.37 (도커) |
|
||||
|---|---|---|
|
||||
| code-assistant | `cd /www/abap-ito/code-assistant/5_django_backend && bash deploy.sh` (안에서 git pull) | `cd ~/codeassist/5_django_backend/deploy/docker && ./deploy.sh update` |
|
||||
| abap-specgen | `bash /www/abap-ito/abap-specgen/web/deploy/bare/deploy.sh` (git pull → pip → restart) | `cd ~/abap-opencode/web/deploy && bash deploy.sh update` |
|
||||
| Phoenix | `deploy/phoenix/run.sh` (pip, -12 안 8915) | `cd ~/codeassist/5_django_backend/deploy/phoenix && docker compose up -d` (`:6006`, 둘이 공유) |
|
||||
|
||||
우리 서버(20.200.170.37, `ssh pwc-rnd-aide-lab`, edge_user)는 고객사 repo 구조가 아니라 **우리 git 두 개를 각각 clone** 해둠: `~/abap-opencode`(ABAP_OPENCODE main), `~/codeassist`(CODE_ASSISTANT master).
|
||||
컨테이너에서 같은 서버 Phoenix 는 `PHOENIX_HOST=http://host.docker.internal:6006`(compose 가 host-gateway 매핑). 바깥 포트 8080(CodeAssist)·6006(Phoenix)은 Azure NSG 에서 열어야 접근됨(2026-09-22 현재 80/22 만 열림).
|
||||
|
||||
-13 에서 `git pull` 이 "local changes would be overwritten" 로 막히면 서버에서 직접 고친 파일이 있는 것:
|
||||
`git diff > /tmp/p.patch && git checkout -- . && git pull && git apply /tmp/p.patch`.
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# Windows 설치본(msi) 만들기 — 팀원용 가이드
|
||||
|
||||
우리 팀 서버(20.200.170.37) 에 붙는 CodeAssist 앱을 Windows PC 에서 빌드하는 순서. 2026-09-22 기준, 앱 버전 0.1.4.
|
||||
전부 PowerShell 에서 (Git Bash 는 Rust 링커가 꼬임 — 아래 "막히면").
|
||||
|
||||
## 0. 한 번만 깔 것
|
||||
|
||||
| 뭐 | 어디서 | 확인 |
|
||||
|---|---|---|
|
||||
| Git | https://git-scm.com | `git --version` |
|
||||
| Node.js 22 LTS | https://nodejs.org | `node --version` → v22.x |
|
||||
| Rust (rustup, MSVC) | https://rustup.rs → `rustup-init.exe` 기본값으로 | `cargo --version` |
|
||||
| Visual Studio Build Tools | https://visualstudio.microsoft.com/visual-cpp-build-tools/ → **"C++ 데스크톱 개발"** 워크로드 체크 | Rust 가 링크할 때 필요 |
|
||||
| WebView2 런타임 | Win11 은 기본 있음. Win10 은 https://developer.microsoft.com/microsoft-edge/webview2/ | 없으면 앱 창이 안 뜸 |
|
||||
|
||||
## 1. 코드 받기
|
||||
|
||||
```powershell
|
||||
git clone https://git.sqnotes.com/20260807_OPENCODE_TEMP/CODE_ASSISTANT.git
|
||||
cd CODE_ASSISTANT
|
||||
git pull # 이미 받아뒀으면
|
||||
```
|
||||
|
||||
## 2. 서버 주소 넣기 (파일 하나)
|
||||
|
||||
`2_frontend\.env.production` 파일을 **새로 만들고** 아래 한 줄만:
|
||||
|
||||
```
|
||||
VITE_API_BASE_URL=http://20.200.170.37:8080/api/v1
|
||||
```
|
||||
|
||||
이 파일은 git 에 안 올라감(PC 마다 다름). 고객사용을 만들 땐 이 주소만 고객사 서버로 바꿔서 빌드하면 됨.
|
||||
|
||||
## 3. 빌드
|
||||
|
||||
```powershell
|
||||
cd 2_frontend
|
||||
npm ci
|
||||
|
||||
cd ..\4_rust_tauri
|
||||
npm ci
|
||||
npx tauri build
|
||||
```
|
||||
|
||||
처음엔 Rust 크레이트 컴파일 때문에 10~15분. 두 번째부턴 1~2분.
|
||||
|
||||
**결과물**: `4_rust_tauri\src-tauri\target\release\bundle\`
|
||||
- `msi\CodeAssist_0.1.4_x64_en-US.msi` ← 이걸 배포
|
||||
- `nsis\CodeAssist_0.1.4_x64-setup.exe` (같은 내용, exe 설치본)
|
||||
|
||||
## 4. 설치하고 확인
|
||||
|
||||
1. msi 더블클릭 → 설치 → 트레이에 CodeAssist 아이콘.
|
||||
2. 창 열리면 로그인: `admin@codeassist.local` / `test1234` (또는 `guest@codeassist.local` / 같은 비번).
|
||||
3. 아무 질문이나 하나 보내서 답이 오면 끝.
|
||||
|
||||
핫키:
|
||||
|
||||
| 키 | 뭐 |
|
||||
|---|---|
|
||||
| Ctrl+Alt+W | 챗 열기/숨기기 |
|
||||
| Ctrl+Alt+Q | 스니펫 팔레트 (Enter = 직전 앱에 붙여넣기) |
|
||||
| Ctrl+Alt+A | 맨 앞 창 통째 캡처 → 새 대화 |
|
||||
| Ctrl+Alt+S | 드래그 영역 캡처 → 새 대화 |
|
||||
| Ctrl+Alt+Z | 맨 앞 창 캡처 → 마지막 대화에 이어서 |
|
||||
| Ctrl+Alt+X | 드래그 영역 캡처 → 마지막 대화에 이어서 |
|
||||
|
||||
## 막히면
|
||||
|
||||
- **`link.exe` 어쩌고 하며 실패** → Git Bash 에서 돌린 것. PowerShell 로.
|
||||
- **`error: linker 'link.exe' not found`** → Build Tools 의 "C++ 데스크톱 개발" 이 안 깔린 것. 깔고 PowerShell 새로 열기.
|
||||
- **설치했는데 옛 버전 그대로** → Windows 는 같은 버전 msi 를 건너뜀. `4_rust_tauri\src-tauri\tauri.conf.json` 과 `Cargo.toml` 의 version 을 올리고(예: 0.1.5) 다시 빌드. 올린 건 커밋해서 푸시.
|
||||
- **로그인이 안 됨 / 화면이 빈 채로** → `.env.production` 을 안 만들었거나 오타. 2번 다시. 그리고 브라우저에서 `http://20.200.170.37:8080/api/v1/health` 가 열리는지 확인(사내망이면 방화벽).
|
||||
- **핫키가 안 먹음** → 다른 프로그램이 같은 키를 먼저 잡은 것. 트레이 아이콘 우클릭 → 열기 로는 됨.
|
||||
- **답변이 안 오고 error** → 서버 쪽 문제. 관측 화면 `http://20.200.170.37:6006` 에서 트레이스 확인하거나 나한테.
|
||||
|
||||
## 참고
|
||||
|
||||
- 맥 빌드본은 `.env.production` 외에 `src-tauri/Info.plist`(http 허용) 가 필요한데 이미 repo 에 있음. Windows 는 무관.
|
||||
- 빌드 결과물(`target/`, `dist/`)은 git 에 안 올림. msi 만 팀 채널로 공유.
|
||||
@@ -0,0 +1,26 @@
|
||||
# 작업로그 · 2026-09-22 (화)
|
||||
|
||||
| 시간 | 내용 |
|
||||
|------|------|
|
||||
| 10:14 | 고객사 repo 를 abap-specgen/ + code-assistant/ 두 폴더로 정리, -13 bare 런타임 이동·-12 clone 전환. 구조·배포 루틴을 docs/tech/customer-repo-layout.md 로 |
|
||||
| 10:47 | 생각하는 중/작성 중 이중 표시 → 하단 상태줄 하나로 합침(첫 글자 전엔 생각하는 중, 후엔 작성 중), 0.1.3 |
|
||||
| 10:49 | 0.1.3 msi 빌드, txt 4조각 |
|
||||
| 13:44 | Langfuse 연동 코드 — 채팅 턴 trace + FabriX 호출 generation 을 HTTP 로 전송(SDK 없이), 테스트 4개. deploy/langfuse 에 compose·env·오프라인 반입 절차 |
|
||||
| 13:53 | 로컬에 Langfuse v4 도커로 띄워 실측 — 옛 ingestion API 는 거부돼 OTLP JSON 으로 바꿈, trace·generation 저장 확인 |
|
||||
| 14:01 | Langfuse 에 빈 input 트레이스 잔뜩 — pytest 가 로컬 .env 보고 진짜 쏜 것. 테스트 기본 차단, 게이트웨이 루트에 질문/답 표시 |
|
||||
| 14:06 | Langfuse 트레이스 모양 바꿈 — 루트가 곧 채팅(질문·답·토큰), 밑에 도구 호출들이 트리로 |
|
||||
| 14:14 | ABAP_OPENCODE 에도 Langfuse — 워처가 session.idle 마다 턴 하나(질문·답·토큰) + 도구 트리 전송, 로컬 Langfuse 로 확인 |
|
||||
| 14:25 | Langfuse 이미지 6개를 오프라인 반입용 tar.gz 하나로 묶음(Desktop) |
|
||||
| 15:39 | -12 는 컨테이너 안이라 도커 불가(unshare 막힘) → Langfuse 접고 Phoenix(pip)로. 전송 모듈에 OpenInference 속성 추가, py3.12 wheel 155개 묶음, deploy/phoenix 절차 |
|
||||
| 15:43 | Phoenix 가 JSON 안 받아(415) protobuf 변환 넣음 — 로컬 Phoenix 에 두 프로젝트(codeassist/abap-specgen) trace 저장 확인 |
|
||||
| 16:26 | 고객사 -12 에 Phoenix(pip) 띄우고 CodeAssist 백엔드 연결 — 실제 채팅 trace 확인. 바깥 8913/8915 는 -12 로 안 이어져 UI 는 ssh 터널로 |
|
||||
| 16:34 | Phoenix 화면을 8914 뒤 /phoenix/ 로 중계(Basic 잠금) — 8913/8915 는 -12 로 안 이어져서. 로컬 e2e 통과 |
|
||||
| 17:15 | 고객사 Phoenix 화면 8914/phoenix/ 로 열림 확인(Basic 잠금). run.sh 옛 프로세스 안 죽던 버그 수정 |
|
||||
| 17:36 | -13 ABAP_OPENCODE 도 Phoenix 연결(8914 중계 경유) — abap-specgen 프로젝트 trace 확인. DB_SSLMODE 는 env 로 |
|
||||
| 17:39 | Phoenix 관측 정리 문서(docs/tech/observability-phoenix.md) — 결정·트레이스 모양·실측·오프라인 설치 요령 |
|
||||
| 18:09 | CodeAssist 도커 배포 세트(compose·Dockerfile·deploy.sh) 만들고 로컬에서 채팅·Phoenix 까지 e2e 확인. ABAP_OPENCODE 엔 bare/deploy.sh 추가 |
|
||||
| 18:19 | 우리 서버(20.200.170.37)에 Phoenix(도커)·CodeAssist 백엔드(도커) 띄우고 ABAP_OPENCODE 갱신 — CodeAssist 채팅→Phoenix 확인, 워처→Phoenix 연결 확인. 바깥 8080/6006 은 NSG 미개방 |
|
||||
| 18:34 | 오늘 정리: docs/orders/20260922.md(한 것·다음 할 일·접속 메모) 작성, 양쪽 git 전부 push |
|
||||
| 20:32 | 우리 서버(20.200.170.37:8080) 앱 빌드 준비 — 8080·6006 바깥에서 200 확인, .env.production 에 서버 API 주소, 빌드 결과에 박히는 것·CORS(tauri origin) 허용 확인. 서버 테스트 계정 t@x.com 삭제(세션 2개 포함). 버전 0.1.4 로 올려 맥 빌드 |
|
||||
| 20:36 | 맥 빌드 앱이 서버에 요청을 못 보내던 원인 — macOS ATS 가 http 차단. src-tauri/Info.plist 에 NSAllowsArbitraryLoads 넣어 재빌드, 앱 요청이 서버 로그에 찍히는 것 확인(0.1.4 dmg) |
|
||||
| 20:39 | Windows msi 빌드 팀원 가이드(docs/tech/windows-build-guide.md) — 준비물·.env.production·빌드·설치·핫키표·막힐 때. 맥 크로스 빌드는 접음 |
|
||||
Reference in New Issue
Block a user