
OpenSpec은 Brownfield를 위해 구축되었습니다. 저는 이것으로 아무것도 없는 상태에서 구축했습니다.
요약
백엔드 엔지니어가 GenAI를 활용하여 선박 검사 보고서 작성을 자동화하는 오프라인 Windows 데스크톱 앱을 구축한 사례를 소개합니다. Wails, Go, Svelte, SQLite를 사용하여 복잡한 워크플로우를 효율적인 디지털 도구로 전환했습니다.
핵심 포인트
- GenAI를 활용해 비전공 분야의 데스크톱 앱을 단 몇 주 만에 개발
- Wails, Go, Svelte, SQLite 조합을 통한 오프라인 환경 구축
- 수동 보고서 작성 시간을 4시간에서 2시간 미만으로 단축
- Brownfield(기존 환경)가 아닌 Greenfield(신규 구축) 방식의 개발 경험
목차
- 문제점
- 제 소개
- 채팅 외부에서 결정 사항 유지하기
- 왜 Spec Kit이 아니라 OpenSpec인가?
- OpenSpec이란 무엇인가?
- 빈 저장소(Repository)에서 시작하기
- 하나의 로드맵(Roadmap) 작업 적용하기
- 학습하면서 변화한 로드맵
- 결과물: 두 번째 검사 유형
- OpenSpec이 다루지 못한 것
- OpenSpec이 실수를 방지했는가?
- 비용
- 배운 점
⚓ 문제점
제 친구 중 한 명은 기술 감독관(Technical Superintendent)입니다. 그들은 선박의 상태와 안전한 운항을 감독합니다. 즉, 장비 검사, 기록 및 절차를 관리합니다. 일정은 매우 바쁘고 예측 불가능하며, 언제든 문제가 발생하여 주의를 기울여야 할 수 있습니다.
검사를 마치는 것이 업무의 끝이 아니었습니다. 답변, 메모, 사진을 공식 보고서로 변환해야 했습니다.
검사에는 400개의 질문이 포함된 체크리스트가 사용되었습니다. 어떤 질문은 모든 선박에 적용되지 않았습니다. 어떤 질문은 메모, 사진 또는 후속 조치가 필요했습니다. 보고서 자체는 Word에서 작성되었습니다.
사진이 가장 고통스러운 부분이었습니다. 각 이미지를 삽입하고, 크기를 조정하고, 위치를 잡아야 했습니다. 사진 한 장이 주변 텍스트를 밀어내거나 다음 섹션의 서식을 깨뜨릴 수도 있었습니다. 검사에서 생성되는 증거 자료가 많아질수록 서식 지정에 더 많은 시간이 소요되었습니다.
또한 Word 문서는 진행 상황을 전혀 보여주지 않았습니다. 무엇이 완료되었는지, 무엇이 남았는지, 또는 휴식 후 어디서부터 계속해야 하는지를 보여주지 않았습니다. 제 친구는 다른 문제들 사이를 오가는 동안 이 모든 것을 머릿속에 담아두어야 했습니다.
보고서 하나를 작성하는 데 최소 4시간이 걸렸습니다. 사실상 대기 상태에 있는 사람에게 이는 이미 꽉 찬 일정에 더해진 4시간이었습니다.
따라서 목표는 간단했습니다. 감독관이 체크리스트를 따라갈 수 있도록 안내하고, 각 메모와 사진을 답변과 함께 유지하며, 진행 상황을 보여주고, 로컬에 저장하며, 나중에 재개할 수 있도록 하는 것입니다. 그리고 이는 Windows 노트북에서 오프라인으로 작동해야 했습니다.
👋 제 소개
저는 백엔드 엔지니어 (Backend Engineer)로 시작하여 인프라 및 플랫폼 엔지니어링 (Infrastructure and Platform Engineering) 분야로 이동했습니다. 요즘은 REST API보다 컨트롤러 (Controllers)와 서비스 브로커 (Service Brokers)를 더 많이 다룹니다. 혼자서 데스크톱 앱을 만드는 것은 제 경험의 범위를 크게 벗어난 일처럼 느껴졌습니다. 저는 여전히 div를 중앙 정렬하는 데 애를 먹곤 합니다.
생성형 AI (GenAI)는 제가 시도해 볼 수 있는 것들을 바꾸어 놓았습니다. 몇 주 만에 작동 가능한 오프라인 Windows 앱을 만들었습니다. Wails와 Go가 데스크톱 셸 (Desktop Shell)과 로직을 처리했고, Svelte가 화면을 담당했으며, SQLite가 노트북에 검사 내용을 저장했습니다. 덕분에 제 친구는 선박을 선택하고, 질문에 답하며, 메모와 사진을 첨부하고, 작업을 중단했다가 재개하며, 누락된 내용을 검토하고, PDF를 내보낼 수 있었습니다. 그들은 2시간도 채 되지 않아 실제 보고서를 만들어냈습니다.

