Skip to content
jphacksPublic

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

157 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Re: Read

Re: Read

読書の途中で生まれた気持ちを、色のついた「しおり」として残す読書記録アプリ

re_read_demo.mp4

参考用の体験デモ

スマートフォン・PCのブラウザで体験する(ログイン不要)

アプリの主要な画面や操作の流れを参考として体験できるデモです。実際のアプリを完全に再現したものではなく、UI・UXや一部の挙動に違いがあります。 以下のアプリ紹介と併せて、参考程度にご覧ください。

  • ホームのサンプル本から、ページ番号・感想を入力してしおりを追加し、本の詳細で自分とみんなのしおりを見比べられます。
  • 書籍・既存の感想・感情グラフは架空のサンプルです。他の実利用者の記録は表示しません。
  • デモではJevによるAI解析を行いません。 入力した感想の色は内容によらず固定の仮の色になり、感情グラフも解析によって変化しません。
  • ログイン・外部の書籍検索・サーバー保存などは省略または制限しています。入力した感想をバックエンドへ送信せず、変更はページの再読み込みでリセットされます。

目次

Re: Read について

Re: Read Re: Read

Re: Read は、本が好きな人のための、感情を色で残す読書記録アプリです。

本をたくさん読むなかで、「どのページまで読んだか」「あの場面で何を感じていたか」を忘れてしまうことがあります。 同じ本を読んだほかの人はどう感じたのか、以前読んだときの自分はどんな気持ちだったのか、知りたくなることもあります。

けれど、感想をメモしていても、あとから本のページと照らし合わせたり、過去の自分やほかの人が書いた文章を一つずつ読み返したりするには手間がかかります。 読書中の気持ちを気軽に残し、その変化や違いをひと目でたどれるようにしたい。そんな思いからできたアプリが、Re: Readです。

Re: Readでは、紙の本にしおりをはさむように、ページ番号と短い感想を記録します。 文章に表れた感情をAIモデルのJevで分析し、複数の感情の混ざり合いや強さを、細かな色の違いとして表現します。 色のついたしおりをページに沿ったタイムラインや感情グラフで可視化することで、心が動いた場所や、そのときの気持ちを視覚的に振り返れるようにします。

さらに、過去の自分やほかの読者が残したしおりの色を見比べ、同じページから生まれる感じ方の違いにも出会える体験を目指しています。

Jevによる分析をすばやく色の表示につなぎ、しおりを記録したその場で、感情の色がわかる操作感を目指します。 記録や振り返りが読書の負担にならず、自分の気持ちを再発見したり、ほかの読者の感じ方に触れたりできる、新しい読書体験を届けたいと考えています。

特長

1. 読書中の気持ちを、ページと一緒に残せる

長いレビューを書く必要はなく、印象に残った瞬間にページ番号と短い言葉を残せます。

同じ読書回・同じページのしおりは更新でき、読了済み・過去の読書回の記録は閲覧専用として扱います。

2. 感情が、しおりの色になる

Jevによる感情分析を設定した環境では、感想から次の8感情を分析します。

  • 喜び
  • 信頼
  • 恐れ
  • 驚き
  • 悲しみ
  • 嫌悪
  • 怒り
  • 期待

分析結果は独自の変換ロジックによって、しおりの色へ変換されます。

単純に感情ごとへ固定色を割り当てるのではなく、感情の方向・まとまり・強さを、それぞれ色相・彩度・明るさへ反映します。

3. しおりをたどって、読書体験を振り返れる

保存したしおりは、本のページ上の位置を示すタイムラインと感想一覧から確認できます。

「どこで、どんな気持ちになったか」を文章と色の両方から振り返れるため、読了後の一括レビューとは異なる形で、自分の読書体験を残せます。

本の詳細画面では、同じ本に対するJev解析済み感想を「自分」と「みんな」に分けて集計します。8感情の平均値を自分は実線、みんなは点線で同じグラフに重ね、それぞれの感情色とともに、感じ方の違いを見比べられます。

