실험실

LuckyPicky

선행을 적으면 네잎클로버가 자라는 앱

화면


01
홈
01

선행 한 번에 잎이 하나씩 붙는다

선행 기록
02선행 기록

오늘 한 일을 한 줄로 적어 넣는다

03클로버 완성

네 장째를 채우면 클로버가 상단 배지로 날아간다

행운 뽑기
04행운 뽑기

코인 하나로 캡슐 머신을 돌린다

행운지수
05행운지수

왕복하는 게이지를 탭한 순간이 오늘 점수가 된다

행운지수 결과
06행운지수 결과

잡은 점수와 오늘의 색·숫자·아이템을 한 장으로 받는다

보관함
07보관함

뽑은 행운권이 등급별로 쌓인다

재료 고르기
08재료 고르기

태울 카드를 직접 골라 성공 확률을 올린다

09강화 연출

재료가 빨려 들어가고 게이지가 한 바퀴 돌면 성패가 갈린다

나의 기록
10나의 기록

선행한 날이 달력에 색으로 남는다

기술 스택


02
FlutterDartRiverpodSupabasePostgreSQLGoogle AdMobGitHub Actions

데이터와 API


03
Supabase

재화·카드·기록을 서버가 들고 있고, 앱은 결과만 받는다

Google AdMob

광고를 보면 뽑기용 코인이 하루 다섯 개까지 들어온다

구상


04
착한 일을 한 줄 적으면 잎이 하나 붙고, 네 장이 모이면 클로버가 완성된다
완성된 클로버로 소원권을 만든다
지난 기록을 달력에서 한눈에 본다
한국어·영어·일본어로 같이 낸다

기획


05

어떤 서비스인가요?

착한 일을 한 줄 적으면 잎이 하나 붙고, 네 장이 모이면 네잎클로버가 완성되는 앱이에요. 그 클로버로 행운권을 뽑고 모읍니다

어떤 계기로 만들게 됐나요?

평소에 업보라는 걸 자주 생각했어요. 카르마라고도 하죠. 덕은 쌓는 거라고 하잖아요. 야구선수 오타니도 자기 덕을 위해 쓰레기를 줍는다고 알려져 있고요

제가 좋아하는 롤 프로팀 T1 의 팬 문화에서도 영감을 받았어요. 1년에 한 번 열리는 롤드컵 기간이 되면 팬들이 일부러 착한 일을 하고 인증을 올려요. 내 선행이 조금이라도 응원하는 팀에 보탬이 되길 바라면서요

그러다 생각이 들더라고요. 운이라는 게 정말 문득 찾아오기만 하는 걸까, 그렇게 수동적인 걸까. 능동적으로 얻을 수는 없을까. 그러다 네잎클로버가 떠올랐고, 선행을 쌓아 스스로 운을 만드는 서비스로 만들어 봤어요

이름은 어떻게 지었나요?

처음엔 ooloo 였는데, 가챠 쪽으로 방향을 틀면서 LuckyPicky 로 바꿨어요. "럭키비키"랑 발음이 비슷해서 입에 붙고, 골라 뽑는다는 성격에도 picky 가 맞더라고요

주로 어떤 분이 쓰나요?

2030 여성을 주 타깃으로 잡았어요. 하루에 한두 번 잠깐 들어와 한 줄 적고 나가는 쪽이요

만드는 데 얼마나 걸렸나요?

6월 중순에 시작해서 두 달쯤 됐어요. 아직 스토어에는 안 올렸고요

작업하면서 어떤 제약이 있었나요?

작업 PC 가 윈도우라 iOS 는 코드만 맞춰 두고 빌드 검증을 못 해요. 화면 확인은 전부 안드로이드 에뮬레이터에서 합니다

지금은 안 하기로 한 게 있나요?

중국어는 뺐어요. 간체·번체가 갈리고 본토 스토어는 심사와 퍼블리셔가 따로라, 혼자 감당할 운영비가 아니라서요

소셜 로그인도 아직이에요. 익명 로그인으로 시작하고 복구 코드로 막아 뒀습니다

유저 플로우


06
  1. 01
    오늘 한 선행을 한 줄 적는다

    홈 한가운데 클로버에 잎이 하나 붙어요.

  2. 02
    잎 네 장을 채운다

    네 장째를 적는 순간 클로버가 완성돼서 상단 배지로 날아갑니다.

    온라인비행 연출 뒤 숫자가 오른다오프라인연출이 아예 재생되지 않는다
  3. 03
    뽑기 탭에서 캡슐 머신을 돌린다

    코인 한 개로 행운권 한 장이 나와요.

    코인이 있다바로 돌린다없다광고를 보고 코인을 받는다
  4. 04
    보관함에서 카드를 굽는다

    같은 등급 셋을 태워 재조합하거나, 여러 장을 먹여 한 장을 강화합니다.

    성공카드가 뒤집히며 등급이 오른다실패화면이 흔들리고 재료만 사라진다
  5. 05
    운세 탭에서 오늘의 행운지수를 잡는다

    게이지가 왕복하는 걸 탭한 순간의 값이 오늘 점수가 돼요.

