` → { text, updatedAt }
+// 투자 결정의 근거/관전 포인트를 짧게 적어두는 용도. 다른 사용자에게는 보이지 않음.
+
+const PREFIX = "notes:";
+const MAX_LEN = 2000; // 너무 큰 입력 방어 — localStorage quota 보호.
+
+export type Note = {
+ text: string;
+ updatedAt: string; // ISO
+};
+
+export function readNote(code: string): Note | null {
+ if (typeof window === "undefined") return null;
+ try {
+ const raw = window.localStorage.getItem(`${PREFIX}${code}`);
+ if (!raw) return null;
+ const parsed = JSON.parse(raw) as Partial;
+ if (typeof parsed.text !== "string" || typeof parsed.updatedAt !== "string") return null;
+ return { text: parsed.text, updatedAt: parsed.updatedAt };
+ } catch {
+ return null;
+ }
+}
+
+export function writeNote(code: string, text: string): Note | null {
+ if (typeof window === "undefined") return null;
+ const trimmed = text.slice(0, MAX_LEN);
+ // 공백만이면 키 자체 제거 → 빈 잔여물 방지.
+ if (!trimmed.trim()) {
+ clearNote(code);
+ return null;
+ }
+ const next: Note = { text: trimmed, updatedAt: new Date().toISOString() };
+ try {
+ window.localStorage.setItem(`${PREFIX}${code}`, JSON.stringify(next));
+ return next;
+ } catch {
+ return null; // quota 등 — UI 가 저장 실패 처리
+ }
+}
+
+export function clearNote(code: string): void {
+ if (typeof window === "undefined") return;
+ try {
+ window.localStorage.removeItem(`${PREFIX}${code}`);
+ } catch {
+ /* ignore */
+ }
+}
+
+export const NOTE_MAX_LEN = MAX_LEN;
diff --git a/web/lib/targets.ts b/web/lib/targets.ts
index 0b0f618..19f8f6c 100644
--- a/web/lib/targets.ts
+++ b/web/lib/targets.ts
@@ -24,9 +24,10 @@ export function readTargets(code: string): Targets {
export function writeTargets(code: string, t: Targets): void {
if (typeof window === "undefined") return;
// 둘 다 비어 있으면 키 자체를 지움 → 빈 객체 잔여물 제거.
+ // 양수 유한값만 통과. UI 가 이미 가드하지만 lib 자체도 방어 — 외부에서 직접 호출돼도 안전.
const cleaned: Targets = {};
- if (t.target != null && Number.isFinite(t.target)) cleaned.target = t.target;
- if (t.stop != null && Number.isFinite(t.stop)) cleaned.stop = t.stop;
+ if (t.target != null && Number.isFinite(t.target) && t.target > 0) cleaned.target = t.target;
+ if (t.stop != null && Number.isFinite(t.stop) && t.stop > 0) cleaned.stop = t.stop;
try {
if (cleaned.target == null && cleaned.stop == null) {
window.localStorage.removeItem(`${PREFIX}${code}`);