Re: Read Re: Read

使い方

  1. 本を探す
    Google Booksでタイトルを検索し、読みたい本・読んでいる本を自分の本棚へ追加します。

Re: Read

  1. しおりを書く
    読書中の本を開き、ページ番号と1〜140文字の感想を入力します。

Re: Read

  1. しおりを保存する
    保存ボタン、またはカードを上方向にスワイプして記録します。このとき、しおりとチェックマークの色が、Jevの分析結果に基づいた色に変わります。

Re: Read Re: Read

  1. 読書体験を振り返る
    本の詳細画面から、ページ順のしおり・感想・読書進捗・感情の傾向を確認します。

こだわったポイント

ページ単位・読書回単位で記録する

しおりはユーザー・本・読書回・ページごとに記録し、ログイン中のユーザーの感想を取得・更新します。

これにより、現在読んでいるときの記録と過去の読書記録を分離し、再読した場合にも別の読書体験として扱える構造にしています。

本の詳細画面の感情比較では、「自分」は最新読書回のしおり(非公開も含む)、「みんな」は同じ本を読むほかの読者の公開しおり(全読書回)を対象に、Jev解析済み感想の8感情を平均して表示します。自分の過去の読書回はどちらにも含めません。読書進捗の表示色には、自分の感情色を使います。

8感情から、しおりの色を生成する

感情分析で得られた8次元の感情ベクトルを2次元へ投影し、結果を色へ変換します。

  • 感情の方向 → 色相
  • 感情のまとまり → 彩度
  • 最も強い感情の強度 → 明るさ
  • 感情が表れない場合 → グレー

これにより、感情ラベルを単純な固定色へ置き換えるのではなく、複数の感情が混ざった状態も色として表現します。

実装:

「しおりをはさむ」操作感をUIに落とし込む

しおり入力画面では、保存ボタンだけでなく、カードを上方向へスワイプする操作でも保存できます。

保存に成功した場合のみ、バックエンドから返された色を使って完了演出を表示します。失敗した場合は入力内容を保持し、そのまま再試行できるようにしています。

実装:

DDD(ドメイン駆動設計)を参考にしたコンテキスト分割

エリック・エヴァンスのDDD(ドメイン駆動設計)を参考に、バックエンドを業務の責務に応じた4つの境界づけられたコンテキストに分割しています。

コンテキスト 担当する責務 実装
認証認可 ユーザープロフィール、登録・ログイン、メール確認、パスワード再設定、セッション、本人操作の認可 identity/
蔵書 書誌情報、Google Books連携、本棚、読書回、読了、読書進捗 library/
感想 ページ別の感想本文、改訂番号、解析状態、感想一覧、ページ別集計 reviews/
AI分析 Jev・モック分析、8感情モデル、色変換、分析履歴、実AI結果の集約 analysis/

各コンテキスト内をdomain・application・infrastructure・presentationに分け、業務ルールをHTTPやDBの処理から分離しています。 他コンテキストのORMや内部実装を直接参照せず、public.pyの公開契約をintegration/のアダプターで変換し、composition/で実装を組み立てます。

これにより、認証・読書記録・感情分析それぞれの変更範囲を明確にし、機能追加時に他の業務へ変更が広がりにくい構成を目指しています。

設計・確認方法:DDDコンテキストと依存関係

実装:

Get Started(開発者向け)

ローカルでAPI・DB・Redisとアプリを起動し、開発用ユーザーでログインする手順です。 この手順ではSMTPを使わず、メール確認済みユーザーをCLIから作成します。JevのAPIキーがなければモック分析で動作します。

1. 必要なツールを用意する

  • Node.js 24とnpm(frontend/.nvmrcに合わせたバージョン)
  • DockerとDocker Compose v2
  • OpenSSL(JWT秘密鍵の生成に使用)
  • スマートフォン実機で動かす場合はExpo Go

