2026年3月9日 - Exploreページの「見えない壁」を壊した日
2026年3月9日 - Exploreページの「見えない壁」を壊した日 Mintor開発日記 --- 今日やったこと(ダイジェスト) Exploreページに長期間潜んでいた根本的なバグを発見・修正。加えてカードUIの細かい改善を多数実施。 --- SWRフェッチャーの二重展開バグ 今日一番大きかった発見。 Exploreページの「人気・新着・急上昇ミックスフィード」が、ずっとフォールバックデータを表示していた。 つまり、APIで作った「人気+新着+急上昇のミックスフィード」機能は一度も使われていなかった。ずっと古いフォールバックのデータが表示されていた。 修正は1行:data?.data?.items → data?.items --- 管理者コンテンツの後回し Mintorは開発初期なので、コンテンツの大半が管理者(自分)のもの。記事188件中186件が自分。 Exploreページは「発見」のためのページなのに、自分のコンテンツばかり表示されていた。 対策:管理者のuser_idをハードコードして、APIレスポンスで他ユーザーのコンテンツを先に、管理者のを後ろに配置。 シンプルだけど効果絶大。他のユーザーのプロダクトや記事がちゃんとトップに表示されるようになった。 --- プロダクトが4件しか表示されない問題 Community Statsには「10プロダクト」と表示されているのに、Exploreには4件しか出ない。 原因:APIが .not('published_at', 'is', null) でフィルタしていたが、公開済みプロダクトの6件が published_at = NULL だった。 is_draft = false(公開済み)なのにpublished_atが未設定という不整合。新規作成時にpublished_atをセットしていなかった。 修正: 既存データをUPDATEで埋め(published_at = created_at) 新規作成・編集時にpublished_atを自動設定 APIのフィルタ条件を修正 --- カードUIの改善 日付表示追加: 記事カード・質問カードに「15分前」「1日前」などの相対日時を表示 フォローボタン統一: 全variantでニューモーフィズムシャドウ統一、アイコンも統一 料金表示修正: 相談サービスの「/分」→「/回」に修正 アバター修正: 関連記事セクションでアイコン→実際のアバター画像に すりガラスアイコン: プロダクトカードのアイコンに記事と同じfrosted glass効果 --- 学び SWRのデータ展開: カスタムフェッチャーがレスポンスを加工する場合、hookでのアクセスパスに注意 NULLフィルタの罠: published_at IS NOT NULLのような条件は、データ投入時の整合性が前提 Exploreページの本質: 「発見」のページでは自分のコンテンツより他者のコンテンツが重要 --- Mintor開発日記 | Generated with Claude Code
2026年3月8日 - 「ようこそ」を言えるようになった日
2026年3月8日 - 「ようこそ」を言えるようになった日 Mintor開発日記 --- 今日やったこと オンボーディング通知シーケンスの設計・実装(8通・21日間) 通知の多言語対応(JSON形式でDB保存、tText()で表示時翻訳) 通知ページのリファクタリング(fetchロジックの重複解消) ナビゲーションメニューの並び替え(全4箇所統一) サイドバーヘッダー画像のクリップ修正 既存26ユーザーへのオンボーディング通知配信 LPモバイル改行最適化(全セクションの文章が自然な位置で改行されるように) --- なぜやったのか ユーザーが登録してくれても、Mintorは何も声をかけていなかった。 「ようこそ」も「まずはこれをやってみて」もない。登録した瞬間から放置。それに気づいて、すごく申し訳なくなった。 --- 迷ったこと 何通送るか。 業界標準は14日間で4〜6通。でもMintorは機能が多い。プロダクト、記事、Q&A、相談サービス、Discord、Stripe……。全部紹介したいけど、多すぎると嫌がられる。 結局3週間に伸ばして8通にした。約2.5日に1通。ギリギリ許容範囲だと思う。 文面のトーン。 最初に書いた文面は「エンジニアの世界を探索しよう」みたいな、どこにでもあるSaaSの通知だった。Mintorのコンセプトに合っていない。 「ひとりで抱え込まなくて大丈夫」「作っている過程も、誰かの力になります」。こっちのほうが、Mintorらしい。書き直してよかった。 既存ユーザーに「ようこそ」って言っていいのか。 もう使ってくれている人に「ようこそ」は変かもしれない。でもいいと思った。改めて歓迎したかった。 --- 気づいたこと 通知の文面を書くことは、自分のサービスが何者なのかを言語化する作業だった。 「あなたの経験が、誰かの『わからない』をやさしくほどく力になります」 この一文を書いた時、Mintorのことが前より好きになった気がする。 あと、コードの重複(fetchロジックが2箇所にあった)を直したら、言語切替が一発で動くようになった。リファクタリングは面倒だけど、やった後はいつも「もっと早くやればよかった」って思う。 LPのモバイル表示で、「個人開発コミュニティ」が「個人開発コミュ/ニティ」で切れていた。ユーザーからのフィードバック。翻訳テキストに\nで改行位置を明示して、<br className="md:hidden" />でモバイルのみ改行する方式にした。PCには影響なし。「。」の後で改行するだけで、ぐっと読みやすくなる。 --- 今日の数字 | 指標 | 値 | |------|-----| | オンボーディング通知 | 8通 | | 配信期間 | 21日間 | | 対応言語 | 2(ja/en) | | 配信ユーザー数 | 26人 | | INSERT件数 | 208件 | | ナビ修正箇所 | 4箇所 | | LP改行修正セクション | 6箇所 | | 変更ファイル | 15ファイル | --- 📝 Mintor開発日記 | https://mintor.dev --- 📝 Mintor開発日記 | 🤖 Generated with Claude Code
親子で楽しむ絵合わせゲーム「ピクマ α版」リリースしました!
はじめまして。 ジョブホッパー宮崎と申します。 この度、初めての個人Webサービスを開発してα版をリリースしました。 リリースしたα版の「ピクマ」というサービスについてざっくりと内容をまとめた記事を書きましたので、もしよろしければご覧いただけますと嬉しいです。 ▼記事詳細は下記URL https://note.com/jhpw/n/n045707eb4e17 引き続き、よろしくお願い致します。
READMEの全面更新 - Mintor開発日記
READMEの全面更新 - Mintor開発日記 2026-02-03 今日のハイライト README.mdを2026年2月時点の最新状態に全面更新した。機能追加やアーキテクチャの変化に伴い、実態と乖離していた記述を整理して正確な情報に差し替えた。 実装内容 ドキュメント README.mdの全体を2026年2月時点の最新情報に更新 現在の機能一覧、技術スタック、セットアップ手順を反映 古くなった記述や不要なセクションを整理 まとめ READMEはプロジェクトの顔であり、新しいコントリビューターや自分自身が振り返る際の出発点になる。定期的な更新で信頼できるドキュメントを維持することが大切だと改めて感じた。 --- Mintor開発日記 | Generated with Claude Code
2026年3月8-9日 - 38箇所直した日、あるいは「統一感」との戦い
2026年3月8-9日 - 38箇所直した日、あるいは「統一感」との戦い Mintor開発日記 --- 今日やったこと(ダイジェスト) 1日で38項目。多すぎるので、テーマ別にまとめる。 通知をカードにした 通知をクリックしたら、Mintorからの「メッセージカード」が開くようにした。ミントグラデーションのヘッダーにMintorのロゴ、通知タイプのバッジ、本文、CTAボタン。外部リンク(Discord招待など)は新しいタブで開く。 ついでに使われていないコンポーネントを3つ削除した。NotificationDropdown、NotificationBadge、UserArea。コードが減るのは気持ちいい。 ボタンの「統一感」問題に向き合った Mintorには似たようなボタンが何種類もある。フォロー、応援する、シェア、いいね、ブックマーク。それぞれ別のタイミングで作ったから、微妙にスタイルが違う。 フォローボタンの問題: variant(default、compact、icon-only、detailed)ごとに独自のシャドウ定義があった 「未フォロー」のアイコンがチェックマーク(紛らわしい) ユーザー一覧とユーザー詳細でアイコンが違う 応援ボタンに比べて地味すぎる 全部直した。シャドウは shadow-neumo-raised / shadow-neumo-inset に統一。アイコンは全variantで共通化(未フォロー=+マーク、フォロー中=チェック、ホバーで×マーク+赤色)。未フォロー時にミントのボーダーを追加。コード量は92行減って74行増えた。つまり18行減。統一すると減る。 シェアボタンの問題: ユーザー詳細ページで、シェアボタンが独立した行に横幅いっぱいで表示されていた。スカスカ。フォロー・応援と同じ行にアイコンボタンとして配置した。 SNSリンクボタンの問題: ユーザー詳細、サイドバー、相談サービスの提供者カードで、SNSリンクのスタイルがバラバラだった。ユーザー詳細のニューモフィズムスタイルに3箇所全部揃えた。 プロダクト詳細ページを大改造した アクションバー(いいね/ブクマ/シェア)をカルーセル直下に移動 ユーザー情報をメインから削除(サイドバーの作成者カードに集約) 外部リンクをExternalLinkCardでリッチに表示 投稿日をアクションバー内に移動 通報ボタンを三点メニューの中に格納 細かいバグを大量に潰した 画像カルーセルが最後の画像から表示される問題 画像モーダルのモバイル対応(矢印をインジケーターに統合) R2アップロードで拡張子が二重になるバグ(.webp.webp) 下書き保存後のリダイレクト先がおかしい フィルターのプルダウンがカードの後ろに隠れる(z-index) 相談サービスカードのユーザー名が途切れる 相談サービスの料金が「3,000/分」と表示される(正しくは「/回」) Exploreで相談サービスの無料バッジが表示されない --- なぜやったのか 統一感がないUIは、ユーザーに「雑に作ってる」と思われる。 フォローボタンのvariantが4つあって、それぞれ独自のシャドウ定義を持っていた。書いた時はそれで良かったんだろう。でも並べて見ると、同じ「フォロー」なのに場所によって影の濃さが違う。ボタンの高さも違う。アイコンまで違う。 1つ1つは些細な差だけど、積み重なると「このサービス、ちゃんと作ってるのかな?」という印象になる。 --- 迷ったこと フォローボタンを目立たせるべきか。 応援ボタン(グラデーション)と比べて、フォローボタン(白背景)は地味だった。でも「フォロー」は「いいね」と同じ軽いアクション。応援は特別なアクション。この差は意図的であるべき。 結論: フォローはActionButton系(白背景+ニューモ)のままにして、ミントのボーダーだけ追加。存在感は少し上がるけど、応援ボタンより控えめ。 応援系ボタンのバラつきをどうするか。 プロフィールではSupportUserButton(グラデーション、バッジ/Mint選択モーダル)、サイドバーではSendMintButton(白背景、直接Mint送信)。見た目も導線も違う。 調べてみたら、これは意図的な差だった。プロフィール=「この人を応援する」(選択肢あり)、サイドバー=「記事が良かったからチップ」(直接)。文脈が違うからUIも違っていい。 --- 気づいたこと 「全部調査してから直す」が正解。 最初はフォローボタンだけ直すつもりだった。でも「他のページではどうなってる?」と網羅的に調べたら、SNSリンクボタンのスタイル不一致も見つかった。相談サービスの料金表示バグも見つかった。1つ直すと芋づる式に出てくる。 コード量は統一すると減る。 フォローボタンの独自シャドウ定義は、サイズ(sm/md/lg) × 状態(active/inactive) × hover の組み合わせで膨大だった。Tailwindのユーティリティクラス(shadow-neumo-raised)に統一したら、一気にシンプルになった。 z-indexは親を見ろ。 フィルターのドロップダウンにz-[100]が付いていたのに、カードの後ろに隠れた。原因は親要素のスタッキングコンテキスト。子のz-indexがどんなに高くても、親のz-indexで天井が決まる。 --- 今日の数字 | 指標 | 値 | |------|-----| | 完了項目 | 38 | | コミット数 | 19 | | 削除したコンポーネント | 3 | | フォローボタンvariant統一 | 4種類 | | SNSリンクスタイル統一 | 3箇所 | | バグ修正 | 14件 | | コード純減 | -18行(フォローボタンのみ) | --- 技術メモ ニューモフィズムの設計システム Mintorのボタンには3段階のシャドウがある: これをActionButton、フォローボタン、SNSリンクで統一した。独自のRGBA値を書かなくていいので、後から色味を変えたくなった時も1箇所変えるだけで済む。 group-hoverでアイコン切り替え フォロー中のボタンにホバーすると、チェックマークが×マークに変わる。CSSだけで実現: JavaScriptのstate管理不要。Tailwindのgroup/group-hoverは便利。 --- 📝 Mintor開発日記 | https://mintor.dev --- 📝 Mintor開発日記 | 🤖 Generated with Claude Code
2026年3月7日 - 通知の居場所を変えた日
2026年3月7日 - 通知の居場所を変えた日 Mintor開発日記 --- 今日やったこと 通知ベルをヘッダーから外して、アカウントメニューの中に入れた。 Discordに自動でリリース情報を投稿するスクリプトを作った。 その他、たくさんのバグ修正とUI改善。 --- なぜやったのか ヘッダーにベルアイコンがあると、アバターと並んでごちゃごちゃする。 「アカウントメニューを開いたら通知も見れる」の方がシンプル。 PC でもモバイルでも同じ体験にしたかった。 --- やってみたこと 通知をアカウントメニューに統合 ヘッダーのベルアイコンを外した。 代わりにアバターに赤い未読バッジを付けた。 メニューを開くと「通知」リンクがある。未読数も表示される。 モバイルも同じ。設定リンクを外して通知リンクに置き換えた。 Discordリリース通知 開発の進捗をDiscordに自動投稿できるスクリプトを作った。 技術的な表現を自動でユーザー向けに変換してくれる。 テストチャンネルで見た目を確認してから、本番チャンネルに投稿する流れ。 その他の改善 iPhoneで撮った写真がアップロードできない問題を修正 モバイルメニューに「記事」が抜けていたのを追加 レビュー表示の不具合修正 ヘッダーメニューが他の要素に隠れてしまう問題を修正 --- 困ったこと 通知の未読数を取得する仕組みが、もともとベルアイコンのコンポーネントに埋まっていた。 PCのヘッダーとモバイルのメニュー、両方で使いたい。 共通のフックとして切り出すことで解決した。 --- 気づいたこと 「動いてる感」は大事。 Discordにリリース情報を流すだけで、サービスが生きている感じがする。 ユーザーが参加したとき「あ、ちゃんと更新されてるんだ」と思ってもらえる。 コードを書くだけじゃなくて、書いたことを伝えるのも大事な仕事。 --- 今日の数字 | 項目 | 数値 | |------|------| | 改善項目 | 18件 | | 新スクリプト | 1つ | | 新フック | 1つ | --- Mintor開発日記 https://mintor.jp --- 📝 Mintor開発日記 | 🤖 Generated with Claude Code
Exploreページ情報量改善 + モバイルUI修正 - Mintor開発日記
Exploreページ情報量改善 + モバイルUI修正 - Mintor開発日記 2026-03-06 | 5件の作業完了 今日のハイライト <!-- ここに一言サマリーを書く --> 実装内容 新機能 Exploreページ情報量改善 P0(トレンドタグチップ・VIEW ALL・統計強化・ランキングUI刷新) Exploreページ NEW CREATORSセクション追加 Exploreページ競合調査レポート作成(note/Zenn/Qiita/ココナラ/BOOTH/MENTA 6社分析) バグ修正 モバイルメニュー記事追加・ユーザーアイコン統一・ハンバーガー挙動修正 相談サービス料金計算バグ修正(consultation_feeをmin_duration基準に統一) 今日学んだこと <!-- ここに学び・気づきを書く --> まとめ <!-- ここにまとめを書く --> --- Mintor開発日記 | Generated with Claude Code
ユーザー投稿から見つけた6つのUIバグを一気に修正した話 - Mintor開発日記
ユーザー投稿から見つけた6つのUIバグを一気に修正した話 - Mintor開発日記 2026-03-03 | 6項目の作業完了 | 10ファイル変更 今日のハイライト 実際にユーザーがnote記事を投稿してくれたことで、リンクカードの表示崩れやサイドバーの表示名問題など、開発中には気づけなかったUIバグが一気に見つかった。ユーザーフィードバックの大切さを実感した1日。 実装内容 🐛 バグ修正(4件) カルーセルが最後の画像で開くバグ プロダクト詳細ページ(/products/pikuma等)を開くと、画像カルーセルが最後の画像からスタートする問題。SwiperのcenteredSlides={true}とslidesPerView="auto"の組み合わせで、initialSlide未指定だと最後のスライドがアクティブになるケースがあった。initialSlide={0}を追加するだけで解決。 サイドバーのユーザーカードで@ハンドルが表示名になっていた サイドバーのユーザーカードで、「めいこ / @めいこ」のように表示名とハンドルが同じになっていた。原因はDBの構造理解不足: profiles.username = 表示名(日本語OK、例:"めいこ") profiles.slug = URLハンドル(英数字、例:"meiko") @{username} → @{slug || username} に変更。また、元々displayNameにprofiles.display_nameを渡そうとしていたが、profilesテーブルにそのカラムは存在せず400エラーの原因になっていた。 LinkCardのhydrationエラー Markdownレンダラー内でリンクカードが表示される際、<p>タグの中に<div>や<h3>がネストされてReactのhydrationエラーが発生。全ブロック要素を<span className="block ..."> に変更して解決。 ファビコン・OGP画像のマージンずれ prose(Markdown)CSS のグローバルルール img { margin: 24px 0 } がLinkCard内の画像にも適用されて、画像が下にずれる問題。!m-0で打ち消し。 ✨ 新機能(2件) LinkCard横長レイアウト(variant="horizontal") ユーザーがnote.comの記事URLを貼ったところ、縦型のカードが大きすぎて画像にタイトルが被る問題が発覚。note.comのリンクカードを参考に横長レイアウトを実装: テキスト左 + 画像右 画像は16:9(aspect-video)でobject-contain全体表示 タイトルはtext-lg font-boldで大きく 説明文はline-clamp-3で3行まで LinkCardSkeleton横長バリアント ローディング中のスケルトンも横長レイアウトに対応。variantをLinkCardからSkeletonに伝達。 今日学んだこと SwiperのcenteredSlidesとinitialSlide centeredSlides={true}を使う場合、initialSlide={0}を明示しないと予期しないスライドがアクティブになることがある。特にslidesPerView="auto"との組み合わせで発生しやすい。 Markdown内のHTML制約 <p>の中には<div>、<h3>、<p>などのブロック要素を入れられない(HTML仕様)。Reactは厳密にチェックしてhydrationエラーを出す。対策は<span className="block">でインライン要素にしつつblock表示にすること。 prose CSSの影響範囲 TailwindのproseCSSはimgに対してグローバルにマージンを付与する。カスタムコンポーネント内の画像にも影響するため、!m-0で明示的に打ち消す必要がある。 DBスキーマの確認は必須 「display_nameカラムがあるはず」と推測でコードを書くと400エラーになる。必ず型定義(supabase.ts)やDB構造を確認してから実装すること。 まとめ 今回の修正は全て「ユーザーが実際にコンテンツを投稿した」ことで発覚したバグ。開発中のテストデータでは再現しにくい、リアルなユースケースでしか見えない問題ばかりだった。プロダクトは使われて初めて磨かれる。ユーザーに感謝。 --- 📝 Mintor開発日記 | 🤖 Generated with Claude Code
i18n大量作業 Phase A-1c〜A-5e完了 - Mintor開発日記
i18n大量作業 Phase A-1c〜A-5e完了 - Mintor開発日記 2026-02-28 | 58ファイル・900+文字列のi18n化を1日で完了 今日のハイライト Phase A(部分i18n済みファイルの漏れ修正)の残り全てを1日で一気に完了。 前回のPhase 1〜9a(新規i18n化)に続き、既にt()を使っているが日本語ハードコードが残っているファイルを徹底的にクリーンアップした。 数字で見る成果 | 指標 | 値 | |------|-----| | 完了フェーズ | 11(A-1c〜A-5e) | | 編集ファイル数 | 58 | | i18n化した文字列 | 900+ | | コミット数 | 18 | | TypeScript新規エラー | 0 | 実装内容 Phase A-1c〜A-2b: common/・consultation/の漏れ修正(12ファイル ~105文字列) UnifiedMarkdownEditor、SendMintModal、EnhancedSkillSearch等の残留ハードコード修正 ProviderInfoCard、ServiceDetailsCard: メンバー歴/レビュー/料金ラベル PendingReviewBanner、ServiceSuspensionBanner: defaultValue一括除去 Phase A-2c〜2e: consultation/残り(16ファイル ~263文字列) IntegrationStatusDashboard: Google Calendar統合状態の全文字列 LineNotificationSettings: LINE通知設定UI Meeting系・小型コンポーネント7ファイル ProposalCard/BookingList等残り6コンポーネント Phase A-3: pricing/mypage/mobile(11ファイル ~42文字列) 各コンポーネントの散発的な漏れを修正 Phase A-4: dashboard/questions/products(4ファイル ~35文字列) Phase A-5a〜5e: app/mypageページ全体(15ファイル ~459文字列) ここが今日最大の作業量。mypage配下のページコンポーネント全てを処理した。 小〜中規模(7ファイル ~65文字列) error/layout/posts/profile: 基本的なi18n追加 consultation-availability: 曜日配列をDAY_KEYS+useMemoパターンに変換 consultation-daily-schedule: 全UI文字列+locale対応日付 favorites: defaultValue 15箇所を一括除去 大規模(3ファイル ~144文字列) dashboard: analysisData関数内60文字列。投稿/エンゲージメント/Mint分析の全ラベル・インサイト points: ACTION_TYPE_LABELSをlabelKeyパターンに変換(80文字列) reviews: reply関連4文字列 記事・商品・相談系(5ファイル ~250文字列) articles/products: || 'fallback'パターン一括除去 + 公開/下書きダイアログ products/drafts: 進捗テキスト+locale対応日付 consultation-services: 最大のファイル。80+文字列(toast/提案ステータスフィルタ/承認却下フロー/ダイアログ全て) consultation-packages: useTranslationsを新規導入して35文字列を全i18n化 今日使った技術パターン パターン1: labelKeyパターン(モジュールレベル定数対応) Reactフック(useTranslations)はコンポーネント内でしか使えない。モジュールレベルで定義されたオブジェクトには翻訳キーだけ保持し、使う側でt()解決する。 パターン2: DAY_KEYS + useMemoパターン 曜日名のようなlocale依存の配列も同様。 パターン3: defaultValue一括除去 t('key') || 'fallback'は翻訳キーが揃っていれば不要。JSONに確実にキーが存在することを確認してから、フォールバックを系統的に除去した。 パターン4: dangerouslySetInnerHTML + t.raw() HTMLタグを含む翻訳(<strong>等)はt.raw()で取得してdangerouslySetInnerHTMLで挿入。 効率化のポイント Task Agent並列実行: 大きなファイル(dashboard 60文字列、points 80文字列、consultation-services 80文字列等)は専用のTask Agentに委譲して並列処理 Node.jsスクリプトでJSON更新: 翻訳キーの追加はfs.readFileSync → merge → fs.writeFileSyncのスクリプトで一括処理 TypeScriptチェックを各フェーズ後に実行: 既知エラー3件以外の新規エラーがないことを毎回確認 残りの作業 Phase A(部分i18n済みファイル)は完了。残りは: Phase A-6: app/publicページ(~15ファイル、~250文字列) Phase A-7: app/adminページ(~10ファイル、~500文字列) Phase B〜E: 新規i18n化(~189ファイル) 学び 1ファイル80文字列超のような大規模ファイルでも、パターンが確立していれば機械的に処理可能 || 'fallback'パターンはi18n初期実装の痕跡。翻訳JSONが揃ったら一掃すべき consultation-packagesのように翻訳フック未導入のファイルは、導入時に全文字列を一気にi18n化するのが効率的 --- 📝 Mintor開発日記 | 🤖 Generated with Claude Code
大規模i18n対応 Phase 1〜9a完了 - Mintor開発日記
大規模i18n対応 Phase 1〜9a完了 - Mintor開発日記 2026-02-26 | 42ファイル・600+文字列のi18n化 今日のハイライト Mintorの全コンポーネントを対象とした系統的な多言語対応(i18n)プロジェクトを実施。 9フェーズに分けて42ファイル、推定600以上のハードコード日本語文字列をnext-intlのuseTranslationsに移行した。 数字で見る成果 | 指標 | 値 | |------|-----| | 完了フェーズ | 9(Phase 1〜9a) | | 編集ファイル数 | 42 | | i18n化した文字列 | 600+ | | 新規翻訳ネームスペース | 25+ | | TypeScript新規エラー | 0 | 実装内容 🌐 多言語対応(i18n) Phase 1: 共通カードコンポーネント(3ファイル) SquareCard、VerticalGridCard、UnifiedListCard Phase 2: コメント・通報・通知(3ファイル) CommentSection、ReportButton、NotificationBellDropdown Phase 3: フォームコンポーネント(4ファイル) ProductFormUnified、QuestionForm、ConsultationServiceForm、ArticleEditor Phase 4-5: 相談サービス(11ファイル) 予約/レビュー/チャット/提案/カレンダー/パッケージ/カード/セクション Phase 6: ダッシュボード・収益(6ファイル) InteractiveGoalSetting、ActivityCalendar、BalanceCard、StripeAccountSettings、MintAnalyticsDashboard、MintHistory Phase 7: 管理画面(4ファイル) Create/EditNotificationModal(共通namespace admin.notifications.common で重複排除) UnifiedNotificationPanel、LineBotTestPanel Phase 8: モバイル(8ファイル) BottomNavigation、FloatingActionButton、MobileMenu(フォールバック全削除) MoreMenuModal、MobileHeader、MobileCommentInput、MobileImageUpload、MobileUserMenu Phase 9a: 認証・オンボーディング(3ファイル) PasswordAddForm/ChangeForm(共通バリデーション Auth.passwordValidation) OnboardingGuideModal(locale === "ja" ? ... 三項演算子パターンを完全排除) 設計のポイント パターン1: 共通翻訳の集約 Create/Editモーダルのように同じフィールドラベルを使うコンポーネントは、commonサブネームスペースに集約して重複を排除。 パターン2: 配列のインデックスアクセス セットアップ手順などの配列データは、インデックスベースの翻訳キーに変換。 パターン3: locale三項演算子の排除 locale === "ja" ? "日本語" : "English" パターンを t('key') に統一。 翻訳ファイル側で言語ごとの値を管理する正しいi18nパターンに移行。 残りの作業 ~189ファイルが未対応。優先度順: 設定画面 (GoogleCalendarSecure, StripeConnect) 検索 (InstantSearch) ホーム画面 (CommunitySection, CategoryFilter) LP (PersonaProblems, PersonaFaq, PersonaHowItWorks等) common系 (ProductSelector, ErrorBoundary, PWAInstallPrompt等) 学び 翻訳キーの追加は一時的なNode.jsスクリプトでJSONに一括挿入するのが効率的 既存の翻訳キー名と衝突する場合がある(例: Auth.passwordが文字列→ネストオブジェクトにできない) フォールバック(t('key') || 'デフォルト')は翻訳キーが揃えば不要。削除して翻訳を信頼する設計にすべき --- 📝 Mintor開発日記 | 🤖 Generated with Claude Code
記事一覧ページ無限スクロール&記事詳細UI統一 - Mintor開発日記
記事一覧ページ無限スクロール&記事詳細UI統一 - Mintor開発日記 2026-02-22 | 記事ページの使い勝手を大幅改善した一日 今日のハイライト 記事一覧ページが50件で頭打ちだった問題を無限スクロールで解決。173件の開発日記が全て閲覧可能に。記事詳細のアクションバーもカードと統一し、一貫したUIに。 実装内容 ✨ 無限スクロール実装 記事一覧ページ(/articles)に無限スクロールを実装。 サーバーアクション getArticlesPage(offset, limit) を追加し、20件ずつのページネーションに対応 IntersectionObserver で画面下部200px手前で自動的に次ページを読み込み カウント取得ロジック(いいね・ブックマーク・コメント)を attachArticleCounts 共通関数に整理 ハイドレーション不一致を防ぐため、センチネル要素はクライアントマウント後にのみ表示 🎨 記事カード・詳細ページのUI統一 記事カードにコメントボタン追加: VerticalGridCard で type === 'article' でもコメントボタンを表示 記事詳細アクションバー統一: 独自の <button> だったコメントボタンを ActionButton コンポーネントに統一 配置をTwitter/X風に統一: ❤️💬(左)... 🔖シェア(右端) カード高さ揃え: VerticalGridCard のA案に h-full を追加し、グリッド内で高さを統一(全一覧ページに自動適用) 🐛 バグ修正 LinkCardハイドレーションエラー: Markdown内の単独URLリンクを含む <p> タグを <div> に変換し、<p> 内に <div> がネストされる不正なHTML問題を修正 記事編集ボタン: product_id が無い記事でも投稿者本人には編集ボタンを表示するよう修正 📊 開発日記の一括投稿 scripts/post-daily-logs.js を作成し、Supabaseのarticlesテーブルに開発日記を一括投稿 Service Role Key(RLSバイパス)を使用 173件の開発日記が全てSupabaseに投稿済み 技術メモ IntersectionObserverとSSRの共存 Next.jsのサーバーコンポーネントからクライアントコンポーネントに hasMore を渡す際、センチネル要素がサーバーとクライアントで一致しないハイドレーションエラーが発生。mounted フラグで制御することで解決。 rehypeRewriteでのHTML構造修正 @uiw/react-markdown-preview の rehypeRewrite フックで、リンクのみを含む <p> タグを検出し <div> に変換。URLテキストとhref属性が一致する場合のみ変換対象とし、通常のテキスト内リンクには影響しない。 明日やること Exploreページの情報量改善 一時スクリプトの整理 --- 📝 Mintor開発日記 | 🤖 Generated with Claude Code
カードUI改善・応援バッジ・コメント状態修正 - Mintor開発日記
カードUI改善・応援バッジ・コメント状態修正 - Mintor開発日記 2026-02-21 | カードの使いやすさを一気に底上げした日 今日のハイライト SNSでよく見る「いいね左・ブックマーク右」のレイアウトをカード全体に導入。さらにコメント済みの色が表示されないバグ修正、応援バッジにアバター表示、Threadsシェア対応など、細かいけどユーザー体験に直結する改善をまとめて実施しました。 数字で見る成果 | 指標 | 値 | |------|-----| | 修正ファイル数 | 8 | | 対応カードコンポーネント | 4(UnifiedListCard / VerticalGridCard / SquareCard / BadgeCount) | | Threads追加箇所 | 6ページ | | コミット数 | 4 | 実装内容 カードアクションボタンの配置変更 Before: ❤️ 💬 🔖 が全部左寄せ After: ❤️ 💬(左)... 🔖(右端)のTwitter/X風レイアウト 3つのカードコンポーネント(UnifiedListCard / VerticalGridCard / SquareCard)すべてに適用。ml-auto でブックマークボタンを右端に配置するシンプルな実装です。 コメント済みボタンの色付き修正 コメントしたプロダクトのカードで💬ボタンに色がつかない問題を修正しました。 原因は2つ: VerticalGridCard / SquareCard のコメントボタンに active プロパティが渡されていなかった ユーザー詳細ページ・Exploreページで comments テーブルからコメント済み状態を取得していなかった 修正: 各カードの型定義に hasCommented を追加 comments テーブルからユーザーのコメント済みIDを取得する処理を追加(likes/bookmarksと同じパターン) 応援バッジに応援者アバター表示 BadgeCountコンポーネントに、応援してくれた人のアバター画像を重ねて表示する機能を追加。 APIのlimitを1→20に変更 バッジデータからユニークな応援者を最大5人分抽出 -space-x-1.5 で重ねて表示(よくあるGitHubのContributors風UI) 応援バッジモーダルのネスト問題修正 「応援する」→「バッジを贈る」でモーダルの中にモーダルが開いてしまう問題を修正。BaseModalを閉じてからBadgeListModalを直接起動するように変更しました。 Threadsシェアボタン追加 Meta Threadsをシェアボタンに追加。UnifiedShareButton / DetailPageActionButtonsの定義追加と、6ページのplatforms配列に追加。 シェアボタンslideOut幅改善 slideOutバリアントのシェアボタンが w-full クラス指定時にカード幅いっぱいに広がるように修正。固定ピクセル幅から親要素幅に追従するようにしました。 今日学んだこと カードのアクションボタン配置は意外と印象が変わる。左寄せから「左右分離」にするだけで、一気にSNSっぽい見慣れた操作感になる コメント状態の取得は likes/bookmarks と同じパターンだが、テーブルが comments(product_id)と異なるので注意が必要 モーダルのネストは気づきにくいバグ。BaseModal内でさらにモーダルを開くコンポーネントを使うと発生する まとめ 今日は「カードの細かいけど大事なUI改善」に集中した日でした。ボタン配置、色付き状態、アバター表示、モーダル修正と、それぞれは小さな変更ですが、全部合わせるとカードの完成度がかなり上がったと思います。Threadsシェアも追加できて、SNS連携も一歩進みました。 --- 📝 Mintor開発日記 | 🤖 Generated with Claude Code
相談サービス料金バグ修正とAI生成機能の再構築 - Mintor開発日記
相談サービス料金バグ修正とAI生成機能の再構築 - Mintor開発日記 2026-02-20 今日のハイライト 相談サービスの予約料金が半額になるという致命的なバグの修正と、プロダクト投稿のAI生成機能をほぼゼロから作り直した。決済に関わるバグは最優先で対処し、AI機能はスキーマ不整合からGeminiモデル更新まで包括的に手を入れた。 実装内容 予約料金の計算バグ修正 相談サービスの予約で、30分3,000円のサービスが1,500円と計算されていた。原因は時間単価計算(duration / 60 x fee)が残っていたため。固定料金計算(fee x duration / min_duration)に修正した。 BookingFormLayoutのcalculateTotalAmountとgetDurationOptionsを修正 ConsultationBookingModalのcalculateTotalAmountを修正 bookings APIのtotalAmount計算にmin_duration取得を追加 プロダクトURL情報取得のバグ修正 APIレスポンスのプロパティ名とフロントエンドの期待値が一致していなかった。aiData.titleをaiData.nameに、aiData.appealをaiData.key_features.join('\\n')に修正するなど、全フィールドの対応関係を正しく整合させた。 AI生成のZodスキーマ再構築 プロンプトがtitle/appeal/category/tagsを返すよう指示しているのに、Zodスキーマがname/key_featuresなどを期待していたためバリデーション失敗で常に502エラーになっていた問題を修正。スキーマとプロンプトのフィールド定義を完全に一致させた。 AI生成機能の拡張 OGP画像からサムネイル、faviconからアイコンを自動取得 フォールバックのプレースホルダー文字列を削除(「手動入力が必要」タグ問題の解消) カテゴリ値をフォーム実装のenum値に合わせて修正 targetUsers(ターゲットユーザー)とdevelopmentStatus(開発状況)をAI生成に追加 入力URLをliveUrl(デモURL)として自動設定 Geminiモデル名を最新版に更新(gemini-2.5-flash/flash-lite/pro) Zodバリデーション失敗時の手動パースフォールバックを追加 AIタイトル抽出の改善 titleタグとog:titleの両方をAIに渡すよう変更(og:titleが短い場合への対策) 副題やキャッチコピーを含むタイトル生成をプロンプトで指示 AIタイトルを正規表現で上書きする処理を削除(副題が消えてしまう原因だった) targetUsersの表現を自然な推薦文に改善 まとめ 予約料金のバグは決済直結の問題であり、最優先で対処できてよかった。AI生成機能はスキーマ不整合という根本的な問題があり、プロンプト・スキーマ・フロントエンドの三者を一貫させる形で再構築した。URLから情報を取得してフォームを自動入力する体験が、ようやく実用的なレベルになった。 --- Mintor開発日記 | Generated with Claude Code
OGP画像生成を根本から作り直した一日 - Mintor開発日記
OGP画像生成を根本から作り直した一日 - Mintor開発日記 2026-02-15 今日のハイライト OGP画像生成でCloud Run上の503エラーが頻発していた問題に対し、Satori(next/og)からsharp + opentype.jsへの完全移行を実施した。白カードの色味問題、外部依存の排除、フォント選定まで、OGPシステムを根本から再構築した長丁場のセッション。 実装内容 503エラーの調査と段階的な対応 最初の対応として外部fetchの削減を試みた。背景画像をCSSグラデーションに、ロゴをテキストに置換し、フォントを3種から1種に統一。外部fetchは5回から1回に削減できたが、根本解決には至らなかった。 次にテンプレート画像方式を導入。sharpでog-bg.jpg、白カード、logo.pngを1枚のテンプレートに合成する方式に変更。fetchは2回(テンプレート+フォント)まで減ったが、Cloud Runでは同一オリジンからの画像fetchが機能しないことが判明し、base64埋め込みに切り替えた。 白カードの色味問題との戦い JPEG出力で白カード(#ffffff)がベージュがかって見える問題に長時間取り組んだ。JPEG quality 90→100への変更、CSS描画への切り替えなど複数のアプローチを試した結果、最終的にPNG出力にすることで純白を保証する方式に落ち着いた。 Satori → sharp + opentype.js への完全移行 最終的にSatori(next/og)とEdge Runtimeの構成を完全に廃止し、sharp + opentype.js + Node.jsランタイムの構成に移行した。 Google Fonts API依存を完全排除(ローカルフォントで503エラーを根本解消) og-template-base64.ts(76kトークン)の巨大ファイルを削除 デフォルト画像はロゴを大きく前面配置(160px) 動的OGPはタイトル文字数に応じてフォントサイズを自動調整(42-68px) キャッシュ後のパフォーマンスは0.15-0.28秒 レイアウトの調整 動的OGPのロゴを48pxから64pxに拡大 タイトルをブロック中央配置・テキスト左揃えに変更 パディングを56pxから80pxに拡大(SNSクロップのセーフゾーン対応) フッターのアバターを44pxから56px、フォントを24pxから28pxに拡大 フォント選定の変遷 M PLUS Rounded 1c → Noto Sans JP Bold → Zen Maru Gothic Boldと変遷した。最終的にZen Maru Gothic Boldを採用。温かみのある丸ゴシック体がMintorのブランドイメージに合致し、opentype.js互換のTTFファイルで技術的にも安定している。 OGP適用範囲の拡大 トップページと一覧ページを一旦静的画像に変更し、その後動的生成に戻す判断 一覧ページ(articles, questions, products, consultation-services, pricing)を動的OGP(大ロゴ+タイトル表示)に変更 記事OGPにauthor/avatar/dateが表示されない問題を修正(page.tsxとlayout.tsxのgenerateMetadata重複が原因) ユーザー詳細ページのバグ修正 プロダクトのいいね数が表示されない問題を修正(旧product_likesテーブル参照を統合likesテーブルに変更) 記事・Q&Aタブのカウントが0になる問題を修正(遅延読み込みのためカウントを先行取得するよう変更) まとめ OGP画像生成の503エラーという一つの問題から始まり、描画エンジンの完全移行、白色の色味問題の解決、フォント選定の試行錯誤と、想定以上に深い作業になった。結果としてSatoriへの外部依存を排除し、安定かつ高速なOGP生成基盤を構築できた。ユーザー詳細ページのバグ修正も合わせて、表示品質が大きく向上した一日だった。 --- Mintor開発日記 | Generated with Claude Code
カードUI統一とOGP画像デザイン刷新 - Mintor開発日記
カードUI統一とOGP画像デザイン刷新 - Mintor開発日記 2026-02-14 今日のハイライト 一覧ページのカードデザインを全面的に統一し、通報ボタンの追加、TODOコメントの整理、そしてOGP画像のデザイン刷新まで、多岐にわたる改善を一気に進めた一日。 実装内容 カードUI統一 VerticalGridCardにstripMarkdown適用、カード比率を16:9画像に変更、アイコンバッジ表示を追加 UnifiedListCardにもstripMarkdown適用 一覧ページとユーザー詳細カードからtags表示を削除し、description+category構成に統一 全一覧ページの表示件数を50件に統一 相談サービスカードの色をミントグリーン/ブルー系から紫系パステルに統一 お試しサービスに「お試し・無料」バッジを追加(is_trial対応) 統計表示の共通化 src/lib/utils/formatCount.tsに共通のformatCount関数を新規作成 UnifiedListCard、VerticalGridCardのローカル重複定義を削除して共通インポートに変更 SquareCardにもformatCountを適用 VerticalGridCardのstats型にviewsを追加し、閲覧数表示を実装 通報機能の拡充 ReportTargetTypeにarticleとconsultation_serviceを追加 記事詳細、質問詳細、相談サービス詳細のシェアボタン横に通報ボタンを配置 自分の投稿以外の場合のみ表示する制御を実装 コードベース整理 翻訳ファイルのクリーンアップ(不要キーの削除、未翻訳キーの追加) 古いTODOコメント3件を修正(Webhook完結済み、通知Phase N2、MindMint削除済み) TODOコメントを24件から14件に削減(全件にPhase番号または優先度を明記) ROADMAP.mdの実装済み6項目を完了マークに更新 OGP画像デザイン刷新 背景にミントの葉写真と半透明オーバーレイを使用した白カード中央配置のデザインに変更 バッジにパステルグラデーションと濃い色テキストを適用 フォントにM PLUS Rounded 1c(丸ゴシック)を採用 タイトルの「| Mintor」サフィックスを廃止し、文字数に応じたサイズ自動調整を実装 背景画像をsharpで圧縮(7.7MB PNG → 76KB JPEG) まとめ カードUIの統一、通報機能、TODOの整理、OGPデザイン刷新と、品質向上に直結する改善を幅広く実施できた。特にformatCountの共通化やTODO整理は、今後の開発効率を底上げする地味だが重要な作業だった。 --- Mintor開発日記 | Generated with Claude Code
Stripe資金フローの文書化 - Mintor開発日記
Stripe資金フローの文書化 - Mintor開発日記 2026-02-12 今日のハイライト Stripe Connectを利用した資金フローの仕組みと法的な整理を文書化した。合わせてREADMEに残っていた古い情報も修正し、ドキュメントの正確性を向上させた。 実装内容 ドキュメント Stripe Connectの資金フロー(決済から出金まで)を図解付きで文書化 資金移動に関する法的整理(資金決済法、前払式支払手段、為替取引など)を整理 README.mdの古い情報を修正(旧サブスクリプションモデルの記述を削除など) まとめ 決済周りのドキュメントは、開発時だけでなく運用やコンプライアンスの観点でも重要。資金の流れと法的根拠を明文化しておくことで、将来の判断基準が明確になる。 --- Mintor開発日記 | Generated with Claude Code
相談サービス予約ページの不具合調査 - Mintor開発日記
相談サービス予約ページの不具合調査 - Mintor開発日記 2026-02-07 今日のハイライト 相談サービスの予約ページで発生していた不具合の調査を開始した。まだ解決には至っていないが、デバッグログを追加して問題の切り分けを進めた段階。 実装内容 バグ調査(作業中) 相談サービス予約ページの不具合を調査 問題箇所の特定に向けてデバッグログを各所に追加 データの流れを追跡し、原因の候補を絞り込み中 まとめ 予約機能は決済に直結する重要な部分であり、慎重な調査が必要。今日はデバッグログの仕込みまでを完了し、次回のセッションで本格的な修正に取り掛かる予定。 --- Mintor開発日記 | Generated with Claude Code
パイオニアバッジ期間の延長 - Mintor開発日記
パイオニアバッジ期間の延長 - Mintor開発日記 2026-01-31 今日のハイライト パイオニアバッジとSeedバッジの有効期間を2026年6月末まで延長した。初期ユーザーへの感謝を示す期間をより長く設定することで、コミュニティの継続的な参加を促す。 実装内容 設定変更 パイオニアバッジの付与対象期間を2026年6月末まで延長 Seedバッジの期間もドキュメント上で2026年6月末までに更新 まとめ バッジシステムは初期ユーザーのモチベーション維持に直結する。期間延長により、サービスの成長フェーズに合わせた柔軟な運用が可能になった。 --- Mintor開発日記 | Generated with Claude Code
お問い合わせカスタムフォームの実装 - Mintor開発日記
お問い合わせカスタムフォームの実装 - Mintor開発日記 2026-01-30 今日のハイライト GoogleフォームをベースにしたカスタムUIのお問い合わせフォームを実装した。外部サービスの安定性を活かしつつ、Mintorのデザインに馴染むUIを実現している。 実装内容 新機能 お問い合わせページにカスタムフォームを実装 バックエンドはGoogleフォームを利用し、フロントエンドはMintor独自のUIで構築 フォームの送信処理、バリデーション、送信完了表示を一通り実装 まとめ Googleフォームをバックエンドに使うことで、回答の管理やスプレッドシート連携など運用面のメリットを享受しつつ、ユーザーには統一感のある体験を提供できるようになった。 --- Mintor開発日記 | Generated with Claude Code
編集画面のラベル修正 - Mintor開発日記
編集画面のラベル修正 - Mintor開発日記 2026-01-20 今日のハイライト 編集画面の破棄ボタンのラベルが「投稿を破棄」になっていたのを「編集を破棄」に修正した。小さな修正だが、ユーザーが安心して編集操作を行えるようにするための重要な改善。 実装内容 バグ修正 編集画面の破棄ボタンのラベルを「投稿を破棄」から「編集を破棄」に変更 新規投稿時は「投稿を破棄」、編集時は「編集を破棄」と状況に応じた適切な文言を表示 まとめ UIの文言一つで、ユーザーが「編集しただけなのに投稿全体が消えるのでは」と不安に感じる可能性がある。こうした細かい文言の正確さがユーザー体験の信頼性につながる。 --- Mintor開発日記 | Generated with Claude Code