흥미로운 점은 제가 그곳에 도달한 방식이었습니다. 저는 단순히 '바이브 코딩 (Vibe-coding)'만으로 앱을 만들어낸 것이 아닙니다.
📌 채팅 외부에서 결정 사항 유지하기
이것은 제 본업이 아니었습니다. 시간이 날 때 작업하고, 중단했다가 나중에 다시 돌아왔습니다.
만약 계획이 채팅창 안에만 존재했다면, 저는 제가 어디서 멈췄는지, 그리고 왜 각 결정을 내렸는지를 다시 재구성해야 했을 것입니다. 다음 세션의 다른 에이전트 (Agent) 역시 동일한 문제에 직면했을 것입니다.
그래서 저는 초기에 한 가지 규칙을 만들었습니다. 계획과 결정 사항은 오래된 대화 속에 두는 것이 아니라 코드 옆에 두는 것입니다. 작성된 명세서 (Specification)가 인수인계 수단이 되었습니다. 이 인수인계 방식 덕분에 저는 프로젝트를 몇 주 동안 중단할 수 있었고, 에이전트와 모델 (Models) 사이를 전환할 수 있었으며, 제가 멈췄던 지점부터 다시 시작할 수 있었습니다.
문제는 어떤 명세서 워크플로우 (Specification Workflow)를 또 다른 부담이 되지 않게 하면서 계속 사용할 수 있느냐는 것이었습니다.
⚖️ 왜 Spec Kit이 아니라 OpenSpec인가?
Spec Kit과 OpenSpec은 모두 소프트웨어 아이디어를 인간과 에이전트를 위한 서면 요구 사항 (Requirements) 및 작업 (Tasks)으로 변환합니다.
저는 교육 훈련 과정 중에 업무에서 Spec Kit을 사용해 보았습니다. 그것이 해결하고자 하는 문제, 즉 에이전트가 소프트웨어를 구축할 때 프롬프트 (Prompt)만으로는 충분하지 않다는 점은 이해했습니다. 하지만 워크플로우 (Workflow)가 번거롭게 느껴졌습니다. 너무 많은 파일이 생성되었고, 그것들을 일일이 읽는 것에 지쳐갔습니다. 그것이 당시의 제 경험이었으며, Spec Kit은 그 이후로 변했을 수도 있습니다.
OpenSpec은 제가 따라가기에 더 쉬웠습니다. 각 작업 단위가 그 이유, 설계 (Design), 요구 사항 (Requirements) 및 작업 (Tasks)을 함께 유지했습니다. 완료된 작업은 결정 사항을 잃지 않고 영구적인 히스토리 (History)로 이동했습니다. 저는 이것이 아무것도 없는 상태에서 구축된 전체 애플리케이션을 감당할 수 있을지 알고 싶었습니다.
❓ OpenSpec이란 무엇인가?
OpenSpec은 작업을 변경 사항 (Changes)으로 조직화합니다.
변경 사항은 앱이 재시작된 후 완료되지 않은 검사를 다시 열 수 있도록 하는 것과 같은 하나의 작업 단위입니다. 각 부분은 다음과 같은 역할을 수행합니다:
proposal.md: 변경 사항이 왜 필요한지, 그리고 무엇이 범위 (Scope) 내에 있고 범위 외에 있는지를 설명합니다.design.md: 기술적 결정 (Technical decisions), 대안 및 리스크 (Risks)를 기록합니다.spec.md: 사용자 또는 시스템이 무엇을 할 수 있어야 하는지를 기술합니다.tasks.md: 구현을 확인 가능한 작업으로 나눕니다.
저는 몇 가지 명령어를 사용하여 저의 coding-agent로부터 이를 구동했습니다.
OpenSpec 워크플로우 (Workflow)
/opsx-explore: 문제를 논의하고 가능한 접근 방식 (Approaches)을 탐색합니다./opsx-propose: 제안서 (Proposal), 설계 (Design), 사양 (Specs) 및 작업 (Tasks)을 생성합니다./opsx-apply: 작업을 수행합니다./opsx-sync: 수락된 요구 사항을 프로젝트의 영구적인 사양 (Specs)으로 복사합니다./opsx-archive: 완료된 변경 사항을 참조용으로 유지하면서 히스토리 (History)로 이동합니다.
에이전트들이 계획, 코드 및 테스트를 작성했습니다. 저의 역할은 실제 보고 문제를 논의에 가져오고, 범위를 선택하며, 설계를 검토하고, 결과가 충분히 좋은지 결정하는 것이었습니다. 모든 변경 사항에 대해 저는 구현 전에 계획을 검토했고, 완료라고 판단하기 전에 결과를 테스트했습니다.
📂 빈 리포지토리 (Repository)에서 시작하기
OpenSpec은 이미 존재하는 시스템을 변경하는 것, 즉 모든 변경 사항이 이미 존재하는 무언가를 수정하는 brownfield 작업(work)을 중심으로 구축되었습니다. 저는 그 반대의 상황에 있었습니다. 빈 폴더와 변경할 애플리케이션이 전혀 없는 상태였습니다. 따라서 저는 빈 프로젝트에 방향성을 부여할 방법이 필요했습니다.
저는 guided-marpol-inspection-mvp라고 불리는 포괄적인 (umbrella) OpenSpec 변경 사항으로 시작했습니다. 이는 로드맵 (roadmap)과 동일한 목표를 담고 있었습니다. 즉, 단 하나의 검사 유형인 MARPOL을 통해 보고 문제를 해결할 수 있는 가장 작은 버전의 제품을 만드는 것이었습니다. 앱이 수행해야 할 작업 외에도, 완료된 검사를 서명된 보고서로 전환하는 단계들을 명시했습니다:
- 어떤 체크리스트 질문이 선박에 적용되는지 결정하기;
- 발견 사항 및 누락된 정보 검토하기;
- 승인 (sign off)하기;
- 저장된 검사를 보고서로 내보내기 (export).
이 포괄적 변경 사항은 변경 사항의 개요를 설명하는 로드맵이었습니다. 예를 들어, 로드맵 작업 중 하나는 다음과 같이 명시했습니다:
자식 변경 사항(child change)
initialize-desktop-app-foundation생성.
이 작업을 적용한다고 해서 데스크톱 애플리케이션이 바로 구현되는 것은 아니었습니다. 대신 openspec/changes/initialize-desktop-app-foundation/ 아래에 또 다른 OpenSpec 변경 사항을 생성했습니다.
해당 자식 변경 사항은 자체적인 proposal.md, tasks.md, specs/ 아래의 사양서 (specifications), 그리고 설계 결정이 필요할 때를 위한 design.md를 가지고 있었습니다. 저는 이러한 산출물 (artifacts)들을 검토한 다음, 자식 변경 사항을 적용하여 애플리케이션 코드와 테스트를 생성할 수 있었습니다.
포괄적 변경 사항은 완전한 MVP에 무엇이 필요한지를 설명했습니다. 각 자식 변경 사항은 한 부분이 어떻게 구현되고 검증될지를 설명했습니다.
로드맵에는 약 12개의 자식 변경 사항이 포함되어 있었습니다.
전체 MVP 로드맵 (모든 자식 변경 사항)
initialize-desktop-app-foundation은 Wails, Svelte, Go, SQLite 프로젝트를 생성했습니다.prepare-verified-marpol-docx-template은 내보내기 템플릿으로 사용할 공식 Word 보고서를 준비했습니다.create-resumable-inspection-draft는 로컬에 저장된 검사(inspection) 내용을 생성하고 다시 열 수 있도록 했습니다.capture-vessel-profile-applicability는 선박 장비를 사용하여 어떤 체크리스트 섹션이 적용될지 결정했습니다.answer-guided-question-slice는 첫 번째 질문, 답변, 노트, 자동 저장(autosave) 및 진행 상황 추적 기능을 추가했습니다.attach-evidence-to-question은 사진을 특정 체크리스트 질문에 연결했습니다.export-docx-answer-slice는 저장된 답변 하나를 Word 템플릿에 배치했습니다.export-docx-evidence-slice는 첨부된 사진 하나를 Word 템플릿에 배치했습니다.expand-marpol-checklist-coverage는 첫 번째로 작동하는 슬라이스(slice)를 나머지 MARPOL 체크리스트로 확장했습니다.review-findings-and-actions는 발생 가능한 지적 사항(findings)과 그에 따른 조치(actions)를 다루었습니다.final-review-readiness는 답변되지 않은 질문, 누락된 증거, 보류 중인 지적 사항이 있는지 확인했습니다.complete-docx-report-export는 SQLite에 저장된 검사 데이터를 바탕으로 전체 Word 보고서를 생성했습니다.package-macos-desktop-build및package-windows-desktop-build는 macOS 및 Windows용 설치 가능한 빌드를 준비했습니다.

