전체 글

개 발 자 로 살 아 남 기
· TIL
1. TL; DRexport const revalidate = 3600 은 "이 라우트는 정적이라고 내가 선언한다"이고,use cache 는 "이 값은 캐시해도 된다고 내가 표시하면 빌드가 나머지를 검증한다"이다.전자는 틀려도 아무 일이 안 일어나고, 후자는 틀리면 빌드가 깨진다. 이것이 전부였다.2. 왜 없앴을까 - route segment config 의 구조적 결함2-1. 선언은 라우트에 있고 원인은 라우트 밖에 있다revalidate 는 라우트 세그먼트에 붙는다.그런데 라우트를 동적으로 만드는 건 대개 라우트 파일이 아니라 그 아래 어딘가였다.공유 레이아웃이 부르는 훅, 데이터 계층이 타는 headers(), 서드파티 라이브러리 안의 Math.random() 등.즉 선언의 위치와 원인의 위치가 다..
· TIL
export * 한 줄이 sharp를 브라우저 번들로 실어 날랐다pnpm build가 6개 에러로 죽었다.겉보기엔 두 종류였다. 하나는 이미지 라이브러리 sharp가 브라우저 청크에 못 들어간다는 것,다른 하나는 next/headers를 클라이언트에서 쓰면 안 된다는 것. 서로 상관없어 보이는 두 문제가 동시에 터졌다고 생각했다.전부 한 줄에서 나온 파편이었다.1. 그 한 줄서버 액션에서 쓸 함수를 하나 만들고, 같은 디렉토리의 배럴에 얹었다.// src/hooks/queries/auth/index.tsexport * from "./start-provider-login-server"; // ← 이것export * from "./use-provider-login-start-query";export * f..
· TIL
embedding 컬럼을 만들어두고 17일을 비워뒀다Claude와 ChatGPT등 LLM들이 공유하는 개인 메모리 레이어를 만들었다.Next.js 라우트 하나, Postgres 테이블 하나,툴 네 개(remember / recall / list_memories / forget)가 전부인 장난감 같은 도구다. 기록해두고 싶은 건 완성된 구조가 아니라 거기까지 간 순서다.커밋 로그에는 무엇을 했는지만 남고, 무엇을 하지 않기로 했는지는 남지 않는다.이 프로젝트에서 값이 나온 부분은 대부분 후자였다.1. 사지 않기로 한 것부터시작할 때 머릿속에 있던 선택지는 이랬다.LangGraph로 제대로 된 RAG 파이프라인을 짠다최근 화제가 된 메모리 특화 오픈소스(mem-palace 류)를 붙인다직접 최소한으로 만든다..
· etc
Q최근 memory를 임베딩 벡터화하면서 조금 선명해진 생각이 있어요. 들어주세요. 4년전 gpt-3 가 상용화되었을 때 바로 결제하고 사용해보면서 느낀점들이 그동안 일하고 공부하느라 저 밑에 있다가 이번 구현을 계기로 수면위로 올라왔어요. ai 는 코딩하고, 음악만들고, 영상만들고, 문서만드는데 쓰는 도구이기도 하지만 그런 사용법은 과도기에나 적합한 것이라는 생각이에요.제 생각에 AI 는 인간을 증강하는데 사용되는게 이상적일 것 같습니다. AI는 인간 사고의 태생적 결함인 편향성을 극복하는데 너무나도 적합한 도구이자, (제가 오래전부터 신념으로 가지고 있는 바) 새로운 존재 - 동반자 라고 생각이되어요. 인간은 고정관념, 편향을 버릴 수 없어요. 단순화된 인지모델이 없으면 지각자체가 불가능하죠. 그렇기..
· TIL
React Compiler와 라이브러리 호환성 - 사라질 문제와 남을 원리두 프로젝트에서 각각 한 번씩 크게 물렸다.한쪽은 폼(react-hook-form), 한쪽은 테이블(TanStack Table v8)이었는데 증상 문장은 똑같았다."눌렀는데 아무 일도 안 일어난다."런타임 에러도 없고 콘솔 경고도 없다.라이브러리는 제대로 동작하고 있고 화면만 옛날 값이다.1. 한 문장 원리React Compiler의 판단 기준은 오직 하나다. Object.is 참조 비교.if ($[13] !== label || $[14] !== registration) { t8 = …;} else { t8 = $[15]; // ← 캐시된 JSX를 그대로 재사용} 캐시된 엘리먼트를 그대로 돌려주면 React는 그 서브트리 전..
· TIL
Next.js에서 Gmail SMTP + nodemailer로 메일 발송하기1. 이 접근법의 핵심Gmail 계정 하나 + 앱 비밀번호 하나로 SMTP 발송이 끝난다.EmailJS 같은 서드파티 SDK도, 자체 SMTP 서버 구축도, SendGrid/Resend 같은 외부 서비스 가입도 필요 없다.성립하는 이유는 세 가지다.Gmail은 그 자체가 완성된 SMTP 서버다. smtp.gmail.com은 이미 SPF/DKIM/DMARC가 잡혀 있고 IP 평판도 확보돼 있다. 자체 SMTP를 띄웠을 때 가장 고통스러운 "메일이 스팸함으로 간다" 문제를 Google이 대신 해결해 준 상태에서 시작한다.앱 비밀번호가 OAuth를 대체한다. Gmail API를 쓰면 OAuth 동의 화면, 리프레시 토큰 관리, 토큰 만..
· TIL
Effect-TS 개론: Parse, don't validate 에서 Effect 생태계까지TL;DRPromise 는 성공 채널만 타입에 있고 실패 채널이 없다.Effect 는 성공·실패·의존성을 전부 타입에 새긴다.그 사상의 뿌리는 "검증(validate)이 아니라 파싱(parse)하라"에 있다. zod 로 충분하다고 느끼고 있었는데, Parse, don't validate 계열의 글을 읽고Effect-TS 생태계를 알게 되면서 사고방식 자체가 확장됐다.zod 도 사실 이 사상의 산물이라는 걸 뒤늦게 이해했다.이 노트는 그 궤적과 실전 감각을 정리한 것.1. 사상의 궤적King 의 원칙 → fp-ts 학술적 구현 → zod 실용적 축약 → Effect 전방위 확장① Haskell 진영의 원전 (2019..
· TIL
useSyncExternalStore로 useIsMobile 재구성뷰포트가 모바일 폭인지 알려주는 흔한 훅 하나를 리팩토링했다.결과만 보면 코드 줄 수는 비슷한데, 고쳐진 문제가 네 개쯤 된다. 정리해둔다.Before"use client";import * as React from "react";const MOBILE_BREAKPOINT = 550;export function useIsMobile() { const [isMobile, setIsMobile] = React.useState( () => window.innerWidth { if (typeof window === "undefined") return; const onResize = () => { setIsMobile(w..
· TIL
TL;DR현대 TLS는 대칭키 암호와 비대칭키 암호를 함께 사용하는 복합적인 프로토콜입니다.대표적으로 다음 두 기술을 결합합니다.ECDHE: 클라이언트와 서버가 공유 비밀을 네트워크로 직접 전송하지 않고 안전하게 합의합니다.RSA-PSS, ECDSA, EdDSA 등의 디지털 서명: 키 합의 상대가 인증된 서버이며, 해당 서버가 인증서의 개인키를 실제로 보유하고 있음을 증명합니다.이 둘을 결합한 것이 인증된 키 교환입니다.합의된 공유 비밀로부터 세션용 대칭키를 생성하고, 이후 실제 HTTP 요청과 응답은 대칭키 암호 방식으로 보호합니다.AES-GCM 혹은 ChaCha20-Poly1305TLS 1.3에서는 과거처럼 RSA 공개키로 비밀값을 암호화해 서버에 전달하는 RSA 키 운반 방식을 사용하지 않습니다.0..
· TIL
JWT vs 세션, 그리고 JWK의 정체TL;DR"JWT가 죽은 게 아니라, JWT를 브라우저 세션 관리 도구로 쓰던 오용이 교정된 것."다시 상기하자, 쿠키 vs JWT는 대립 축이 아님, 쿠키는 전송 수단, JWT는 토큰 포맷.발단better-auth, Supabase Auth 등 최근 인증 솔루션들이 JWT(JWK)를 지원하면서도기본값은 쿠키+세션인 걸 보고 의문이 생겼다. 분명 몇 년 전엔 "JWT로 통일" 분위기였는데?1. 인증 트렌드는 실제로 한 바퀴 돌았다JWT 전성기 (~2015–2021)SPA + REST API 분리 아키텍처의 유행과 정확히 겹친다.프론트와 백이 다른 도메인, "stateless라 스케일링에 좋다"는 마케팅,튜토리얼마다 복붙되던 localStorage 저장 패턴.실무에서..
adminisme
elseif