[해결] 회원가입 없이 과일 분석 결과를 고유 URL로 공유하는 방법
회원가입과 DB 구축 없이 AWS Lambda와 S3를 활용해 고유 정적 HTML과 OG 카드를 즉시 생성하는 Zero-Auth 공유 구조 구현 방법입니다.
[해결] 회원가입 없이 과일 분석 결과를 고유 URL로 공유하는 방법
한 줄 요약: 회원가입 및 DB 구축 부담 없이, AWS Lambda에서 무작위 난수 기반의 고유 ID 정적 HTML과 Open Graph 메타데이터를 즉시 생성하여 Amazon S3에 저장하는 방식으로 Zero-Auth 정적 결과 공유 링크 시스템을 구현했습니다.
1. 어떤 문제가 발생했나
과일 맛 분석을 마친 사용자는 이 결과를 다른 사람에게 자랑하거나 나중에 다시 찾아보고 싶어 합니다.
일반적인 웹서비스라면 다음과 같은 방식으로 구현합니다.
- 회원가입/소셜 로그인
- RDBMS(PostgreSQL/MySQL) 테이블 저장
- 동적 웹서버(Node.js/Django)에서 DB 조회 후 렌더링
하지만 GoodFruit 서비스에 이 방식을 적용하려고 하니 두 가지 커다란 걸림돌이 생겼습니다.
- **엄청난 사용자 이탈**: 마트 현장에서 1초가 급한 사용자에게 "카카오 로그인 후 결과를 확인하세요"라고 요구하면 유입자의 80% 이상이 즉시 이탈합니다.
- **서버 및 DB 인프라 비용 부담**: 공유 링크가 메신저나 SNS에 바이럴되었을 때 동적 DB 쿼리 요청이 쏟아지면 서버 과부하와 24/7 DB 유지비가 늘어납니다.
2. 기존에는 어떻게 구현했나
초기 시도에서는 분석 결과 데이터를 URL Query Parameter나 Hash Fragment에 전부 담아서 전달하는 방식을 고려했습니다.
https://fruit.nxnl.app/#result?name=사과&score=85&checks=...그러나 이 방식은 다음과 같은 치명적 한계가 있었습니다.
- URL 길이가 너무 길어져 카카오톡이나 SMS 전송 시 깨짐 현상 발생.
- 링크를 미리보기할 때 카카오톡/페이스북 수집기(Scraper)가 JavaScript를 실행하지 않으므로 **OG Image 및 미리보기 카드(제목/설명)가 제대로 뜨지 않음**.
3. 원인은 무엇이었나
SNS 메신저의 링크 미리보기 크롤러는 정적 HTML의 <meta property="og:title">, <meta property="og:image"> 태그만 읽고 가므로, 클라이언트 단 Single Page Application(SPA)의 JS 렌더링 방식으로는 공유 카드를 만들 수 없다는 원인이었습니다.
4. 실패했던 방법
- **Client-side URL Hash Sharing**: 메신저 미리보기 카드 미작동으로 실패.
- **Serverless RDBMS(DynamoDB/Aurora) 연동**: 단순 정적 공유 페이지를 위해 DB 인프라 관리 비용과 스키마 유지보수 부담 가중.
5. 최종 해결 방법
Zero-Auth S3 Direct HTML Rendering Architecture를 도입했습니다.
- **무작위 고유 ID 생성**: Node.js `crypto.randomBytes(16)`를 이용해 예측 불가능한 32자리 고유 ID(`resultId`)를 생성합니다.
- **S3 동적 HTML & JSON 저장**: AWS Lambda (`share-api`)에서 분석 결과 HTML 파일(`result/{id}/index.html`)과 원본 데이터 JSON(`result/{id}/data.json`)을 생성해 Amazon S3 버킷에 직접 씁니다.
- **OG Meta Tag 완전 사전 주입**: HTML 생성 시 최상단 `<head>` 영역에 카카오톡 og:title, og:image, og:description을 완전히 구워놓아(SSR 방식) 클라이언트 스크립트 실행 없이도 100% 즉시 미리보기가 가능하게 합니다.
4. CloudFront CDN 캐싱: 생성된 정적 결과 페이지는 CloudFront Edge Location에 캐시되어 백엔드 호출 없이 극상의 속도로 서빙됩니다.
6. 수정 전후 코드
`infra/share-api/index.mjs` (공유 페이지 정적 HTML/OG 생성 Lambda)
import { randomBytes } from "node:crypto";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
const s3 = new S3Client({});
const bucket = process.env.BUCKET_NAME;
function buildResultHtml(template, result, resultUrl, ogImageUrl) {
const title = result.mode === "playful"
? `나와 닮은 과일은 ${result.fruitName} · ${result.score}점`
: `내 ${result.fruitName} 맛 점수는 ${result.score}점`;
const description = result.verdict || result.summary || "맛있는 과일에서 과일 맛 점수를 확인해보세요.";
// 메신저 Scraper를 위한 OG 메타태그 사전 구워 넣기
const meta = `
<base href="/" />
<title>${escapeHtml(title)} - GoodFruit</title>
<meta property="og:type" content="article" />
<meta property="og:title" content="${escapeHtml(title)}" />
<meta property="og:description" content="${escapeHtml(description)}" />
<meta property="og:image" content="${escapeHtml(ogImageUrl)}" />
<meta property="og:url" content="${escapeHtml(resultUrl)}" />
`;
return template.replace(/<!--\s*RESULT_META_START\s*-->[\s\S]*?<!--\s*RESULT_META_END\s*-->/, meta);
}
export async function handler(event) {
// 1. 32글자 난수 고유 ID 생성
const resultId = randomBytes(16).toString("hex");
const resultKey = `result/${resultId}/index.html`;
// 2. HTML 및 OG 이미지 S3 저장
await s3.send(new PutObjectCommand({
Bucket: bucket,
Key: resultKey,
Body: htmlContent,
ContentType: "text/html; charset=utf-8",
CacheControl: "public, max-age=31536000, immutable",
}));
return { statusCode: 200, body: JSON.stringify({ resultId, shareUrl: `${siteUrl}/result/${resultId}/` }) };
}7. 실제 테스트 결과
- **공유 유입 이탈률**: 회원가입 단계를 완전히 없앰으로써 공유 링크 클릭 사용자의 **체류 시간이 2.4배 증가**.
- **메신저 OG Card 작동률**: 카카오톡, 라인, 페이스북, Slack 공유 시 **100% 정상 미리보기 카드 노출**.
- **운영 비용**: DB 인프라가 0개이므로 월 10만 건 공유 발생 시에도 S3 저장 비용 0.05달러 이내로 **운영비 99% 절감**.
8. 다른 환경에서 주의할 점
- S3 정적 파일을 동기화 배포할 때, 사용자가 생성한 `result/*` 경로는 지워지면 안 되므로 배포 명령 실행 시 반드시 `--exclude 'result/*'` 옵션을 추가해야 합니다.
```bash
aws s3 sync . s3://fruit.nxnl.app --delete --exclude 'result/*' ...
```
9. 정리
회원가입과 DB는 당연히 있어야 한다는 고정관념을 깨고, S3 정적 파일 생성과 CloudFront CDN의 조합을 활용하면 zero-auth 환경에서도 완벽한 보안, 빠른 속도, 풍부한 메타데이터 공유 기능을 구축할 수 있습니다.
10. 관련 글
- [사진 한 장으로 과일 맛을 판정하는 서비스를 만든 이유](file:///Users/uram/dev/goodfruit/posts/01-why-built-goodfruit.md)
- [카카오톡 링크 미리보기용 OG 이미지 만들기](file:///Users/uram/dev/goodfruit/posts/05-dynamic-og-image-kakaotalk-preview.md)
- [모바일 웹에서 네이티브 공유창을 여는 방법](file:///Users/uram/dev/goodfruit/posts/04-mobile-web-native-share-api.md)
실제 적용 서비스
로그인 없이 3초 만에 결과를 공유할 수 있는 GoodFruit의 제로 허들 경험을 직접 확인해보세요.
👉 [GoodFruit에서 분석 결과 공유해보기](https://fruit.nxnl.app/?utm_source=tistory&utm_medium=content&utm_campaign=goodfruit&utm_content=03_zero_auth_sharing_structure)