구조


07
보내는 것되돌아오는 것

개발 과정


08
  1. 01

    착한 일을 적으면 잎이 붙는 화면부터

    처음 만든 건 화면 세 개였어요. 한 줄 적으면 잎이 하나 붙고, 네 장이 되면 클로버가 되는 것. 목업을 먼저 잡아 놓고 그대로 옮겼는데, 여기서 규칙을 하나 세웠습니다. Material 기본 모양은 하나도 쓰지 않는다. 기본 AppBar, 잉크 리플, 보라색 시드 컬러가 한 개라도 남아 있으면 "플러터로 만든 티"가 나거든요. 버튼도 카드도 Container 로 직접 그리고, 색·그림자·자간은 목업 값을 그대로 옮겨 적었어요.

  2. 02

    소원권을 걷어내고 캡슐 머신을 넣었어요

    처음 메인은 소원권이었어요. 선행 하나에 잎 하나, 네 번이면 클로버가 완성되고, 그 클로버로 소원권을 만드는 구조요. 그런데 만들고 보니 소원 문구를 사용자가 직접 써야 하더라고요. 쓰는 부담이 있는 데다 다 쓰고 나면 그걸로 끝이라, 재미 요소가 영 떨어졌어요.

    그래서 클로버를 아예 코인처럼 쓰기로 했습니다. 클로버 하나를 넣고 캡슐 머신을 돌려 행운권을 랜덤으로 뽑는 쪽으로요. 무엇이 나올지 모르는 도파민이 붙으니까 매일 열어볼 이유가 생겼어요.

  3. 03

    재화를 전부 서버로 넘겼어요

    로컬에만 저장하던 시절엔 앱을 지우면 모은 게 전부 날아갔어요. 뽑기까지 붙이고 나니 이건 더 못 미루겠더라고요. 게다가 클라이언트가 재화를 계산하면 마음만 먹으면 얼마든지 늘릴 수 있고요.

    Supabase 로 옮기면서 앱이 테이블을 직접 쓰지 못하게 막았어요. 잎 적립도 뽑기도 강화도 전부 security definer 함수 안에서만 일어나고, 앱은 결과 JSON 만 받습니다. 대신 테스트용으로 똑같은 규칙을 구현한 로컬 백엔드를 하나 더 뒀어요 — 규칙을 고칠 땐 SQL 과 그 파일을 항상 같이 고칩니다.

    붙인 것
    Supabase
  4. 04

    강화·재조합은 피파에서 착안했어요

    뽑기만 있으면 카드가 쌓이기만 하고 쓸 데가 없어요. 중복 카드도 계속 나오고요. 피파 게임에서 선수 카드를 재료로 태워 등급을 올리잖아요 — 그걸 그대로 가져왔습니다. 같은 등급 셋을 태워 다시 뽑는 재조합, 여러 장을 먹여 한 장을 올리는 강화 두 가지로요.

    처음엔 카드 상세 아래에 바텀시트로 붙였어요. 좁으니까 재료를 고르는 화면이 답답했고, 무엇을 태우는지도 잘 안 보였고요. 아예 전용 화면으로 꺼내서 지갑에서 카드를 직접 골라 태우게 바꿨습니다. 강화는 대상 → 재료 두 단계, 재조합은 재료 세 장 한 단계로요.

    연출도 여기서 많이 갈아엎었어요. 재료 카드가 중앙으로 빨려 들어가고, 게이지가 차고, 성공하면 카드가 뒤집히고 실패하면 화면이 흔들립니다. 그 과정에서 결과가 미리 새는 문제로 한참 고생했는데, 그건 아래 시행착오에 적었어요.

  5. 05

    운을 잡는 감각을 화면에 넣고 싶었어요

    이 서비스의 모토가 운은 찾아오는 게 아니라 찾아가는 거잖아요. 그런데 앱 안에서 그걸 몸으로 느끼는 대목이 없더라고요. 선행을 적는 것도, 뽑기를 돌리는 것도 결국 결과는 서버가 정하는 거니까요.

    그래서 운세 탭에 타이밍 게임을 넣었어요. 게이지가 0에서 100 사이를 왕복하고, 탭한 순간의 값이 그대로 오늘의 행운지수가 됩니다. 오늘 내 운을 내 손으로 정하는 거죠. 표시값에 커브를 걸어서 90 점대 구간을 순식간에 스쳐 지나가게 했어요 — 그래야 100 을 잡는 맛이 나거든요.

  6. 06

    코인과 클로버를 갈랐어요

    광고 규칙을 만지다 보니 모델이 계속 어긋났어요. 클로버 하나가 곧 뽑기 한 번이면, 선행으로 만든 클로버와 광고로 받은 클로버가 구분이 안 되잖아요. 그러면 "선행으로 운을 만든다"는 축이 통계에서부터 무너집니다.

    그래서 재화를 둘로 나눴어요. 뽑기는 광고로만 들어오는 코인을 쓰고, 선행으로 만든 클로버는 커스텀 행운권 제작·강화 전용이 됩니다. 클로버는 여전히 선행으로만 생기고, 통계에도 그것만 쌓여요. 사용자가 문구를 직접 써서 만드는 커스텀 행운권도 이때 붙였습니다.

    붙인 것
    Google AdMob
  7. 07

    문구를 앱 밖으로 뺐어요

    문구를 고칠 때마다 스토어 심사를 기다리는 게 말이 안 됐어요. 그래서 문구를 Supabase 테이블에서 받아오고, 못 받으면 앱에 실린 문구로 떨어지게 했습니다. 폴백 단위를 (면, 언어, 등급) 조합별로 잘게 쪼개서, 한 면씩 천천히 서버로 옮겨도 안전하게요.

    그 다음에 소스를 어디에 둘지로 한 번 뒤집혔는데, 그것도 시행착오에 적었습니다.

    붙인 것
    GitHub Actions
  8. 08

    기기를 바꾸면 다 날아가는 걸 뒤늦게 알았어요

    익명 로그인은 세션을 기기에 둬요. 웹은 localStorage 고요. 그래서 다른 기기에서 열면 새 계정이 되고, 모은 게 전부 사라진 것처럼 보입니다. 소셜 로그인을 붙이는 게 정석이지만 그건 심사·약관까지 딸려 오는 일이라, 먼저 복구 코드를 만들었어요.

    계정마다 "형용사 + 뜬금없는 명사" 조합의 코드를 발급해 두고 — 명란한 참치마요 오붓한 스파게티 같은 — 새 기기에서 그 코드를 넣으면 옛 계정의 재화·카드·기록이 현재 세션으로 넘어옵니다. 세션은 건드리지 않고 서버에서만 옮기는 방식이라, 로그인 구조를 바꾸지 않고도 자산이 안 날아가요.

