Skip to content

SIDE PROJECT

PromSpoon 앱 아이콘

PromSpoon

좋은 프롬프트를 한 스푼

FlutterDartRiverpodSQLite

AI 프롬프트를 찾고, 저장하고, 바로 활용하는 Flutter 앱과 React 웹 서비스

PromSpoon 앱 홈과 프롬프트 검색 화면

PromSpoon - Apps on Google Play

AI 프롬프트를 검색·저장해 바로 활용하는 앱 · Google Play 배포 완료

https://play.google.com/store/apps/details?id=com.Dopaminus.promspoon&hl=ko

MOBILE APPLICATION

PromSpoon 앱

Flutter로 개발한 프롬프트 탐색·저장 앱입니다. 서버에서 내려온 콘텐츠를 검색·카테고리·정렬로 탐색하고, 상세 화면에서 본문을 복사하거나 ChatGPT·Gemini로 넘겨 바로 사용할 수 있도록 사용 흐름을 구성했습니다. 좋아요는 POST 요청으로 서버와 동기화하고, 북마크와 언어 설정은 기기에 남겨 앱을 다시 열어도 이어지게 했습니다.

앱 개발
Flutter · Dart
상태 · 모델
Riverpod · Freezed · JSON Serializable
네트워크
Dart package:http · HTTPS JSON REST API · 15초 timeout
데이터 · 이미지
PHP API · MariaDB · Cloudinary thumbnail URL
로컬 · 다국어
SQLite(sqflite) · SharedPreferences · URL Launcher · 한국어 / 영어 / 일본어

담당 범위|Flutter 화면·상태·모델 설계, HTTP API 연동, 좋아요 POST 동기화, SQLite 북마크, Cloudinary 이미지 표시, 다국어와 예외 처리를 앱 전반에서 담당

APP SCREENS

앱 화면과 주요 기능

검색·카테고리 필터와 최신순·좋아요순 정렬로 프롬프트를 탐색합니다. 상세 화면에서는 본문을 복사하거나 ChatGPT·Gemini로 이동할 수 있고, 자주 쓰는 프롬프트는 북마크로 보관할 수 있습니다.

APP / 01

홈 · 검색 · 카테고리

Cloudinary 썸네일과 API에서 내려온 프롬프트를 홈 화면에 구성하고, 검색어와 카테고리로 필요한 콘텐츠를 빠르게 좁힐 수 있도록 했습니다.

  • 검색어 기반 프롬프트 필터링
  • 카테고리 선택과 전체 목록 전환
  • 최신순·좋아요순 정렬 진입
화면 원본 보기 — 홈 · 검색 · 카테고리 (새 탭)
PromSpoon · App
PromSpoon 앱 홈 — 프롬프트 검색과 카테고리
홈 · 검색 — 검색어와 카테고리로 필요한 프롬프트를 탐색합니다.

APP / 02

목록 · 정렬 · 좋아요

목록에서 콘텐츠의 제목·요약·반응 수를 한눈에 보여주고, 좋아요와 북마크를 반복해서 사용해도 상태가 자연스럽게 이어지도록 구현했습니다.

  • 최신순·좋아요순 목록 정렬
  • 좋아요 POST와 낙관적 카운트 반영
  • SQLite 북마크 상태 표시
화면 원본 보기 — 목록 · 정렬 · 좋아요 (새 탭)
PromSpoon · App
PromSpoon 앱 프롬프트 목록 — 좋아요와 북마크
목록 · 정렬 — 최신순·좋아요순 정렬과 좋아요·북마크를 제공합니다.

APP / 03

프롬프트 상세 · 본문 복사

상세 화면에서 대표 이미지, 카테고리, 설명, 좋아요 수와 본문을 분리해 읽기 흐름을 만들고, 필요한 프롬프트를 바로 복사할 수 있게 했습니다.

  • 프롬프트 메타데이터와 본문 구분
  • 복사 동작과 저장 상태 피드백
  • 게시일·반응 정보 표시
