refactor: 프론트 템플릿 리펙토링

This commit is contained in:
donghyeon-ka
2026-09-18 15:16:58 +09:00
parent c10a709f2c
commit 5cc41467ae
80 changed files with 7227 additions and 4672 deletions
@@ -0,0 +1,97 @@
import type {
BrowserDataResult,
IndexedDbRepositoryPort,
} from "../../../../src/application/ports/browser-file-storage/index.ts";
export type LocalDraft = Readonly<{
draftId: string;
title: string;
body: string;
}>;
export type SaveLocalDraftCommand = Readonly<{
draft: LocalDraft;
expectedRevision: number | null;
idempotencyKey: string;
}>;
export type RemoveLocalDraftCommand = Readonly<{
draftId: string;
expectedRevision: number;
idempotencyKey: string;
}>;
export type LocalDraftRecord = Readonly<{
draft: LocalDraft;
revision: number;
}>;
export interface LocalDraftStore {
save(
command: SaveLocalDraftCommand,
signal?: AbortSignal,
): Promise<BrowserDataResult<Readonly<{ revision: number }>>>;
find(
draftId: string,
signal?: AbortSignal,
): Promise<BrowserDataResult<LocalDraftRecord | null>>;
remove(
command: RemoveLocalDraftCommand,
signal?: AbortSignal,
): Promise<BrowserDataResult<void>>;
}
/**
* Feature-owned binding over the technology-neutral IndexedDB application port.
*
* The feature knows its domain type and optimistic concurrency inputs. It does
* not know database names, stores, transactions, native IDB objects, codecs,
* migrations, quota handling or connection lifecycle.
*/
export function createLocalDraftStore(
repository: IndexedDbRepositoryPort<LocalDraft, never>,
): LocalDraftStore {
const store: LocalDraftStore = {
async save(command, signal) {
const result = await repository.compareAndSwap({
key: command.draft.draftId,
value: command.draft,
expectedRevision: command.expectedRevision,
idempotencyKey: command.idempotencyKey,
signal,
});
if (!result.ok) return result;
return Object.freeze({
ok: true as const,
value: Object.freeze({ revision: result.value.revision }),
});
},
async find(draftId, signal) {
const result = await repository.read(draftId, signal);
if (!result.ok) return result;
return Object.freeze({
ok: true as const,
value:
result.value === null
? null
: Object.freeze({
draft: result.value.value,
revision: result.value.revision,
}),
});
},
async remove(command, signal) {
const result = await repository.remove({
key: command.draftId,
expectedRevision: command.expectedRevision,
idempotencyKey: command.idempotencyKey,
signal,
});
if (!result.ok) return result;
return Object.freeze({ ok: true as const, value: undefined });
},
};
return Object.freeze(store);
}