fix(B05): 구조물 저장이 판번호 때문에 통째로 사라지던 것 수정

화면 진입 때 받은 판번호로 저장해, 그 사이 정본이 한 번이라도 바뀌면(다른 창
저장·노선 재계산) 409 로 거절되고, 실패 처리가 세션 초안까지 지워 사용자가 넣은
구조물이 사라졌음.

- 판번호를 **쓰기 직전에** 서버에서 다시 받아 씀.
- 저장이 실패해도 세션 초안·화면 목록을 지우지 않음(다시 [저장]하면 됨).

실화면 검증: 고치기 전 구조물 추가 후 [저장] → 정본 0건. 고친 뒤 → 정본 1건, 2건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-06 18:38:04 +09:00
co-authored by Claude Opus 5
parent 8dab657930
commit cdb9799e64
+16 -6
View File
@@ -248,7 +248,16 @@ export function createStructuresBridge(deps: StructuresBridgeDeps) {
async function persistStructures(next: StructureInstance[]): Promise<void> {
if (deps.isRestoring()) return;
try {
const saved = await saveStructures(deps.projectId, structureRevision, next);
// 판번호는 **쓰기 직전에** 서버에서 다시 받는다. 진입 때 받은 값으로 보내면,
// 화면이 떠 있는 동안 정본이 한 번이라도 바뀌었을 때(다른 창 저장·노선 재계산)
// 409 로 거절되고 아래 실패 처리가 초안을 지워 **사용자가 넣은 구조물이 통째로
// 사라졌다**(2026-09-06 실측: B06에서 구조물을 넣고 [저장]해도 정본에 안 남음).
const current = await fetchStructures(deps.projectId).catch(() => null);
const saved = await saveStructures(
deps.projectId,
current ? current.revision : structureRevision,
next,
);
structureRevision = saved.revision;
writePending(null);
// 서버가 새 항목에 식별자를 붙이므로 그 결과로 화면 목록을 맞춘다.
@@ -263,14 +272,15 @@ export function createStructuresBridge(deps: StructuresBridgeDeps) {
);
}
} catch (error) {
// 실패해도 **초안은 지우지 않는다** — 지우면 사용자가 넣은 구조물이 사라진다
// (2026-09-06 정정). 화면 목록도 그대로 두고 다시 [저장]하면 된다.
if (error instanceof StructureConflictError) {
await refreshStructuresFromServer();
showToast("다른 창에서 구조물이 먼저 저장되어 최신 내용으로 되돌렸습니다.", "error");
showToast(
"다른 창에서 구조물이 먼저 저장돼 이번 저장을 건너뛰었습니다. 다시 [저장]해 주세요.",
"error",
);
return;
}
// 저장이 거절되면 화면에만 남은 항목은 식별자가 없어 고치지도 지우지도 못한다.
// 서버 정본으로 되돌려 화면과 정본을 다시 일치시킨다(2026-08-16 크로스체크 지적 1).
await refreshStructuresFromServer();
showToast(error instanceof Error ? error.message : "구조물 저장에 실패했습니다.", "error");
}
}