📱 003 クラウド同期・iPhone設計
画面構成・Service Worker・データ構造・データフロー
設計書 v1.4 / 2026-04-27
1 画面構成
iPhone PWA は step state で切り替わる5画面の単一ページアプリです。
1.1 各画面の役割
banner・login・push・list・write の5画面それぞれの表示条件と役割を説明します。
追加してください
- 表示条件
- SafariでURLを直接開いた(PWAではない)
- 目的
- ホーム画面への追加手順を案内する。初回インストール時のみ使う。
- バージョン表示
app x.x.xのみ。ServiceWorkerは表示しない。- 備考
- skipWaiting導入済みのため、バージョンアップ目的で開く必要はない。
してください
- 表示条件
- アクセストークンがない(初回 or 有効期限切れ)
- 操作
- 「Googleでログイン」ボタン → Google OAuth(PKCE)→ トークン取得後 push へ遷移
- バージョン表示
app x.x.x / ServiceWorker x.x.x(右下固定)
有効にしてください
- 表示条件
- トークンあり +
viewer_push_doneが未設定 - 操作
- 「通知を許可する」→ OS権限ダイアログ → 許可後 list へ遷移。
viewer_push_done=trueを localStorage に保存。 - バージョン表示
app x.x.x / ServiceWorker x.x.x(右下固定)
- 表示条件
- トークンあり +
viewer_push_done=true(通常の起動時) - 操作
- + → write(新規)
メモタップ → write(編集)
🔔 → ロック画面に表示 ON/OFF
🗑️ → メモ削除 - バージョン表示
app x.x.x / ServiceWorker x.x.x(右下固定)
- 表示条件
- ① list からメモ選択・新規作成
② 通知タップ(notificationclick または pending_open) - 操作
- 「PCへ送る」→ Drive経由でPC送信 → list へ
「iPhoneに置く」→ IndexedDBに下書き保存 → list へ
「← 戻る」→ list へ(保存なし) - バージョン表示
app x.x.x / ServiceWorker x.x.x(右下固定)
1.2 起動時の遷移ルール
PWA起動時にどの画面から始まるかを決める4つのルールを定義します。
図 3-1 起動時の画面遷移ルール
表 1.2-1 起動時画面遷移ルール
| No | 起動時の状態 | 遷移先 |
|---|---|---|
| 1 | 非 standalone(Safariで開いた) | banner |
| 2 | URL に ?code=(OAuthコールバック) | Vercel でトークン取得 → push |
| 3 | URL に ?note=(通知タップで起動) | IndexedDB からノート読み込み → write |
| 4 | token あり・pending_open あり(30分以内) | IndexedDB からノート読み込み → write |
| 5 | token あり・viewer_push_done=true | list(通常起動) |
| 6 | token あり・push 未設定 | push(通知セットアップ) |
| 7 | token なし | login |
2 モジュール構造
フロントエンド・Service Worker・Vercel API の3層構成です。
2.1 フロントエンド(TypeScript / React)
画面を構成するコンポーネント・フックの依存関係を示します。 また、図には現れない共通ユーティリティファイルも以下の表に一覧します。
表 2.1-1 共通ユーティリティ(viewer/ 配下)
| No | ファイル名 | 役割 |
|---|---|---|
| 1 | types.ts | フロントエンド全体で共有する型定義(DraftRecord 等) |
| 2 | utils.ts | 依存を持たない汎用的なユーティリティ関数群 |
| 3 | editor-helpers.ts | テキストエリア操作やタグ管理(localStorageとの連携)を担うヘルパー |
図 3-2 フロントエンドモジュール構成
2.2 Service Worker(worker/index.js)
push受信・notificationclick等を処理するSWのイベントハンドラ5点を一覧します。
表 2.2-1 SW イベントハンドラ一覧
| No | イベント | 処理内容 |
|---|---|---|
| 1 | install | skipWaiting() 呼び出し。新バージョンを即時有効化。 |
| 2 | activate | clients.claim() でページの制御を取得。SW バージョンをログに記録。 |
| 3 | push | ① Push ペイロード(title / body_rich / id)を取得 ② fusen-meta からアクセストークンを取得③ Drive から画像をダウンロード ④ fusen-drafts にノートを保存⑤ Drive から画像ファイルを削除 ⑥ notes_to_iphone.json から当該 ID を削除⑦ pending_open を fusen-meta に記録⑧ 既存の同 ID 通知を閉じてから新規通知を表示 |
| 4 | notificationclick | 通知をタップ → locked 確認 → true なら再通知・アプリを前面に出す。⚠️ iOS では発火しない(既知の制約)。タップ後の再通知は page.tsx の pending_open フローが代替。 |
| 5 | message | アプリからの通信を受信。CLOSE_NOTIFICATION で通知を閉じる、GET_VERSION で SW のバージョンを返す等の処理。 |
2.3 サーバーサイド(Vercel API Routes)
Google OAuth2 の client_secret を保護するVercel APIエンドポイント2点を説明します。
表 2.3-1 Vercel API Routes 一覧
| No | ファイル | 役割 |
|---|---|---|
| 1 | app/api/auth/token/route.ts | OAuth 認証コード → アクセストークン+リフレッシュトークン交換。初回ログイン時のみ呼ばれる。 |
| 2 | app/api/auth/refresh/route.ts | リフレッシュトークン → 新しいアクセストークン取得。Drive API 呼び出し時にトークン期限切れを検出したら自動呼び出し。 |
環境変数(Vercel)
Vercel の Environment Variables に設定する変数の一覧です。.env ファイルやコードにハードコードしないこと。
表 2.3-2 Vercel 環境変数一覧
| 変数名 | 公開範囲 | 取得元 | 用途 |
|---|---|---|---|
GOOGLE_CLIENT_SECRET_PWA | サーバー専用 | Google Cloud Console → 認証情報 → OAuth 2.0 クライアント(PWA用) → クライアント シークレット | トークン交換・リフレッシュ時に Google へ提示する秘密鍵。ブラウザに渡してはいけない。 |
NEXT_PUBLIC_GDRIVE_CLIENT_ID | 公開可 | Google Cloud Console → 認証情報 → OAuth 2.0 クライアント(PWA用) → クライアント ID | iPhone PWA の OAuth フロー開始時に使う。公開しても問題ない。 |
NEXT_PUBLIC_VAPID_PUBLIC_KEY | 公開可 | Web Push 鍵ペア生成時の公開鍵(web-push generate-vapid-keys 等で生成) | iPhone の Web Push 購読登録(pushManager.subscribe)時に使う。 |
DISCORD_WEBHOOK_URL | サーバー専用 | Discord サーバー → チャンネル設定 → 連携サービス → Webhook → URL をコピー | PC 設定画面のフィードバック送信ボタンから Discord へ通知を転送する。 |
3 データ構造
IndexedDB・localStorage・Google Drive の3か所にデータを分散して保存します。
3.1 IndexedDB
PWA端末内に保存されるfusen-drafts・fusen-meta・fusen-logsの3ストアを定義します。
3.1.1 🗄 fusen-drafts(ノートデータ)
表 3-4 fusen-drafts スキーマ
| No | フィールド | 型 | 意味 |
|---|---|---|---|
| 1 | id | string | 主キー(UUID) |
| 2 | title | string | ノートタイトル |
| 3 | body | string | 本文(Markdown) |
| 4 | images | Object[] | 添付画像({ fileName: string, blob: Blob }[]) |
| 5 | tags | string[] | 付与されたタグの配列 |
| 6 | locked | boolean | ロック画面に表示が ON なら true |
| 7 | created_at | string | 作成日時(JST ISO 8601) |
| 8 | sent_at | string | 送信日時(未送信時は undefined) |
| 9 | received_pc | boolean | PC 側が受信済みかどうか |
3.1.2 🗄 fusen-meta(メタ情報)
表 3-5 fusen-meta スキーマ
| No | キー | 意味 |
|---|---|---|
| 1 | access_token | Google Drive アクセストークン(SW が参照) |
| 2 | pending_open | 次回起動時に開くノートの情報。{ id: string, t: number } |
3.1.3 🗄 fusen-logs(デバッグログ)
表 3-6 fusen-logs スキーマ
| No | フィールド | 意味 |
|---|---|---|
| 1 | t | タイムスタンプ(JST) |
| 2 | msg | ログメッセージ |
3.2 localStorage
セッション管理に使うlocalStorageのキーと値の一覧です。
3.2.1 🔑 認証・設定フラグ
表 3-7 localStorage キー一覧
| No | キー | 意味 |
|---|---|---|
| 1 | viewer_access_token | Google API アクセストークン |
| 2 | viewer_refresh_token | リフレッシュトークン(Vercel API 経由で更新) |
| 3 | viewer_expires_at | アクセストークンの有効期限(ms) |
| 4 | viewer_push_done | "true" なら通知設定済み → list へ直行 |
| 5 | pkce_verifier | OAuth PKCE の code_verifier(認証中のみ存在) |
| 6 | pending_note | PKCE 認証後に自動で開くノート ID |
| 7 | viewer_device_id | Web Push 用のクライアント識別子 |
| 8 | fusen_known_tags | 過去に入力したタグの履歴(サジェスト用) |
3.3 Google Drive ファイル
PCとiPhone間の中継に使うDriveファイルの種類と書き込み/削除責務を説明します。
表 3.3-1 Google Drive ファイル一覧
| No | ファイル名 | 書き込み | 読み取り・削除 | 意味 |
|---|---|---|---|---|
| 1 | notes_to_iphone.json | PC(gdrive.rs) | iPhone SW (push受信時) | PC → iPhone 未処理キュー。SW が受信して IndexedDB に保存後、当該 ID を除いて書き戻す(または全削除)。 |
| 2 | notes_from_iphone.json | iPhone (useBackgroundSend) | PC(gdrive.rs 30秒ポーリング) | iPhone → PC 未処理キュー。PC 受信後は処理済みアイテムを除いた残りのみ書き戻す。 |
| 3 | fusen_img_*.jpg | iPhone または PC | 受信側が処理後に削除 | 添付画像ファイル。 規則: fusen_img_YY..._N.jpg |
| 4 | push_devices.json | iPhone(lib/push.ts) が upsert | PC(webpush.rs)が 全端末へ Push 送信 | Web Push 宛先一覧。端末ごとの device_id / endpoint 等を保持。複数端末対応。 |
4 データフロー
起動・PC→iPhone受信・iPhone→PC送信・通知ON/OFFの4つのシーケンス図を示します。
4.1 アプリ起動(初回:Safari でインストール → Google ログイン → 通知許可)
初回起動(Safari→インストール→ログイン→通知許可)の全ステップを示します。
図 3-3 アプリ起動シーケンス(初回:インストール → 認証 → 通知許可)
4.2 PC → iPhone 受信(ユーザー体験 + 内部処理)
PCで「iPhoneに送る」を押した瞬間から、iPhoneのロック画面に通知が出て、ユーザーがタップして内容を確認するまでの全体フロー。
図 3-4 PC → iPhone 受信シーケンス
4.3 iPhone → PC 送信(ユーザー体験 + 内部処理)
iPhoneのwrite画面で「PCに送る」を押した瞬間から、PCに新しい付箋が開くまでの全体フロー。
図 3-5 iPhone → PC 送信シーケンス
4.4 ロック画面に表示 ON/OFF と再通知サイクル(REQ_IP_05)
「消す意思がないかぎりロック画面から消えない」体験を実現する ON/OFF 操作と、タップ後の再通知サイクル。 ユーザー体験の手順は ①〜⑥ で示す(REQ_IP_05 の①〜④に対応)。
図 3-6 ロック画面常駐サイクル(ON/OFF と再通知の実装フロー)
5 UI インタラクション
5.1 画面モード定義
リスト・ライトの 2 モードとその遷移条件を定義します。
表 5.1-1 画面モード定義
| No | モード | 状態 | 遷移トリガー |
|---|---|---|---|
| 1 | リストモード | Drive から同期した付箋を一覧表示している状態 | アプリ起動後の初期画面 |
| 2 | ライトモード | 1 枚の付箋を全画面で編集している状態(800ms 自動保存) | 付箋タップ or +ボタン |
図 3-7 画面モード遷移図
5.2 各モードの操作一覧
表 3-10 リストモードの操作
| No | 操作 | 対象 | 結果 |
|---|---|---|---|
| 1 | タップ | 付箋アイテム | ライトモードへ遷移 |
| 2 | 🔔 タップ | ロック画面に表示ボタン | locked フラグの ON/OFF 切り替え |
| 3 | 🗑️ タップ | 削除ボタン | 確認ダイアログ → Drive から削除 |
| 4 | + タップ | 新規ボタン | 空のライトモードへ遷移 |
表 3-11 ライトモードの操作
| No | 操作 | 対象 | 結果 |
|---|---|---|---|
| 1 | 文字入力 | エディタ | 800ms debounce で自動保存 |
| 2 | 画像貼り付け | エディタ | IndexedDB に保存・プレビュー表示 |
| 3 | ← タップ | 戻るボタン | リストモードへ遷移(保存確定) |
5.3 インタラクション・マトリックス
表 5.3-1 インタラクション・マトリックス
| No | 操作 | リストモード | ライトモード |
|---|---|---|---|
| 1 | タップ | ライトモードへ | - |
| 2 | 🔔 | locked ON/OFF | - |
| 3 | 🗑️ | 削除確認ダイアログ | - |
| 4 | 文字入力 | - | 自動保存 |
| 5 | ← 戻る | - | リストモードへ |
6 機能一覧
画面ごとの機能と、各機能の設計意図を記します。
6.1 メモ一覧画面(list)
表 6.1-1 メモ一覧画面の機能
| 機能 | 設計意図・工夫 |
|---|---|
| Drive → IndexedDB 同期 | 一覧を開くたびに notes_to_iphone.json を Drive から取得し、ローカルにない新着ノートを IndexedDB に取り込む。取り込み後は Drive ファイルを削除(Drive = 未処理キュー)。Drive 失敗時は IndexedDB だけで一覧表示を続ける(フォールセーフ) |
| 画像サムネイル | 添付画像がある場合、IndexedDB の Blob から URL.createObjectURL() で URL を生成してサムネイルを表示。アンマウント時に URL.revokeObjectURL() で解放する |
| ステータスバッジ | draft(下書き)/ sent(PC送信済み)/ PC受信 の3状態を sent_at フィールドの有無と received_pc フラグで判定して色分け表示する |
| 相対時間表示 | created_at から「3分前」「1時間前」「昨日」の形式に変換(formatRelativeTime())。 数字と絶対時刻を並べるより一目で新鮮度がわかる |
| 🔔/🔕 ロック画面常駐 | 後述(6.2) |
| 🗑️ 削除 | IndexedDB から削除後、Drive 上の同 ID ファイルも削除する |
| + 新規作成 | 新しい下書き ID を crypto.randomUUID() で生成し write 画面へ遷移 |
| 🔔 デバイス再登録(フッター) | silentReRegisterIfNeeded() を呼び出し、push_devices.json に自デバイスが存在しない場合のみ静かに再登録する。既存デバイスがいれば何もしない |
6.2 ロック画面常駐(🔔)
このアプリの核心機能。「消す意思がないかぎり、ロック画面から消えない」体験を実現する。
表 6.2-1 ロック画面常駐の仕組みと設計意図
| 観点 | 設計意図・工夫 |
|---|---|
| 通知表示の方式 | iOS ではメインスレッドの new Notification() が動かない。navigator.serviceWorker.ready → reg.showNotification() を使う。これが iOS で通知を出せる唯一の方法 |
| 重複防止 | reg.getNotifications() で既存通知を取得し、同じ data.id を持つものをすべて n.close() してから新規通知を表示する |
| タイトル・本文の生成 | # タイトル 行があれば it を通知タイトルに。なければ本文冒頭20文字をタイトルに使う。本文から画像タグ  を正規表現で除去してから40〜60文字を表示する |
| 楽観的更新 | ボタンを押した瞬間に UI の 🔔/🔕 を切り替える。SW 操作や IndexedDB 書き込みに失敗した場合のみロールバックする。ユーザーに「レスポンスが遅い」と感じさせない |
| 通知権限の動的確認 | Notification.permission === 'default' なら許可ダイアログを表示。denied なら UI を元に戻してエラーを表示する |
| 通知を消す権限 | ロック解除時に reg.active?.postMessage({ type: 'CLOSE_NOTIFICATION', tag }) で SW に通知クローズを依頼する。メインスレッドは通知を直接閉じられない |
| locked フラグの永続化 | locked: true/false を IndexedDB に書き込む。次回 Push 受信時に SW がこの値を参照して再通知を行うかどうかを決める |
| 効果音 | ON 時は bell_on.wav、OFF 時は bell_off.wav を Audio API で再生。操作の結果をユーザーが音で確認できる |
6.3 メモ編集画面(write)
表 6.3-1 メモ編集画面の機能
| 機能 | 設計意図・工夫 |
|---|---|
| contenteditable エディタ | contentEditable="true" の div で実装。React の value/onChange モデルを使わず DOM を直接操作。serializeEditor() が HTML → Markdown 形式に変換する |
| 3秒自動保存 | 入力のたびにタイマーをリセット。3秒間入力がなければ IndexedDB に保存(useAutoSave)。Drive は使わない。ネットワーク不要・オフライン動作 |
| バックグラウンド遷移時の強制保存 | visibilitychange で非表示になった瞬間にも保存(useVisibilitySave)。アプリを閉じてもデータが消えない |
| 📷 画像添付 | ファイル選択 → CropModal でトリミング → IndexedDB に Blob 保存 → buildImageFileName() でファイル名生成 → カーソル位置に ![]() を挿入。PCへ送るときに Drive に実際にアップロードされる |
| 🔷 Mermaid | MermaidModal でフローチャートのコードを書いて確定するとエディタに挿入される |
| ☑ チェックボックス | カーソルのある行を data-checkbox-line 属性を持つ <span> に変換(再押しで解除)。行頭が IMG ノードの場合は次の兄弟ノードに処理を移す特殊ケース対応あり |
| 🏷️ タグ | タグバーを展開。Enter または Space で確定。過去に入力したタグを localStorage(fusen_known_tags) から自動サジェスト。送信時に mergeKnownTags() で履歴に追加 |
| ← 一覧に戻る | 内容がある場合は IndexedDB に下書き保存してから list 画面へ遷移。保存はサイレントに行われ、確認ダイアログは不要 |
| 「iPhoneに置いておく」 | Drive を一切使わず IndexedDB のみに保存。ネットワーク不要。削除するまで端末に残り続ける |
| 「PCへ送る」 | 後述(6.4) |
6.4 「PCへ送る」
表 6.4-1 PCへ送る の処理ステップ
| ステップ | 設計意図・工夫 |
|---|---|
| ① トークン有効期限確認 | viewer_expires_at と Date.now() を比較。期限5分前を切っていたら送信前に Vercel /api/auth/refresh を呼んでトークンを更新する。送信中に突然期限切れにならないための先読み更新 |
| ② セッション切れ処理 | リフレッシュが失敗した場合は localStorage のトークンを削除し、login 画面へ遷移。エラーメッセージを5秒表示して消す |
| ③ 画像アップロード | 添付画像を Promise.all() で並列アップロード。直列より速い |
| ④ キューへの追記 | notes_from_iphone.json を Drive から読み取り、既存アイテムの末尾に新しいアイテムを追加して上書き(read-modify-write)。旧スキーマのファイルが残っていても自動変換して引き継ぐ後方互換処理あり |
| ⑤ IndexedDB に sent を記録 | 送信後、同 ID のレコードに sent_at をセットして IndexedDB を更新。一覧画面に「送信済み」バッジが表示される |
| ⑥ 成功フィードバック | 3秒間 backgroundSendSuccess = true にして UI に成功インジケータを表示。その後自動で消える |
6.5 通知許可・デバイス登録(push 画面)
表 6.5-1 プッシュ通知登録の処理ステップ
| ステップ | 設計意図・工夫 |
|---|---|
| ① 通知権限取得 | Notification.requestPermission() で OS レベルの許可ダイアログを表示。拒否された場合はエラーを表示して処理を停止 |
| ② 購読の再生成 | 既存の Push 購読があれば一度 unsubscribe() してから再登録する。クリーンな状態を保つためのリセット処理 |
| ③ VAPID 鍵での購読 | process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY(Vercel 環境変数)を使って pushManager.subscribe() を実行。この鍵は PC 側の WebPush 送信時の署名鍵と対になる |
| ④ デバイス ID の永続化 | crypto.randomUUID() で端末固有の device_id を生成。localStorage に保存し以降の再登録でも同一 ID を使う |
| ⑤ push_devices.json への upsert | Drive から push_devices.json を取得し、同 device_id のエントリを更新(または新規追加)して上書き保存。旧スキーマ(endpoint 直下方式)は自動的に新スキーマに移行する |
7 エラーハンドリング・リカバリ方針
7.1 通信・認証エラー
7.1.1 Drive API エラーとトークン自動更新
Drive API 呼び出し(ダウンロードやアップロード)が失敗した場合、drive.ts 内の downloadWithAutoRefresh 等によりトークンの自動リフレッシュが試行される(実施済み)。 リフレッシュにも失敗した場合は例外がスローされ、呼び出し元の React コンポーネント側でキャッチされる。 UI上のエラーフィードバック(トースト表示等)は ⚠️ 未実施。
7.1.2 認証切れ時のフォールバック
トークンリフレッシュ(Vercel API /api/auth/refresh)が 4xx 等で失敗し、リフレッシュトークン自体が失効していると判定された場合、localStorage からトークン情報を破棄し null を返す。 これによりアプリは未認証状態とみなされ、自動的にログイン画面(login ステップ)へフォールバックする(実施済み)。
7.1.3 PCアプリ側での Drive API 失敗(gdrive.rs)
PC アプリ(Rust)が Drive API 呼び出しに失敗した場合、Err(String) を返して Tauri コマンド経由でPCフロントエンドにエラーを通知する。 PC側のアクセストークンは期限到来の 60 秒前に自動リフレッシュされ、失敗時は「Googleの認証が切れました」と返す。 PCフロントエンドでのエラーダイアログ表示(トースト等)は ⚠️ 未実施。
7.1.4 PCからの Web Push 送信失敗
PC アプリから APNs / FCM へのプッシュ送信が失敗した場合(201 以外の HTTP ステータス)、エラーコードを含む Err を返す。 **PC側での送信失敗時の自動リトライ機構は ⚠️ 未実施。**送信失敗時は iPhone に通知が届かないまま終了する。
7.2 バックグラウンド処理・リカバリ
7.2.1 Push 受信時のフォールバック(画像DL失敗時)
Service Worker (worker/index.js) 内での Push 受信処理では、画像(fusen_img_*)の Drive ダウンロードがネットワークエラー等で失敗した場合でも処理を中断しないフェイルセーフ機構がある。 画像取得に失敗した場合でも、テキスト本文のみを IndexedDB(fusen-drafts)に保存し、ユーザーへの OS 通知を確実に表示する(実施済み)。
7.2.2 デバッグログの運用方針(fusen-logs)
UIを持たない Service Worker 内で発生した処理結果やエラー(トークン取得失敗、画像保存失敗など)は、IndexedDB の fusen-logs ストアに対して fire-and-forget で記録される(実施済み)。 後から Chrome DevTools 等で内部状態や Push 受信時のエラー原因を追跡できるようになっている。
7.2.3 iOS特有の制約とリカバリサイクル
iOS の PWA 環境では、バックグラウンドでの通知タップ時(notificationclick イベント)が正常に発火しない・あるいは Web API へのアクセスが制限されるケースがある。 この制限に対するリカバリとして、通知受信時に次回開くべきノート ID を IndexedDB に保存(pending_open)し、次にユーザーがアプリを開いた際(page.tsx マウント時)に自動的にそのノートを表示するサイクルを構築している(実施済み)。
7.2.4 Service Worker の更新
skipWaiting() + clients.claim() で新しい SW が即時有効化される。バグ修正版をリリースした際に古い SW が動き続けることはない。
8 改版履歴
表 8-1 改版履歴
| No | バージョン | 日付 | 変更内容 |
|---|---|---|---|
| 1 | 1.0 | 26-04-19 | 新規作成。005_VIEWER_SCREENS.html / 007_VIEWER_CODE_STRUCTURE.html / 004_PWA_DATA_FLOW.html の内容を統合・整理 |
| 2 | 1.1 | 26-04-20 | 4.4 にロック画面常駐体験(REQ_IP_05)の再通知サイクル(①②③④)を追加。4.2 に REQ_IP_05 への参照を追加 |
| 3 | 1.2 | 26-04-20 | 4.4 の再通知フローを実態に合わせて修正。iOS では notificationclick が発火しないため pending_open + page.tsx が再通知を担う仕組みを図入りで明記。2.2 の notificationclick 説明に iOS 制約を追記 |
| 4 | 1.3 | 26-04-24 | モジュール構造図を graph LR(横向き)に変更。スクロールなしで全体が見えるよう改善。 |
| 5 | 1.4 | 26-04-27 | セクション6「機能一覧」を新規追加。メモ一覧・ロック画面常駐・メモ編集・PCへ送る・プッシュ登録の設計意図を記載。旧6→7、旧7→8に繰り下げ。 |