70일차 자료 추가(답 제외), 69일차 flow.py call -v 반영
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
eb1903bb51
commit
2478da876f
62 files changed
+4961
-30
No files matched your search
@@ -0,0 +1,184 @@
|
||||
# 70일차 개요 · Workflow 템플릿화와 모듈화
|
||||
|
||||
> 운영·확장 관점의 AI 워크플로우 설계 고도화 · 2026-10-22
|
||||
> 13장 · 각 장은 가로줄(`---`)로 나뉩니다. 1교시에는 1~5장을 보고, 나머지 장은 각 단계를 설명할 때 함께 띄웁니다.
|
||||
|
||||
| 장 | 범위 |
|
||||
| --- | --- |
|
||||
| 1~5 | 표지 · 목표 · 시간표 · 복사의 비용 · 오늘의 그림 |
|
||||
| 6~7 | 1단계 · 템플릿화 |
|
||||
| 8~9 | 2단계 · 모듈화 |
|
||||
| 10~11 | 3단계 · 변경 관리 |
|
||||
| 12~13 | 7교시 바이브 코딩 · 정리와 예고 |
|
||||
|
||||
---
|
||||
|
||||
## 1 / 13 · 표지
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
K["공지 키트<br/>설정 표"] --> M[["규칙 검사<br/>모듈"]]
|
||||
S["SMS"] --> M
|
||||
T["시험용 웹훅"] --> M
|
||||
classDef o fill:#F2A541,stroke:#F2A541,color:#fff
|
||||
classDef t fill:#0F7C80,stroke:#0F7C80,color:#fff
|
||||
classDef g fill:#8A9BA0,stroke:#8A9BA0,color:#fff
|
||||
class K,S o
|
||||
class M t
|
||||
class T g
|
||||
```
|
||||
|
||||
**70일차**
|
||||
|
||||
# Workflow 템플릿화와 모듈화
|
||||
|
||||
같은 것과 다른 것 · 설정 표 · Sub-workflow 모듈 · 계약 · 하위 호환 · 버전
|
||||
|
||||
<sub>운영·확장 관점의 AI 워크플로우 설계 고도화 · 2026-10-22</sub>
|
||||
|
||||
---
|
||||
|
||||
## 2 / 13 · 오늘 할 수 있게 될 세 가지
|
||||
|
||||
| | 오늘 할 수 있게 될 것 |
|
||||
| :-: | --- |
|
||||
| **①** | 복사본에서 같은 것·다른 것을 찾아 **설정 표 하나**로 여러 종류를 처리하는 워크플로우로 만든다 |
|
||||
| **②** | 여러 곳에서 쓰는 일을 **모듈**(Sub-workflow)로 떼어 따로 시험하고, 두 워크플로우가 함께 쓴다 |
|
||||
| **③** | 모듈을 바꿀 때 **하위 호환**은 같은 id로, **깨지는 변경**은 새 버전으로 두고 영향 받는 테스트를 모두 돌린다 |
|
||||
|
||||
---
|
||||
|
||||
## 3 / 13 · 오늘의 시간표
|
||||
|
||||
| ① 1~2교시 | ② 3~4교시 | ③ 5~6교시 | ④ 7~8교시 |
|
||||
| --- | --- | --- | --- |
|
||||
| **1단계** | **2단계** | **3단계** | **바이브 코딩** |
|
||||
| 템플릿화 | 모듈화 | 변경 관리 | `tkit` |
|
||||
| Lab 01 복사본 → 공지 키트 | Lab 02 모듈 · SMS | Lab 03 v1.1 · v2 · 영향 표 | 만들기 · 발표 · 정리 |
|
||||
|
||||
> 09:00 시작 · 50분 수업 10분 휴식 · 4교시 뒤 13:00~14:00 점심
|
||||
|
||||
---
|
||||
|
||||
## 4 / 13 · 복사의 비용
|
||||
|
||||
`samples/`: 69일차 공지 팀을 점검·보안·교육용으로 복사한 3개 (파일에서 비교한 값)
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| 노드 | 9개, 이름은 모두 같음 |
|
||||
| 다른 노드 | 4개 (웹훅 경로, 작성자 지시문, 규칙 검사 코드, 결과의 종류) |
|
||||
| 같은 값이 두 곳에 | 꼭 넣을 문장이 지시문과 검사 코드에 따로 |
|
||||
| 공통 규칙 하나 더하기 | 6곳 (파일 3개 × 지시문·검사) |
|
||||
|
||||
> 복사는 처음에는 빠르고, 고칠 때 비쌉니다.
|
||||
|
||||
---
|
||||
|
||||
## 5 / 13 · 오늘의 그림
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
W(["kind · facts"]) --> KS["Kind settings<br/>(설정 표)"] --> A{{"작성자"}} --> M[["규칙 검사 모듈<br/>v1.1 · v2"]] --> R(["공지"])
|
||||
SW(["facts"]) --> SA{{"SMS 작성"}} --> M1[["규칙 검사 모듈 v1.1"]] --> SR(["문자"])
|
||||
```
|
||||
|
||||
> Lab 01(설정 표) → Lab 02(모듈, 두 번째 사용처) → Lab 03(모듈 바꾸기) 순서로 완성합니다.
|
||||
|
||||
---
|
||||
|
||||
## 6 / 13 · 1단계 · 같은 것, 다른 것, 우연히 다른 것
|
||||
|
||||
| 분류 | 예 | 어디로 |
|
||||
| --- | --- | --- |
|
||||
| 같은 것 | 흐름(웹훅 → 작성 → 검사 → 결과), 날짜·연락처 검사 | 그대로 하나 · 여러 곳에서 쓰면 모듈 |
|
||||
| 종류마다 다른 것 | 머리말, 최대 길이, 꼭 넣을 문장 | **설정 표** |
|
||||
| 우연히 다른 것 | 한 파일만 고친 규칙, 오타 | 복사가 만든 버그 → 하나로 맞춤 |
|
||||
|
||||
---
|
||||
|
||||
## 7 / 13 · 1단계 · 설정 표와 없는 값 (수업 준비 측정)
|
||||
|
||||
| | 결과 |
|
||||
| --- | --- |
|
||||
| 공지 키트 (표 3줄) `lab01` | 5/5 |
|
||||
| 표에 없는 `survey`를 보냄 (예제) | 머리말·익명 문장 없이 **그대로 게시** |
|
||||
| 표에 한 줄 + 없는 종류는 400과 목록 | `lab01-challenge` 1/4 → 4/4 |
|
||||
|
||||
> 표에 없는 종류는 규칙도 없습니다. 없으면 멈추고, 있는 종류를 알려 줍니다.
|
||||
|
||||
---
|
||||
|
||||
## 8 / 13 · 2단계 · Sub-workflow 모듈
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
C["부르는 쪽<br/>Execute Workflow<br/>id modRuleCheck01"] -->|"facts · draft ·<br/>max_length · required_phrases"| T["모듈<br/>Execute Workflow Trigger"] --> R["Rule checks"] -->|"passed · codes · issues"| C
|
||||
```
|
||||
|
||||
| 확인 (n8n 2.42.6) | |
|
||||
| --- | --- |
|
||||
| 웹훅 없는 모듈도 push로 게시되고 불러짐 | ✔ |
|
||||
| 시험용 웹훅으로 모듈만 시험 `lab02-module` | 5/5, 0.1초 (LLM 없음) |
|
||||
| 키트가 모듈을 부르게 바꾼 뒤 `lab01` | 5/5 → 5/5 (테스트 수정 없음) |
|
||||
|
||||
---
|
||||
|
||||
## 9 / 13 · 2단계 · 두 번째 사용처: SMS
|
||||
|
||||
| | 공지 키트 | SMS |
|
||||
| --- | --- | --- |
|
||||
| 모듈 | 같은 `modRuleCheck01` | 같은 `modRuleCheck01` |
|
||||
| `max_length` | 설정 표 (500~800) | 80 |
|
||||
| `required_phrases` | 설정 표 | `[]` |
|
||||
| 테스트 | `lab01` 5/5 | `lab02-challenge` 4/4 |
|
||||
|
||||
> 다른 값은 모듈 **안**이 아니라 **입력**으로. 모듈 안에 "SMS면 80"이 들어가면 쓰는 곳이 늘 때마다 모듈을 고칩니다.
|
||||
|
||||
---
|
||||
|
||||
## 10 / 13 · 3단계 · 하위 호환 변경 (같은 id)
|
||||
|
||||
사외 링크 금지: 새 입력 `allowed_domains`(없으면 `intra.example.com`), 새 코드 `external_link`
|
||||
|
||||
| 수업 준비 때 | 결과 |
|
||||
| --- | --- |
|
||||
| 처음 (`new URL()`로 호스트 읽기) | `lab03` 2/4 — 사내 링크도 막음 (Code 노드에 `URL` 없음) |
|
||||
| 글자로 호스트 자르기 | 4/4 |
|
||||
| push 직후 쓰는 곳 모두 | 모듈 시험 5/5 · 키트 5/5 · SMS 4/4 |
|
||||
|
||||
---
|
||||
|
||||
## 11 / 13 · 3단계 · 깨지는 변경은 v2 (새 id)
|
||||
|
||||
| | v1.1 (`modRuleCheck01`) | v2 (`modRuleCheck02`) |
|
||||
| --- | --- | --- |
|
||||
| 결과 | `passed`, `codes`, `issues` | `passed`, `blocking`, `warnings`, `issues` |
|
||||
| `too_long` | 막음 | 경고 |
|
||||
| 쓰는 곳 | SMS, 시험용 웹훅 | 공지 키트, v2 시험용 웹훅 |
|
||||
|
||||
> 수업 준비 때: 키트를 v2로 옮기며 키트 결과의 `codes`를 빼자 `lab01` **2/5**. `codes`를 남기고 새 필드를 **더해** 5/5. 계약은 층마다 있습니다.
|
||||
|
||||
---
|
||||
|
||||
## 12 / 13 · 7교시 · 바이브 코딩 `tkit`
|
||||
|
||||
```text
|
||||
$ tkit ~/vibe/templates
|
||||
▸ n8n-notice-kit name: [training-mail] prefix: [[교육 신청 확인]] max_length: [400]
|
||||
```
|
||||
|
||||
- 템플릿 폴더 + `template.yaml` → 변수를 채워 새 파일 (cookiecutter 방식)
|
||||
- 가장 까다로운 곳: 템플릿 변수와 n8n 표현식 `{{ }}`이 겹침
|
||||
|
||||
---
|
||||
|
||||
## 13 / 13 · 정리와 71일차 예고
|
||||
|
||||
| 오늘 | 한 줄 |
|
||||
| --- | --- |
|
||||
| 1단계 | 다른 것은 설정 표 한 곳에, 표에 없으면 멈춘다 |
|
||||
| 2단계 | 여러 곳에서 쓰는 일은 모듈로, 다른 값은 입력으로, 시험용 웹훅으로 따로 시험 |
|
||||
| 3단계 | 하위 호환은 같은 id, 깨지는 변경은 새 id. 바꾸면 영향 표의 테스트를 모두 |
|
||||
|
||||
- 71일차: **RAG 기반 검색·응답** — 사내 규정 문서를 검색해 근거와 함께 답하기 · 바이브 코딩 `tdoc`
|
||||
@@ -0,0 +1,79 @@
|
||||
# 70일차 실습 준비 · 수업 전에 미리 해 두면 좋은 것
|
||||
|
||||
- 수업일: 2026-10-22 (70일차) · Workflow 템플릿화와 모듈화, 재사용 가능한 구조 설계
|
||||
- 준비 시간: 약 10분 (69일차 준비를 했다면 1·2절만)
|
||||
- 먼저 WSL에서 `cd ~/aio-01d4-stu && git pull`로 오늘 자료를 받습니다 (수강생 저장소: https://gl.isitsoft.kr/publicproj/aio-01d4-stu).
|
||||
- **수업 전날까지** 1~2절을 끝내 주세요.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["1. n8n 켜기"] --> B["2. doctor<br/>ready"] --> C["3. 미리 읽기"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. n8n 켜기 (전날 필수, 2분)
|
||||
|
||||
오늘은 데이터 API를 쓰지 않습니다 (켜 두어도 됩니다).
|
||||
|
||||
```bash
|
||||
sudo systemctl disable --now ollama 2>/dev/null # WSL에 설치한 Ollama가 있으면 끄고 자동 시작도 끔
|
||||
cd ~/aio-01d4-stu/Last3Mon/65/n8n
|
||||
docker compose rm -sf ollama # Ollama 컨테이너가 있으면 지움 (없으면 그냥 지나감)
|
||||
docker compose start
|
||||
```
|
||||
|
||||
- **66일차부터 LLM은 OpenAI API 키(`Last3Mon/.env`, Credential `OpenAI (.env)`)만 씁니다.** Ollama는 쓰지 않으므로 위처럼 꺼서 메모리를 아낍니다. 다음 날부터는 같은 명령을 그대로 써도 됩니다.
|
||||
- `.../day65-n8n/compose.yml: no such file or directory` → 홈이 아닌 곳에 설치함. `Last3Mon/65/n8n/.env`에 `N8N_HOME=<설치 폴더>` ([67일차 준비](../67/00-DAY67-PREP.md) 1절).
|
||||
|
||||
## 2. 준비 확인 (전날 필수, 2분)
|
||||
|
||||
```bash
|
||||
cd ~/aio-01d4-stu/Last3Mon/70
|
||||
uv run tools/flow.py doctor
|
||||
```
|
||||
|
||||
```text
|
||||
✔ n8n install folder /home/<사용자>/day65-n8n
|
||||
✔ n8n container day65-n8n-n8n-1
|
||||
✔ n8n http://localhost:5678
|
||||
! data API http://localhost:8800 (not used today) ← 켜 두었다면 ✔
|
||||
✔ credential 'OpenAI (.env)' (openAiCourse0001)
|
||||
✔ node catalog (for check)
|
||||
✔ CLI coding agent: codex, claude
|
||||
ready
|
||||
```
|
||||
|
||||
| ✘ 항목 | 할 일 |
|
||||
| --- | --- |
|
||||
| n8n container | 1절 |
|
||||
| credential | `cd ~/aio-01d4-stu/Last3Mon/65/n8n && bash register-credentials.sh` |
|
||||
| CLI coding agent | [67일차 준비](../67/00-DAY67-PREP.md) 2절 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 미리 읽어 오면 좋은 내용 (선택, 약 5분)
|
||||
|
||||
### 3.1 복사해서 고친 워크플로우
|
||||
|
||||
69일차 공지 팀을 보안 공지용으로 쓰고 싶다면, 보통 복사해서 머리말과 규칙을 고칩니다. 교육 공지, 설문 공지도 그렇게 하면 파일이 4개가 됩니다. 이때 **모든 공지에 같은 규칙**(예: 사외 링크 금지)을 더하려면 몇 곳을 고쳐야 할까요?
|
||||
|
||||
### 3.2 용어
|
||||
|
||||
| 용어 | 한 줄 설명 |
|
||||
| --- | --- |
|
||||
| 템플릿화 | 같은 흐름은 하나로 두고, 다른 값만 **설정**으로 뺌 |
|
||||
| 모듈 (Sub-workflow) | 여러 워크플로우가 **불러 쓰는** 워크플로우. n8n의 Execute Workflow · Execute Workflow Trigger |
|
||||
| 계약 | 모듈의 입력·결과 이름과 모양 |
|
||||
| 하위 호환 | 모듈을 바꿔도 예전 호출이 그대로 동작 |
|
||||
| 버전 | 깨지는 변경은 새 id로 나란히 두고 쓰는 곳을 하나씩 옮김 |
|
||||
|
||||
## 4. 당일 준비물
|
||||
|
||||
- 충전된 노트북과 충전기, WSL의 Docker, Windows Terminal(WSL) 창 **두 개**, 웹 브라우저
|
||||
- (선택) 69일차 `Last3Mon/69/my-work/*.json` 공지 팀 (오늘 `samples/`와 비교해 볼 수 있음), 68일차 `~/vibe/tflow`
|
||||
|
||||
## 확인
|
||||
|
||||
- [ ] `docker compose start` 후 http://localhost:5678 이 열린다
|
||||
- [ ] `uv run tools/flow.py doctor`에서 n8n · credential · CLI 에이전트가 ✔
|
||||
@@ -0,0 +1,93 @@
|
||||
# 1단계 · 템플릿화: 같은 것과 다른 것 나누기
|
||||
|
||||
- 교시: 1~2교시 (09:00~10:50)
|
||||
- 실습: [Lab 01](../../Last3Mon/70/LAB-01-Q-TEMPLATE-KIT.md)
|
||||
- 이 단계가 끝나면: 복사해서 고친 워크플로우에서 같은 것과 다른 것을 찾고, 다른 것만 **설정 표**로 빼서 하나의 워크플로우로 만들 수 있다.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["1. 복사의 비용"] --> B["2. 같은 것 · 다른 것 ·<br/>우연히 다른 것"] --> C["3. 설정 표"] --> D["4. 표에 없으면<br/>멈춤"] --> E["5. 요청문으로"]
|
||||
```
|
||||
|
||||
## 1. 복사의 비용
|
||||
|
||||
공지 팀(69일차)이 잘 동작하자 보안 공지, 교육 공지에도 쓰고 싶어졌습니다. 가장 쉬운 방법은 파일을 복사해서 조금 고치는 것입니다. `samples/`의 세 파일이 그렇게 만든 것입니다.
|
||||
|
||||
| 파일에서 비교한 값 | |
|
||||
| --- | --- |
|
||||
| 노드 | 세 파일 모두 9개, 이름 같음 |
|
||||
| 다른 노드 | 4개: `Notice webhook`(경로), `Writer agent`(지시문의 머리말·꼭 넣을 문장·주의), `Rule checks`(최대 길이·꼭 넣을 문장), `Build result`(종류 이름) |
|
||||
| 같은 값이 두 곳에 | 꼭 넣을 문장이 지시문과 검사 코드에 **따로** |
|
||||
|
||||
| 할 일 | 복사본 3개 | 템플릿 1개 |
|
||||
| --- | --- | --- |
|
||||
| 공통 규칙 하나 더하기 (예: 사외 링크 금지) | 6곳 (파일 3 × 지시문·검사) | 1곳 (2단계에서는 모듈 1곳) |
|
||||
| 새 종류 더하기 | 파일 하나 더 복사 | 표 한 줄 |
|
||||
| 한쪽만 고친 실수 | 찾기 어려움 | 생기지 않음 |
|
||||
|
||||
## 2. 같은 것 · 다른 것 · 우연히 다른 것
|
||||
|
||||
| 분류 | 묻는 것 | 예 | 처리 |
|
||||
| --- | --- | --- | --- |
|
||||
| 같은 것 | 모든 종류에서 같아야 하나? | 흐름, 날짜·연락처 검사 | 하나로 (여러 워크플로우가 쓰면 모듈, 2단계) |
|
||||
| 종류마다 다른 것 | 업무상 종류마다 달라야 하나? | 머리말, 최대 길이, 꼭 넣을 문장, 주의 | **설정 표** |
|
||||
| 우연히 다른 것 | 같아야 하는데 다르게 되어 있나? | 한 파일만 고친 규칙, 오타 | 복사가 만든 버그 → 하나로 맞춤 |
|
||||
|
||||
에이전트에게 비교를 맡길 때는 **노드 단위로**, 업무상 뜻과 함께, 동작과 상관없는 차이(위치, id)는 빼고 달라고 합니다. 표를 받은 뒤 분류는 사람이 합니다.
|
||||
|
||||
## 3. 설정 표
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
W(["kind · facts"]) --> KS["Kind settings<br/>kind → 한 줄"] --> A{{"Writer agent<br/>표의 prefix · 문장 · 주의"}} --> R["Rule checks<br/>표의 max_length · 문장"] --> O(["결과"])
|
||||
```
|
||||
|
||||
| kind | prefix | max_length | required_phrases |
|
||||
| --- | --- | --- | --- |
|
||||
| maintenance | `[점검 안내]` | 600 | — |
|
||||
| security | `[보안 안내]` | 500 | IT팀은 절대 비밀번호를 묻지 않습니다. |
|
||||
| training | `[교육 안내]` | 800 | 신청은 IT 포털에서 할 수 있습니다. |
|
||||
|
||||
- 표는 **한 곳**(Code 노드 `Kind settings`)에만. 작성자 지시문과 검사가 **같은 표**를 읽습니다. 지시문에 값을 다시 쓰면 복사가 다시 생깁니다.
|
||||
- 공통 지시문에는 종류 이야기를 넣지 않습니다 ("머리말은 주어진 prefix로 시작").
|
||||
|
||||
수업 준비 때 공지 키트(표 3줄): `cases/lab01.json` 5/5, 1.4~3.8초.
|
||||
|
||||
## 4. 표에 없으면 멈춘다
|
||||
|
||||
예제 상태의 키트에 표에 없는 `survey`, `party`를 보내면 **공지를 써서 게시**했습니다 (수업 준비 측정, `lab01-challenge` 1/4). 표에 없으니 머리말도, 꼭 넣을 문장도, 길이 제한도 없고, 검사할 것도 없어 통과했습니다.
|
||||
|
||||
| 할 일 | 방법 |
|
||||
| --- | --- |
|
||||
| 새 종류 | 표에 한 줄 (`survey`) |
|
||||
| 없는 종류 | 400 + `kinds` 목록 (목록은 **표에서** 만들어야 종류를 더할 때 따로 고치지 않음) |
|
||||
|
||||
고친 뒤 4/4. 없는 종류는 0.2초 (LLM을 부르지 않음).
|
||||
|
||||
> 템플릿은 "값만 바꾸면 된다"가 장점이지만, **값이 없을 때**를 정하지 않으면 조용히 틀린 결과를 냅니다.
|
||||
|
||||
## 5. 요청문으로
|
||||
|
||||
Lab과 다른 업무(사내 교육 신청 확인 메일)로 예를 듭니다.
|
||||
|
||||
```text
|
||||
samples/ 를 보지 말고, my-work/course-mail.json 을 만들어 줘.
|
||||
① 파일: my-work/course-mail.json
|
||||
② 입력: POST 웹훅 my-course-mail, 본문 course(과정 코드), name(신청자). 둘 다 필수.
|
||||
③ 처리: 과정마다 다른 것은 Code "Course settings" 표 한 곳에만:
|
||||
n8n-basic → 제목 "[n8n 기초] 신청 확인", 장소 "본관 3층", 준비물 "노트북"
|
||||
rag-intro → 제목 "[RAG 입문] 신청 확인", 장소 "별관 2층", 준비물 "없음"
|
||||
메일 본문을 쓰는 LLM 지시문은 공통 문장만, 값은 표에서 읽는다.
|
||||
표에 없는 course 면 400 {"error": "unknown course", "courses": 표의 키 목록}.
|
||||
④ 결과: {"course", "subject", "body"}
|
||||
⑤ 기대 결과: cases/course-mail.json
|
||||
```
|
||||
|
||||
- "값은 **한 곳에만**", "지시문은 **공통 문장만**", "표에 없으면"을 적었습니다. 이 세 줄이 템플릿화의 요점입니다.
|
||||
|
||||
## 정리
|
||||
|
||||
- [ ] 복사본은 고칠 때 비싸다: 같은 값이 여러 곳에
|
||||
- [ ] 같은 것 · 종류마다 다른 것 · 우연히 다른 것으로 나눈다
|
||||
- [ ] 다른 것은 설정 표 한 곳에, 모든 노드가 같은 표를 읽는다
|
||||
- [ ] 표에 없으면 멈추고, 있는 것을 알려 준다
|
||||
@@ -0,0 +1,81 @@
|
||||
# 2단계 · 모듈화: Sub-workflow와 계약
|
||||
|
||||
- 교시: 3~4교시 (11:00~12:50)
|
||||
- 실습: [Lab 02](../../Last3Mon/70/LAB-02-Q-MODULES.md)
|
||||
- 이 단계가 끝나면: 여러 워크플로우가 쓰는 일을 n8n **Sub-workflow 모듈**로 떼어 내고, 따로 시험하고, 결과가 그대로인지 테스트로 확인하며 바꿀 수 있다.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["1. 무엇을 모듈로"] --> B["2. Sub-workflow"] --> C["3. 다른 값은 입력으로"] --> D["4. 시험용 웹훅"] --> E["5. 바꿔도 결과는<br/>그대로"]
|
||||
```
|
||||
|
||||
## 1. 무엇을 모듈로
|
||||
|
||||
| 모듈 후보 | 아님 |
|
||||
| --- | --- |
|
||||
| **두 곳 이상**에서 쓴다 (공지, 문자) | 한 곳에서만 씀 |
|
||||
| 입력과 결과를 **이름으로** 말할 수 있다 | 앞뒤 노드를 마음대로 읽어야 함 |
|
||||
| 혼자 시험할 수 있다 | 전체를 돌려야만 확인됨 |
|
||||
| 바뀌는 이유가 하나 (검사 규칙) | 여러 이유로 자주 바뀜 |
|
||||
|
||||
오늘의 모듈: **규칙 검사** (날짜·시간, 연락처, 길이, 꼭 넣을 문장). LLM이 없어 빠르고(0.1초), 공지 키트와 SMS가 함께 씁니다.
|
||||
|
||||
## 2. Sub-workflow
|
||||
|
||||
| 노드 | 하는 일 |
|
||||
| --- | --- |
|
||||
| Execute Workflow Trigger (모듈 쪽) | 모듈의 시작. **입력 이름과 종류**를 적는다 (`facts` 글자, `max_length` 숫자, `required_phrases` 목록) |
|
||||
| Execute Workflow (부르는 쪽) | 모듈을 **id**로 찾아 입력을 넘기고, 모듈 마지막 노드의 결과를 받는다 |
|
||||
|
||||
| | 웹훅으로 부르기 (68·69일차) | Sub-workflow (오늘) |
|
||||
| --- | --- | --- |
|
||||
| 부르는 법 | HTTP POST `/webhook/<path>` | Execute Workflow, id |
|
||||
| 계약이 보이는 곳 | 문서와 테스트 | Trigger 노드의 입력 목록 |
|
||||
| 밖에서 바로 시험 | `call`로 바로 | 시험용 웹훅이 필요 |
|
||||
| 꺼졌을 때 | 404 (68·69일차에서 다룸) | 모듈이 없으면 부르는 노드에서 실패 |
|
||||
|
||||
수업 준비 때 확인: n8n 2.42.6에서 웹훅이 없는(Trigger만 있는) 모듈도 `flow.py push`로 게시되고, 다른 워크플로우에서 id로 불러졌습니다. 모듈 파일에는 id(`modRuleCheck01`)를 **직접** 씁니다.
|
||||
|
||||
## 3. 다른 값은 입력으로
|
||||
|
||||
키트 안의 규칙 검사 코드는 웹훅 본문, 설정 표, 앞 노드를 바로 읽었습니다. 모듈은 그럴 수 없습니다 (부르는 쪽이 다르기 때문). 필요한 값을 모두 **입력**으로 받습니다.
|
||||
|
||||
| 입력 | 공지 키트가 주는 값 | SMS가 주는 값 |
|
||||
| --- | --- | --- |
|
||||
| `facts` | 웹훅 본문 | 웹훅 본문 |
|
||||
| `draft` | 작성자 결과 | SMS 작성 결과 |
|
||||
| `max_length` | 설정 표 (500~800) | 80 |
|
||||
| `required_phrases` | 설정 표 | `[]` |
|
||||
|
||||
> 모듈 안에 "SMS면 80" 같은 **쓰는 곳 이야기**가 들어가면, 쓰는 곳이 늘 때마다 모듈을 고쳐야 합니다.
|
||||
|
||||
## 4. 시험용 웹훅
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
W(["Test webhook<br/>my-rule-check"]) --> E["Execute Workflow<br/>modRuleCheck01"] --> R(["Respond"])
|
||||
```
|
||||
|
||||
- 본문을 그대로 모듈 입력으로 넘기는 세 노드짜리 워크플로우. 모듈만 따로 `test` 할 수 있습니다.
|
||||
- 수업 준비 때 `cases/lab02-module.json` 5/5. 처음 호출 1.6초, 그다음 0.1초씩.
|
||||
- 일부러 틀린 초안(시간 빠짐, 전화번호, 꼭 넣을 문장 빠짐, 짧은 한도)을 넣어 **검사 코드 하나하나**를 확인합니다. 공지 전체를 돌려서는 이렇게 정확히 확인하기 어렵습니다.
|
||||
|
||||
## 5. 바꿔도 결과는 그대로 (리팩터링)
|
||||
|
||||
키트 안의 검사 코드를 지우고 모듈 호출로 바꿉니다. 바꾸기 전과 뒤에 **같은 테스트**를 돌립니다.
|
||||
|
||||
| 수업 준비 때 | `cases/lab01.json` |
|
||||
| --- | --- |
|
||||
| 바꾸기 전 (코드가 키트 안에) | 5/5 |
|
||||
| 바꾼 뒤 (모듈 호출) | 5/5, 테스트 수정 없음 |
|
||||
| SMS를 같은 모듈로 (`lab02-challenge`) | 4/4 |
|
||||
|
||||
- 테스트를 하나도 고치지 않고 통과해야 "결과는 그대로"입니다. 테스트를 고쳤다면 결과가 바뀐 것입니다.
|
||||
- n8n **Executions**에는 키트 실행과 모듈 실행이 따로 남아, 어느 쪽에서 문제가 났는지 볼 수 있습니다.
|
||||
|
||||
## 정리
|
||||
|
||||
- [ ] 두 곳 이상에서 쓰고, 입력·결과를 이름으로 말할 수 있으면 모듈
|
||||
- [ ] Execute Workflow Trigger에 입력 이름·종류, 부르는 쪽은 id로
|
||||
- [ ] 쓰는 곳마다 다른 값은 모듈 안이 아니라 입력으로
|
||||
- [ ] 시험용 웹훅으로 모듈만 따로, 바꾼 뒤에는 같은 테스트를 그대로
|
||||
@@ -0,0 +1,81 @@
|
||||
# 3단계 · 재사용 구조의 변경 관리
|
||||
|
||||
- 교시: 5~6교시 (14:00~15:50)
|
||||
- 실습: [Lab 03](../../Last3Mon/70/LAB-03-Q-CHANGE-AND-VERSION.md)
|
||||
- 이 단계가 끝나면: 여러 곳에서 쓰는 모듈을 바꿀 때 하위 호환인지 판단하고, 깨지는 변경은 새 버전으로 나란히 두며, 영향 받는 테스트를 모두 돌릴 수 있다.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["1. 재사용의 대가"] --> B["2. 하위 호환<br/>(같은 id)"] --> C["3. 깨지는 변경<br/>(새 id)"] --> D["4. 계약은 층마다"] --> E["5. 영향 표"]
|
||||
```
|
||||
|
||||
## 1. 재사용의 대가
|
||||
|
||||
모듈을 한 번 고치면 쓰는 곳이 **모두 함께** 바뀝니다. 좋은 점(규칙 하나로 모두 고침)이자 위험(하나 고쳤는데 여럿이 깨짐)입니다.
|
||||
|
||||
| 질문 | 답에 따라 |
|
||||
| --- | --- |
|
||||
| 예전 호출이 아무것도 바꾸지 않아도 예전처럼 동작하나? | 예 → 하위 호환, **같은 id**로 고침 |
|
||||
| 결과 필드가 없어지거나 뜻이 바뀌나? | 예 → 깨지는 변경, **새 id**로 새 버전 |
|
||||
|
||||
## 2. 하위 호환 변경: 사외 링크 금지
|
||||
|
||||
| 바꾼 것 | 하위 호환인 이유 |
|
||||
| --- | --- |
|
||||
| 새 입력 `allowed_domains` | 없으면 기본값 `intra.example.com` → 예전 호출은 고칠 필요 없음 |
|
||||
| 새 코드 `external_link` | 기존 결과 필드(`passed`, `codes`, `issues`)는 그대로, `codes`에 하나 더 들어갈 뿐 |
|
||||
|
||||
수업 준비 때 (1회씩):
|
||||
|
||||
| 단계 | 결과 |
|
||||
| --- | --- |
|
||||
| 바꾸기 전 `lab03` | 3/4 (바깥 링크를 못 잡음) |
|
||||
| 처음 고침: `new URL(...)`로 호스트 읽기 | 2/4 — **사내 링크까지 막음**. Code 노드 안에서 `URL`을 쓸 수 없어 모든 링크가 "읽기 실패 = 바깥"으로 처리됨 |
|
||||
| 호스트를 글자로 잘라 읽기 | 4/4 |
|
||||
| push 직후 쓰는 곳 | 모듈 시험 5/5 · 공지 키트 5/5 · SMS 4/4 |
|
||||
|
||||
> 같은 id로 push한 순간 키트와 SMS가 **모두** 새 모듈을 씁니다. 그래서 쓰는 곳 테스트를 모두 다시 돌립니다. 사내 링크까지 막혔던 버그가 그대로 나갔다면 공지와 문자가 함께 멈췄을 것입니다.
|
||||
|
||||
## 3. 깨지는 변경: 심각도
|
||||
|
||||
팀장: "글자 수 초과는 경고만, 나머지는 막기. 결과에 `blocking`과 `warnings`를." 문자는 지금 그대로.
|
||||
|
||||
| | v1.1 `modRuleCheck01` | v2 `modRuleCheck02` |
|
||||
| --- | --- | --- |
|
||||
| `passed` 뜻 | 문제가 하나도 없음 | **막는** 문제가 없음 (경고는 있어도 됨) |
|
||||
| 결과 | `codes`, `issues` | `blocking`, `warnings`, `issues` |
|
||||
| 쓰는 곳 | SMS, 시험용 웹훅 | 공지 키트, v2 시험용 웹훅 |
|
||||
|
||||
`passed`의 뜻과 결과 필드가 바뀌므로 같은 id로 고치면 SMS가 그 순간 깨집니다. 그래서 v2를 **나란히** 두고 키트만 옮겼습니다. 수업 준비 때 `cases/lab03-v2.json`(v2 모듈 · 키트 · SMS를 한 번에) 5/5.
|
||||
|
||||
## 4. 계약은 층마다
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
T["lab01 테스트<br/>(키트를 쓰는 쪽)"] -->|"codes를 읽음"| K["공지 키트"] -->|"blocking · warnings"| M[["모듈 v2"]]
|
||||
```
|
||||
|
||||
| 수업 준비 때 | `lab01` |
|
||||
| --- | --- |
|
||||
| 키트를 v2로 옮기며 결과를 `blocking`·`warnings`로 **바꾸고** `codes`를 뺌 | **2/5** |
|
||||
| `codes`를 남기고(`blocking` + `warnings`) 새 필드를 **더함** | 5/5 |
|
||||
|
||||
> 모듈의 깨지는 변경을 새 id로 막아도, 중간 층(키트)이 그 변화를 **자기 계약**으로 흘려보내면 그 위가 깨집니다. 새 필드는 더하고, 예전 필드는 남깁니다.
|
||||
|
||||
## 5. 영향 표
|
||||
|
||||
모듈을 바꾸기 전에 "누가 쓰나"를 표로 만듭니다. 에이전트에게 `my-work/*.json`에서 `executeWorkflow`의 `workflowId`를 찾게 하면 빠릅니다 (확인은 사람이).
|
||||
|
||||
| 모듈 · 버전 | 쓰는 워크플로우 | 돌릴 테스트 |
|
||||
| --- | --- | --- |
|
||||
| `modRuleCheck01` (v1.1) | SMS, 시험용 웹훅 | `lab02-challenge`, `lab02-module`, `lab03` |
|
||||
| `modRuleCheck02` (v2) | 공지 키트, v2 시험용 웹훅 | `lab01`, `lab01-challenge`, `lab03-v2` |
|
||||
|
||||
수업 준비 때 키트의 어려운 케이스 7개 (`kind`의 대소문자·공백, 한국어 이름, 공백만 보낸 사실, 없는 종류, 바깥·사내 링크, "아주 짧게"): 예제 2 키트 3/7 → 최종본 7/7. 고친 곳은 **키트만**(설정 표 앞에서 `kind` 다듬기, 사실 공백 확인, 없는 종류 처리)이었고 모듈은 고치지 않았습니다. 영향 표 덕분에 "키트 테스트만 돌리면 된다"는 것을 바로 알 수 있습니다.
|
||||
|
||||
## 정리
|
||||
|
||||
- [ ] 예전 호출이 그대로 동작하면 하위 호환 → 같은 id, 그리고 쓰는 곳 테스트를 **모두**
|
||||
- [ ] 결과의 뜻·필드가 바뀌면 새 id로 나란히, 쓰는 곳을 하나씩 옮긴다
|
||||
- [ ] 계약은 층마다: 중간 층도 예전 필드를 남기고 새 필드를 더한다
|
||||
- [ ] 바꾸기 전에 영향 표: 누가 쓰고, 어떤 테스트를 돌릴지
|
||||
@@ -0,0 +1,77 @@
|
||||
# 7·8교시 · 바이브 코딩 (`tkit`)
|
||||
|
||||
- 교시: 7교시 16:00~16:50 (각자 만들기), 8교시 17:00~17:50 (발표 · 정리 · 강사 바이브 코딩 · 팁 · 예고)
|
||||
- 과제: [VIBE-Q-TKIT](../../Last3Mon/70/VIBE-Q-TKIT.md)
|
||||
- 오늘은 `tkit`: 템플릿 폴더를 고르고 변수를 채우면 새 파일을 만드는 TUI (cookiecutter 방식). 오늘 만든 공지 키트를 템플릿으로 만들어 새 업무 워크플로우를 찍어 냅니다.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["7교시<br/>각자 만들기 50분"] --> B["발표<br/>10분"] --> C["강사 정리<br/>10분"] --> D["강사 바이브 코딩<br/>15분"] --> E["보충 · 팁<br/>10분"] --> F["71일차 예고<br/>5분"]
|
||||
```
|
||||
|
||||
## 1. 7교시 · 각자 만들기 (50분)
|
||||
|
||||
| 시간 | 단계 | 확인 |
|
||||
| --- | --- | --- |
|
||||
| 16:00~16:05 | 0. 준비 · 템플릿 폴더 직접 만들기 | `~/vibe/templates/n8n-notice-kit/template.yaml` |
|
||||
| 16:05~16:20 | 1. 글자 모드로 채우기 (R1 · R2) | n8n 표현식이 그대로, 숫자는 숫자 |
|
||||
| 16:20~16:30 | 2. 미리 보기 · 덮어쓰기 · 검사 (R3 · R5) | 두 번 만들면 멈춤, `flow.py check` |
|
||||
| 16:30~16:43 | 3. TUI (R4) | 입력칸이 YAML에서 |
|
||||
| 16:43~16:50 | 4. 정리 · 만든 워크플로우를 push · call · 발표 메모 | |
|
||||
|
||||
| 볼 것 | 막혔을 때 한마디 |
|
||||
| --- | --- |
|
||||
| n8n 표현식 `{{ $json }}`까지 바뀌어 JSON이 깨짐 | "템플릿 변수 표시를 다른 모양으로 정하세요" |
|
||||
| 숫자가 글자로 들어감 | "숫자 변수는 따옴표 없는 자리에" |
|
||||
| 만들 때마다 덮어씀 | "있으면 멈추고 알려 주게" |
|
||||
| 노드 이름·연결까지 변수로 만듦 | "흐름은 그대로 두고 값만 변수로 (Lab 01과 같음)" |
|
||||
| 실행해 보지 않고 다음 요청 | "만든 JSON을 직접 push · call" |
|
||||
|
||||
수업 준비 때 tkit를 미리 만들어 보지는 않았습니다. 강사 바이브 코딩(4절)에서 걸린 시간을 재어 정답본(`VIBE-A-TKIT.md`)에 남깁니다.
|
||||
|
||||
## 2. 8교시 · 발표 (10분)
|
||||
|
||||
- 1~2명. **`{{ }}` 충돌을 스스로 푼 사람**을 먼저 고릅니다.
|
||||
- 3분 발표 · 2분 질문: 잘 먹힌 요청문 / 안 먹힌 요청문 / 에이전트가 틀린 곳 / 템플릿으로 만든 워크플로우를 n8n에서 호출.
|
||||
|
||||
## 3. 강사 정리 (10분)
|
||||
|
||||
| | n8n 공지 키트 | tkit |
|
||||
| --- | --- | --- |
|
||||
| 다른 것을 빼는 곳 | `Kind settings` 표 | `template.yaml` 변수 |
|
||||
| 같은 것 | 흐름, 규칙 검사 모듈 | 템플릿 파일 내용 |
|
||||
| 없는 값 | 없는 종류 400 + 목록 | 필수 변수 빔 · 정의 안 된 변수 오류 |
|
||||
| 덮어쓰지 않기 | 모듈은 새 id로 v2 | 있는 파일은 멈춤 |
|
||||
| 결과 확인 | `cases/*.json` | 만든 JSON 검사, `flow.py check` |
|
||||
|
||||
- 템플릿(tkit)은 **복사를 빠르게** 하고, 설정 표·모듈(n8n)은 **복사를 없앱니다.** 둘 다 필요합니다: 처음 뼈대는 템플릿으로 찍고, 여러 곳에서 쓰는 일은 모듈로.
|
||||
|
||||
## 4. 강사 바이브 코딩 (15분)
|
||||
|
||||
| 주제 | 요청문 요지 | 보여 줄 것 |
|
||||
| --- | --- | --- |
|
||||
| 템플릿에 테스트 파일도 | "n8n-notice-kit 템플릿에 cases/[[ name ]].json 도 넣어, 변수로 기대 결과 머리말을 채워" | 만들자마자 `flow.py test` |
|
||||
| 영향 표 자동 | "my-work/*.json 에서 executeWorkflow 의 workflowId 를 모아 모듈 → 쓰는 곳 표를 출력" | Lab 03 영향 표를 명령 하나로 |
|
||||
| tflow로 비교 | "어제 tflow 로 samples/notice-security.json 과 my-work/notice-kit.json 을 차례로 열기" | 복사본과 템플릿의 구조 차이 |
|
||||
|
||||
걸린 시간과 결과를 `Last3Mon/70/VIBE-A-TKIT.md`에 적어 둡니다.
|
||||
|
||||
## 5. 보충 · 팁 (10분)
|
||||
|
||||
| 팁 | 설명 |
|
||||
| --- | --- |
|
||||
| 값만 변수로 | 흐름(노드·연결)을 변수로 만들면 템플릿이 쉽게 망가짐 |
|
||||
| 표시가 겹치지 않게 | 템플릿 언어와 대상 파일의 문법(`{{ }}`)이 겹치면 다른 표시를 씀 |
|
||||
| 덮어쓰지 않기 | 만드는 도구는 기본이 "있으면 멈춤" |
|
||||
| 만든 뒤 검사 | JSON이면 열어 보고, 가능하면 그 파일의 검사 도구까지 |
|
||||
| 계약을 지키며 바꾸기 | 더하기는 쉽고, 빼거나 뜻을 바꾸면 새 버전 |
|
||||
|
||||
## 6. 71일차 예고 (5분)
|
||||
|
||||
- 오늘: 템플릿과 모듈. 내일: **RAG 기반 검색·응답** — 사내 규정 문서를 잘게 나눠 검색하고, 근거 문단과 함께 답하는 워크플로우. 검색 품질을 바꿔 가며 비교합니다.
|
||||
- 바이브 코딩: `tdoc` (내 md 문서를 임베딩해 SQLite에 저장하고, 질문하면 답과 근거 문단을 보여 주는 RAG TUI).
|
||||
|
||||
## 확인 (강사)
|
||||
|
||||
- [ ] 7교시 시작 전 템플릿 폴더 만드는 방법을 화면에 띄웠다.
|
||||
- [ ] 발표자 1~2명, 강사 정리 표, 강사 바이브 코딩 1개(시간 기록), 팁, 예고.
|
||||
@@ -0,0 +1,39 @@
|
||||
# 70일차 · Workflow 템플릿화와 모듈화, 재사용 가능한 구조 설계 (바이브 코딩)
|
||||
|
||||
- 일자: 2026-10-22 (70일차)
|
||||
- 교과목: 노코드 멀티 에이전트 워크플로우 설계 및 운영
|
||||
- 단원: 운영·확장 관점의 AI 워크플로우 설계 고도화
|
||||
- 학습 내용: Workflow 템플릿화 및 모듈화, 재사용 가능한 구조 설계
|
||||
- 실습 폴더: [Last3Mon/70](../../Last3Mon/70/README.md)
|
||||
- 실습 환경: 65일차 n8n 2.42.6 + OpenAI API(`gpt-4.1-mini`) + **CLI 코딩 에이전트**(Codex · Claude Code · Antigravity 중 하나)
|
||||
- **실습 준비: [00-DAY70-PREP.md](00-DAY70-PREP.md) (수업 전날까지 1~2절 완료)**
|
||||
|
||||
## 오늘의 시간표
|
||||
|
||||
| 교시 | 시간 | 내용 | 자료 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | 09:00~09:50 | 오늘의 개요 · 1단계 · 템플릿화: 같은 것과 다른 것 나누기 | [개요](00-DAY70-OVERVIEW.md), [1단계](01-STAGE1-TEMPLATE.md) |
|
||||
| 2 | 10:00~10:50 | 1단계 · Lab 01 (복사본 비교, 공지 키트, 과제: 새 종류 · 없는 종류) | [Lab 01](../../Last3Mon/70/LAB-01-Q-TEMPLATE-KIT.md) |
|
||||
| 3 | 11:00~11:50 | 2단계 · 모듈화: Sub-workflow와 계약, Lab 02 예제 1·2 | [2단계](02-STAGE2-MODULES.md), [Lab 02](../../Last3Mon/70/LAB-02-Q-MODULES.md) |
|
||||
| 4 | 12:00~12:50 | 2단계 · Lab 02 과제 35분 (SMS도 같은 모듈) · 풀이 | [Lab 02](../../Last3Mon/70/LAB-02-Q-MODULES.md) |
|
||||
| - | 13:00~14:00 | 점심 | |
|
||||
| 5 | 14:00~14:50 | 3단계 · 재사용 구조의 변경 관리, Lab 03 예제 1·2 | [3단계](03-STAGE3-CHANGE-AND-VERSION.md), [Lab 03](../../Last3Mon/70/LAB-03-Q-CHANGE-AND-VERSION.md) |
|
||||
| 6 | 15:00~15:50 | 3단계 · Lab 03 과제 40분 (영향 표 · 어려운 테스트) · 풀이 | [Lab 03](../../Last3Mon/70/LAB-03-Q-CHANGE-AND-VERSION.md) |
|
||||
| 7 | 16:00~16:50 | 바이브 코딩 · `tkit` 만들기 (각자) | [VIBE-Q-TKIT](../../Last3Mon/70/VIBE-Q-TKIT.md), [진행](04-VIBE-CODING.md) |
|
||||
| 8 | 17:00~17:50 | 바이브 코딩 발표 · 정리 · 강사 바이브 코딩 · 팁 · 71일차 예고 | [진행](04-VIBE-CODING.md) |
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
P["개요"] --> S1["1단계<br/>복사본 → 설정 표"] --> S2["2단계<br/>규칙 검사 모듈<br/>두 곳에서 사용"] --> S3["3단계<br/>하위 호환 · v2<br/>영향 표"] --> V["7·8교시<br/>바이브 코딩 tkit"]
|
||||
```
|
||||
|
||||
## 자료 목록
|
||||
|
||||
| 파일 | 내용 |
|
||||
| --- | --- |
|
||||
| `00-DAY70-PREP.md` | 실습 준비: n8n 켜기, `flow.py doctor` (수업 전) |
|
||||
| `00-DAY70-OVERVIEW.md` | 개요 13장 (PPT 대신 Markdown, 가로줄로 장 구분) |
|
||||
| `01-STAGE1-TEMPLATE.md` | 복사의 비용, 같은 것·다른 것·우연히 다른 것, 설정 표, 없는 값은 멈춤 |
|
||||
| `02-STAGE2-MODULES.md` | 모듈의 조건, Sub-workflow(Execute Workflow · Trigger), 입력으로 받기, 시험용 웹훅, 리팩터링 |
|
||||
| `03-STAGE3-CHANGE-AND-VERSION.md` | 하위 호환 변경, 깨지는 변경과 새 버전, 계약은 층마다, 영향 표 |
|
||||
| `04-VIBE-CODING.md` | 7·8교시 바이브 코딩 진행 (tkit), 발표, 강사 정리, 추가 바이브 코딩, 팁 |
|
||||
Reference in new issue
Block a user