リポジトリを取得し、ルートのtkb_2629/を開いてください。 バックエンドのPython・uvはDockerイメージに含まれています。

2. バックエンドの環境変数を設定する

リポジトリのルートから実行します。cp -nは既存の.envを上書きせず、初回のみ設定例をコピーします。

cd fastapi
cp -n .env.example .env
openssl rand -hex 32

fastapi/.envを開き、次の値を設定します。AUTH_JWT_SECRETの<...>は、直前のコマンドで生成した64桁の16進数へ置き換えてください。

DATABASE_URL=postgresql+psycopg://postgres:postgres@postgres:5432/fastapi
APP_ENV=development
AUTH_JWT_SECRET=<生成した64桁の16進数>
AUTH_JWT_ISSUER=re-read-api

SMTP関連の値は設定例のままで進められます。BOOKS_APIは省略可能で、未設定時はキーなしでGoogle Booksを検索します。 TYPESAFE_API_KEYを空欄にするとモック分析を使います。実際のJev分析を使う場合だけAPIキーを設定してください。

3. API・DB・Redisを起動する

引き続きfastapi/で実行します。

docker compose up -d --build
docker compose ps
docker compose exec api uv run alembic upgrade head

PostgreSQL・Redisがhealthy、APIが起動済みであることを確認してからマイグレーションを実行します。 マイグレーション完了後、PCのブラウザーでAPIドキュメントを開ければAPIの起動を確認できます。

この手順は新規DB、またはAlembicで管理済みのDB向けです。Alembic履歴のない既存DBがある場合の対応は、バックエンドのREADMEを参照してください。

4. 開発用ユーザーを作成する

マイグレーション完了後、fastapi/で実行します。

docker compose exec api uv run python -m backend.composition.development_user \
  --email dev@example.com \
  --name 開発ユーザー

ログイン用パスワードを対話で2回入力します。パスワードは12〜128文字で、入力中は画面に表示されません。 「開発用ユーザーを保存しました」と表示されれば、メール確認済みのユーザーがDBへ保存されています。

同じメールアドレスで再実行すると、既存のユーザーID・読書記録を維持してパスワードを更新し、既存セッションを失効します。 別の開発用ユーザーが必要な場合は--emailを変更してください。このコマンドはAPP_ENV=developmentでのみ利用できます。

5. フロントエンドを起動してログインする

別のターミナルを開き、リポジトリのルートから実行します。

cd frontend
cp -n .env.example .env
npm install

frontend/.envのEXPO_PUBLIC_API_URLを、アプリを動かす環境に合わせて設定します。

実行環境 API接続先
スマートフォン実機のExpo Go http://192.168.1.10:8000(IPアドレスは開発用PCのLAN内IPへ置き換える)
Androidエミュレーター http://10.0.2.2:8000
PCのWebブラウザー・iOSシミュレーター http://localhost:8000

実機を使う場合はPCとスマートフォンを同じLANへ接続し、スマートフォンのブラウザーからhttp://<PCのLAN内IP>:8000/docsを開けることを確認してください。 localhostは実機自身を指すため、PCのAPIへ接続するときはPCのIPアドレスを指定します。

npm start

Expo GoでターミナルのQRコードを読み取るか、ターミナルでwを押してWeb版を開きます。 アプリのログイン画面で、手順4のメールアドレス(例:dev@example.com)と入力したパスワードを使ってログインしてください。 ログイン後、「本を探す」から本を追加し、ページと感想を入力してしおりを保存できます。

SMTPを省略している場合、アプリの新規登録・メール確認の再送・パスワード再設定にはメール送信環境の設定が必要です。 設定方法は認証設定を参照してください。

6. 設定変更・終了・再開

APIの.envを変更した場合は、fastapi/で次を実行してコンテナへ設定を反映します。

docker compose up -d --force-recreate api