화면 원본 보기 — 프롬프트 상세 · 본문 복사 (새 탭)
PromSpoon · App
PromSpoon 앱 프롬프트 상세 — 설명과 본문 복사
프롬프트 상세 — 설명과 본문을 확인하고 필요한 프롬프트를 복사합니다.

APP / 04

ChatGPT · Gemini · 관련 콘텐츠

프롬프트를 복사하는 데서 끝나지 않고 URL Launcher로 외부 AI 서비스로 이동하며, 같은 카테고리의 관련 프롬프트를 이어서 탐색할 수 있도록 했습니다.

  • ChatGPT·Gemini 바로가기
  • 외부 앱·브라우저 이동
  • 좋아요 기준 관련 프롬프트 추천
화면 원본 보기 — ChatGPT · Gemini · 관련 콘텐츠 (새 탭)
PromSpoon · App
PromSpoon 앱 ChatGPT·Gemini 바로 사용하기와 관련 프롬프트
AI 서비스 연결 — ChatGPT·Gemini로 이동하고 관련 프롬프트를 이어서 살펴봅니다.

APP / 05

다국어 · 설정 · 정책

앱 언어와 버전, 이용약관·개인정보처리방침을 한 화면에서 제공하고, 선택한 언어를 SharedPreferences에 저장해 재실행 후에도 유지했습니다.

  • 한국어·영어·일본어 전환
  • 앱 버전과 운영 정책 안내
  • 설정값 로컬 저장 및 복원
화면 원본 보기 — 다국어 · 설정 · 정책 (새 탭)
PromSpoon · App
PromSpoon 앱 설정 — 한국어·영어·일본어와 약관
다국어 · 설정 — 한국어·영어·일본어, 앱 정보와 약관을 제공합니다.

Riverpod · Freezed

DataSource → Repository → Provider → UI로 책임을 나누고, Riverpod으로 비동기 데이터를 관리했습니다. Freezed와 JSON Serializable로 불변 모델과 JSON 변환 코드를 구성했습니다.

기기에 남는 북마크 · 다국어

SQLite에 프롬프트와 저장 시점을 보관해 북마크를 관리합니다. SharedPreferences에는 언어 설정을 저장하고 한국어·영어·일본어 UI를 제공합니다.

APP IMPLEMENTATION

Flutter 앱 구현 범위

화면을 그리는 데서 끝내지 않고, API 응답을 모델로 변환하는 시점부터 사용자가 다시 앱을 열었을 때의 북마크·언어 상태까지 전체 흐름을 구현했습니다. 원격 콘텐츠와 기기 상태를 분리하고 기능별 폴더의 책임을 나눠 API나 저장 방식이 바뀌어도 화면 로직이 흔들리지 않도록 구성했습니다.

검색·카테고리·정렬

Riverpod의 SearchQueryNotifier와 SelectedCategoryNotifier로 검색어·카테고리를 분리해 관리하고, 최신순·좋아요순을 PromptSortNotifier로 전환했습니다. 목록은 같은 API 응답을 바탕으로 화면에서 즉시 필터링해 탐색 흐름을 빠르게 유지했습니다.

HTTP 네트워크 계층

Dio 대신 Dart의 package:http Client를 주입해 HomeRemoteDataSource를 만들었습니다. GET /api/prompts와 /api/tables/prompt_categories를 호출하고, 15초 timeout·상태 코드 확인·UTF-8 bodyBytes 디코딩·JSON 파싱을 한 곳에서 처리했습니다.

좋아요 POST와 낙관적 UI

POST /api/prompts/{slug}/like에 liked 값을 JSON으로 보내고 X-PromSpoon-Visitor 헤더로 방문자를 구분했습니다. 화면에서는 먼저 좋아요·카운트를 반영한 뒤 서버 결과를 확정하고, 연속 탭은 syncing key로 묶어 중복 요청을 줄였습니다.

