# SQLite + FastAPI + Vue CRUD 구현 계획 > **에이전트 작업자용:** 각 작업은 체크박스(`- [ ]`)로 추적합니다. **목표:** SQLite의 `messages` 테이블 데이터를 FastAPI CRUD API로 조작하고 Vue 화면에서 생성, 조회, 수정, 삭제할 수 있게 만든다. **아키텍처:** 백엔드는 `sqlite3`와 FastAPI로 단순 CRUD 엔드포인트를 제공하고, 프론트엔드는 브라우저용 Vue ESM 번들로 목록형 CRUD UI를 구현한다. 구현은 기존 파일 구조를 유지하면서 최소한의 상태만 추가하고, 마지막에 API와 화면 흐름을 직접 검증한다. **기술 스택:** Python 3, FastAPI, sqlite3, Vue 3 ESM, 정적 HTML --- - [ ] **작업 1: DB 초기화 스크립트 유지 여부 점검** - **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/init_db.py` (수정) - **할 일:** `messages` 테이블 구조가 CRUD 요구사항에 충분한지 확인하고, 초기 데이터 `hello world` 1건을 유지하는 방식으로 정리한다. - **최소 구현 예시:** ```python cursor.execute( "CREATE TABLE IF NOT EXISTS messages (id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT NOT NULL)" ) cursor.execute("DELETE FROM messages") cursor.execute("INSERT INTO messages (content) VALUES (?)", ("hello world",)) ``` - **검증 명령:** `python3 backend/init_db.py` - **기대 결과:** `backend/app.db`가 다시 생성되거나 갱신되고, `messages` 테이블에 `hello world` 1건이 들어간다. - [ ] **작업 2: FastAPI용 요청 모델과 DB 헬퍼 추가** - **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (수정) - **할 일:** SQLite 연결 헬퍼, 메시지 직렬화 헬퍼, 입력 검증용 Pydantic 모델을 추가한다. - **최소 구현 예시:** ```python class MessagePayload(BaseModel): content: str @field_validator("content") @classmethod def validate_content(cls, value: str) -> str: stripped_value = value.strip() if not stripped_value: raise ValueError("Content must not be empty") return stripped_value ``` - **검증 명령:** `python3 -m py_compile backend/main.py` - **기대 결과:** API 함수들이 공통 검증 로직과 연결 헬퍼를 재사용할 준비가 된다. - [ ] **작업 3: 메시지 목록 조회 API 구현** - **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (수정) - **할 일:** `GET /api/messages` 엔드포인트를 추가해 전체 메시지 목록을 `id` 오름차순으로 반환한다. - **최소 구현 예시:** ```python @app.get("/api/messages") def list_messages() -> list[dict[str, object]]: with get_connection() as connection: rows = connection.execute( "SELECT id, content FROM messages ORDER BY id ASC" ).fetchall() return [serialize_message(row) for row in rows] ``` - **검증 명령:** `python3 -c "from backend.main import list_messages; print(list_messages())"` - **기대 결과:** `hello world`가 포함된 리스트가 출력된다. - [ ] **작업 4: 메시지 생성 API 구현** - **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (수정) - **할 일:** `POST /api/messages` 엔드포인트를 추가해 메시지를 저장하고 생성된 `id`와 `content`를 반환한다. - **최소 구현 예시:** ```python @app.post("/api/messages", status_code=201) def create_message(payload: MessagePayload) -> dict[str, object]: with get_connection() as connection: cursor = connection.execute( "INSERT INTO messages (content) VALUES (?)", (payload.content,), ) connection.commit() return {"id": cursor.lastrowid, "content": payload.content} ``` - **검증 명령:** `python3 - <<'PY'\nfrom backend.main import create_message, MessagePayload\nprint(create_message(MessagePayload(content='created from plan')))\nPY` - **기대 결과:** 새 `id`와 저장된 `content`가 출력된다. - [ ] **작업 5: 메시지 수정 API 구현** - **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (수정) - **할 일:** `PUT /api/messages/{id}` 엔드포인트를 추가해 해당 메시지를 수정하고, 없는 `id`는 404를 반환한다. - **최소 구현 예시:** ```python @app.put("/api/messages/{message_id}") def update_message(message_id: int, payload: MessagePayload) -> dict[str, object]: with get_connection() as connection: cursor = connection.execute( "UPDATE messages SET content = ? WHERE id = ?", (payload.content, message_id), ) connection.commit() if cursor.rowcount == 0: raise HTTPException(status_code=404, detail="Message not found") return {"id": message_id, "content": payload.content} ``` - **검증 명령:** `python3 - <<'PY'\nfrom backend.main import update_message, MessagePayload\nprint(update_message(1, MessagePayload(content='updated hello world')))\nPY` - **기대 결과:** 수정된 메시지 객체가 출력된다. - [ ] **작업 6: 메시지 삭제 API 구현** - **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (수정) - **할 일:** `DELETE /api/messages/{id}` 엔드포인트를 추가해 해당 메시지를 삭제하고 성공 여부를 반환한다. - **최소 구현 예시:** ```python @app.delete("/api/messages/{message_id}") def delete_message(message_id: int) -> dict[str, bool]: with get_connection() as connection: cursor = connection.execute( "DELETE FROM messages WHERE id = ?", (message_id,), ) connection.commit() if cursor.rowcount == 0: raise HTTPException(status_code=404, detail="Message not found") return {"success": True} ``` - **검증 명령:** `python3 - <<'PY'\nfrom backend.main import delete_message\nprint(delete_message(1))\nPY` - **기대 결과:** `{'success': True}`가 출력된다. - [ ] **작업 7: Vue 상태를 목록형 CRUD 구조로 변경** - **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (수정) - **할 일:** 단일 `message` 상태를 `messages`, `newContent`, `editingId`, `editingContent` 상태로 교체하고 목록 조회 함수를 만든다. - **최소 구현 예시:** ```javascript const messages = ref([]) const newContent = ref('') const editingId = ref(null) const editingContent = ref('') ``` - **검증 명령:** `python3 -m py_compile backend/main.py` - **기대 결과:** 프론트 로직이 CRUD API 구조와 맞는 상태 이름으로 정리된다. - [ ] **작업 8: Vue 생성/수정/삭제 액션 구현** - **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (수정) - **할 일:** `fetch`를 사용해 생성, 수정, 삭제 요청을 보내고 성공 후 목록을 다시 불러오거나 상태를 갱신한다. - **최소 구현 예시:** ```javascript const createMessage = async () => { await fetch(`${API_BASE_URL}/messages`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: newContent.value.trim() }), }) await loadMessages() } ``` - **검증 명령:** `python3 backend/init_db.py` - **기대 결과:** 프론트에서 각 버튼이 API 호출 함수와 연결된다. - [ ] **작업 9: Vue 템플릿을 목록형 CRUD UI로 교체** - **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (수정) - **할 일:** 입력 폼, 목록, 인라인 편집, 빈 상태, 에러 상태를 모두 표시하는 템플릿으로 교체한다. - **최소 구현 예시:** ```html
  • {{ message.content }}
  • ``` - **검증 명령:** `python3 -m http.server 5173 -d frontend` - **기대 결과:** 브라우저에서 목록형 CRUD 화면이 렌더링된다. - [ ] **작업 10: README 실행/검증 문구를 CRUD 기준으로 갱신** - **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/README.md` (수정) - **할 일:** 단일 조회 설명을 목록형 CRUD 예제 설명으로 바꾸고, 확인 포인트를 CRUD 흐름에 맞게 수정한다. - **최소 구현 예시:** ```markdown - 백엔드 API: `http://127.0.0.1:8000/api/messages` - 프론트엔드 화면: `http://127.0.0.1:5173` - 정상 동작 시 메시지 추가, 수정, 삭제가 모두 가능하다. ``` - **검증 명령:** `python3 -m py_compile backend/init_db.py backend/main.py` - **기대 결과:** README만 읽어도 CRUD 예제 실행과 확인 방법을 이해할 수 있다. - [ ] **작업 11: 백엔드 문법과 API 흐름 검증** - **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/init_db.py` (검증), `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (검증) - **할 일:** DB를 초기화하고, Python에서 API 함수를 직접 호출해 생성, 조회, 수정, 삭제 흐름이 모두 동작하는지 확인한다. - **실행 명령:** ```bash python3 backend/init_db.py python3 - <<'PY' from backend.main import MessagePayload, create_message, delete_message, list_messages, update_message print("LIST-1", list_messages()) created = create_message(MessagePayload(content="plan create")) print("CREATED", created) print("LIST-2", list_messages()) updated = update_message(created["id"], MessagePayload(content="plan update")) print("UPDATED", updated) print("LIST-3", list_messages()) print("DELETED", delete_message(created["id"])) print("LIST-4", list_messages()) PY ``` - **기대 결과:** 각 단계 출력에 따라 CRUD가 순서대로 성공한다. - [ ] **작업 12: 진단 점검 및 인라인 실행 정리** - **대상 파일:** `/Users/woozooni/Documents/trae_projects/skillDesk/backend/main.py` (진단), `/Users/woozooni/Documents/trae_projects/skillDesk/frontend/src/main.js` (진단), `/Users/woozooni/Documents/trae_projects/skillDesk/README.md` (진단) - **할 일:** 진단 도구로 오류를 확인하고 바로 수정한 뒤, 변경 파일과 실행 방법을 사용자에게 인계한다. - **검증 도구:** IDE 진단 확인 - **기대 결과:** 새 오류 없이 CRUD 예제를 실행할 수 있는 상태로 마무리된다.