# 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
    <form @submit.prevent="createMessage">
      <input v-model="newContent" />
      <button type="submit">추가</button>
    </form>
    <li v-for="message in messages" :key="message.id">
      <span>{{ message.content }}</span>
    </li>
    ```
  - **검증 명령:** `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 예제를 실행할 수 있는 상태로 마무리된다.