시행착오


09
증상처음엔 광고를 보면 뽑기가 그냥 한 번 돌아가는 "무료 뽑기"였어요. 그런데 이러면 뽑기에 경로가 두 개가 됩니다. 클로버를 쓰는 길과 광고를 보는 길이요. 그러면 클로버가 뽑기 코인이라는 모델 자체가 흔들려요.
시도먼저 클로버 완성 순간에 전면 광고를 넣었어요. 가장 기분 좋은 지점이니 여기서 받자는 계산이었는데, 완성 연출을 만들고 나니 정반대였습니다. 클로버가 배지로 날아가 숫자가 오르는 그 순간에 광고가 덮으면, 선행에 대한 보상 대신 광고가 되더라고요. 그래서 전면 광고를 도로 뺐어요.
결론광고는 **얻는 순간이 아니라 쓰는 순간**에만 두기로 했어요. 무료 뽑기를 없애고, 광고를 보면 코인이 하루 다섯 개까지 들어오게 바꿨습니다. 뽑기는 언제나 코인 한 개를 쓰고요. 얻는 경로가 하나로 정리되니 재화 모델도 같이 단순해졌어요.
재조합 카드가 뒤집히기 전에 결과가 보였어요. 게이지가 차는 동안 이미 무슨 카드인지 알 수 있으니, 뒤집는 연출이 아무 의미가 없었죠.
재료를 골라 강화 버튼을 눌렀는데 서버가 규칙 위반으로 거절하면, 화면이 그냥 지갑으로 돌아가 있었어요. 왜 안 됐는지도 안 나오고, 애써 고른 카드 선택도 사라져 있고요.
처음엔 Supabase `copy_lines` 테이블을 원본으로 뒀어요. 문구를 고치려면 대시보드에서 행을 편집하고요. 그런데 이러니 **누가 언제 무슨 문구를 왜 바꿨는지가 아무 데도 안 남더라고요.** 리뷰도 안 되고, 잘못 넣으면 되돌릴 방법도 없었어요.
웹으로 빌드해서 열었더니 스플래시에서 안 넘어갔어요. 코드를 아무리 봐도 초기화가 안 끝날 이유가 없었고요.
앱이 뜨긴 하는데 탭이 하나도 안 먹었어요. 자동화 스크립트로 좌표를 찍어도 반응이 없고, 손으로 눌러도 그대로였고요.

남은 것


10
  • 개발자 웹사이트 도메인이 아직 없어요.이것 하나가 없어서 app-ads.txt 와 개인정보처리방침이 만들어만 두고 걸리지를 못합니다.
  • 웹 빌드를 공개하면 재화 경제가 깨져요.웹에는 광고가 없어서 보상형이 즉시 지급되기 때문에, 공개하려면 웹에서 보상 버튼을 막는 가드가 먼저 필요합니다.
  • 소셜 로그인이 없어요.복구 코드로 급한 불은 껐지만, 결국 Google·Apple 계정 연동으로 가야 합니다.
  • iOS 는 코드만 맞춰 뒀어요.빌드와 심사 검증은 Mac 이 있어야 합니다.
  • 월간 문구 리서치 루틴이 멈춰 있어요.유행어를 뺀 뒤로 매달 갱신할 이유가 사라져서, 다시 돌릴지는 아직 안 정했습니다.