フロントエンドの.envを変更した場合はExpoを停止してnpm startし直します。 Web版で接続元のホスト名・ポートを変えた場合は、fastapi/.envのCORS_ORIGINSにもそのOriginを追加してください(既定はhttp://localhost:8081,http://localhost:19006)。

開発終了時はExpoをCtrl+Cで停止し、fastapi/でdocker compose downを実行します。DBのデータはボリュームに残ります。 次回はfastapi/でdocker compose up -d、別のターミナルのfrontend/でnpm startを実行します。作成済みの開発用ユーザーで再びログインできます。

リポジトリ構成

フロントエンドとバックエンドは、それぞれ個別のREADMEで起動方法や設定を案内しています。

ディレクトリ 内容
frontend/ Expo / React Nativeで実装したiOS・Android・Web向けフロントエンド
fastapi/ FastAPIによるAPI、書籍検索、読書記録、感情分析、データアクセス
docs/ READMEで利用する画像などのドキュメント関連ファイル

開発技術

技術構成

フロントエンドはExpo / React Native / TypeScript、バックエンドはPython / FastAPIで実装しています。 バックエンドは単一のFastAPIアプリ内を、認証認可・蔵書・感想・AI分析の4コンテキストに分割しています。

flowchart LR
    F["Expo / React Native / TypeScript<br/>iOS・Android・Web"]
    P["PostgreSQL<br/>ユーザー・蔵書・感想・分析履歴"]
    R["Redis<br/>書誌情報のキャッシュ"]
    G["Google Books API"]
    J["Jev / TypeSafe SDK"]
    M["SMTP<br/>メール確認・パスワード再設定"]

    subgraph B["バックエンド:FastAPI / Python"]
        H["HTTP API / Pydantic"]
        A["認証認可コンテキスト"]
        L["蔵書コンテキスト"]
        V["感想コンテキスト"]
        E["AI分析コンテキスト"]
        H --> A
        H --> L
        H --> V
        V -->|公開契約・アダプター| L
        V -->|公開契約・アダプター| E
    end

    F -->|JSON / 認証後はBearer JWT| H
    A --> P
    L --> P
    V --> P
    E --> P
    A --> M
    L --> G
    L --> R
    E --> J
Loading

図のコンテキスト間の矢印は、公開契約を通した実行時の連携を表しています。 ユーザー・認証情報・本棚・読書回・感想・分析履歴はPostgreSQLに保存し、Google Books由来の書誌情報はRedisに一時的にキャッシュします。

2026-10-25にAPIキー付きの書籍検索・詳細取得の正常応答を確認した際、Cache-Control・Expiresによる有効期限の明示はありませんでした。 そこで、連続タップや画面の再表示による同じ書誌情報の重複取得を減らし、長期間保持し続けないため、アプリ側の運用方針として**API取得から24時間(86,400秒)**のTTLを設定しています。

感想本文と読書進捗を保存した後にJevを呼び出し、分析結果は感想の改訂番号に対応させて保存します。

キャッシュの実装:

主な技術

分類 技術 Re: Readでの役割
フロントエンド Expo SDK 58 / React Native 0.88 / React 19.3 / TypeScript 5.9 iOS・Android・Web向けUI、画面遷移、型付きAPIクライアント
UI・表現 React Native Animated / react-native-svg / expo-blur スワイプ保存、感情グラフ、SVGのグラデーション、半透明表現
バックエンド Python 3.12 / FastAPI / Pydantic 各コンテキストのHTTP API、入力・出力の検証
認証認可 Argon2id / PyJWT / JWT パスワードのハッシュ化、短期アクセストークンの発行・検証、DBでのリフレッシュトークン管理
ログイン状態の保持 Expo SecureStore / HttpOnly Cookie スマホ版はSecureStore、Web版はHttpOnly Cookieでリフレッシュトークンを保持
ORM・DB SQLAlchemy / psycopg / Alembic / PostgreSQL 17 各コンテキストの永続化、Unit of Workによるトランザクション管理、スキーマ変更
書籍検索 Google Books API / httpx タイトル検索、著者・ページ数・ISBN・表紙などの書誌情報取得
感情分析 Jev / typesafe-sdk 感想文から独立した8感情の強度を分析し、AI分析ドメインで色へ変換
キャッシュ Redis 7 / redis-py Google Booksの書誌情報を24時間キャッシュ
メール送信 SMTP / Python標準のsmtplib 登録後のメール確認、確認メールの再送、パスワード再設定
開発・依存管理 Docker Compose / uv / npm ローカルのAPI・DB・Redis起動、Python・フロントエンドの依存管理
静的チェック Ruff / TypeScript / 独自の依存チェッカー lint・型チェック、コンテキスト間の直接参照・層の逆依存・循環参照の検出

現在の開発環境

対象 環境・設定
フロントエンド ホスト側のNode.jsとnpm。.nvmrcは24、package.jsonの指定は22.13以上
アプリの起動 frontend/でnpm install後にnpm start。Expo Goでの実機開発に加え、npm run android・npm run ios・npm run webを用意
バックエンド fastapi/のDocker Composeでapiサービスを起動。Python 3.12でFastAPIの開発サーバーを起動し、8000番ポートを公開
データストア Docker ComposeのPostgreSQL 17(5432番)・Redis 7(6379番)。PostgreSQLのデータは名前付きボリュームで保持
DBスキーマ Alembicで管理。API利用前にdocker compose exec api uv run alembic upgrade headを実行
環境変数 フロントはfrontend/.env、APIはfastapi/.env。設定例は各ディレクトリの.env.exampleを参照

実機からAPIに接続する場合、EXPO_PUBLIC_API_URLにはPCのLAN内IPアドレスと8000番ポートを指定します。 フロントエンド側で使用するExpoの配信ポートと、バックエンドのAPIポートは分けています。

開発環境ではAPP_ENV=developmentの専用CLIで、メール確認済みユーザーをDBに直接作成できます。 この方法ならSMTPを設定せずに、アプリの通常のログイン画面から利用できます。ログインにはAUTH_JWT_SECRETの設定が必要です。 通常の新規登録・メール確認・パスワード再設定を使う場合は、SMTPの接続情報を設定します。 JevはTYPESAFE_API_KEYを設定した場合に利用し、未設定時はモック分析へ切り替わります。

詳しい起動手順・環境変数・開発用ユーザー作成方法は、次のドキュメントを参照してください。

現在の開発状況

Re: Readは現在開発中です。

  • メール+パスワードの登録・ログイン、メール確認、トークン更新・失効、ログアウト、ログイン試行回数制限、パスワード再設定を実装しています。
  • 読書記録は認証済みユーザーごとに保存します。API利用には環境変数の設定と最新のDBマイグレーションの適用が必要です。
  • ローカル開発では、メール確認済みユーザーをDBへ作成する専用CLIを利用できます。
  • JevのAPIキーが未設定の場合はモック分析を利用し、実際の感情分析とは区別して表示します。
  • 本の編集・プロフィール変更・読書設定など、一部の画面操作は準備中です。
  • 既存のバックエンドテストはコンテキスト分割前の構成を参照しており、新構成への追従が必要です。

起動方法や必要な環境変数については、各READMEを参照してください。

今後の展望

  • ページに沿った感情の変化や、同じ本を再読した際の違いを比較できるようにし、読書体験の振り返りをさらに深められるようにしたい。
  • AIによる検閲など、荒らし対策を考えたい。
  • 複数の感情が入り混じると、中立的な色にまとまり、その複雑さが伝わりにくい場合がある。感情が弱い状態と、さまざまな感情が混ざり合った状態を見分けられるよう、色の組み合わせやグラデーションなどの表現を検討したい。

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

Generated from jphacks/JP_sample