Category

Tech

Supabse를 활용한 통합 인증(SSO) 시스템 구축에 대한 기록
Tech4/25/2026

Supabse를 활용한 통합 인증(SSO) 시스템 구축에 대한 기록

현재 네모네AIM과 지금여기 2개의 서비스를 운영하면서 어쩔 수 없이 각각 2개의 회원 체계를 가지고 가고 있었는데 조만간 3번째 서비스 구축에 들어가면서 회원들의 통합 인증(SSO) 시스템 구축에 대한 니즈가 필요해졌다. 일반 회사에서는 대 작업이었겠지만 현재 서비스는 아주 가볍고 로그인이 활발한 서비스는 아니기에 빠르게 도입하는 것이 좋겠다고 생각했다.📋 사전에 정의(결정)해야 할 사항  1. 지원할 로그인 수단 (Auth Providers) 이메일/비밀번호 가입을 유지할 것인가? 소셜 로그인 채널은 무엇을 열 것인가? (예: Google 필수, Kakao/Naver/Apple 추가 여부)  2. 회원 고유 식별자 (Primary Key) 정책 기존에는 이메일(user_email)을 기준으로 데이터를 저장했다. Supabase는 가입 시 무조건 고유한 UUID를 발급하며 앞으로 모든 서비스의 DB(게시글, 댓글, 좋아요 등)는 이메일 대신 이 UUID를 기준으로 연결하는 것이 가장 안전하고 정석적인 방법이라고.  3. 프로필 정보 저장 위치 (매우 중요) 옵션 A (추천): 닉네임, 프로필 사진 등은 Supabase의 자체 DB(public.profiles 테이블)에 저장하고, 각 서비스의 FastAPI 백엔드는 "이 유저의 UUID가 이거구나!" 인증만 처리. 옵션 B: Supabase는 오직 '로그인(토큰 발급)'만 담당하고, 기존처럼 각 서비스의 DB에 회원 테이블을 유지하여 가입 성공 시 동기화.🚀 통합 로그인 개발 단계별 프로세스 (데이터 초기화 가정)Phase 1: Supabase 초기 세팅 (Dashboard)  1. 프로젝트 생성: Supabase에 가입하고 'Nemone SSO'라는 단일 프로젝트를 생성.  2. 로그인 채널 설정: Google 클라우드 콘솔의 OAuth 키를 Supabase에 등록(이메일 가입 사용 시 인증 이메일 템플릿도 세팅)  3. 리다이렉트 URL 등록: 로그인 성공 후 돌아갈 모든 서비스의 주소를 허용 목록에 추가. Phase 2: 백엔드(FastAPI) 전면 개편 (인증 로직 덜어내기)  1. 자체 인증 코드 삭제: 기존 main.py에 있던 낡은 회원가입, 로그인, 비밀번호 해싱 코드를 완전히 삭제.  2. DB 스키마(테이블) 변경: 기존 DB의 users 테이블을 삭제하거나 역할을 축소합니다. comments, likes, saved_courses, themes 테이블의 user_email 컬럼을 모두 user_id (UUID 타입)로 변경.  3. 토큰 검증 미들웨어 추가: 프론트엔드가 API를 찌를 때 Authorization: Bearer <토큰>을 보내면, FastAPI가 Supabase의 JWT 시크릿 키를 이용해 "위조되지 않은 진짜 토큰인지" 검증하는 함수를 만듬. Phase 3: 프론트엔드 통합 (Next.js)  1. 기존 NextAuth 제거: 네모네AIM과 지금여기에 설치된 무거운 next-auth 패키지와 관련 API 폴더(app/api/auth)를 모두 삭제.  2. Supabase SSR 도입: @supabase/ssr 패키지를 설치하여, 서버와 클라이언트 양쪽에서 로그인 상태를 알 수 있게 세팅.  3. 통합 쿠키(SSO) 설정: 사용자가 nemoneai.com에서 로그인하면, 쿠키의 도메인을 .nemoneai.com으로 굽도록 설정. 이렇게 하면 사용자가 now.nemoneai.com으로 넘어갔을 때, 다시 로그인할 필요 없이 자동으로 로그인된 상태(SSO)가 유지.  4. UI 컴포넌트 수정: 기존 로그인 버튼들이 NextAuth 대신 Supabase Auth 함수를 호출하도록 연결합니다.🆚 옵션 A vs 옵션 B 심층 비교 🚀 옵션 A: Supabase에 모든 프로필 저장 Supabase의 자체 DB(`public.profiles`)에 이메일, 닉네임, 프로필 사진을 모두 저장하고, 자체 백엔드(GCP DB)는 오직 UUID(고유번호)만 가지고 게시글/댓글과 연결하는 방식.  * 장점 (Pros): 가장 완벽한 SSO (Single Sign-On): 네모네AIM에서 닉네임을 바꾸면, NOW HERE나 새로 만들 서비스에서도 즉시 바뀐 닉네임이적용. 진정한 '통합 계정'. 백엔드 초경량화: 자체 백엔드(GCP DB)에 users 테이블 자체가 필요 없어집니다. 백엔드 코드가 매우 단순해짐. 보안성 최상: 유저의 모든 개인정보가 암호화된 강력한 Supabase 인프라 안에 격리되므로, 자체 서버가 뚫리더라도 유저의 민감 정보는 안전.  * 단점 (Cons): 데이터 조인(Join)의 불편함: 게시글이나 댓글을 불러올 때 자체 DB(GCP)에는 '글 내용'과 '작성자 UUID'만 있음. 프론트엔드에서 작성자 닉네임을 보여주려면 Supabase API를 한 번 더 호출해서 가져와야 하므로, 초기 로딩 시 API 통신이 약간 늘어남. 🏗 옵션 B: Supabase는 인증만, 프로필은 기존 DB(GCP)에 저장 Supabase는 "이메일 맞음, 토큰 발급해줄게!" 역할만 하고, 유저가 가입/로그인할 때 발급된 UUID와 프로필 정보를 우리 백엔드(GCP DB의 `users` 테이블)에 동기화해 두는 방식.  * 장점 (Pros): 조회 성능 최상: 게시글을 불러올 때 기존처럼 한 번의 SQL 쿼리(Join)로 작성자 닉네임, 사진까지 한 방에 가져올 수 있어 매우 빠름. 데이터 주권: 모든 유저의 상세 활동 데이터와 프로필이 우리 통제하에 있는 GCP DB 한곳에 모여 있어 데이터 분석(통계)이 편리.  * 단점 (Cons): 동기화의 늪 (가장 큰 단점): 유저가 네모네AIM에서 닉네임을 바꿨을 때, NOW HERE DB에도 그 변경 사항을 쏴줘야 하는(혹은 중앙 DB를 따로 파서 각 백엔드가 바라보게 해야 하는) 복잡한 데이터 동기화 지옥이 시작. 아키텍처 복잡: 회원가입 시 Supabase가 성공 응답을 주면, 백엔드의 Webhook이나 프론트엔드의 별도 API 호출을 통해 우리 DB에도 유저를 생성하는 코드를 짜야 해서 버그가 생길 확률이 높음.[신규 회원가입 프로세스 시나리오]1단계: 진입 (Entry)유저가 '지금여기'나 '네모네AIM' 중 어느 곳에서 가입을 시도하든, 디자인과 로직이 통일된 통합 로그인/가입 페이지를 마주.2단계: 약관 동의 (Consent)가입 버튼을 누르면 가장 먼저 약관 동의 화면이 나옵니다. 여기서 '통합 회원'임을 명확히 인지시킵니다.3단계: 인증 및 정보 입력 (Auth & Profile)소셜 로그인(OAuth) 또는 이메일 인증을 진행합니다.4단계: 가입 완료 및 웰컴 가이드 (Welcome)가입이 끝나면 유저에게 이 계정의 가치를 설명해 줍니다.💡 독립된 서브도메인 구축도메인 통일: 가입 페이지의 주소를 auth.nemoneai.com과 같이 독립된 서브도메인으로 운영하여, 유저에게 "여기가 인증 센터구나"라는 신뢰감을 줌.자동 리다이렉트: '지금여기'에서 가입을 시작했다면, 가입 완료 후 다시 '지금여기'의 메인 화면으로 자연스럽게 돌아가게끔 redirect_url 파라미터를 정교하게 세팅.프로필 연동: Supabase Storage에 저장된 프로필 사진 하나가 모든 앱에서 똑같이 뜨게 함.네모네만의 특별한 질문(예: "당신을 설레게 하는 것은 무엇인가요? ) : 향후 취향에 따른 메인페이지 설정에 활용 예정

Read Story
[Google Search Console 오류 조치] 바이브코딩의 한계라고 볼 수 있나
Tech4/22/2026

[Google Search Console 오류 조치] 바이브코딩의 한계라고 볼 수 있나

구글에서 회사 홈페이지를 검색하면 제대로 정보가 표기되지 않았음. 그래서 구글 서치 콘솔(Google Search Console)에 들어가보면 색인은 성공했다는 메시지는 떴음. 아무래도 이상해서 하나하나 클릭하다보니 크롤링된 페이지>추가정보>페이지리소스를 확인하니 이런 메시지가 작게 써있었다.총 23개 중 18개 리소스를 로드하지 못함 아니, 이런 정도면 메인페이지에서 에러를 알려줘야지 어렵게 숨겨놓은 것! 부랴부랴 에러의 원인을 찾아봤는데 치명적이진 않으나 '사용자 경험(LCP 등)'과 '렌더링 완성도'를 위해 수정이 불가피 했습니다.                                                                                                           1. 주요 오류 원인 분석                                                    jsDelivr(Pretendard 글꼴) 및 Google Fonts 오류                                            cdn.jsdelivr.net이나 fonts.gstatic.com에서 발생하는 '기타 오류'는 크롤러(Googlebot)가 해당 파일을 가져오지 못했다는 뜻입니다.  크롤러의 타임아웃: 구글봇은 페이지를 렌더링할 때 무한정 기다려주지 않습니다. 외부 CDN 서버의 응답이 아주 미세하게 늦으면 그냥 '무시'하고 다음 단계로 넘어갑니다.                                                                    크롤링 예산(Crawl Budget): 구글봇이 한 사이트에서 한꺼번에 요청할 수 있는 리소스 양을 초과했을 때 발생합니다.                                                                                 Tailwind CSS 리디렉션/기타 오류                                                    cdn.tailwindcss.com을 직접 호출하는 방식은 개발용(Play CDN)입니다.                            리디렉션 오류: 특정 버전으로 리디렉션되는 과정에서 봇이 추적을 포기했을 수 있습니다.  실제 문제: 구글봇이 CSS를 제대로 로드하지 못하면 사이트의 레이아웃이 깨진 상태로 렌더링됩니다. 이는 '모바일 사용 편의성' 평가에 악영향을 줄 수 있습니다. Unsplash 이미지 오류                                                         이미지 파일이 너무 크거나(w=2000 등), 고화질(q=80)인 경우 봇이 로드를 포기합니다. 봇 입장에서는 텍스트 정보가 중요한데, 무거운 이미지를 기다릴 이유가 없기 때문입니다. 🚨 프로젝트 진단 및 대응 1. Tailwind CSS 렌더링 지연 (가장 치명적) 현재 상태를 보면 Tailwind CSS가 정식으로 설치되어 있지 않습니다. 대신 index.html에서 <script src="https://cdn.tailwindcss.com"></script> (Play CDN)를 불러와 브라우저가 접속할 때마다 실시간으로 CSS를 연산하여 그리고 있다. 문제점: 구글 봇은 자바스크립트를 오래 실행해주지 않아 봇이 보기에 사이트는 디자인이 싹 다 깨진 하얀 바탕의 글씨만 있는 페이지로 인식될 확률이 높다. 대응 방안: Node.js 환경(npm)에 tailwindcss, postcss, autoprefixer를 정식 설치하고 tailwind.config.js와 postcss.config.js를 세팅하여, 빌드(npm run build) 시 최적화된 하나의 .css 파일로 구워지도록 프로젝트 구조를 싹 바꾼다. 2. 외부 폰트(Pretendard 등) 타임아웃 현재 상태: index.html에서 jsdelivr를 통해 Pretendard 폰트를 @import로 불러오고 있으며, 구글 폰트도 외부 CDN을 사용 중. 문제점: 외부 서버 응답이 0.1초만 늦어도 구글 봇은 폰트를 포기하고 에러를 뱉는다. 대응 방안: @import 방식은 렌더링 블로킹(로딩 지연)을 심하게 유발하므로, <link rel="preload"> 방식으로 변경하고 &display=swap 속성을 명시적으로 적용하여 폰트가 다운로드되기 전이라도 기본 텍스트가 먼저 구글 봇에게 노출되도록 최적화. 3. Unsplash 고해상도 이미지 과부하 현재 상태: 파일에 정의된 이미지 주소를 보면 w=2000, w=1600 등 4K 모니터급 고해상도를 원본(JPEG) 형태로 불러오고 있음. 문제점: 이미지 한 장이 수 MB에 달해 로딩이 매우 느려지고, 구글 봇의 크롤링 예산(시간)을 갉아먹고 있음. 대응 방안: Unsplash URL 파라미터에 fm=webp를 추가하여 용량이 획기적으로 적은 WebP 포맷으로 변환해서 가져오게 하고 w=2000 같은 해상도를 w=1200 이하로 줄임. 마지막으로 화면 아래쪽에 있는 이미지 태그(<img>)들에는 loading="lazy" 속성을 달아주어, 사용자가 스크롤을 내릴 때만 로딩되도록 하여 첫 페이지 로딩 속도를 극대화합니다. 결국 빠르게 진행하기 위해 구글 AI 스튜디오의 'build'를 통해 빠르게 홈페이지를 바이브코딩하고 여기에 게시판을 붙혀서 백엔드까지 구축했음. "시각적으로는 예쁘지만, 구글 봇이 읽기에는 너무 무겁고 불친절한 구조"로 되어 있었음. 이는 바이브코딩의 한계가 아닌 내 자신의 능력부족이 더 정확한 표현일듯 함.

Read Story
구글 애널리틱스(GA4)와 자체 AnalyticsTracker 차이와 시사점
Tech4/21/2026

구글 애널리틱스(GA4)와 자체 AnalyticsTracker 차이와 시사점

현재 네모네AIM 시스템 내부적으로 구축된 자체 애널리틱스(AnalyticsTracker)와 구글 애널리틱스(GA4)의 데이터가 차이 나는 이유를 알아보았는데 이는 측정하는 '기준'과 '원리'가 근본적으로 다르기 때문이라고. 🔍 네모네 자체 통계 측정 원리 1. 5초 체류(Delay) 규칙 (가장 큰 차이점) 원리: 사용자가 페이지에 접속하자마자 방문자 수나 조회수를 올리지 않습니다. 정확히 5초 이상 머물렀을 때만 백엔드 API를 호출하여 카운트를 +1 한다. (코드 내 주석: '광고가 충분히 로드된 후 조용히 통계를 기록'하기 위한 목적) GA와의 차이: 구글 애널리틱스는 접속하자마자(0초) 즉시 페이지 뷰(PV)를 발생시킵니다. 즉, 들어왔다가 1~4초 만에 바로 나간 사람(이탈자, Bounce)은 구글에는 잡히지만 네모네 통계에는 잡히지 않는다. 2. 탭(Tab) 단위의 방문자 집계 (`sessionStorage`) 원리: 방문자 중복 카운트를 막기 위해 브라우저의 sessionStorage를 사용하고 있다. 네모네: sessionStorage는 '브라우저 탭(Tab)' 기준임. 같은 사람이 크롬에서 탭을 2개 띄워서 네모네에 접속하면 방문자가 2명으로 찍힙니다. 탭을 닫았다가 다시 열어도 새로운 방문자로 인식합니다. 구글(GA): 쿠키(Cookie)와 기기 지문을 기반으로 판단하므로, 탭을 여러 개 띄우거나 브라우저를 껐다 켜도 (기본 30분 이내라면) 1명(동일 세션)으로 정확히 묶어냅니다. 3. 광고 차단 프로그램 (Ad Blockers) 무시 원리: 네모네 통계는 내 서버(API)로 직접 요청(/api/analytics/log-visit)을 보냅니다. GA와의 차이: 요즘 아이폰(Safari)이나 광고 차단 프로그램(uBlock 등)을 쓰는 사용자는 구글 애널리틱스 추적 코드를 강제로 차단해 버립니다. 이 경우 구글 통계에서는 누락되지만, 네모네 자체 통계는 우리 서버로 보내는 정상 요청이므로 차단되지 않고 모두 집계됩니다. 📊 데이터가 어떻게 다르게 나타날까? 네모네 통계가 더 높게 나올 때: 사람들이 5초 이상 머무는 '진성 유저' 비율이 높고, 이들 중 광고 차단기(애드블록)를 쓰는 사람이 많거나, 모바일에서 창을 닫았다 열었다를 반복하는 경우. 구글(GA) 통계가 더 높게 나올 때: 페이스북이나 인스타그램 링크를 통해 들어왔다가 글을 안 읽고 1~2초 만에 뒤로 가기를 눌러 나가는(이탈) 트래픽이 많을 때. 💡 권장 방향현재 네모네의 자체 통계 방식(5초 체류 후 카운트)은 '허수(Bot이나 1초 이탈자)를 걸러내고 진짜로 우리 글에 관심을 갖고 읽은 유의미한 수치(Engagement)'를 보여준다는 점에서 목적을 분리해서 모니터링하는 것이 맞을 수 있겠다. 따라서 두 데이터가 다른 것은 오류는 아닌듯. 구글 애널리틱스: 외부 마케팅 유입량 측정용 (얼마나 많이 들어왔는가) 네모네 어드민 통계: 실제 콘텐츠 소비량 측정용 (얼마나 진득하게 읽었는가)

Read Story
Google Search Console : 페이지 색인이 생성되지 않는 이유와 해결 정리
Tech4/17/2026

Google Search Console : 페이지 색인이 생성되지 않는 이유와 해결 정리

구글 서치 엔진 데이터를 체크하다가 현재 우리 페이지가 색인이 되고 있지 않다는 문구를 발견!(아니, 이런건 노티를 주거나 눈에 잘 뛰게 해야지. 구석에 숨겨져 있었다)구글 검색에서 색인이 잘 안 되는 핵심 원인을 명확하지 않게 그냥 '자세히 보기' 페이지 링크만 있어서 해당 내용을 차근차근 살펴보았다. 🔍 원인 분석: "모든 페이지가 자신이 메인 페이지라고 우기고 있었다!" 프론트엔드 소스코드를 확인해 보니, .../layout.tsx 파일에 다음과 같은 코드가 들어있었다.  1 export const metadata: Metadata = {  2  // ... 생략  3  alternates: {  4   canonical: '/', // <-- 바로 이 부분!  5  },  6 };  * 표준 URL(Canonical URL)이란? "이 페이지의 원본 진짜 주소는 여기야!"라고 구글에게 알려주는 명찰.  * 현재 상황의 문제점: 이 코드가 전체 레이아웃 파일(layout.tsx)에 박혀 있다 보니, 메인 페이지뿐만 아니라 상세 기사 페이지(`/posts/123`), 카테고리 페이지(`/category/taste`) 등 사이트의 모든 페이지가 구글에게 "내 진짜 원본 주소는 메인 페이지(`/`)야!"라고 잘못된 명찰을 보여주고 있는 상태 파악 🤖 구글 봇의 반응 (에러의 의미) 구글 로봇이 기사 페이지(/posts/123)에 들어옵니다.  1. 구글 봇: "오, 새로운 기사네. 원본 주소가 어딘지 볼까?"  2. 코드(사용자 선언): "제 원본은 메인 페이지(/)입니다!"  3. 구글 봇: "어라? 메인 페이지랑 이 기사랑 내용이 완전 다른데? 네가 단 명찰(표준 URL: /)은 가짜구나. 내가 알아서 이 페이지 주소(/posts/123)를 원본으로 취급할게." 이 과정에서 발생하는 에러가 바로 올려주신 "중복 페이지, Google에서 사용자와 다른 표준 URL을 선택함" 입니다. 🚨 SEO(검색엔진 최적화)에 미치는 악영향구글은 웹사이트가 스스로 엉뚱한 표준 URL을 제시하면, 해당 사이트의 SEO 구조가 망가져 있다고 판단하여 색인(인덱싱) 순위를 뒤로 미루거나 크롤링을 게을리하게 됩니다. 즉, 아무리 좋은 글을 써도 구글 검색에 잘 노출되지 않게 된다고. 🛠 해결 방법"각 페이지가 자기 자신의 정확한 주소를 표준 URL로 가지도록 (동적으로) 수정"해야 합니다.  전역 레이아웃(layout.tsx)에 고정된 canonical 설정을 지우거나 동적으로 변경.  상세 페이지(posts/[id]/page.tsx) 등에서 generateMetadata 함수를 통해 정확한 자기 자신의 URL을 지정.근데 구글이 명확하게 무엇이 문제인지를 알려주지를 않아 가이드페이지를 더 살펴보니 이런 내용도 있었다.<사용자가 선택한 표준이 없는 중복 페이지>이 페이지는 기본 표준 페이지를 나타내지는 않지만 다른 페이지와 중복됩니다. Google에서 다른 페이지를 이 페이지의 표준으로 선택했기 때문에 이 페이지는 Google 검색에 게재되지 않습니다. 이 URL을 검사하여 Google에서 이 페이지의 표준으로 간주하는 URL을 확인할 수 있습니다.이는 오류가 아니며 Google에서 중복 페이지를 게재하지 않기 때문에 정상적으로 작동하는 것입니다. 하지만 Google에서 잘못된 URL을 표준 URL로 선택했다고 생각되면 이 페이지의 표준 URL을 명시적으로 표시할 수 있습니다. 또는 이 페이지가 Google에서 선택한 표준 페이지와 중복되지 않는다고 생각되면 두 페이지의 콘텐츠가 크게 달라지지 않도록 해야 합니다. 💡 이 메시지의 의미구글 봇: "이 페이지를 확인해 보니 다른 페이지랑 내용이 비슷하거나, 시스템상 중복으로 보이네? 그런데 주인이 '이게 진짜 원본 주소야!'라고 명찰(표준 URL, Canonical)을 안 달아놨네? 그래서 내가 임의로 다른 페이지를 원본으로 치고, 이건 중복이니까 검색 결과에서 뺄게." ✅ 왜 발생했고, 어떻게 해결되었나?  * 과거 상태: 이전에 우리 서비스의 많은 페이지들(기사 상세 등)에는 정확한 자기 자신의 주소를 가리키는 canonical 태그가 누락되어 있거나, 무조건 메인 페이지(/)를 가리키고 있었다.  * 해결 상태: 제가 방금 모든 상세 페이지(posts/[id]), 카테고리, 스페셜 페이지마다 "나의 진짜 주소는 바로 여기야! (`https://nemoneai.com/posts/123`)" 라고 명시적으로 선언하는 코드를 삽입. 🚀 결론 구글 서치 콘솔의 안내문 마지막에 있는 "Google에서 잘못된 URL을 표준 URL로 선택했다고 생각되면 이 페이지의 표준 URL을 명시적으로 표시할 수 있습니다" 라는 권고사항을 방금 수정한 코드로 동시에 해결!우리 서비스는 검색유입이 중요한 부분이라 색인에 대해 계속 공부할 수 밖에 없을 것 같네요!

Read Story
🛠️ [지금여기 / NOW HERE] Full-Stack Technical Specification
Tech3/20/2026

🛠️ [지금여기 / NOW HERE] Full-Stack Technical Specification

이 프로젝트[지금여기 / NOW HERE]는 Google 에코시스템을 중심으로 하이퍼-로컬 데이터와 AI를 결합한 전형적인 Modern RAG(Retrieval-Augmented Generation) 아키텍처를 따르고 있습니다.[지금여기 / NOW HERE] 바로가기 🛠️ [지금여기 / NOW HERE] Full-Stack Technical Specification 1. Frontend (User Experience)Framework: Next.js 14+ (App Router) - 서버 사이드 렌더링(SSR)과 클라이언트 사이드 렌더링(CSR)을 하이브리드로 운용하여 SEO와 실시간성을 모두 확보.Deployment Mode: Standalone Mode - 프로덕션 환경에서 용량을 최소화하고 실행 속도를 극대화한 최적화 빌드 방식. Styling: Tailwind CSS - 유틸리티 퍼스트 프레임워크를 사용하여 고속 UI 개발 및 유지보수 효율 증대. Animation: Framer Motion - 탭 전환, 모달 팝업 등 네이티브 앱 수준의 매끄러운 UX 제공. Auth: NextAuth.js (Google Provider) - 안전한 구글 소셜 로그인 및 세션 관리.  cons: Lucide React - 가볍고 일관된 벡터 아이콘 라이브러리. 2. Backend (Core Logic)Framework: Python 3.10+ FastAPI - 비동기(Asynchronous) 처리에 특화된 초고속 웹 프레임워크.Task Scheduler: APScheduler - 매일 자정 30일 경과 데이터를 자동 삭제(TTL)하는 백그라운드 워커.ORM: SQLAlchemy - 파이썬 객체 지향 방식의 데이터베이스 모델링 및 쿼리 최적화.Server: Uvicorn - 고성능 ASGI 서버를 통해 PM2 기반의 멀티 프로세스 운용. 3. AI & Data (Intelligence)Reasoning: Google Gemini 1.5 Flash - 동선 설계(Itinerary), 자동 영문 번역, 실시간 질문 답변(Chat)을 수행하는 고속 추론 모델.Vectorizing: Vertex AI Text-Embedding-004 - 다국어 대응이 가능한 고차원 벡터 임베딩 모델을 사용하여 검색 정확도 극대화.RAG Engine: 사용자 질문과 가장 유사한 로컬 데이터를 벡터 검색하여 AI에게 컨텍스트로 제공하는 지능형 가이드 로직. 4. Database (Storage)RDBMS: PostgreSQL 15+ - 대규모 데이터 처리에 안정적인 오픈소스 데이터베이스.Vector Search: pgvector - PostgreSQL 확장을 통해 고차원 임베딩 벡터 간의 코사인 유사도 검색을 DB 엔진 레벨에서 수행. 5. Infrastructure & DevOps (Deployment)OS/VM: GCP (Google Cloud Platform) VM Instance.Web Server: Nginx (Reverse Proxy) - 포트를 /api-now/ 경로로 통합 라우팅 및 SSL(HTTPS) 처리.Process Manager: PM2 - 무중단 서비스 운영 및 환경 변수 기반의 프로세스 생명주기 관리.Protocol: SSH Tunneling - 로컬 개발 환경과 리모트 DB 간의 보안 연결. 6. Global SEO (Market Strategy)Standard: Schema.org JSON-LD (Event) - 구글 검색 결과에 행사 날짜, 장소, 이미지가 노출되는 리치 스니펫 적용.Localization: Hreflang / Metadata Alternates - 한국어(ko)와 영어(en)에 최적화된 메타태그 및 언어별 경로 최적화. 요약하자면: "지금여기"는 Next.js의 강력한 UI와 FastAPI의 빠른 데이터 처리, 그리고 Google Gemini의 지능형 동선 설계를 PostgreSQL/pgvector 위에 안착시킨 최첨단 하이퍼-로컬 AI 서비스입니다.

Read Story
NEMOneAI에 대한 기술 스택 정리 (광고 제외)_ 2026. 3. 2 현재
Tech3/2/2026

NEMOneAI에 대한 기술 스택 정리 (광고 제외)_ 2026. 3. 2 현재

1. Frontend  * Framework: Next.js 14.2.3 (App Router)  * Language: TypeScript  * Styling: Tailwind CSS (Glassmorphism & Dark Theme 적용)  * Icons: Lucide React  * Rendering: SSG(Static Site Generation), ISR(Incremental Static Regeneration)  * Key Logic:    * generateStaticParams를 통한 상세 페이지 정적 빌드    * URL 기반 자동 썸네일 추출 시스템    * dangerouslySetInnerHTML을 통한 에디터 콘텐츠 렌더링 2. Backend  * Framework: Python FastAPI  * ORM: SQLAlchemy  * Database: PostgreSQL  * Dependencies: uvicorn, python-multipart (파일 업로드), psycopg2-binary  * Key Logic:    * 카테고리별 필터링 기능 (Query Parameter 기반)    * UUID 기반 이미지 파일 저장 및 정적 서빙    * CRUD API (GET, POST, PUT, DELETE) 3. Admin  * Framework: Next.js 14.2.3 (App Router)  * Authentication: NextAuth.js (Google OAuth 2.0)  * Editor: ReactQuill (Rich Text Editor 적용)  * Key Logic:    * 이미지 파일 업로드 및 게시물 수정(PUT) 로직    * Next.js Standalone 배포 방식 적용 4. Infrastructure & DevOps  * OS: Linux (Server), Darwin (Local - macOS)  * Web Server: Nginx (Reverse Proxy & HTTPS Certbot)  * Process Manager: PM2 (frontend, backend, admin 관리)  * Deployment Strategy:    * 로컬 빌드 후 서버 전송: 서버 자원 보호를 위한 Standalone 빌드 방식    * rsync/scp: 무결성 확보를 위한 메타데이터 제외 전송 (--no-xattrs)  * Network: 내부망 통신 및 API Proxy 구축 5. Design Specification (Brand Identity)  * Font: Noto Serif KR (font-serif), Italic 스타일 고정  * Theme Color: #0c0c0c (Pure Black), #D4AF37 (Gold)  * Key Component: 3단 독립 섹션(Article, Ad, Footer), Drop Cap 스타일 적용

Read Story
[구글 애드센스 적용 실패기] 구글은 답변하기 바란다
Tech3/1/2026

[구글 애드센스 적용 실패기] 구글은 답변하기 바란다

지난 2월 9일 애드센스 신청을 하고 한 달 가까이 지나고 있는 지금 여전히 그들의 승인은 나고 있지 않다. 이 실패담을 공유하고자 글을 쓴다.1차 실패 : 애드센스를 붙이고 시작하는 것이 아니였다.나는 그렇게 생각했다. 나의 소중한 컨텐츠와 데이터를 가치있게 보여줄 수 있는 방법은 무엇일까. 지금까지 수많은 창작물을 제작하고 그것을 다른 플랫폼에 게재하면서 언젠가부터 이런 생각이 들었다.'내가 지금 누구 좋은 일을 시키고 있나'지금까지 블로그, 브런치, 팟캐스트, 유튜브에 분산되어 있는 나의 창작물을 한 곳으로 모은다면? 나의 브랜드를 구축하여 나의 오리지널 창작의 전초 기지를 구축할 수 있다면 좋겠다는 생각을 하게 되었다.그래서 난 모든 창작활동을 중단하고 이 사이트를 구축하기로 했다. AI의 기술을 이용하여 지난 한 달에 걸쳐 기본적인 CMS(Contents Management System)을 구축했고 나의 모든 컨텐츠를 모우고 이제 이곳을 나의 베이스캠프로 삼을려고 했다,적절한 나의 컨텐츠 가치를 인정받고 싶었고 그것의 구현은 바로 '구글 애드센스'라고 생각했다. 나는 바로 구글 애드센스에 가입해서 '코드'를 받아 광고 공간을 마련하여 그 코드를 넣고 광고 승인이 나기를 기다렸다.<애드센스 프로세스>회원 가입 : 구글 아이디로 가입하고 자신의 사이트 url을 알려줘야 한다.주인 인증 : 해당 사이트가 내가 주인인지 인증하는 건 당연하다. 구글은 나에게 2가지를 제시하며 하나를 선택하라고 했다. 하나는 메인페이지 상단에 코드를 입력하거나 다른 하나는 특정 디렉토리에 코드가 들어가 파일을 위치시키라고 했다.최종 승인 : 이렇게 하고 기다리면 최종 승인이 나온다고 했다.구글의 승인은 아무리 기다려도 나오지 않았다. 아니 몇 일 뒤에 간단한 코멘트가 왔는데. 나의 페이지 구조상 '검색 색인'이 중복되고 있다는 내용이었다. 나는 아직 정식 서비스는 아니고 승인이 나오면 그런 것을 정리할 생각이었는데. AI에게 물어뵈도 크게 중요한 것이 아니고 수정하면 되다는 답변이었는데. 일단 나는 다시 알겠다고 다시 검증 요청을 보냈다.승인에 2주~4주정도가 걸린다고 했는데. 2주가 지나도 감감무소식이었다.일단 지적받았던 검색 색인의 중복 문제는 페이지에 메타 테크를 생성하는 함수를 넣으면서 해결한 듯 했다. 그럼에도 2주가 지나도 소식이 없어 다시 AI에게 현재 상황을 물어봤는데. 어이가 없게도 내가 '광고 태크'를 페이지에 넣은 것이 문제라는 것이다.나는 광고가 노출되야 비로소 신규 컨텐츠를 입력할 생각이었는데 오히려 구글에서는 완전한 페이지, 정상적인 사이트, 어느 정도의 트래픽을 동반한 사이트에 광고를 승인한다는 것이다.이걸 미리 알았다면 그리 하였을텐데. 왜 그것을 지금 알려주는지 그를 원망했던 것 같다. 나는 부랴부랴 광고 태그를 다 삭제하고 정상적으로 운영되는 모습을 보여줘야겠다고 생각했다. 다행히 검색 색인을 페이지마다 정성스럽게 넣었더니 구글이나 네이버에서 검색 결과는 잘 노출이 되는 듯 했다.2차 실패 : 내 컨텐츠라도 다시 게재하면 안된다.3주 정도가 지난 금요일 저녁에 리젝트 메일이 왔다. 4가지씩이나 되는 거절 사유와 함께. 아마도 담당자는 금요일 퇴근하며 그런 메일을 나에게 보낸 듯 하다. 연휴기간 나의 마음을 타들어 가는데. 거절 사유는 이랬다.'내 컨텐츠가 어디서 퍼온 걸로 서비스하면 안된다는 것이다. 구글은 '원소스멀티유즈'도 모르나? 내가 다양하게 제작했던 유튜ㅂ, 블로그, 팟캐스트를 이제 이곳을 베이스캠프로 일단 불러와서 텍스트/영상/음성으로 다각적으로 보여주는 플랫폼을 추구했고 이제 이곳을 메인 플랫폼으로 다른 플랫폼을 홍보 네트워드로 트래픽을 끌고 오려는 내 전략은 엉망징창이 된 듯 하다.일단 나는 페이지에 임베디드 시킨 타 플랫폼에 있는 나의 컨텐츠 페이지를 삭제했다. 결국 이 플랫폼은 음성과 영상 지원이 어렵기에 텍스트 위주로 운영을 해야할 것 같다. 물론 타 플랫폼에 있는 나의 컨텐츠의 저작권이 나한테 있는지 구글 담당자가 인지하기 힘들다는 점은 인정한다.그렇다면 이런 경우 본인 컨텐츠의 재편집을 통한 게재의 경우는 왜 유독 구글에서만 문제를 삼는 것인지? 현재 브런치와 네이버 블로그도 함께 운영중이고 장기적으로 그쪽을 페이드아웃 시킬 전략이 있는 플랫폼에 구글 애드센스 도입을 계속 거절할 요양이라면 다른 수준 낮은 페이지에 잘도 떠 있는 구글 광고들은 어떻게 설명할지 궁금한다.이렇게 내가 글을 쓰는 이유도 나 같은 바보 같은 시간 낭비를 하지 말았으면 하는 생각과 이 플랫폼이 타 사이트의 글을 복사해 오는 그런 곳이 아닌 곳임을 증명하기 위해서.구글은 이런 현실에 대해 잘 설명해줬으면 한다. 현재 구글 애드센스에 이런 문의나 설명을 듣는 아무런 창구도 없어 보인다. 단지, 그들의 지적에 대해 재검증을 요청할 단 하나의 '버튼'만이 존재할 뿐이다.

Read Story