<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://tech.umosone.ai/</id>
    <title>UMOSONE Tech Blog Blog</title>
    <updated>2026-06-23T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://tech.umosone.ai/"/>
    <subtitle>UMOSONE Tech Blog Blog</subtitle>
    <icon>https://tech.umosone.ai/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[AI 하네스: 요구사항부터 검증까지 같은 흐름으로 일하기]]></title>
        <id>https://tech.umosone.ai/ai-harness</id>
        <link href="https://tech.umosone.ai/ai-harness"/>
        <updated>2026-06-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[AI를 개발 업무에 쓰는 사람은 늘었지만, 결과의 품질은 사람마다 달라지기 쉬웠습니다. 그래서 저희는 더 좋은 프롬프트를 찾기보다, AI가 매번 같은 순서로 일하고 같은 기준으로 멈추게 만드는 팀의 작업 장치를 먼저 만들었습니다. 이 글에서는 그 장치를 AI 하네스라고 부르겠습니다.]]></summary>
        <content type="html"><![CDATA[<p>AI를 개발 업무에 쓰는 사람은 늘었지만, 결과의 품질은 사람마다 달라지기 쉬웠습니다. 그래서 저희는 더 좋은 프롬프트를 찾기보다, AI가 매번 같은 순서로 일하고 같은 기준으로 멈추게 만드는 팀의 작업 장치를 먼저 만들었습니다. 이 글에서는 그 장치를 <code>AI 하네스</code>라고 부르겠습니다.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="왜-하네스를-만들었나">왜 하네스를 만들었나<a href="https://tech.umosone.ai/ai-harness#%EC%99%9C-%ED%95%98%EB%84%A4%EC%8A%A4%EB%A5%BC-%EB%A7%8C%EB%93%A4%EC%97%88%EB%82%98" class="hash-link" aria-label="Direct link to 왜 하네스를 만들었나" title="Direct link to 왜 하네스를 만들었나">​</a></h2>
<p>처음에는 각자 AI를 꽤 잘 쓰고 있다고 생각했습니다. 누군가는 티켓을 먼저 정리했고, 누군가는 바로 구현을 시작했습니다. 누군가는 테스트까지 챙겼고, 누군가는 "동작할 것 같다"는 설명만 듣고 다음 단계로 넘어갔습니다. 문제는 AI 사용 여부가 아니라, AI를 쓰는 방식의 편차였습니다.</p>
<p><img decoding="async" loading="lazy" alt="AI 하네스를 만든 이유" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjcyMCIgdmlld0JveD0iMCAwIDEyMDAgNzIwIiByb2xlPSJpbWciIGFyaWEtbGFiZWxsZWRieT0idGl0bGUgZGVzYyI+CiAgPHRpdGxlIGlkPSJ0aXRsZSI+QUkg7ZWY64Sk7Iqk66W8IOunjOuToCDsnbTsnKA8L3RpdGxlPgogIDxkZXNjIGlkPSJkZXNjIj7sgqzrnozrp4jri6Qg64uk66W4IEFJIOyCrOyaqSDrsKnsi53sl5DshJwg7JqU6rWs7IKs7ZWtLCDqtaztmIQsIOqygOymnSwg66eI66y066as7J2YIO2OuOywqOqwgCDsg53quLDqs6AsIEFJIO2VmOuEpOyKpOqwgCDsnbTrpbwg7J287KCV7ZWcIOyekeyXhSDtnZDrpoTqs7wg6rKM7J207Yq466GcIOustuuKlCDqtazsobDrpbwg64KY7YOA64K4IOq3uOumvDwvZGVzYz4KICA8ZGVmcz4KICAgIDxzdHlsZT4KICAgICAgLmJnIHsgZmlsbDogI2Y1ZjhmYzsgfQogICAgICAuZ3JpZCB7IHN0cm9rZTogI2RiZTRlZjsgc3Ryb2tlLXdpZHRoOiAxOyBvcGFjaXR5OiAwLjg7IH0KICAgICAgLmNhcmQgeyBmaWxsOiAjZmZmZmZmOyBzdHJva2U6ICNkN2RlZWE7IHN0cm9rZS13aWR0aDogMjsgfQogICAgICAuc29mdCB7IGZpbGw6ICNlZWYzZjk7IHN0cm9rZTogI2Q3ZGVlYTsgc3Ryb2tlLXdpZHRoOiAyOyB9CiAgICAgIC5kYXJrIHsgZmlsbDogIzE1MTkyMzsgfQogICAgICAudGVhbCB7IGZpbGw6ICMxMjhmODI7IH0KICAgICAgLmNvcmFsIHsgZmlsbDogI2Q5NTY0ODsgfQogICAgICAuYW1iZXIgeyBmaWxsOiAjYjQ3YTE2OyB9CiAgICAgIC52aW9sZXQgeyBmaWxsOiAjNjI1NWM4OyB9CiAgICAgIC5ncmVlbiB7IGZpbGw6ICMyODdmNTI7IH0KICAgICAgLm11dGVkIHsgZmlsbDogIzY4NzM4NjsgfQogICAgICAuaW5rIHsgZmlsbDogIzEyMTcyMjsgfQogICAgICAud2hpdGUgeyBmaWxsOiAjZmZmZmZmOyB9CiAgICAgIC50aXRsZSB7IGZvbnQ6IDgwMCA0MnB4IHVpLXNhbnMtc2VyaWYsIHN5c3RlbS11aSwgLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCAiU2Vnb2UgVUkiLCBzYW5zLXNlcmlmOyB9CiAgICAgIC5zdWJ0aXRsZSB7IGZvbnQ6IDUwMCAyMnB4IHVpLXNhbnMtc2VyaWYsIHN5c3RlbS11aSwgLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCAiU2Vnb2UgVUkiLCBzYW5zLXNlcmlmOyB9CiAgICAgIC5sYWJlbCB7IGZvbnQ6IDgwMCAyMnB4IHVpLXNhbnMtc2VyaWYsIHN5c3RlbS11aSwgLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCAiU2Vnb2UgVUkiLCBzYW5zLXNlcmlmOyB9CiAgICAgIC5ib2R5IHsgZm9udDogNjAwIDE4cHggdWktc2Fucy1zZXJpZiwgc3lzdGVtLXVpLCAtYXBwbGUtc3lzdGVtLCBCbGlua01hY1N5c3RlbUZvbnQsICJTZWdvZSBVSSIsIHNhbnMtc2VyaWY7IH0KICAgICAgLnNtYWxsIHsgZm9udDogNzAwIDE1cHggdWktc2Fucy1zZXJpZiwgc3lzdGVtLXVpLCAtYXBwbGUtc3lzdGVtLCBCbGlua01hY1N5c3RlbUZvbnQsICJTZWdvZSBVSSIsIHNhbnMtc2VyaWY7IH0KICAgICAgLm1vbm8geyBmb250OiA4MDAgMTVweCB1aS1tb25vc3BhY2UsIFNGTW9uby1SZWd1bGFyLCBNZW5sbywgQ29uc29sYXMsIG1vbm9zcGFjZTsgfQogICAgICAuYXJyb3cgeyBmaWxsOiBub25lOyBzdHJva2U6ICM3Yjg3OTc7IHN0cm9rZS13aWR0aDogNDsgc3Ryb2tlLWxpbmVjYXA6IHJvdW5kOyBzdHJva2UtbGluZWpvaW46IHJvdW5kOyB9CiAgICAgIC5waXBlIHsgZmlsbDogbm9uZTsgc3Ryb2tlOiAjMTI4ZjgyOyBzdHJva2Utd2lkdGg6IDg7IHN0cm9rZS1saW5lY2FwOiByb3VuZDsgfQogICAgICAuc2hhZG93IHsgZmlsdGVyOiBkcm9wLXNoYWRvdygwIDE4cHggMzBweCByZ2IoMzEgNDUgNjYgLyAwLjEyKSk7IH0KICAgIDwvc3R5bGU+CiAgICA8bWFya2VyIGlkPSJhcnJvd2hlYWQiIG1hcmtlcldpZHRoPSIxMiIgbWFya2VySGVpZ2h0PSIxMiIgcmVmWD0iOSIgcmVmWT0iNiIgb3JpZW50PSJhdXRvIj4KICAgICAgPHBhdGggZD0iTTIsMiBMMTAsNiBMMiwxMCBaIiBmaWxsPSIjN2I4Nzk3Ii8+CiAgICA8L21hcmtlcj4KICA8L2RlZnM+CgogIDxyZWN0IGNsYXNzPSJiZyIgd2lkdGg9IjEyMDAiIGhlaWdodD0iNzIwIi8+CiAgPGcgb3BhY2l0eT0iMC42NSI+CiAgICA8cGF0aCBjbGFzcz0iZ3JpZCIgZD0iTTAgOTBIMTIwME0wIDE4MEgxMjAwTTAgMjcwSDEyMDBNMCAzNjBIMTIwME0wIDQ1MEgxMjAwTTAgNTQwSDEyMDBNMCA2MzBIMTIwMCIvPgogICAgPHBhdGggY2xhc3M9ImdyaWQiIGQ9Ik0xMDAgMFY3MjBNMjAwIDBWNzIwTTMwMCAwVjcyME00MDAgMFY3MjBNNTAwIDBWNzIwTTYwMCAwVjcyME03MDAgMFY3MjBNODAwIDBWNzIwTTkwMCAwVjcyME0xMDAwIDBWNzIwTTExMDAgMFY3MjAiLz4KICA8L2c+CgogIDx0ZXh0IHg9Ijc0IiB5PSI3OCIgY2xhc3M9InRpdGxlIGluayI+7JmcIEFJIO2VmOuEpOyKpOulvCDrp4zrk6Tsl4jrgpg8L3RleHQ+CiAgPHRleHQgeD0iNzQiIHk9IjExOCIgY2xhc3M9InN1YnRpdGxlIG11dGVkIj7tlITroaztlITtirjrpbwg7Ya17J287ZWY6riw67O064ukLCDtjIDsnZgg7J6R7JeFIOyInOyEnOyZgCDqsoDspp0g6riw7KSA7J2EIOuovOyggCDqs6DsoJXtlojsirXri4jri6QuPC90ZXh0PgoKICA8ZyBjbGFzcz0ic2hhZG93Ij4KICAgIDxyZWN0IHg9IjcyIiB5PSIxNzgiIHdpZHRoPSIyODAiIGhlaWdodD0iMTAyIiByeD0iMTIiIGNsYXNzPSJjYXJkIi8+CiAgICA8Y2lyY2xlIGN4PSIxMTIiIGN5PSIyMjkiIHI9IjIyIiBjbGFzcz0idGVhbCIvPgogICAgPHRleHQgeD0iMTA0IiB5PSIyMzYiIGNsYXNzPSJzbWFsbCB3aGl0ZSI+QTwvdGV4dD4KICAgIDx0ZXh0IHg9IjE1MCIgeT0iMjE5IiBjbGFzcz0ibGFiZWwgaW5rIj7rsJTroZwg6rWs7ZiEPC90ZXh0PgogICAgPHRleHQgeD0iMTUwIiB5PSIyNDkiIGNsYXNzPSJib2R5IG11dGVkIj7smpTqtazsgqztla0g7KCV66asIOyDneuetTwvdGV4dD4KCiAgICA8cmVjdCB4PSI3MiIgeT0iMzA0IiB3aWR0aD0iMjgwIiBoZWlnaHQ9IjEwMiIgcng9IjEyIiBjbGFzcz0iY2FyZCIvPgogICAgPGNpcmNsZSBjeD0iMTEyIiBjeT0iMzU1IiByPSIyMiIgY2xhc3M9ImNvcmFsIi8+CiAgICA8dGV4dCB4PSIxMDQiIHk9IjM2MiIgY2xhc3M9InNtYWxsIHdoaXRlIj5CPC90ZXh0PgogICAgPHRleHQgeD0iMTUwIiB5PSIzNDUiIGNsYXNzPSJsYWJlbCBpbmsiPkFJ6rCAIOu5iOy5uCDstpTsoJU8L3RleHQ+CiAgICA8dGV4dCB4PSIxNTAiIHk9IjM3NSIgY2xhc3M9ImJvZHkgbXV0ZWQiPuygleyxheqzvCDsmIjsmbjqsIAg7Z2U65Ok66a8PC90ZXh0PgoKICAgIDxyZWN0IHg9IjcyIiB5PSI0MzAiIHdpZHRoPSIyODAiIGhlaWdodD0iMTAyIiByeD0iMTIiIGNsYXNzPSJjYXJkIi8+CiAgICA8Y2lyY2xlIGN4PSIxMTIiIGN5PSI0ODEiIHI9IjIyIiBjbGFzcz0iYW1iZXIiLz4KICAgIDx0ZXh0IHg9IjEwNCIgeT0iNDg4IiBjbGFzcz0ic21hbGwgd2hpdGUiPkM8L3RleHQ+CiAgICA8dGV4dCB4PSIxNTAiIHk9IjQ3MSIgY2xhc3M9ImxhYmVsIGluayI+7JmE66OMIOyEoOyWuDwvdGV4dD4KICAgIDx0ZXh0IHg9IjE1MCIgeT0iNTAxIiBjbGFzcz0iYm9keSBtdXRlZCI+7Iuk7ZaJIOqygOymnSDriITrnb08L3RleHQ+CiAgPC9nPgoKICA8cGF0aCBjbGFzcz0iYXJyb3ciIG1hcmtlci1lbmQ9InVybCgjYXJyb3doZWFkKSIgZD0iTTM4MiAzNTUgQzQ0NCAzNTUsIDQ2MCAzNTUsIDUyMCAzNTUiLz4KCiAgPGcgY2xhc3M9InNoYWRvdyI+CiAgICA8cmVjdCB4PSI1MzIiIHk9IjE2OCIgd2lkdGg9IjMwMCIgaGVpZ2h0PSIzODAiIHJ4PSIxOCIgY2xhc3M9ImRhcmsiLz4KICAgIDx0ZXh0IHg9IjU5MCIgeT0iMjIyIiBjbGFzcz0idGl0bGUgd2hpdGUiIGZvbnQtc2l6ZT0iMzQiPkFJIO2VmOuEpOyKpDwvdGV4dD4KICAgIDx0ZXh0IHg9IjU4NSIgeT0iMjYwIiBjbGFzcz0iYm9keSB3aGl0ZSIgb3BhY2l0eT0iMC43OCI+6rCZ7J2AIOyInOyEnCDCtyDqsJnsnYAg6riw7KSAIMK3IOqwmeydgCDrqYjstqQg7KGw6rG0PC90ZXh0PgogICAgPHBhdGggY2xhc3M9InBpcGUiIGQ9Ik01OTIgMzE4SDc3MiIvPgogICAgPGNpcmNsZSBjeD0iNTk0IiBjeT0iMzE4IiByPSIxNiIgY2xhc3M9InRlYWwiLz4KICAgIDxjaXJjbGUgY3g9IjY1NCIgY3k9IjMxOCIgcj0iMTYiIGNsYXNzPSJjb3JhbCIvPgogICAgPGNpcmNsZSBjeD0iNzE0IiBjeT0iMzE4IiByPSIxNiIgY2xhc3M9ImFtYmVyIi8+CiAgICA8Y2lyY2xlIGN4PSI3NzQiIGN5PSIzMTgiIHI9IjE2IiBjbGFzcz0iZ3JlZW4iLz4KICAgIDx0ZXh0IHg9IjU3NiIgeT0iMzgzIiBjbGFzcz0iYm9keSB3aGl0ZSI+MS4gc3BlY+ycvOuhnCDrqqjtmLjtlagg7ZmV7J24PC90ZXh0PgogICAgPHRleHQgeD0iNTc2IiB5PSI0MjMiIGNsYXNzPSJib2R5IHdoaXRlIj4yLiBwbGFu7Jy866GcIOq1rOyhsOyZgCDrspTsnIQg6rOg7KCVPC90ZXh0PgogICAgPHRleHQgeD0iNTc2IiB5PSI0NjMiIGNsYXNzPSJib2R5IHdoaXRlIj4zLiBpbXBsZW1lbnTripQgdGFzayDri6jsnIQg7KeE7ZaJPC90ZXh0PgogICAgPHRleHQgeD0iNTc2IiB5PSI1MDMiIGNsYXNzPSJib2R5IHdoaXRlIj40LiB0ZXN0IOyLpO2MqCDsi5wgY29tbWl0IOywqOuLqDwvdGV4dD4KICA8L2c+CgogIDxwYXRoIGNsYXNzPSJhcnJvdyIgbWFya2VyLWVuZD0idXJsKCNhcnJvd2hlYWQpIiBkPSJNODUyIDM1NSBDOTAwIDM1NSwgOTIwIDM1NSwgOTcwIDM1NSIvPgoKICA8ZyBjbGFzcz0ic2hhZG93Ij4KICAgIDxyZWN0IHg9Ijk4MiIgeT0iMTc0IiB3aWR0aD0iMTQ2IiBoZWlnaHQ9IjgyIiByeD0iMTIiIGNsYXNzPSJjYXJkIi8+CiAgICA8dGV4dCB4PSIxMDIyIiB5PSIyMDciIGNsYXNzPSJsYWJlbCBpbmsiPlNwZWM8L3RleHQ+CiAgICA8dGV4dCB4PSIxMDEwIiB5PSIyMzUiIGNsYXNzPSJzbWFsbCBtdXRlZCI+7KeI66y4IOuqqeuhnTwvdGV4dD4KICAgIDxyZWN0IHg9Ijk4MiIgeT0iMjc4IiB3aWR0aD0iMTQ2IiBoZWlnaHQ9IjgyIiByeD0iMTIiIGNsYXNzPSJjYXJkIi8+CiAgICA8dGV4dCB4PSIxMDI2IiB5PSIzMTEiIGNsYXNzPSJsYWJlbCBpbmsiPlBsYW48L3RleHQ+CiAgICA8dGV4dCB4PSIxMDE0IiB5PSIzMzkiIGNsYXNzPSJzbWFsbCBtdXRlZCI+6rWs7ZiEIOuylOychDwvdGV4dD4KICAgIDxyZWN0IHg9Ijk4MiIgeT0iMzgyIiB3aWR0aD0iMTQ2IiBoZWlnaHQ9IjgyIiByeD0iMTIiIGNsYXNzPSJjYXJkIi8+CiAgICA8dGV4dCB4PSIxMDIzIiB5PSI0MTUiIGNsYXNzPSJsYWJlbCBpbmsiPkNvZGU8L3RleHQ+CiAgICA8dGV4dCB4PSIxMDE1IiB5PSI0NDMiIGNsYXNzPSJzbWFsbCBtdXRlZCI+6riw7KG0IO2MqO2EtDwvdGV4dD4KICAgIDxyZWN0IHg9Ijk4MiIgeT0iNDg2IiB3aWR0aD0iMTQ2IiBoZWlnaHQ9IjgyIiByeD0iMTIiIGNsYXNzPSJjYXJkIi8+CiAgICA8dGV4dCB4PSIxMDI4IiB5PSI1MTkiIGNsYXNzPSJsYWJlbCBpbmsiPkdhdGU8L3RleHQ+CiAgICA8dGV4dCB4PSIxMDA4IiB5PSI1NDciIGNsYXNzPSJzbWFsbCBtdXRlZCI+6rKA7KadIOq4sOuhnTwvdGV4dD4KICA8L2c+CgogIDxnPgogICAgPHJlY3QgeD0iNDEwIiB5PSI2MDQiIHdpZHRoPSIzODAiIGhlaWdodD0iNTQiIHJ4PSIyNyIgY2xhc3M9InNvZnQiLz4KICAgIDx0ZXh0IHg9IjQ3NSIgeT0iNjM4IiBjbGFzcz0iYm9keSBpbmsiPkFJ7J2YIOyZhOujjCDshKDslrjsnYQg7Iuk7ZaJIOqysOqzvOuhnCDrsJTqvrjquLA8L3RleHQ+CiAgPC9nPgo8L3N2Zz4K" width="1200" height="720" class="img_ev3q"></p>
<p>특히 반복해서 보였던 문제는 네 가지였습니다.</p>
<ul>
<li>사람마다 요구사항을 정리하는 깊이가 달랐습니다.</li>
<li>애매한 티켓을 AI가 임의로 채우는 경우가 있었습니다.</li>
<li>완료라고 했지만 컴파일, 단위 테스트, 브라우저 확인, API smoke 중 필요한 검증이 빠진 적이 있었습니다.</li>
<li>코드는 올라갔지만 JIRA 상태, MR 본문, 검증 결과가 비어 있어 다음 사람이 다시 확인해야 했습니다.</li>
</ul>
<p>그래서 목표를 바꿨습니다. "AI가 더 똑똑하게 답하게 하자"가 아니라 "AI가 팀의 작업 방식 안에서만 움직이게 하자"로요.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="하네스의-구조">하네스의 구조<a href="https://tech.umosone.ai/ai-harness#%ED%95%98%EB%84%A4%EC%8A%A4%EC%9D%98-%EA%B5%AC%EC%A1%B0" class="hash-link" aria-label="Direct link to 하네스의 구조" title="Direct link to 하네스의 구조">​</a></h2>
<p>하네스는 별도의 거대한 플랫폼이 아닙니다. 저희는 FE와 BE가 같은 모노레포에 있기 때문에, 하네스도 repository 안에 함께 둡니다. repo를 열면 원칙, 도메인 지식, 템플릿, 스킬을 같은 위치에서 읽고 실행할 수 있게 만드는 방식입니다.</p>
<p>대표 구조는 다음과 같습니다.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">.agents/                     # 도구 중립 지식 베이스</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── domain/                   # 주문, 배차, 정산 등 도메인 지식</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── patterns/                 # 아키텍처와 구현 패턴</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── guides/                   # TDD, workflow 등 작업 가이드</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── templates/                # spec, plan 등 산출물 템플릿</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── skills/                   # 반복 판단을 실행 단위로 만든 스킬</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── roles/</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── scripts/</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">└── scratch/</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">.claude/                     # Claude Code 전용 설정</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── settings.json             # 모델, env, hook</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── rules/                    # glob 기반 자동 로드 규칙</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── agents/                   # 역할별 agent</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── hooks/                    # 자동 검증 hook</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">└── skills -&gt; ../.agents/skills</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>핵심은 <code>.agents</code>를 도구 중립의 단일 진실원으로 두는 것입니다. Claude, Codex, Gemini처럼 사용하는 도구가 달라도 같은 도메인 지식과 같은 스킬을 읽게 만들면, 도구별 프롬프트를 각각 관리하는 부담을 줄일 수 있습니다.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="일하는-흐름-입력-하네스-출력">일하는 흐름: 입력, 하네스, 출력<a href="https://tech.umosone.ai/ai-harness#%EC%9D%BC%ED%95%98%EB%8A%94-%ED%9D%90%EB%A6%84-%EC%9E%85%EB%A0%A5-%ED%95%98%EB%84%A4%EC%8A%A4-%EC%B6%9C%EB%A0%A5" class="hash-link" aria-label="Direct link to 일하는 흐름: 입력, 하네스, 출력" title="Direct link to 일하는 흐름: 입력, 하네스, 출력">​</a></h2>
<p>하네스가 하는 일은 간단히 말해 입력을 정리하고, 정해진 단계로 처리하고, 결과를 기록하게 만드는 것입니다.</p>
<table><thead><tr><th>단계</th><th>내용</th><th>예시</th></tr></thead><tbody><tr><td>Input</td><td>무엇을 보고 시작할지 정합니다.</td><td>JIRA 티켓, Figma, Confluence, 코드베이스, 팀 규칙</td></tr><tr><td>Process</td><td>어떤 순서와 기준으로 일할지 정합니다.</td><td><code>feature-start</code> → <code>feature-spec</code> → <code>feature-plan</code> → <code>feature-implement</code> → <code>feature-test</code></td></tr><tr><td>Output</td><td>결과를 어디에 남길지 정합니다.</td><td>코드, 테스트, 커밋, MR, JIRA 코멘트</td></tr></tbody></table>
<p>이 흐름에서 가장 중요한 스킬은 <code>feature-workflow</code>입니다. 이 스킬은 지휘자 역할을 합니다. 티켓을 받아 작업 경로를 고르고, 각 phase 스킬을 호출하고, 단계 전환을 통제합니다.</p>
<p>각 phase는 자기 산출물과 통과 조건만 책임집니다.</p>
<table><thead><tr><th>Phase</th><th>역할</th><th>통과 조건</th></tr></thead><tbody><tr><td><code>feature-start</code></td><td>작업 공간, 브랜치, JIRA 맥락 준비</td><td>시작 상태가 고정되어야 spec 진입</td></tr><tr><td><code>feature-spec</code></td><td>JIRA, Figma, Confluence를 구현 가능한 요구사항으로 정리</td><td>모호함이 남아 있으면 plan 차단</td></tr><tr><td><code>feature-plan</code></td><td>API, 데이터, 화면, 테스트 설계로 번역</td><td>구현 가능 수준의 계획이 있어야 implement 진입</td></tr><tr><td><code>feature-implement</code></td><td>plan을 task로 쪼개 구현하고 빌드타임 검증</td><td>plan 밖 구현이나 빌드 실패 시 test 차단</td></tr><tr><td><code>feature-test</code></td><td>실제 실행 검증과 커밋 게이트 담당</td><td>테스트 실패 시 커밋과 MR 차단</td></tr></tbody></table>
<p>이렇게 나누면 AI가 "이제 구현할게요"라고 성급하게 넘어가기 어렵습니다. spec에서 질문이 남으면 plan으로 가지 못하고, test에서 실패하면 commit으로 가지 못합니다.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="실제-사례-tms-8103">실제 사례: TMS-8103<a href="https://tech.umosone.ai/ai-harness#%EC%8B%A4%EC%A0%9C-%EC%82%AC%EB%A1%80-tms-8103" class="hash-link" aria-label="Direct link to 실제 사례: TMS-8103" title="Direct link to 실제 사례: TMS-8103">​</a></h2>
<p>예를 들어 <code>[FE] Admin 동기화 현황 상세 페이지 데이터 덮어쓰기 및 외부 재전송 API 연동</code> 작업이 있었습니다.</p>
<p>그냥 시작했다면 API를 붙이고 "동작함"으로 끝났을 가능성이 컸습니다. 하지만 하네스는 구현 전에 먼저 다음을 잡았습니다.</p>
<ul>
<li>Acceptance Criteria</li>
<li>에러 매트릭스</li>
<li>기존 drawer/service 패턴</li>
<li>검증 범위</li>
</ul>
<p>그 결과 작업은 다음 순서로 정리됐습니다.</p>
<ol>
<li><code>spec</code>: 요구사항을 구현 단위로 바꾸기 전에 AC, edge case, 에러 매트릭스를 확정했습니다.</li>
<li><code>plan</code>: 변경 파일, API 계약, 테스트 범위를 정하고 기존 구현 패턴을 확인했습니다.</li>
<li><code>code</code>: <code>forceUpdateFailedSyncOrder</code>, <code>forceResendDispatch</code>를 기존 service/component 흐름 안에 연결했습니다.</li>
<li><code>test</code>: type-check, unit, 브라우저 검증 결과를 커밋 전 게이트로 남겼습니다.</li>
</ol>
<p>최종 산출물은 코드 변경뿐 아니라 테스트, MR/JIRA 요약까지 포함했습니다. "무엇을 바꿨는지"보다 "무엇을 확인했는지"가 같이 남는 것이 중요했습니다.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ai-결과는-말이-아니라-실행으로-믿습니다">AI 결과는 말이 아니라 실행으로 믿습니다<a href="https://tech.umosone.ai/ai-harness#ai-%EA%B2%B0%EA%B3%BC%EB%8A%94-%EB%A7%90%EC%9D%B4-%EC%95%84%EB%8B%88%EB%9D%BC-%EC%8B%A4%ED%96%89%EC%9C%BC%EB%A1%9C-%EB%AF%BF%EC%8A%B5%EB%8B%88%EB%8B%A4" class="hash-link" aria-label="Direct link to AI 결과는 말이 아니라 실행으로 믿습니다" title="Direct link to AI 결과는 말이 아니라 실행으로 믿습니다">​</a></h2>
<p>AI가 설명을 잘했다고 해서 믿지 않습니다. 실행 결과로 믿습니다.</p>
<p>FE 작업에서는 보통 다음을 봅니다.</p>
<ul>
<li>Playwright로 실제 화면, viewport, 주요 interaction 확인</li>
<li>Vitest 단위 테스트</li>
<li>확인한 화면, 조건, 미검증 영역을 report로 기록</li>
</ul>
<p>BE 작업에서는 다음을 봅니다.</p>
<ul>
<li>서버를 띄우고 변경된 endpoint를 직접 호출하는 API smoke</li>
<li>OpenAPI 요청/응답 계약 확인</li>
<li>Kotest BehaviorSpec 등 단위 테스트</li>
<li>Kotlin/Gradle compile 검증</li>
</ul>
<p><code>feature-test</code>는 state의 마지막 단계가 <code>implement</code>가 아니면 시작하지 않습니다. 필요한 smoke나 browser 검증이 실패하면 커밋과 MR 단계로 넘어가지 못합니다. 실패를 사용자가 명시적으로 승인하지 않는 한, AI가 완료로 포장하지 못하게 막습니다.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="사람이-까먹어도-시스템이-강제하게-만들기">사람이 까먹어도 시스템이 강제하게 만들기<a href="https://tech.umosone.ai/ai-harness#%EC%82%AC%EB%9E%8C%EC%9D%B4-%EA%B9%8C%EB%A8%B9%EC%96%B4%EB%8F%84-%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%9D%B4-%EA%B0%95%EC%A0%9C%ED%95%98%EA%B2%8C-%EB%A7%8C%EB%93%A4%EA%B8%B0" class="hash-link" aria-label="Direct link to 사람이 까먹어도 시스템이 강제하게 만들기" title="Direct link to 사람이 까먹어도 시스템이 강제하게 만들기">​</a></h2>
<p>스킬은 능력이고, hook은 강제입니다. 사람이 기억하면 좋겠지만, 반복되는 품질 게이트는 사람이 기억하지 않아도 실행되어야 합니다.</p>
<p>저희가 실제로 설정한 hook 예시는 두 가지입니다.</p>
<table><thead><tr><th>Hook</th><th>역할</th><th>효과</th></tr></thead><tbody><tr><td><code>PostToolUse</code></td><td>스킬 호출 시마다 스킬명, 시각, 성공 여부, args를 기록</td><td>실제 쓰이는 스킬과 안 쓰이는 스킬을 구분</td></tr><tr><td><code>Stop</code></td><td>AI가 턴을 끝내려 할 때 수정된 Kotlin 파일에 ktlint/test 실행</td><td>위반 시 종료 차단, AI가 고쳐야만 끝낼 수 있음</td></tr></tbody></table>
<p>이 방식은 작은 차이를 만듭니다. "테스트 했나요?"라고 사람이 묻는 대신, 테스트를 통과하지 못하면 다음 단계로 가지 못합니다.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="처음부터-잘-된-것은-아니었습니다">처음부터 잘 된 것은 아니었습니다<a href="https://tech.umosone.ai/ai-harness#%EC%B2%98%EC%9D%8C%EB%B6%80%ED%84%B0-%EC%9E%98-%EB%90%9C-%EA%B2%83%EC%9D%80-%EC%95%84%EB%8B%88%EC%97%88%EC%8A%B5%EB%8B%88%EB%8B%A4" class="hash-link" aria-label="Direct link to 처음부터 잘 된 것은 아니었습니다" title="Direct link to 처음부터 잘 된 것은 아니었습니다">​</a></h2>
<p>하네스는 처음부터 완성품이 아니었습니다. 오히려 실패를 하나씩 줄이면서 만들어졌습니다.</p>
<table><thead><tr><th>실패</th><th>바꾼 점</th></tr></thead><tbody><tr><td>AI가 완료라고 했는데 실제로 안 돌아감</td><td><code>feature-test</code> 게이트를 추가해 실행 검증 후에만 완료 선언</td></tr><tr><td>문서의 포트가 실제 <code>vite.config</code>와 다름</td><td>코드가 진실이라는 원칙을 세우고 문서를 최신화</td></tr><tr><td>FE 구현은 끝났지만 Figma와 레이아웃이 미묘하게 다름</td><td><code>browser-test</code>로 viewport, Figma, 브라우저 비교 절차와 report 강제</td></tr><tr><td>만든 스킬이 실제 작업에서 호출되지 않음</td><td>사용량을 추적하고 trigger와 내용을 수정하거나 제거</td></tr></tbody></table>
<p>여기서 얻은 교훈은 단순합니다. 하네스도 운영 대상입니다. 완료 여부, 화면 일치, 스킬 유용성을 말로 믿지 않고 근거로 확인해야 합니다.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ai와-사람의-책임-경계">AI와 사람의 책임 경계<a href="https://tech.umosone.ai/ai-harness#ai%EC%99%80-%EC%82%AC%EB%9E%8C%EC%9D%98-%EC%B1%85%EC%9E%84-%EA%B2%BD%EA%B3%84" class="hash-link" aria-label="Direct link to AI와 사람의 책임 경계" title="Direct link to AI와 사람의 책임 경계">​</a></h2>
<p>AI가 검증까지 도와주더라도 최종 책임은 개발자에게 있습니다. 그래서 역할을 분명히 나눕니다.</p>
<p><img decoding="async" loading="lazy" alt="AI와 사람의 책임 경계" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjcyMCIgdmlld0JveD0iMCAwIDEyMDAgNzIwIiByb2xlPSJpbWciIGFyaWEtbGFiZWxsZWRieT0idGl0bGUgZGVzYyI+CiAgPHRpdGxlIGlkPSJ0aXRsZSI+QUnsmYAg7IKs656M7J2YIOyxheyehCDqsr3qs4Q8L3RpdGxlPgogIDxkZXNjIGlkPSJkZXNjIj5BSeqwgCDstIjslYgg7J6R7ISxLCDrp6Xrnb0g67OR7ZWpLCDthYzsiqTtirgg7KCc7JWI6rO8IOqygOymnSDsi6TtlonsnYQg64u064u57ZWY6rOgIOyCrOuejOydtCDrspTsnIQg6rKw7KCVLCDslYTtgqTthY3sspgg7YyQ64uoLCDstZzsooUg7Iq57J246rO8IOuouOyngOulvCDssYXsnoTsp4DripQg6rK96rOE66W8IOuCmO2DgOuCuCDqt7jrprw8L2Rlc2M+CiAgPGRlZnM+CiAgICA8c3R5bGU+CiAgICAgIC5iZyB7IGZpbGw6ICNmNWY4ZmM7IH0KICAgICAgLmNhcmQgeyBmaWxsOiAjZmZmZmZmOyBzdHJva2U6ICNkN2RlZWE7IHN0cm9rZS13aWR0aDogMjsgfQogICAgICAuYWkgeyBmaWxsOiAjZTdlNGZmOyBzdHJva2U6ICM2MjU1Yzg7IHN0cm9rZS13aWR0aDogMjsgfQogICAgICAuaHVtYW4geyBmaWxsOiAjZDVmOGYxOyBzdHJva2U6ICMxMjhmODI7IHN0cm9rZS13aWR0aDogMjsgfQogICAgICAuZ2F0ZSB7IGZpbGw6ICMxNTE5MjM7IH0KICAgICAgLmxpbmUgeyBzdHJva2U6ICM5YWE1YjU7IHN0cm9rZS13aWR0aDogMzsgc3Ryb2tlLWRhc2hhcnJheTogMTAgMTA7IH0KICAgICAgLmFycm93IHsgZmlsbDogbm9uZTsgc3Ryb2tlOiAjN2I4Nzk3OyBzdHJva2Utd2lkdGg6IDQ7IHN0cm9rZS1saW5lY2FwOiByb3VuZDsgc3Ryb2tlLWxpbmVqb2luOiByb3VuZDsgfQogICAgICAudmlvbGV0IHsgZmlsbDogIzYyNTVjODsgfQogICAgICAudGVhbCB7IGZpbGw6ICMxMjhmODI7IH0KICAgICAgLmNvcmFsIHsgZmlsbDogI2Q5NTY0ODsgfQogICAgICAuYW1iZXIgeyBmaWxsOiAjYjQ3YTE2OyB9CiAgICAgIC5pbmsgeyBmaWxsOiAjMTIxNzIyOyB9CiAgICAgIC5tdXRlZCB7IGZpbGw6ICM2ODczODY7IH0KICAgICAgLndoaXRlIHsgZmlsbDogI2ZmZmZmZjsgfQogICAgICAudGl0bGUgeyBmb250OiA4MDAgNDJweCB1aS1zYW5zLXNlcmlmLCBzeXN0ZW0tdWksIC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgIlNlZ29lIFVJIiwgc2Fucy1zZXJpZjsgfQogICAgICAuc3VidGl0bGUgeyBmb250OiA1MDAgMjJweCB1aS1zYW5zLXNlcmlmLCBzeXN0ZW0tdWksIC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgIlNlZ29lIFVJIiwgc2Fucy1zZXJpZjsgfQogICAgICAubGFiZWwgeyBmb250OiA4MDAgMjRweCB1aS1zYW5zLXNlcmlmLCBzeXN0ZW0tdWksIC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgIlNlZ29lIFVJIiwgc2Fucy1zZXJpZjsgfQogICAgICAuYm9keSB7IGZvbnQ6IDY1MCAxOHB4IHVpLXNhbnMtc2VyaWYsIHN5c3RlbS11aSwgLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCAiU2Vnb2UgVUkiLCBzYW5zLXNlcmlmOyB9CiAgICAgIC5zbWFsbCB7IGZvbnQ6IDc1MCAxNXB4IHVpLXNhbnMtc2VyaWYsIHN5c3RlbS11aSwgLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCAiU2Vnb2UgVUkiLCBzYW5zLXNlcmlmOyB9CiAgICAgIC5zaGFkb3cgeyBmaWx0ZXI6IGRyb3Atc2hhZG93KDAgMThweCAzMHB4IHJnYigzMSA0NSA2NiAvIDAuMTIpKTsgfQogICAgPC9zdHlsZT4KICAgIDxtYXJrZXIgaWQ9ImFycm93aGVhZCIgbWFya2VyV2lkdGg9IjEyIiBtYXJrZXJIZWlnaHQ9IjEyIiByZWZYPSI5IiByZWZZPSI2IiBvcmllbnQ9ImF1dG8iPgogICAgICA8cGF0aCBkPSJNMiwyIEwxMCw2IEwyLDEwIFoiIGZpbGw9IiM3Yjg3OTciLz4KICAgIDwvbWFya2VyPgogIDwvZGVmcz4KCiAgPHJlY3QgY2xhc3M9ImJnIiB3aWR0aD0iMTIwMCIgaGVpZ2h0PSI3MjAiLz4KICA8dGV4dCB4PSI3MiIgeT0iNzgiIGNsYXNzPSJ0aXRsZSBpbmsiPkFJ7JmAIOyCrOuejOydmCDssYXsnoQg6rK96rOEPC90ZXh0PgogIDx0ZXh0IHg9IjcyIiB5PSIxMTgiIGNsYXNzPSJzdWJ0aXRsZSBtdXRlZCI+QUnripQg7LSI7JWI6rO8IOqygOymneydhCDrj5Xqs6AsIOy1nOyihSDtjJDri6jqs7wg7LGF7J6E7J2AIOqwnOuwnOyekOqwgCDqsIDsp5Hri4jri6QuPC90ZXh0PgoKICA8ZyBjbGFzcz0ic2hhZG93Ij4KICAgIDxyZWN0IHg9IjcyIiB5PSIxNjgiIHdpZHRoPSI0MzAiIGhlaWdodD0iNDMwIiByeD0iMTgiIGNsYXNzPSJhaSIvPgogICAgPGNpcmNsZSBjeD0iMTI4IiBjeT0iMjI2IiByPSIyOCIgY2xhc3M9InZpb2xldCIvPgogICAgPHRleHQgeD0iMTEzIiB5PSIyMzUiIGNsYXNzPSJzbWFsbCB3aGl0ZSI+QUk8L3RleHQ+CiAgICA8dGV4dCB4PSIxNzQiIHk9IjIzNiIgY2xhc3M9ImxhYmVsIGluayI+QUnqsIAg64+V64qUIOyYgeyXrTwvdGV4dD4KICAgIDx0ZXh0IHg9IjExOCIgeT0iMzA2IiBjbGFzcz0iYm9keSBpbmsiPuKAoiBzcGVjIOy0iOyViCDsnpHshLE8L3RleHQ+CiAgICA8dGV4dCB4PSIxMTgiIHk9IjM1MCIgY2xhc3M9ImJvZHkgaW5rIj7igKIgSklSQS9GaWdtYS9Db25mbHVlbmNlIOunpeudvSDrs5Htlak8L3RleHQ+CiAgICA8dGV4dCB4PSIxMTgiIHk9IjM5NCIgY2xhc3M9ImJvZHkgaW5rIj7igKIg66qo7Zi47ZWcIOyalOq1rOyCrO2VrSDsp4jrrLgg66qp66Gd7ZmUPC90ZXh0PgogICAgPHRleHQgeD0iMTE4IiB5PSI0MzgiIGNsYXNzPSJib2R5IGluayI+4oCiIHBsYW4vdGFza3Mg67aE7ZW0PC90ZXh0PgogICAgPHRleHQgeD0iMTE4IiB5PSI0ODIiIGNsYXNzPSJib2R5IGluayI+4oCiIOy9lOuTnCDrs4Dqsr3qs7wg7YWM7Iqk7Yq4IOygnOyViDwvdGV4dD4KICAgIDx0ZXh0IHg9IjExOCIgeT0iNTI2IiBjbGFzcz0iYm9keSBpbmsiPuKAoiDqsoDspp0gZ2F0ZSDsi6Ttlonqs7wg6rKw6rO8IOygleumrDwvdGV4dD4KICA8L2c+CgogIDxsaW5lIHgxPSI2MDAiIHkxPSIxNTQiIHgyPSI2MDAiIHkyPSI2MTYiIGNsYXNzPSJsaW5lIi8+CiAgPGcgY2xhc3M9InNoYWRvdyI+CiAgICA8cmVjdCB4PSI1MTgiIHk9IjI5MiIgd2lkdGg9IjE2NCIgaGVpZ2h0PSIxMTgiIHJ4PSIxNiIgY2xhc3M9ImdhdGUiLz4KICAgIDx0ZXh0IHg9IjU2MCIgeT0iMzQwIiBjbGFzcz0ibGFiZWwgd2hpdGUiPkdhdGU8L3RleHQ+CiAgICA8dGV4dCB4PSI1NDgiIHk9IjM3NCIgY2xhc3M9InNtYWxsIHdoaXRlIiBvcGFjaXR5PSIwLjgyIj7qsoDspp0g6rKw6rO8PC90ZXh0PgogICAgPHRleHQgeD0iNTQ2IiB5PSIzOTYiIGNsYXNzPSJzbWFsbCB3aGl0ZSIgb3BhY2l0eT0iMC44MiI+7KeI66y46rO8IOq3vOqxsDwvdGV4dD4KICA8L2c+CiAgPHBhdGggY2xhc3M9ImFycm93IiBtYXJrZXItZW5kPSJ1cmwoI2Fycm93aGVhZCkiIGQ9Ik01MDIgMzUwSDUxOCIvPgogIDxwYXRoIGNsYXNzPSJhcnJvdyIgbWFya2VyLWVuZD0idXJsKCNhcnJvd2hlYWQpIiBkPSJNNjgyIDM1MEg2OTgiLz4KCiAgPGcgY2xhc3M9InNoYWRvdyI+CiAgICA8cmVjdCB4PSI2OTgiIHk9IjE2OCIgd2lkdGg9IjQzMCIgaGVpZ2h0PSI0MzAiIHJ4PSIxOCIgY2xhc3M9Imh1bWFuIi8+CiAgICA8Y2lyY2xlIGN4PSI3NTQiIGN5PSIyMjYiIHI9IjI4IiBjbGFzcz0idGVhbCIvPgogICAgPHRleHQgeD0iNzMzIiB5PSIyMzUiIGNsYXNzPSJzbWFsbCB3aGl0ZSI+REVWPC90ZXh0PgogICAgPHRleHQgeD0iODAwIiB5PSIyMzYiIGNsYXNzPSJsYWJlbCBpbmsiPuyCrOuejOydtCDssYXsnoTsp4DripQg7JiB7JetPC90ZXh0PgogICAgPHRleHQgeD0iNzQ0IiB5PSIzMDYiIGNsYXNzPSJib2R5IGluayI+4oCiIHNwZWMg7LWc7KKFIO2ZleyglTwvdGV4dD4KICAgIDx0ZXh0IHg9Ijc0NCIgeT0iMzUwIiBjbGFzcz0iYm9keSBpbmsiPuKAoiDsp4jrrLgg64u167OA6rO8IOuylOychCDqsrDsoJU8L3RleHQ+CiAgICA8dGV4dCB4PSI3NDQiIHk9IjM5NCIgY2xhc3M9ImJvZHkgaW5rIj7igKIg7JWE7YKk7YWN7LKYIO2MkOuLqDwvdGV4dD4KICAgIDx0ZXh0IHg9Ijc0NCIgeT0iNDM4IiBjbGFzcz0iYm9keSBpbmsiPuKAoiBBSSDsvZTrk5zrpqzrt7Ag7ZmV7J246rO8IOyImOyglTwvdGV4dD4KICAgIDx0ZXh0IHg9Ijc0NCIgeT0iNDgyIiBjbGFzcz0iYm9keSBpbmsiPuKAoiBnYXRlIO2GteqzvCDrmJDripQg7J6s7J6R7JeFIOqysOyglTwvdGV4dD4KICAgIDx0ZXh0IHg9Ijc0NCIgeT0iNTI2IiBjbGFzcz0iYm9keSBpbmsiPuKAoiBNUiDstZzsooUg7Iq57J246rO8IOuouOyngDwvdGV4dD4KICA8L2c+CgogIDxnIGNsYXNzPSJzaGFkb3ciPgogICAgPHJlY3QgeD0iMzAyIiB5PSI2MjYiIHdpZHRoPSI1OTYiIGhlaWdodD0iNTQiIHJ4PSIyNyIgY2xhc3M9ImNhcmQiLz4KICAgIDxjaXJjbGUgY3g9IjMzNiIgY3k9IjY1MyIgcj0iMTAiIGNsYXNzPSJjb3JhbCIvPgogICAgPHRleHQgeD0iMzYyIiB5PSI2NjAiIGNsYXNzPSJib2R5IGluayI+7IaN64+E64qUIEFJ6rCAIOyYrOumrOqzoCwg7LGF7J6E7J2AIOyCrOuejOydtCDri6vsirXri4jri6QuPC90ZXh0PgogIDwvZz4KPC9zdmc+Cg==" width="1200" height="720" class="img_ev3q"></p>
<p>AI가 주로 하는 일은 다음과 같습니다.</p>
<ul>
<li>spec 초안 작성</li>
<li>JIRA, Figma, Confluence 맥락 병합</li>
<li>모호한 요구사항 질문 목록화</li>
<li>plan/tasks 분해</li>
<li>코드 변경 제안</li>
<li>테스트 작성</li>
<li>기존 패턴 탐색</li>
<li>검증 gate 실행</li>
<li>MR/JIRA 업데이트 초안 작성</li>
</ul>
<p>개발자가 책임지는 일은 다음과 같습니다.</p>
<ul>
<li>spec 최종 확정</li>
<li>질문 답변과 범위 결정</li>
<li>AI 코드리뷰 확인과 최종 판단</li>
<li>필요한 코드 수정</li>
<li>테스트 케이스 검증</li>
<li>아키텍처 판단</li>
<li>gate 통과 또는 재작업 결정</li>
<li>MR 최종 승인과 머지</li>
</ul>
<p>AI는 작업의 속도를 올리고 빈틈을 드러내는 도구입니다. 하지만 무엇을 만들지, 어떤 위험을 받아들일지, 최종적으로 머지해도 되는지는 사람이 판단합니다.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="보안-사람이-지키고-시스템이-막는-것">보안: 사람이 지키고, 시스템이 막는 것<a href="https://tech.umosone.ai/ai-harness#%EB%B3%B4%EC%95%88-%EC%82%AC%EB%9E%8C%EC%9D%B4-%EC%A7%80%ED%82%A4%EA%B3%A0-%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%9D%B4-%EB%A7%89%EB%8A%94-%EA%B2%83" class="hash-link" aria-label="Direct link to 보안: 사람이 지키고, 시스템이 막는 것" title="Direct link to 보안: 사람이 지키고, 시스템이 막는 것">​</a></h2>
<p>보안도 같은 방식으로 나눴습니다. 민감 데이터 입력은 사람이 지키는 원칙이고, secret 유출은 하네스 게이트가 막아야 하는 영역입니다.</p>
<p>AI에 입력하지 않는 정보는 명확히 정합니다.</p>
<ul>
<li>고객, 기사 개인정보</li>
<li>사업자번호, 계좌 정보</li>
<li>Keycloak과 운영 인증 정보</li>
<li>주문, 정산 실데이터</li>
</ul>
<p>반대로 공유 가능한 정보도 정합니다.</p>
<ul>
<li>공개 문서</li>
<li>코드 구조</li>
<li>값이 제거된 스키마</li>
<li>마스킹된 데이터</li>
<li>테스트 데이터</li>
</ul>
<p>시스템 쪽에서는 <code>skill-quality-reviewer</code>가 스킬과 스크립트의 plaintext secret을 blocker로 보고, Gitleaks나 패턴 스캔으로 merge를 차단합니다. 테스트에도 inline DB 자격증명이나 계정을 넣지 않고, 등록된 reference만 사용하도록 강제합니다.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="반복-업무는-n8n으로-확장">반복 업무는 n8n으로 확장<a href="https://tech.umosone.ai/ai-harness#%EB%B0%98%EB%B3%B5-%EC%97%85%EB%AC%B4%EB%8A%94-n8n%EC%9C%BC%EB%A1%9C-%ED%99%95%EC%9E%A5" class="hash-link" aria-label="Direct link to 반복 업무는 n8n으로 확장" title="Direct link to 반복 업무는 n8n으로 확장">​</a></h2>
<p>AI 하네스가 개발 작업 안쪽의 판단과 검증 기준을 만든다면, n8n은 정해진 시간과 이벤트에 맞춰 팀 운영 업무를 흘려보내는 장치입니다.</p>
<p>예를 들면 다음과 같은 흐름을 자동화할 수 있습니다.</p>
<ul>
<li>Datadog 알림이 울리면 원인 분석과 해결 후보 정리</li>
<li>2주 누적 FE 에러를 분석해 대응 필요 항목 리포트</li>
<li>MR 이벤트를 받아 리뷰 포인트와 확인 필요 항목 정리</li>
<li>배포 알림, 슬래시 커맨드, 스프린트 대시보드, 데일리 스크럼 요약</li>
</ul>
<p>하네스와 n8n은 같은 방향을 봅니다. 사람의 기억에 맡기던 반복 업무를 팀 시스템으로 옮기는 것입니다.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="마치며">마치며<a href="https://tech.umosone.ai/ai-harness#%EB%A7%88%EC%B9%98%EB%A9%B0" class="hash-link" aria-label="Direct link to 마치며" title="Direct link to 마치며">​</a></h2>
<p>AI 하네스는 스킬을 많이 만드는 일이 아닙니다. 같은 품질을 더 적은 맥락과 비용으로 반복하게 만드는 일입니다.</p>
<p>저희가 특히 중요하게 본 원칙은 네 가지였습니다.</p>
<ul>
<li>FE와 BE가 함께 쓰는 하나의 workflow를 둡니다.</li>
<li>요구사항이 애매하면 구현하지 않고 질문합니다.</li>
<li>spec, plan, tasks, report를 산출물로 남깁니다.</li>
<li>컨텍스트 비용을 줄이기 위해 필요한 맥락만 넘기고, state를 handoff 가능한 형태로 유지합니다.</li>
</ul>
<p>AI를 팀에 도입할 때 중요한 질문은 "어떤 모델을 쓸 것인가"에서 끝나지 않습니다. "어떤 순서로 일하게 할 것인가", "무엇을 통과해야 완료라고 볼 것인가", "사람은 어디서 판단할 것인가"까지 정해야 합니다.</p>
<p>저희 팀의 답은 하네스였습니다. 앞으로도 실패 사례와 운영 경험을 바탕으로 이 하네스를 계속 다듬어갈 예정입니다.</p>]]></content>
        <author>
            <name>UMOSONE 개발팀</name>
            <uri>https://umosone.ai</uri>
        </author>
        <category label="AI" term="AI"/>
        <category label="개발문화" term="개발문화"/>
        <category label="자동화" term="자동화"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[UMOSONE Tech Blog를 시작합니다]]></title>
        <id>https://tech.umosone.ai/welcome</id>
        <link href="https://tech.umosone.ai/welcome"/>
        <updated>2026-06-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[UMOSONE 개발팀의 기술 블로그를 시작합니다.]]></summary>
        <content type="html"><![CDATA[<p>UMOSONE 개발팀의 기술 블로그를 시작합니다.</p>
<p>UMOS ONE은 물류와 모빌리티의 여러 흐름을 하나의 경험으로 연결하는 End-to-End 모빌리티 솔루션을 만들어가고 있습니다. 창고 운영을 지능화하는 WMS, 운송 흐름을 최적화하는 TMS, 자산과 현장을 데이터로 묶는 FMS, 그리고 수요응답형 셔틀과 자율주행 셔틀을 연결하는 TAP!까지, 저희가 다루는 문제는 화면 하나나 API 하나로 끝나지 않습니다.</p>
<p><img decoding="async" loading="lazy" alt="UMOS ONE 플랫폼 개요" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjcyMCIgdmlld0JveD0iMCAwIDEyMDAgNzIwIiByb2xlPSJpbWciIGFyaWEtbGFiZWxsZWRieT0idGl0bGUgZGVzYyI+CiAgPHRpdGxlIGlkPSJ0aXRsZSI+VU1PUyBPTkUg7ZSM656r7Y+8IOqwnOyalDwvdGl0bGU+CiAgPGRlc2MgaWQ9ImRlc2MiPldNUywgVE1TLCBGTVMsIFRBUOydtCBVTU9TIE9ORSDtlIzrnqvtj7wg7KSR7Ius7JeQ7IScIOusvOulmOyZgCDrqqjruYzrpqzti7Ag642w7J207YSw66W8IOyXsOqysO2VmOuKlCDqtazsobDrpbwg64KY7YOA64K4IOq3uOumvDwvZGVzYz4KICA8ZGVmcz4KICAgIDxzdHlsZT4KICAgICAgLmJnIHsgZmlsbDogI2Y1ZjhmYzsgfQogICAgICAuZ3JpZCB7IHN0cm9rZTogI2RiZTRlZjsgc3Ryb2tlLXdpZHRoOiAxOyBvcGFjaXR5OiAwLjc7IH0KICAgICAgLmNhcmQgeyBmaWxsOiAjZmZmZmZmOyBzdHJva2U6ICNkN2RlZWE7IHN0cm9rZS13aWR0aDogMjsgfQogICAgICAuY2VudGVyIHsgZmlsbDogIzE1MTkyMzsgfQogICAgICAudGVhbCB7IGZpbGw6ICMxMjhmODI7IH0KICAgICAgLmJsdWUgeyBmaWxsOiAjMmY3ZGY2OyB9CiAgICAgIC5hbWJlciB7IGZpbGw6ICNiNDdhMTY7IH0KICAgICAgLnZpb2xldCB7IGZpbGw6ICM2MjU1Yzg7IH0KICAgICAgLmdyZWVuIHsgZmlsbDogIzI4N2Y1MjsgfQogICAgICAuY29yYWwgeyBmaWxsOiAjZDk1NjQ4OyB9CiAgICAgIC5pbmsgeyBmaWxsOiAjMTIxNzIyOyB9CiAgICAgIC5tdXRlZCB7IGZpbGw6ICM2ODczODY7IH0KICAgICAgLndoaXRlIHsgZmlsbDogI2ZmZmZmZjsgfQogICAgICAudGl0bGUgeyBmb250OiA4MDAgNDJweCB1aS1zYW5zLXNlcmlmLCBzeXN0ZW0tdWksIC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgIlNlZ29lIFVJIiwgc2Fucy1zZXJpZjsgfQogICAgICAuc3VidGl0bGUgeyBmb250OiA1MDAgMjJweCB1aS1zYW5zLXNlcmlmLCBzeXN0ZW0tdWksIC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgIlNlZ29lIFVJIiwgc2Fucy1zZXJpZjsgfQogICAgICAubGFiZWwgeyBmb250OiA4MDAgMjVweCB1aS1zYW5zLXNlcmlmLCBzeXN0ZW0tdWksIC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgIlNlZ29lIFVJIiwgc2Fucy1zZXJpZjsgfQogICAgICAuYm9keSB7IGZvbnQ6IDY1MCAxOHB4IHVpLXNhbnMtc2VyaWYsIHN5c3RlbS11aSwgLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCAiU2Vnb2UgVUkiLCBzYW5zLXNlcmlmOyB9CiAgICAgIC5zbWFsbCB7IGZvbnQ6IDc1MCAxNXB4IHVpLXNhbnMtc2VyaWYsIHN5c3RlbS11aSwgLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCAiU2Vnb2UgVUkiLCBzYW5zLXNlcmlmOyB9CiAgICAgIC5tb25vIHsgZm9udDogODUwIDE2cHggdWktbW9ub3NwYWNlLCBTRk1vbm8tUmVndWxhciwgTWVubG8sIENvbnNvbGFzLCBtb25vc3BhY2U7IH0KICAgICAgLmxpbmsgeyBmaWxsOiBub25lOyBzdHJva2U6ICM5NGEzYjg7IHN0cm9rZS13aWR0aDogNDsgc3Ryb2tlLWxpbmVjYXA6IHJvdW5kOyBzdHJva2UtZGFzaGFycmF5OiA4IDEwOyB9CiAgICAgIC5zb2xpZCB7IGZpbGw6IG5vbmU7IHN0cm9rZTogIzEyOGY4Mjsgc3Ryb2tlLXdpZHRoOiA1OyBzdHJva2UtbGluZWNhcDogcm91bmQ7IH0KICAgICAgLnNoYWRvdyB7IGZpbHRlcjogZHJvcC1zaGFkb3coMCAxOHB4IDMwcHggcmdiKDMxIDQ1IDY2IC8gMC4xMikpOyB9CiAgICA8L3N0eWxlPgogICAgPG1hcmtlciBpZD0iYXJyb3doZWFkIiBtYXJrZXJXaWR0aD0iMTIiIG1hcmtlckhlaWdodD0iMTIiIHJlZlg9IjkiIHJlZlk9IjYiIG9yaWVudD0iYXV0byI+CiAgICAgIDxwYXRoIGQ9Ik0yLDIgTDEwLDYgTDIsMTAgWiIgZmlsbD0iIzEyOGY4MiIvPgogICAgPC9tYXJrZXI+CiAgPC9kZWZzPgoKICA8cmVjdCBjbGFzcz0iYmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjcyMCIvPgogIDxnPgogICAgPHBhdGggY2xhc3M9ImdyaWQiIGQ9Ik0wIDkwSDEyMDBNMCAxODBIMTIwME0wIDI3MEgxMjAwTTAgMzYwSDEyMDBNMCA0NTBIMTIwME0wIDU0MEgxMjAwTTAgNjMwSDEyMDAiLz4KICAgIDxwYXRoIGNsYXNzPSJncmlkIiBkPSJNMTAwIDBWNzIwTTIwMCAwVjcyME0zMDAgMFY3MjBNNDAwIDBWNzIwTTUwMCAwVjcyME02MDAgMFY3MjBNNzAwIDBWNzIwTTgwMCAwVjcyME05MDAgMFY3MjBNMTAwMCAwVjcyME0xMTAwIDBWNzIwIi8+CiAgPC9nPgoKICA8dGV4dCB4PSI3MiIgeT0iNzgiIGNsYXNzPSJ0aXRsZSBpbmsiPlVNT1MgT05FIFRlY2ggQmxvZzwvdGV4dD4KICA8dGV4dCB4PSI3MiIgeT0iMTE4IiBjbGFzcz0ic3VidGl0bGUgbXV0ZWQiPuusvOulmOyZgCDrqqjruYzrpqzti7DsnZgg7Jq07JiBIO2dkOumhOydhCDtlZjrgpjsnZgg7KCc7ZKIIOqyve2XmOycvOuhnCDsl7DqsrDtlanri4jri6QuPC90ZXh0PgoKICA8cGF0aCBjbGFzcz0ibGluayIgZD0iTTM1NiAyNDYgQzQ1NiAyNDYsIDQ4MiAzMjAsIDU0OCAzNTAiLz4KICA8cGF0aCBjbGFzcz0ibGluayIgZD0iTTg0NCAyNDYgQzc0NCAyNDYsIDcxOCAzMjAsIDY1MiAzNTAiLz4KICA8cGF0aCBjbGFzcz0ibGluayIgZD0iTTM1NiA0OTYgQzQ1NiA0OTYsIDQ4MiA0MjAsIDU0OCAzODgiLz4KICA8cGF0aCBjbGFzcz0ibGluayIgZD0iTTg0NCA0OTYgQzc0NCA0OTYsIDcxOCA0MjAsIDY1MiAzODgiLz4KCiAgPGcgY2xhc3M9InNoYWRvdyI+CiAgICA8cmVjdCB4PSI4NCIgeT0iMTc4IiB3aWR0aD0iMjcyIiBoZWlnaHQ9IjEzNiIgcng9IjE2IiBjbGFzcz0iY2FyZCIvPgogICAgPGNpcmNsZSBjeD0iMTMwIiBjeT0iMjI2IiByPSIyNCIgY2xhc3M9ImJsdWUiLz4KICAgIDx0ZXh0IHg9IjExOSIgeT0iMjM0IiBjbGFzcz0ic21hbGwgd2hpdGUiPlc8L3RleHQ+CiAgICA8dGV4dCB4PSIxNzQiIHk9IjIyNCIgY2xhc3M9ImxhYmVsIGluayI+V01TPC90ZXh0PgogICAgPHRleHQgeD0iMTc0IiB5PSIyNTUiIGNsYXNzPSJib2R5IG11dGVkIj7ssL3qs6Ag7Jq07JiBIOyngOuKpe2ZlDwvdGV4dD4KICAgIDx0ZXh0IHg9IjExNiIgeT0iMjg5IiBjbGFzcz0ic21hbGwgbXV0ZWQiPuyeheqzoCDCtyDsnqzqs6Agwrcg7Lac6rOgIOqwgOyLnOyEsTwvdGV4dD4KICA8L2c+CgogIDxnIGNsYXNzPSJzaGFkb3ciPgogICAgPHJlY3QgeD0iODQ0IiB5PSIxNzgiIHdpZHRoPSIyNzIiIGhlaWdodD0iMTM2IiByeD0iMTYiIGNsYXNzPSJjYXJkIi8+CiAgICA8Y2lyY2xlIGN4PSI4OTAiIGN5PSIyMjYiIHI9IjI0IiBjbGFzcz0idGVhbCIvPgogICAgPHRleHQgeD0iODgxIiB5PSIyMzQiIGNsYXNzPSJzbWFsbCB3aGl0ZSI+VDwvdGV4dD4KICAgIDx0ZXh0IHg9IjkzNCIgeT0iMjI0IiBjbGFzcz0ibGFiZWwgaW5rIj5UTVM8L3RleHQ+CiAgICA8dGV4dCB4PSI5MzQiIHk9IjI1NSIgY2xhc3M9ImJvZHkgbXV0ZWQiPuyatOyGoSDtnZDrpoQg7LWc7KCB7ZmUPC90ZXh0PgogICAgPHRleHQgeD0iODc2IiB5PSIyODkiIGNsYXNzPSJzbWFsbCBtdXRlZCI+66ek7LmtIMK3IOuwsOywqCDCtyDqtIDsoJwg7J6Q64+Z7ZmUPC90ZXh0PgogIDwvZz4KCiAgPGcgY2xhc3M9InNoYWRvdyI+CiAgICA8cmVjdCB4PSI4NCIgeT0iNDI4IiB3aWR0aD0iMjcyIiBoZWlnaHQ9IjEzNiIgcng9IjE2IiBjbGFzcz0iY2FyZCIvPgogICAgPGNpcmNsZSBjeD0iMTMwIiBjeT0iNDc2IiByPSIyNCIgY2xhc3M9ImFtYmVyIi8+CiAgICA8dGV4dCB4PSIxMjEiIHk9IjQ4NCIgY2xhc3M9InNtYWxsIHdoaXRlIj5GPC90ZXh0PgogICAgPHRleHQgeD0iMTc0IiB5PSI0NzQiIGNsYXNzPSJsYWJlbCBpbmsiPkZNUzwvdGV4dD4KICAgIDx0ZXh0IHg9IjE3NCIgeT0iNTA1IiBjbGFzcz0iYm9keSBtdXRlZCI+7J6Q7IKw6rO8IO2YhOyepSDrjbDsnbTthLA8L3RleHQ+CiAgICA8dGV4dCB4PSIxMTYiIHk9IjUzOSIgY2xhc3M9InNtYWxsIG11dGVkIj7si6Tsi5zqsIQg6rSA7KCcIMK3IOyYiOyngOuztOyghDwvdGV4dD4KICA8L2c+CgogIDxnIGNsYXNzPSJzaGFkb3ciPgogICAgPHJlY3QgeD0iODQ0IiB5PSI0MjgiIHdpZHRoPSIyNzIiIGhlaWdodD0iMTM2IiByeD0iMTYiIGNsYXNzPSJjYXJkIi8+CiAgICA8Y2lyY2xlIGN4PSI4OTAiIGN5PSI0NzYiIHI9IjI0IiBjbGFzcz0idmlvbGV0Ii8+CiAgICA8dGV4dCB4PSI4ODEiIHk9IjQ4NCIgY2xhc3M9InNtYWxsIHdoaXRlIj5BPC90ZXh0PgogICAgPHRleHQgeD0iOTM0IiB5PSI0NzQiIGNsYXNzPSJsYWJlbCBpbmsiPlRBUCE8L3RleHQ+CiAgICA8dGV4dCB4PSI5MzQiIHk9IjUwNSIgY2xhc3M9ImJvZHkgbXV0ZWQiPuyFlO2LgOqzvCDsnbTrj5kg6rK97ZeYPC90ZXh0PgogICAgPHRleHQgeD0iODc2IiB5PSI1MzkiIGNsYXNzPSJzbWFsbCBtdXRlZCI+RFJUIMK3IOyekOycqOyjvO2WiSDCtyDsiqTrp4jtirjsi5zti7A8L3RleHQ+CiAgPC9nPgoKICA8ZyBjbGFzcz0ic2hhZG93Ij4KICAgIDxyZWN0IHg9IjQ1MiIgeT0iMjQ0IiB3aWR0aD0iMjk2IiBoZWlnaHQ9IjIzMiIgcng9IjI4IiBjbGFzcz0iY2VudGVyIi8+CiAgICA8dGV4dCB4PSI1MTQiIHk9IjMyMiIgY2xhc3M9InRpdGxlIHdoaXRlIiBmb250LXNpemU9IjM4Ij5VTU9TIE9ORTwvdGV4dD4KICAgIDx0ZXh0IHg9IjUwNiIgeT0iMzYwIiBjbGFzcz0iYm9keSB3aGl0ZSIgb3BhY2l0eT0iMC44MiI+RW5kLXRvLUVuZCBNb2JpbGl0eTwvdGV4dD4KICAgIDx0ZXh0IHg9IjU0NiIgeT0iMzg5IiBjbGFzcz0iYm9keSB3aGl0ZSIgb3BhY2l0eT0iMC44MiI+U29sdXRpb248L3RleHQ+CiAgICA8cGF0aCBjbGFzcz0ic29saWQiIG1hcmtlci1lbmQ9InVybCgjYXJyb3doZWFkKSIgZD0iTTUyNiA0MzAgSDY3MiIvPgogIDwvZz4KCiAgPGcgY2xhc3M9InNoYWRvdyI+CiAgICA8cmVjdCB4PSIyOTIiIHk9IjYyMCIgd2lkdGg9IjYxNiIgaGVpZ2h0PSI1NCIgcng9IjI3IiBjbGFzcz0iY2FyZCIvPgogICAgPGNpcmNsZSBjeD0iMzI2IiBjeT0iNjQ3IiByPSIxMCIgY2xhc3M9ImdyZWVuIi8+CiAgICA8dGV4dCB4PSIzNTIiIHk9IjY1NCIgY2xhc3M9ImJvZHkgaW5rIj7rj4TrqZTsnbgg7KeA7IudLCDsmrTsmIEg642w7J207YSwLCDsoJztkogg6rK97ZeY7J2EIOq4sOyIoOuhnCDsl7DqsrDtlZjripQg7Jes7KCVPC90ZXh0PgogIDwvZz4KPC9zdmc+Cg==" width="1200" height="720" class="img_ev3q"></p>
<p>입고부터 출고까지의 재고 가시성, 화주와 차주의 매칭, 운송 자동화, 실시간 관제, 예지보전, 스마트시티 운영처럼 서로 다른 도메인이 한 시스템 안에서 만납니다. 그래서 UMOSONE 개발팀의 일은 단순히 기능을 빠르게 만드는 일이 아니라, 복잡한 이동과 운영 데이터를 안정적으로 연결하고, 현장에서 믿고 쓸 수 있는 제품으로 다듬는 일에 가깝습니다.</p>
<p>이 블로그에는 그런 과정을 기록하려고 합니다.</p>
<ul>
<li>물류와 모빌리티 도메인을 제품으로 풀어내며 배운 것</li>
<li>대규모 운영 데이터를 다루기 위한 아키텍처와 설계 고민</li>
<li>프론트엔드, 백엔드, 인프라, 데이터, AI를 연결하는 개발 경험</li>
<li>품질을 지키기 위한 테스트, 모니터링, 배포, 자동화 이야기</li>
<li>팀이 더 잘 일하기 위해 만든 개발 문화와 도구</li>
</ul>
<p>좋은 기술 블로그는 완성된 답만 모아두는 곳이 아니라고 생각합니다. 의사결정의 배경, 실패했던 접근, 다시 고친 구조, 운영하면서 알게 된 현실적인 제약까지 남겨야 다음 사람이 더 나은 선택을 할 수 있습니다.</p>
<p>UMOSONE Tech Blog는 저희가 만든 것뿐 아니라, 만들어가는 방식을 공유하는 공간이 되려 합니다. 모든 이동의 가치를 완성하기 위해 저희가 어떤 기술적 선택을 하고, 어떤 문제를 만나고, 어떻게 해결해가는지 차근차근 기록하겠습니다.</p>]]></content>
        <author>
            <name>UMOSONE 개발팀</name>
            <uri>https://umosone.ai</uri>
        </author>
        <category label="소개" term="소개"/>
    </entry>
</feed>