Cloudinary 이미지 서버

API의 thumbnail_image_url로 내려오는 Cloudinary 이미지를 프롬프트 목록·상세 카드에 표시했습니다. 이미지 주소를 콘텐츠 데이터와 함께 관리해 새 이미지를 앱 번들에 다시 포함하지 않고 운영 중 교체할 수 있도록 했습니다.

SQLite 북마크·설정 보관

favorite_prompts 테이블에 프롬프트 JSON과 saved_at을 저장하고 insert·replace·delete를 조건 바인딩으로 처리했습니다. SharedPreferences에는 언어 선택을 저장해 한국어·영어·일본어 설정을 재실행 후에도 유지했습니다.

Freezed 모델과 기능 구조

Prompt·PromptCategory·PromptLikeResult·PromptLikeStatus를 Freezed 모델로 정의하고 JSON Serializable 생성 코드를 사용했습니다. DataSource → Repository → Riverpod Provider/Notifier → UI 구조로 API·로컬 데이터·화면의 결합도를 낮췄습니다.

API & DATA FLOW

앱에서 API와 DB까지 이어지는 데이터 흐름

앱은 package:http로 PHP·MariaDB REST API를 호출합니다. API는 프롬프트 본문·카테고리·태그·좋아요 수·공개 상태·다국어 필드를 JSON으로 내려주고, 썸네일은 Cloudinary URL을 함께 전달합니다. 좋아요는 같은 API에 POST하고 응답의 카운트로 서버 상태를 확정합니다.

  1. 01

    Flutter UI

    검색·카테고리·좋아요 입력을 Riverpod 상태로 수집

  2. 02

    http Client

    GET 목록·카테고리와 POST 좋아요 요청을 HTTPS로 전송

  3. 03

    PHP API · MariaDB

    프롬프트·카테고리·반응 수와 공개 상태를 DB에서 조회·갱신

  4. 04

    JSON · Cloudinary

    Freezed 모델로 변환하고 thumbnail_image_url을 화면에 표시

PromSpoon prompts API JSON 응답 — Cloudinary 썸네일 URL과 다국어 필드
API 응답 구조 예시 — 프롬프트 본문·태그·좋아요 수·공개 일시·다국어 필드와 Cloudinary thumbnail_image_url을 한 응답으로 받아 Freezed 모델에 매핑했습니다.

목록 GET 응답

prompts 테이블의 prompt_id·slug·title·summary·tags·like_count·published_at·is_published와 한국어·영어·일본어 필드를 함께 받아 언어 설정에 맞게 표시합니다.

반응 POST 응답

liked 값을 전송한 뒤 서버가 계산한 liked·like_count를 받아 로컬의 임시 상태와 교체합니다. 요청 실패 시 마지막 확정 상태로 되돌려 화면과 서버가 어긋나지 않게 했습니다.

PROJECT STRUCTURE

기능 단위로 나눈 앱 구조

홈 · 원격 콘텐츠

lib/features/home/data_source/home_remote_data_source.dart
lib/features/home/repository/home_repository.dart
lib/features/home/provider/home_provider.dart
lib/features/home/model/home_model.dart

기기 데이터 · 설정

lib/features/favorite/favorite_local_data_source.dart
lib/features/favorite/favorite_repository.dart
lib/core/locale/app_language.dart
lib/features/prompt_detail/prompt_detail_page.dart

구현 관점 — API 응답·로컬 저장·상태 변경을 화면 코드에 섞지 않고 기능 단위로 분리했습니다. 그래서 좋아요 동기화나 Cloudinary 주소 규칙이 바뀌어도 UI 변경 범위를 제한할 수 있습니다.

사용자 관점 — 검색→상세→복사·외부 AI 실행→북마크, 그리고 좋아요→목록 갱신까지 실제 사용 흐름을 기준으로 연결했습니다.