🎯 로드맵 작업 하나 적용하기
기본적으로 OpenSpec의 /opsx-apply 명령은 변경 사항(change) 내의 남은 모든 작업을 순차적으로 수행했습니다.
만약 제가 상위 변경 사항(umbrella change)을 일반적인 방식으로 적용했다면, 모든 자식 변경 사항(child changes)을 한 번에 생성했을 것입니다. 그렇게 되면 이전 기능들을 구현하기도 전에 나중에 나올 기능들에 대한 상세 요구 사항과 설계 결정 사항들이 미리 추가되었을 것입니다.
저는 /opsx-apply에게 단 하나의 섹션이나 작업(task)만 구현해 달라고 요청하는 자연어 지시문(natural-language instruction)을 작성할 수도 있었습니다. 하지만 그 경우, 모델이 제가 의도한 것과 동일한 방식으로 지시를 해석했는지 확신할 수 있어야 했습니다.
저는 선택 과정이 명시적이기를 원했기에, 세 가지 선택자(selector)를 추가하여 명령어를 확장했습니다:
--section: 하나의 섹션을 적용하기 위한 선택자--tasks: 선택된 작업 세트를 적용하기 위한 선택자--task: 하나의 작업을 적용하기 위한 선택자
이를 통해 저는 더욱 통제된 시퀀스(sequence)를 가질 수 있었습니다.
저의 '한 번에 하나의 작업(one task at a time)' 루프:
- 전체 로드맵(umbrella roadmap)에서 하나의 작업을 선택합니다.
- 해당 작업의 하위 OpenSpec 변경 사항(child OpenSpec change)을 생성합니다.
- 하위 제안(proposal), 사양(specifications), 설계(design) 및 작업(tasks)을 검토합니다.
- 하위 변경 사항을 적용(apply)합니다.
- 기능을 구현하고 테스트합니다.
- 발견한 내용을 바탕으로 다음 하위 변경 사항을 정의합니다.
🗺️ 학습함에 따라 변화한 로드맵
로드맵은 저에게 방향을 제시해 주었지만, 고정된 구현 계약(implementation contract)은 아니었습니다. 애플리케이션이 실체화됨에 따라 세부 사항들은 계속 변했습니다.
원래의 내보내기(export) 계획은 DOCX였습니다. 그러다 친구가 PDF 보고서도 충분히 괜찮다고 말해주었고, 이에 따라 DOCX 내보내기 슬라이스(slices)들은 제거되고 complete-pdf-report-export로 대체되었습니다. 다른 변경 사항들도 나타났습니다. refine-vessel-and-draft-start-flow는 선박(vessel) 생성을 검사(inspection) 생성으로부터 분리했고, 계획되었던 결과물(findings) 워크플로우는 자문(advisory) 성격인 review-and-signoff 변경 사항으로 축소되었습니다.
로드맵은 우리가 어디로 가고 있는지를 알려주어야 합니다. 소프트웨어를 개발하다 보면 첫 번째 계획을 세울 당시에는 보이지 않았던 것들이 항상 드러나기 마련입니다.
🎉 결실: 두 번째 검사 유형
MARPOL 워크플로우와 PDF 내보내기가 완료된 후, 저는 guided-marpol-inspection-mvp를 아카이브(archive)하고 두 번째 검사 유형을 위해 앱을 준비하기 시작했습니다. multi-inspection-type-frontend와 같은 변경 사항들을 통해 모든 검사가 MARPOL이라는 가정을 제거했습니다. 체크리스트 내용, 적용 규칙(applicability rules) 및 보고서 메타데이터(metadata)는 데이터 기반 정의(data-driven definition)로 이동하였고, SQLite에는 사용자의 작업 내용만 남게 되었습니다.
그것이 바로 화재 안전(Fire Safety)을 저렴하게 만든 요소였습니다. 이를 추가하는 것은 대부분 새로운 정의(definition), 즉 질문, 규칙, 후속 조건(follow-up conditions)을 작성하는 작업이었습니다. 저장, 재개, 검토 및 내보내기 기능은 동일한 코드를 통해 계속 작동했습니다. 레이블이 나타나는 방식에 몇 가지 MARPOL 가정이 여전히 숨어 있었기에, 저는 화재 안전 전용 화면을 만드는 대신 공유 인터페이스(shared interface)에서 이를 수정했습니다. 스펙(specs)은 화재 안전을 미리 설계해 두지 않았습니다. 대신, 두 번째 검사 유형을 데이터 변경으로 전환하는 일련의 단순화 과정을 안내했습니다.
🧱 OpenSpec이 다루지 않은 것
OpenSpec은 각 제품 변경 사항이 무엇을 해야 하는지를 기술했습니다. 하지만 모든 에이전트(agent)에게 동일한 엔지니어링 및 테스트 표준을 제공하지는 않았습니다. 저는 이를 모든 코딩 에이전트가 읽는 파일인 AGENTS.md에 유지했습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기