공간적 기억(Spatial Memory) 구축하기: 왜 '물리적 세계를 위한 Pinterest'를 만들었으며 무엇을 배웠는가
요약
특정 GPS 좌표에 사진, 텍스트 등 기억을 고정하는 '공간적 기억 네트워크' 구축 경험과 기술 스택을 공유합니다. 근접성 기반의 콘텐츠 잠금 해제 메커니즘과 이를 구현하기 위한 PostGIS 활용법을 다룹니다.
핵심 포인트
- GPS 좌표 기반의 위치 기반 타임캡슐 개념 구현
- 근접성(Proximity)을 핵심으로 하는 콘텐츠 접근 제어
- PostGIS를 활용한 효율적인 공간 인덱싱 및 근접성 쿼리
- R-tree 기반의 공간 데이터 처리 및 PostgreSQL 활용
공간적 기억(Spatial Memory) 구축하기: 왜 '물리적 세계를 위한 Pinterest'를 만들었으며 무엇을 배웠는가
솔직히 말해서, 이 아이디어는 수년 동안 제 머릿속 한구석에 있었습니다.
만약 사람들이 당신이 서 있던 바로 그 장소에 물리적으로 서 있을 때만 찾을 수 있는 메모, 사진, 이야기를 남길 수 있다면 어떨까요? 디지털 지오캐싱(Geocaching)과 비슷하지만, 더 사회적이고 더 개인적인 형태입니다. 기억이 실제 세계에 닻을 내리는 '공간적 기억 네트워크(spatial memory network)' 말이죠.
저는 마침내 3개월간의 밤샘 작업 끝에 이를 구축했고, 오늘 제가 무엇을 배웠는지, 무엇이 잘못되었는지, 그리고 다시 시작한다면 무엇을 다르게 할 것인지 공유하고자 합니다.
궁금하시다면, 코드는 여기 오픈 소스로 공개되어 있습니다: https://github.com/kevinten10/spatial-memory
사라지지 않는 아이디어
작년에 하이킹을 하던 중, 정말 멋진 전망대에서 멈춰 서서 이런 생각을 했습니다. "내가 여기에 오기 전에 다른 사람들이 이 장소에 대해 어떻게 생각했는지 읽을 수 있다면 좋을 텐데. 그리고 다음 사람을 위해 무언가를 남길 수 있다면 좋을 텐데."
대부분의 사진 앱은 지오태깅(geotag)을 허용하지만, 그것은 이와 다릅니다. 모든 것은 여전히 당신의 피드에 있으며, 누구나 어디서든 발견할 수 있습니다. 마법은 바로 '근접성(proximity)'에 있습니다. 사람들이 이곳에 남긴 것을 잠금 해제하려면 반드시 이곳에 있어야 합니다.
그래서 핵심 개념은 다음과 같습니다:
- GPS 좌표에 기억(사진, 비디오, 텍스트, 음성)을 고정(Pin)
- 약 50미터 이내에 있는 사람들만이 실제 전체 콘텐츠를 볼 수 있음
- 단계적 개인정보 보호: 비공개(Private) → 친구 공개(Friends-only) → 공개(Public)
- 인류가 공동으로 채워나가는 '위치 기반 타임캡슐(location-based time capsules)'이라고 생각하면 됩니다.
충분히 간단해 보였습니다. 스포일러를 하자면, 그렇게 간단하지 않았습니다.
제가 최종적으로 선택한 기술 스택 (Tech Stack)
공간 앱(spatial apps)에는 일반적인 백엔드 프로젝트에는 없는 *특화된 도구(specialized tooling)*가 필요합니다. 제가 무엇을 선택했고 왜 그랬는지 설명해 드리겠습니다.
1. 데이터베이스: PostgreSQL + PostGIS는 고민할 여지도 없었습니다
근접성 검색("내 주변 50미터 이내의 모든 기억 찾기")이 필요하다면 공간 인덱스(Spatial Index)가 필요합니다. 물론 위도/경도(lat/lng)를 부동 소수점(float)으로 저장하고 애플리케이션 코드에서 하버사인(Haversine) 계산을 수행할 수도 있겠지만, 어떤 규모에서든 그것은 무모한 일입니다.
PostGIS는 다음과 같은 기능을 제공합니다:
- R-tree를 이용한 공간 인덱싱 (Spatial indexing)
- 내장된 거리 계산 기능
- 즉시 사용 가능한 근접성 쿼리 (Proximity queries)
- 그냥 PostgreSQL입니다 — 여러분은 이미 이를 알고 있습니다
테이블 구조는 다음과 같습니다:
CREATE TABLE public_memories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
location GEOGRAPHY(POINT, 4326) NOT NULL,
...
그리고 Go에서 실제로 근접성 쿼리를 수행하는 방법은 다음과 같습니다:
package repository
import (
...
끝입니다. 이것이 여러분의 근접성 검색 전부입니다. PostGIS가 모든 힘든 작업을 대신 처리합니다.
2. 캐싱(Caching): 핫 존(Hot Zones)을 위한 Redis GEO
제가 예상하지 못했던 문제가 하나 있었습니다. 인기 있는 관광지는 항상 근접성 쿼리가 쏟아진다는 점입니다. 2초마다 동일한 쿼리로 PostGIS를 호출하고 싶지는 않을 것입니다.
Redis는 3.2 버전부터 네이티브 GEO 명령어를 내장해 왔습니다. 저는 인기 지역의 기억 ID(memory IDs)를 캐싱하는 데 이를 사용합니다:
package cache
import (
...
전문가 팁: Redis에 전체 기억 객체를 캐싱하지 말고, ID만 캐싱하세요. 실제 데이터는 여전히 PostgreSQL에서 가져옵니다. 이렇게 하면 Redis의 메모리 사용량을 최소한으로 유지하면서도 쿼리 시간을 약 20ms에서 약 2ms로 단축할 수 있습니다.
3. 객체 스토리지(Object Storage): Cloudflare R2가 탁월한 선택이었습니다
사용자의 사진과 동영상을 업로드할 때, 만약 백엔드 API를 통해 프록시(proxy) 방식으로 전달한다면 서버는 즉시 과부하로 무너질 것입니다.
저는 2단계 업로드 패턴(two-phase upload pattern)을 채택했습니다:
- 클라이언트가 서버에 사전 서명된 URL(pre-signed URL)을 요청합니다.
- 서버가 서명하여 직접 R2에 업로드할 수 있는 URL을 반환합니다.
- 클라이언트가 R2로 직접 업로드합니다 (여러분의 API에는 절대 닿지 않습니다).
- 클라이언트가 서버에 업로드가 완료되었음을 확인합니다.
Go에서 S3 호환 API를 사용하여 이를 구현하는 방법은 다음과 같습니다:
package storage
import (
...
왜 S3 대신 R2인가요? 데이터 전송 비용(egress fees)이 없기 때문입니다. 그게 전부입니다. 사용자가 미디어를 업로드하는 앱의 경우, 데이터 전송 비용은 수익을 모두 갉아먹을 수 있습니다. R2는 데이터 전송 비용이 0이며 S3 호환성을 제공합니다. 양쪽 모두에게 이득(Win-win)입니다.
4. AI Moderation: 이미지 콘텐츠를 위한 GLM-4V
사용자가 이미지를 업로드하는 공개 앱이기 때문에, Moderation(중재/검열)이 반드시 필요합니다. 저는 ZhipuAI의 GLM-4V를 선택했는데, 이 사용 사례에 있어 저렴하면서도 충분히 성능이 좋기 때문입니다.
제가 사용하는 프롬프트(prompt)는 간단합니다:
prompt := `
이미지에 부적절한 콘텐츠가 포함되어 있는지 확인해 주세요:
- 불법 활동
...
지금까지 제가 테스트한 부적절한 콘텐츠의 98%를 잡아냈습니다. 완벽하냐고요? 아닙니다. 하지만 사이드 프로젝트로 쓰기에는 충분합니다.
예상치 못한 어려운 부분들
솔직히 말씀드리면, 위치 기반 앱을 구축할 때 얼마나 많은 기이한 엣지 케이스(edge cases)를 마주하게 될지 과소평가했습니다.
1. 좌표 정밀도(Coordinate Precision)의 까다로움
GPS 좌표는 소수점 10자리 이상까지 정확할 수 있지만, 과연 그 정도의 정밀도가 정말 필요할까요? 확인 결과는 다음과 같습니다:
- 소수점 6자리 ≈ 약 10cm 정밀도
- 소수점 5자리 ≈ 약 1m
- 소수점 4자리 ≈ 약 10m
저는 PostGIS에 전체 배정밀도(double-precision)를 저장하지만(그냥 작동하니까요), Redis에 캐싱할 때는 소수점 6자리로 반올림합니다. 실제로 사용할 수 없는 정밀도를 위해 공간을 낭비할 필요는 없으니까요.
2. 생각보다 복잡한 개인정보 보호(Privacy)
GPS 좌표에 기억을 핀(pin)으로 고정하는 것은 물리적 장소에 대한 데이터입니다. 사람들이 자신의 집에 기억을 핀으로 고정하기 시작하면 주의해야 합니다. 그래서 세 가지 가시성(visibility) 수준을 추가했습니다:
- Private (비공개): 본인만 볼 수 있음
- Circle (서클): 서클 내의 친구들만 볼 수 있음
- Public (공개): 50미터 이내의 누구나 볼 수 있음
단계적 가시성(Progressive visibility)은 대부분의 개인정보 문제를 해결합니다. 사람들은 자신이 얼마나 노출될지를 선택할 수 있습니다.
3. 모바일 앱 인증(Authentication)의 번거로움
중국 시장을 위해 SMS 로그인과 WeChat OAuth를 모두 지원하고 싶었습니다. 이는 여러 인증 방식을 처리해야 함을 의미합니다. 결국 저는 두 방식 모두를 지원하는 JWT 토큰을 사용하는 것으로 결론을 내렸습니다:
package auth
import (
...
엄청난 기술적 난제는 아니지만, 이것들이 모여 큰 차이를 만듭니다. 모바일 앱은 매끄러운 인증 (auth)을 기대하며, 제3자 OAuth는 항상 예상치 못한 변수를 만들어냅니다.
장단점: 솔직한 리뷰
저는 고생하며 배웠으니, 여러분의 시간을 아껴드리겠습니다. 이 접근 방식의 좋은 점과 그렇지 않은 점은 다음과 같습니다.
✅ 장점
-
PostGIS + Redis GEO는 환상적인 조합입니다 — 실제로 빠른 공간 쿼리 (spatial queries)를 얻을 수 있으며, 두 가지 모두 여러분이 이미 알고 있을 법한 성숙한 도구들입니다. 이상한 특수 데이터베이스를 사용할 필요가 없습니다.
-
Direct-to-R2 업로드는 엄청난 확장성을 가집니다 — 제 백엔드 (backend)가 실제 파일 바이트를 전혀 건드리지 않기 때문에 100배 더 많은 트래픽을 처리할 수 있습니다. 이 패턴은 과소평가되어 있습니다.
-
Go + Gin은 이 작업에 완벽합니다 — 단일 바이너리로 컴파일되며, 메모리 사용량이 적고, HTTP 응답이 빠릅니다. 백엔드 API (backend API)에 필요한 모든 것을 갖추고 있습니다.
-
점진적 가시성 (Progressive visibility)은 개인정보 보호 문제를 해결합니다 — 사용자는 제어권을 갖고, 개발자는 규제 준수 (compliance)에 대한 고민을 덜 수 있습니다. 모두에게 이득입니다.
-
오픈 소스 스택은 벤더 종속성 (vendor lock-in)이 없습니다 — 모든 구성 요소를 자체 호스팅 (self-hostable)할 수 있습니다. 한 달에 몇 달러면 본인의 VPS에서 이 시스템을 실행할 수 있습니다.
❌ 단점
-
GPS 정확도는 여전히 일관적이지 않습니다 — 빌딩 숲 (Urban canyons)은 GPS를 방해합니다. 때때로 사용자는 메모리를 잠금 해제하기 위해 원래 있어야 할 위치에서 10미터 정도 떨어져서 걸어가야 할 수도 있습니다. 이에 대해 할 수 있는 일은 많지 않습니다.
-
콜드 스타트 (Cold start) 문제는 실재합니다 — 충분히 많은 장소에 충분한 메모리가 쌓이기 전까지 앱은 무용지물입니다. 닭이 먼저냐 달걀이 먼저냐의 문제입니다. 실제로 사용하기 즐거워지려면 임계 질량 (critical mass)이 필요합니다.
-
모더레이션 (Moderation)은 결코 "끝나지" 않습니다 — AI를 사용하더라도 예외적인 사례(edge cases)를 위해서는 여전히 사람의 검토가 필요합니다. 이것은 한 번 설정하면 끝나는 기능이 아니라 지속적인 작업입니다.
-
모바일 클라이언트가 싸움의 절반입니다 — 저는 백엔드를 구축했지만, 위치를 실제로 안정적으로 찾아내는 훌륭한 모바일 AR 경험을 구축하는 것은 백엔드보다 훨씬 더 많은 작업이 필요합니다. 만약 이 프로젝트를 포크 (fork)할 생각이라면, 마음의 준비를 하세요.
다시 한다면?
물론입니다. 이것은 제가 수년간 느껴온 갈증을 해소하기 위한 사이드 프로젝트 (side project)입니다. 제품-시장 적합성 (product-market fit)이 있느냐고요? 솔직히 모르겠습니다. 이 아이디어를 들려준 대부분의 사람들은 멋지다고 생각하지만, 그것이 그들이 실제로 매일 사용할 것이라는 의미는 아닙니다.
하지만 괜찮습니다. 사이드 프로젝트란 원래 그런 것이니까요. 저는 이전까지 실무에서 제대로 사용해 본 적이 없었던 공간 데이터베이스 (spatial databases)에 대해 엄청난 것을 배웠습니다. 그것만으로도 3개월간의 밤샘 작업은 가치가 있었습니다.
제가 얻은 가장 큰 교훈은 무엇일까요? 물리적 위치 (physical location)는 소셜 앱 (social apps)에서 과소평가된 차원이라는 점입니다. 지금은 모든 것이 피드 (feed) 안에 있고, 모든 것이 전 지구적입니다. 디지털 콘텐츠를 실제 장소와 연결하는 것에는 마법 같은 무언가가 있습니다. 그것은 세상을 층층이 쌓인 구조로, 이야기가 풍부하고, 더 연결된 것처럼 느끼게 만듭니다.
저는 이미 제가 좋아하는 등산 코스와 커피숍에 기억들을 남겨두었습니다. 언젠가 누군가 그것을 우연히 발견하고 미소 지을 수 있기를 바랍니다. 그것이 이 프로젝트의 전부입니다.
여러분의 차례
위치 기반 (location-based)의 무언가를 만들어 본 적이 있나요? "물리적 장소에 디지털 콘텐츠를 핀 (pinning)한다"는 아이디어를 가져본 적이 있나요? 여행을 하거나 등산을 할 때 실제로 사용할 만한 것이라고 생각하시나요? 여러분의 생각이 진심으로 궁금합니다 — 아래에 댓글을 남겨주세요!
코드는 직접 플레이해 보거나 포크 (fork)할 수 있도록 모두 오픈 소스 (open source)로 공개되어 있습니다: https://github.com/kevinten10/spatial-memory
즐거운 빌딩 (building) 되시길 바랍니다 🗺️
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기