<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>Rebounder Tech Blog</title><description>株式会社Rebounder が自社で運用している本番システムで、実際に起きたことの記録。</description><link>https://tech.rebounder.jp/</link><language>ja</language><item><title>snapshotSignedPolicies の冪等ガードで署名済み契約は二度と上書きできない</title><link>https://tech.rebounder.jp/posts/contract-reconsent-blocked-by-is-null-snapshot-guard/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/contract-reconsent-blocked-by-is-null-snapshot-guard/</guid><description>署名済みの契約に専用版の規約を差し込んでも、再同意しない限り正式な合意にならない。原因はsnapshotSignedPoliciesが両カラムnullのときだけ書き込む冪等ガードで、一度署名されると二度と走らず、UIの案内文だけがリセット手段のない「再同意してください」を表示し続けていた。</description><pubDate>Tue, 13 Oct 2026 00:00:00 GMT</pubDate></item><item><title>gcloud sql clone point-in-time で本番DB復元の記録</title><link>https://tech.rebounder.jp/posts/gcloud-sql-pitr-clone-restore-drill/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/gcloud-sql-pitr-clone-restore-drill/</guid><description>本番の Cloud SQL for PostgreSQL を gcloud sql instances clone --point-in-time で実際に復元した手順の記録。クローン作成から利用可能になるまでの所要時間と費用、復元先がプライベートIPのみで直接接続できない点までまとめた。</description><pubDate>Tue, 13 Oct 2026 00:00:00 GMT</pubDate></item><item><title>配列を空行で挟む実装は空配列で2連続、endsWithでは検出できない</title><link>https://tech.rebounder.jp/posts/renewal-email-conditional-block-wrapped-blank-lines-double/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/renewal-email-conditional-block-wrapped-blank-lines-double/</guid><description>顧客向け更新案内メールで、プランも金額も設定されていない契約だけ本文に空行が2つ連続して出ていた。原因は任意ブロックの前後を固定の空行で挟んでいたことと、回帰テストにこの分岐が無かったこと。締めの文言を endsWith だけで検査すると空行の有無まで区別できない落とし穴も合わせて直した。</description><pubDate>Tue, 13 Oct 2026 00:00:00 GMT</pubDate></item><item><title>is_pinned=falseだけでは特別回を除外できず、日程追加の雛形に選ばれた</title><link>https://tech.rebounder.jp/posts/workshop-new-event-copy-picks-unpinned-special-event-as-template/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/workshop-new-event-copy-picks-unpinned-special-event-as-template/</guid><description>ワークショップの日程追加で「is_pinned=falseかつ直近1件」を自動コピーしていたところ、ピン留めされていない特別回がその直近1件に該当し、通常回の雛形に特別回の内容が入り込んだ。直し方はコピー元を選択式にして自動推測をやめること。</description><pubDate>Tue, 13 Oct 2026 00:00:00 GMT</pubDate></item><item><title>TOTP登録直後、session cookieは第2要素未達のまま残る</title><link>https://tech.rebounder.jp/posts/firebase-totp-enroll-stale-session-cookie-missing-second-factor/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/firebase-totp-enroll-stale-session-cookie-missing-second-factor/</guid><description>TOTP第2要素を強制しても、enroll直後のsession cookieは登録前のIDトークン由来のまま未達判定になる。getIdTokenResult(true)で強制リフレッシュしclaimの有無で再ログインへ誘導する直し方を実装から辿る。</description><pubDate>Fri, 09 Oct 2026 00:00:00 GMT</pubDate></item><item><title>署名済み申込書が、signed_terms_source_versionを見ず現行規約を同意済みと表示</title><link>https://tech.rebounder.jp/posts/signed-application-page-shows-current-terms-text-as-agreed-content/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/signed-application-page-shows-current-terms-text-as-agreed-content/</guid><description>電子署名で契約済みの申込書確認ページが、同意した時点の版ではなく常に現行の規約本文を『ご同意の対象』として表示していた。規約改定後は、顧客が実際には読んでいない条文を同意済みとして見せてしまう経路があり、署名時点の版番号を記録して突き合わせることで塞いだ。</description><pubDate>Fri, 09 Oct 2026 00:00:00 GMT</pubDate></item><item><title>本番のVercel API FunctionsだけCannot find moduleで落ちた</title><link>https://tech.rebounder.jp/posts/vercel-node-functions-relative-import-missing-js-extension/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/vercel-node-functions-relative-import-missing-js-extension/</guid><description>ローカルのtscとvite devはどちらも通るのに、Vercelの本番Node Functionsだけが拡張子なしの相対importを許さずCannot find moduleで落ちた理由と直し方を書く。</description><pubDate>Thu, 08 Oct 2026 00:00:00 GMT</pubDate></item><item><title>SQLのbackfillでEXISTSが1つだけだと is_pilot の条件漏れが起きる</title><link>https://tech.rebounder.jp/posts/backfill-where-exists-misses-creatives-only-companies/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/backfill-where-exists-misses-creatives-only-companies/</guid><description>Supabaseの実証実験フラグをbackfillするUPDATE文で、判定を契約の有無だけのEXISTSにすると、契約なし・広告素材のみの会社が対象から漏れ、顧客向け自動リマインドの除外対象にならないまま本番相当のメールが実証相手に送られてしまう。</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate></item><item><title>掲示物のタイトルが IMG_1234 のまま教室のテレビに出る</title><link>https://tech.rebounder.jp/posts/signage-title-from-filename-machine-name-detect/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/signage-title-from-filename-machine-name-detect/</guid><description>ファイル名をそのままタイトルに使う実装では、カメラやスキャナが自動で付けた IMG_1234 や scan_20261005 のような名前がそのまま教室のテレビの盤面に表示される。機械が付けた名前かどうかを正規表現で判定し、空文字として扱い直すことで解決した方法を書く。</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate></item><item><title>Stripe Checkoutの二重セッションで、負けたPaymentIntentがholdを巻き戻す</title><link>https://tech.rebounder.jp/posts/stripe-paymentintent-canceled-webhook-reverts-winning-hold/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/stripe-paymentintent-canceled-webhook-reverts-winning-hold/</guid><description>Stripeで同一契約に2本のCheckout sessionが完了すると、2つのPaymentIntentが発生する。負けた側PaymentIntentのcanceled webhookはPI id照合の無いUPDATEのWHERE句を通り、採用中のholdをreleasedへ誤って巻き戻していた。</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate></item><item><title>Bing WebmasterのUrlCountが1のまま止まっていたsitemap-indexの罠</title><link>https://tech.rebounder.jp/posts/bing-webmaster-urlcount-stuck-sitemap-index/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/bing-webmaster-urlcount-stuck-sitemap-index/</guid><description>検索エンジンに新着記事を届けるため、tech.rebounder.jpはIndexNowで即時通知し、Bing Webmaster APIでも能動的に登録する。sitemap-index.xmlだけ渡すとBingはUrlCountを1と数えて止まり、改名もリネームを削除+追加と誤認し404URLを送る罠になった。</description><pubDate>Tue, 06 Oct 2026 00:00:00 GMT</pubDate></item><item><title>メディアクエリが効かない原因は、@media(max-width:900px)より後ろの同詳細度ルール</title><link>https://tech.rebounder.jp/posts/css-media-query-overridden-by-later-same-specificity-base-rule/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/css-media-query-overridden-by-later-same-specificity-base-rule/</guid><description>スマホ用@mediaで1列に戻したはずの料金欄が、幅を狭めると文字が1文字ずつ縦に割れた。原因はCSSの詳細度が同じ指定を@mediaブロックより後ろに書いていたため、ソースの「後勝ち」ルールで@media側の指定が丸ごと無効化されていたこと。@mediaを&lt;style&gt;の末尾に移すだけで直った実例。</description><pubDate>Tue, 06 Oct 2026 00:00:00 GMT</pubDate></item><item><title>並行デプロイでTerraformのmigrate_image_tagがliveとズレた</title><link>https://tech.rebounder.jp/posts/terraform-ledger-drift-concurrent-deploy-sessions/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/terraform-ledger-drift-concurrent-deploy-sessions/</guid><description>2つのセッションが同時にCloud Runへデプロイすると、片方が実行した変更の記録がTerraformのlocalsへ書き戻される前に、もう片方のコミットがmainへ先に乗る。live自体は壊れていないのに、台帳の記録だけが一時的に古いタグを指す「未記録のdrift」が起きた。</description><pubDate>Tue, 06 Oct 2026 00:00:00 GMT</pubDate></item><item><title>セット割引プレビューのlistTotalはunitsを掛け忘れ、表示額と契約額が食い違う</title><link>https://tech.rebounder.jp/posts/bundle-discount-preview-missing-units-multiplier/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/bundle-discount-preview-missing-units-multiplier/</guid><description>セット割引適用後の金額をチェック画面に表示する計算が、申込み枠数を表すunitsを掛けていなかった。?units=3のように複数枠をまとめて申し込むと、画面には常に1枠分の金額が出たまま、実際の契約金額だけが枠数ぶん増える状態になっていた。</description><pubDate>Mon, 05 Oct 2026 00:00:00 GMT</pubDate></item><item><title>dpm set-device-ownerはアプリを起動する。先にprefsを書かないとdevice_idを横取りされる</title><link>https://tech.rebounder.jp/posts/dpm-set-device-owner-launches-app-before-prefs-written/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/dpm-set-device-owner-launches-app-before-prefs-written/</guid><description>Android TVをDevice Owner化するdpm set-device-ownerは、実行した瞬間にアプリ自身を起動させる。prefsにdevice_idを書く前に実行すると、アプリが自分で新しいIDを生成して永続化し、Device Owner化後はforce-stopも効かず正しい値が上書かれ続けていた。</description><pubDate>Mon, 05 Oct 2026 00:00:00 GMT</pubDate></item><item><title>招待のcompany_idで重複申込みをチェックすると、共有リンク経由では常にnullになる</title><link>https://tech.rebounder.jp/posts/invite-company-id-null-on-public-link-skips-duplicate-check/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/invite-company-id-null-on-public-link-skips-duplicate-check/</guid><description>まとめ申込みの重複チェックに招待レコードのcompany_idを使っていたが、招待トークンを経由しない公開・共有・QRリンクからの申込みでは招待レコード自体が存在せず常にnullになり、既に保有している枠をもう一度予約できてしまっていた。</description><pubDate>Mon, 05 Oct 2026 00:00:00 GMT</pubDate></item><item><title>Claude Codeのスケジュールタスクが止まる3つの形（ENOTFOUND・enabled: false）</title><link>https://tech.rebounder.jp/posts/claude-code-scheduled-tasks-three-ways-to-stop/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/claude-code-scheduled-tasks-three-ways-to-stop/</guid><description>Claude Codeのスケジュールタスク（定期実行）を1日6枠・7週間回して、止まる形は3つあった。起動しない・途中で死ぬ・枠ごと無効になる。どれも実行ログには出ないので、git の成果物で判定して次の回に取り返させている。</description><pubDate>Sun, 04 Oct 2026 00:00:00 GMT</pubDate></item><item><title>gcloud ADCが約44時間で切れる「Reauthentication failed」を無人実行で避ける</title><link>https://tech.rebounder.jp/posts/gcloud-adc-reauthentication-failed-non-interactive-service-account/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/gcloud-adc-reauthentication-failed-non-interactive-service-account/</guid><description>AIエージェントの定期実行でSearch Console APIを叩くと、Reauthentication failed. cannot prompt during non-interactive execution で止まった。原因はWorkspaceの再認証。サービスアカウントへの切替と403の3通りの原因。</description><pubDate>Sun, 04 Oct 2026 00:00:00 GMT</pubDate></item><item><title>GCSのallUsers+objectViewerは、get専用のつもりがlistも渡っていた</title><link>https://tech.rebounder.jp/posts/gcs-allusers-objectviewer-includes-list-anonymous-enumeration/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/gcs-allusers-objectviewer-includes-list-anonymous-enumeration/</guid><description>キミテラスv2の広告素材バケットはallUsersにstorage.objectViewerを与えていたが、これはlistを含み全オブジェクト名を匿名列挙できた。storage.objects.getのみのcustom roleに置き換えて塞いだ記録。</description><pubDate>Sat, 03 Oct 2026 00:00:00 GMT</pubDate></item><item><title>tokenは合っているのに、design/dateのquery parameterで画面外データが取れるIDOR</title><link>https://tech.rebounder.jp/posts/signage-anonymous-token-trusts-design-date-query-params-idor/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/signage-anonymous-token-trusts-design-date-query-params-idor/</guid><description>キミテラスv2の匿名サイネージAPIはclassTokenでクラスを確定するが、design/dateのクエリパラメータは検証していなかった。有効なtokenのまま書き換えると、画面に出ていない過去日のデザインから氏名入りデータが全期間取れた。2026-10-01のセキュリティ監査で発見し修正した。</description><pubDate>Sat, 03 Oct 2026 00:00:00 GMT</pubDate></item><item><title>Cloud Runのレート制限はインスタンス間で共有されない（maxOutputTokensも無かった）</title><link>https://tech.rebounder.jp/posts/cloud-run-instance-memory-rate-limit-not-shared/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/cloud-run-instance-memory-rate-limit-not-shared/</guid><description>匿名のmagic linkから呼べる生徒チャットは、分単位のレート制限がCloud Runの1インスタンス内のメモリに閉じ端末cookieも作り直せるため、出力・総呼び出し回数とも上限が無かった。日次上限をCloud SQL共有で掛け直す過程で、接続プール枯渇とスコープ判定バイパスの2件もレビューで見つかった。</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate></item><item><title>ScanFilter.setDeviceAddressがIllegalArgumentExceptionで落ちる</title><link>https://tech.rebounder.jp/posts/scanfilter-setdeviceaddress-null-string-crash/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/scanfilter-setdeviceaddress-null-string-crash/</guid><description>Android の ScanFilter.setDeviceAddress は不正な文字列を渡されると IllegalArgumentException を投げる。JSON null が optString で文字列&quot;null&quot;に化けた値がこの検証をすり抜け、Service全体をクラッシュさせていた。</description><pubDate>Thu, 01 Oct 2026 00:00:00 GMT</pubDate></item><item><title>outboxパターンのfail-openで他校の広告配信がsent扱いのまま消えた</title><link>https://tech.rebounder.jp/posts/outbox-fail-open-loop-schools-sent-before-delete/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/outbox-fail-open-loop-schools-sent-before-delete/</guid><description>複数校配信の対象校取得で、クエリエラーを空配列へ倒すfail-open実装にすると、一過性のエラー1回で対象校が代表校1件に縮み、送信自体は成功してoutboxがsent確定するため、他校の広告配信が再送もアラートも無いまま削除される。</description><pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate></item><item><title>RLSのINSERT WITH CHECKが会社IDしか見ず、承認ステータス列を自己申告できた</title><link>https://tech.rebounder.jp/posts/rls-insert-with-check-owner-only-status-columns-self-reportable/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/rls-insert-with-check-owner-only-status-columns-self-reportable/</guid><description>SupabaseのRLS INSERTポリシーはcompany_idの一致だけを検証していた。二者承認ゲートを追加した際、新しく増えた承認ステータス列をWITH CHECKに含め忘れ、広告主が直接PostgRESTへINSERTすれば『承認済み』を自己申告できる状態が残っていた。</description><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate></item><item><title>vercel --prodの同時実行は、vercel inspectでコミットが分からなくなる</title><link>https://tech.rebounder.jp/posts/vercel-cli-deploy-concurrent-collision-inspect-blind/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/vercel-cli-deploy-concurrent-collision-inspect-blind/</guid><description>Vercel CLIから直接vercel --prodでデプロイする運用（GitHub連携なし）は、複数人が同時に叩くと後勝ちで上書きされる。デプロイ後にvercel inspectで確認しても、どのgitコミットが本番に入っているかを示す情報は無い。</description><pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate></item><item><title>契約月数を延長すると、term_monthsを見た帳票表示だけ金額とズレる</title><link>https://tech.rebounder.jp/posts/invoice-document-period-drifts-from-term-extension/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/invoice-document-period-drifts-from-term-extension/</guid><description>単位制で契約月数を延長して申し込むと、契約金額はperiod_start/period_endの実効期間ベースなのに、申込書・請求書・同意ページの「契約期間」表示は枠に固定されたterm_monthsを見たままで、金額と期間の表示が矛盾していた。</description><pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate></item><item><title>semgrep ci --config=autoでコード変更なしにmainが赤くなる</title><link>https://tech.rebounder.jp/posts/semgrep-config-auto-registry-mutable-ci-breaks-without-code-change/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/semgrep-config-auto-registry-mutable-ci-breaks-without-code-change/</guid><description>semgrep ci --config=autoはSemgrepレジストリの規則(実測1074件)を毎回取得する。リポジトリを一切変更していなくても、上流が規則を追加した日だけCIのmainが赤くなる。規則セットを明示列挙しエンジンをdigest固定して直した。</description><pubDate>Fri, 25 Sep 2026 00:00:00 GMT</pubDate></item><item><title>実寸プレビューは常に横16:9なのに、スマホ用@media(max-width:899px)が紛れ込み崩れた</title><link>https://tech.rebounder.jp/posts/scaled-signage-preview-inherits-mobile-media-query-layout/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/scaled-signage-preview-inherits-mobile-media-query-layout/</guid><description>1280×720に固定してtransform: scale()で縮小表示するプレビューでも、@media (max-width: 899px)はブラウザの実ビューポート幅を評価するため、PCブラウザの横幅を899px以下に狭めると実機のスマホ向け縦積みレイアウトがプレビューに混入して崩れた。</description><pubDate>Thu, 24 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Stripe Checkout amount_unsetで「7日で自動切替」が永久に発動しない</title><link>https://tech.rebounder.jp/posts/stripe-checkout-amount-unset-card-window-never-closes/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/stripe-checkout-amount-unset-card-window-never-closes/</guid><description>Stripe Checkoutの署名時自動請求で、金額未設定の契約は「7日で自動切替」とSlack通知されるが、日次フォールバックの対象条件がamount!=nullを要求するため実際は窓が永久に閉じなかった。</description><pubDate>Thu, 24 Sep 2026 00:00:00 GMT</pubDate></item><item><title>招待経路の申込ページがsp.unitsをそのまま表示し、確定枚数と食い違い</title><link>https://tech.rebounder.jp/posts/invite-apply-page-trusts-query-units-while-server-confirms-one-unit/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/invite-apply-page-trusts-query-units-while-server-confirms-one-unit/</guid><description>招待リンク経由の申込ページは、サーバー確定枚数がinviteのとき常に1なのに、表示枚数はクエリパラメータsp.unitsをそのまま使っていた。?units=5なら1枠の契約なのに5枠・5倍の金額を見せ続ける。</description><pubDate>Wed, 23 Sep 2026 00:00:00 GMT</pubDate></item><item><title>gen-og.tsのキャッシュが壊れた画像を「更新済み」と誤認し、日英95本中91本が同じOGP画像になっていた</title><link>https://tech.rebounder.jp/posts/og-image-same-slug-lang-collision-incremental-cache-masks-it/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/og-image-same-slug-lang-collision-incremental-cache-masks-it/</guid><description>OG画像を生成するgen-og.tsは日英とも同じog/${slug}.pngに書き込んでいたため、後から処理された言語側がもう一方を上書きし、しかもインクリメンタルキャッシュが上書きを「更新済み」と誤判定して作り直さず、95スラッグ中91件で日本語記事のシェアカードに英語タイトルが描かれたままだった。</description><pubDate>Wed, 23 Sep 2026 00:00:00 GMT</pubDate></item><item><title>古いNext.jsのままpushしたら脆弱性バージョン判定でデプロイがブロックされた</title><link>https://tech.rebounder.jp/posts/vercel-blocks-vulnerable-nextjs-version/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/vercel-blocks-vulnerable-nextjs-version/</guid><description>package.json の next を 15.1.6 に固定したままVercelへpushすると、ビルドが走る前の段階でデプロイ自体がブロックされた。原因はVercelが脆弱バージョンと判定したためで、^15.5.23へ上げてpackage-lock.jsonを再生成するまで直らなかった。</description><pubDate>Wed, 23 Sep 2026 00:00:00 GMT</pubDate></item><item><title>別商品がサブドメインを足しただけで、他のAレコードが消えた（お名前.com／01.dnsv.jp はゾーン全体を送信）</title><link>https://tech.rebounder.jp/posts/onamae-dns-full-zone-replace-record-vanishes/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/onamae-dns-full-zone-replace-record-vanishes/</guid><description>お名前.comのDNSレコード設定画面は編集した1件だけでなくゾーン全体をまとめて送信する仕様のため、別のサブドメインを1件追加しただけで、その時点の控えに無かった既存のAレコードが消えることがある。HTTP監視はリゾルバのキャッシュに守られて数分は200を返し続けるため、消えたことに気づけなかった。</description><pubDate>Tue, 22 Sep 2026 00:00:00 GMT</pubDate></item><item><title>マイグレーション番号衝突を直した1時間後、0041_console_name.sqlでまた衝突した</title><link>https://tech.rebounder.jp/posts/duplicate-migration-number-from-parallel-prs-needs-rename/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/duplicate-migration-number-from-parallel-prs-needs-rename/</guid><description>手番号のマイグレーションで0040番の重複を直し、リネームして0041にした。ところが58分後、別の2本のブランチがそれぞれ独立に0041を選んでマージされ、同じ番号のファイルが3つトランクに並んだ。</description><pubDate>Mon, 21 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Next.js server actionでerrorを握りつぶし、保留失敗を保留成功と誤通知した</title><link>https://tech.rebounder.jp/posts/nextjs-server-action-fail-open-error-swallow/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/nextjs-server-action-fail-open-error-swallow/</guid><description>server actionのDB更新がSupabaseのerrorを捨てて{data}の有無だけで成否を判定していたため、一過性障害で保留に失敗しても顧客画面は「保留しています」、社内Slackは「既に署名済のため保留していません」と、逆方向に食い違ったまま断定していた。</description><pubDate>Mon, 21 Sep 2026 00:00:00 GMT</pubDate></item><item><title>未追跡のpnpm-lock.yamlがVercelをpnpmプロジェクトと誤検知させた</title><link>https://tech.rebounder.jp/posts/vercel-pnpm-lockfile-misdetect/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/vercel-pnpm-lockfile-misdetect/</guid><description>正本はnpm（package-lock.json）のリポジトリなのに、未追跡のまま残っていたpnpm-lock.yamlが.vercelignoreの存在でアップロード対象に含まれ、Vercelがpnpmプロジェクトと誤判定してstripeの依存解決が食い違い、型エラーでビルドが落ちた。</description><pubDate>Mon, 21 Sep 2026 00:00:00 GMT</pubDate></item><item><title>reminder_log_kind_checkを正規表現で抽出するテストが偽greenだった</title><link>https://tech.rebounder.jp/posts/regex-check-constraint-name-mention-false-green-test/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/regex-check-constraint-name-mention-false-green-test/</guid><description>DB migrationのSQLからCHECK制約の許可値を正規表現で抽出し、コードのunion型と整合しているかを検証する静的テストが、制約名の「言及」に食いつき、SQLコメントや別テーブルの同名check(kind in)を誤って許可値と解釈しうる状態だった。</description><pubDate>Sun, 20 Sep 2026 00:00:00 GMT</pubDate></item><item><title>RegExp.testの部分一致で&quot;unsigned&quot;が&quot;signed&quot;に誤検出した</title><link>https://tech.rebounder.jp/posts/anyflow-unanchored-regex-unsigned-matches-signed/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/anyflow-unanchored-regex-unsigned-matches-signed/</guid><description>Anyflowのwebhookで締結完了を判定する正規表現が非アンカーの部分一致で、&quot;unsigned&quot;が&quot;signed&quot;に誤検出。JavaScriptのincludesでも同じ形で起きる。未署名文書を締結済として自動保管しうる状態だった。</description><pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate></item><item><title>検索順位の実査にGoogle Custom Search APIではなくBrave Search APIを使う理由</title><link>https://tech.rebounder.jp/posts/google-cse-403-switched-to-brave-search-api/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/google-cse-403-switched-to-brave-search-api/</guid><description>画面なしでSEO順位を実査すると、This project does not have the access to Custom Search JSON API の403が返り続けた。診断手順と、Braveを既定にしSerperで補う設計を書く。</description><pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate></item><item><title>直接申込に入れたfail-closedガードが、団体配分と招待発行の別経路には無かった</title><link>https://tech.rebounder.jp/posts/group-distribution-loop-invite-missing-start-month-guard/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/group-distribution-loop-invite-missing-start-month-guard/</guid><description>kimiteras-portalは直接申込にstart_month未設定のfail-closedガードを入れた直後、再レビューで団体配分と招待発行という別の書き込み経路には同じガードが複製されていないことが発覚した。占有枠は非公開で顧客自身が実行でき、招待は外部に出て回収できない。2つの穴と直し方を書く。</description><pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate></item><item><title>supabase-js の count クエリが失敗してもnullで、監視は自分の異常に気づけなかった</title><link>https://tech.rebounder.jp/posts/integration-health-monitor-swallows-its-own-query-error/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/integration-health-monitor-swallows-its-own-query-error/</guid><description>連携ヘルス監視は、supabase-jsのcountクエリがerrorではなくnullを返す（returns null instead of throwing）形に対応せず0件へ倒していた。queryErrorsを集約して必ず先頭に出す直し方まで書く。</description><pubDate>Sat, 19 Sep 2026 00:00:00 GMT</pubDate></item><item><title>copyOneDayの一括置換で固定フラグの連絡が黙って消えていた</title><link>https://tech.rebounder.jp/posts/editor-copy-day-overwrite-drops-pinned-notice/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/editor-copy-day-overwrite-drops-pinned-notice/</guid><description>対象日の連絡欄を複製元で全置換する上書きコピーで、固定フラグ（pinned）を保全するpreservePinnedNoticesがコピー経路だけ呼ばれておらず、教員が入力した固定連絡が複製の瞬間に消えていた。</description><pubDate>Fri, 18 Sep 2026 00:00:00 GMT</pubDate></item><item><title>掲載枠のstart_monthが未設定だと、契約periodがNULLで満了処理が止まる</title><link>https://tech.rebounder.jp/posts/loop-start-month-missing-publishes-null-period-contract/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/loop-start-month-missing-publishes-null-period-contract/</guid><description>広告枠(placement_loops)はstart_month(掲載開始月)が未設定でもpublished:trueにできる。公開一覧・申込フォームで特別扱いしないと、成立した契約のperiod_start/period_endがNULLになり、満了・自動更新・素材の期限切れが無言で止まる。原因と直し方を書く。</description><pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Next.jsのmiddlewareで公開リンクの除外を書き忘れるとログイン必須になる</title><link>https://tech.rebounder.jp/posts/middleware-excludes-public-share-link-from-login-redirect/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/middleware-excludes-public-share-link-from-login-redirect/</guid><description>Next.jsのmiddleware(proxy)は認証チェックを全ルートに既定でかける。後から追加したログイン不要のルート（取引先向けの公開共有リンク /p/[token]）を除外条件に足し忘れると、未ログインで開いても一律 /login へ飛ばされる。原因のコードと直し方を書く。</description><pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate></item><item><title>外部APIが200を返しても安全ではない — Server Componentを壊した型アサーション</title><link>https://tech.rebounder.jp/posts/fetch-200-contract-drift-missing-field-crashes-server-component/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/fetch-200-contract-drift-missing-field-crashes-server-component/</guid><description>外部APIが200を返しJSONパースにも成功しても、形が契約通りとは限らない。res.json() as Tは実行時に中身を検証しないため、totalsが欠けた200応答でServer Componentがクラッシュしていた。</description><pubDate>Wed, 16 Sep 2026 00:00:00 GMT</pubDate></item><item><title>PostgRESTの.or()にカンマを含む検索語を渡すと無音でフィルタが壊れる</title><link>https://tech.rebounder.jp/posts/supabase-or-filter-comma-breaks-query-silently/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/supabase-or-filter-comma-breaks-query-silently/</guid><description>全体検索の担当者クエリは.or()に生の検索語を差し込んでおり、カンマ等のPostgREST予約文字を含む語でフィルタ文法が壊れ、supabase-jsはthrowせず{data:null}を返すため担当者だけ無音で消えていた。個別のparameterized .ilike()に分けて直した。</description><pubDate>Wed, 16 Sep 2026 00:00:00 GMT</pubDate></item><item><title>監査ログのentity_idがuuid列なのにトークンを入れて22P02で無記録になった</title><link>https://tech.rebounder.jp/posts/audit-log-entity-id-uuid-token-22p02-swallowed-by-catch/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/audit-log-entity-id-uuid-token-22p02-swallowed-by-catch/</guid><description>監査ログのentity_idはuuid列だが64hexトークンをそのまま入れていたため、insertがinvalid input syntax for type uuidで失敗し、logAuditのcatchによる握りつぶしで無記録になっていた。</description><pubDate>Tue, 15 Sep 2026 00:00:00 GMT</pubDate></item><item><title>system_adminの操作だけ外部キー制約違反(23503)で500になった</title><link>https://tech.rebounder.jp/posts/audit-log-fk-violation-system-admin-not-in-users-table/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/audit-log-fk-violation-system-admin-not-in-users-table/</guid><description>監査ログのactor参照がusersテーブルへの外部キーだったため、別テーブルで管理するsystem_adminの操作だけがinsert時に violates foreign key constraint (23503) で失敗し、削除は本番マスクの500、作成は誤った「競合」表示になっていた。</description><pubDate>Tue, 15 Sep 2026 00:00:00 GMT</pubDate></item><item><title>末尾スラッシュ除去の正規表現がCodeQLでpolynomial-redosに3箇所引っかかった</title><link>https://tech.rebounder.jp/posts/trailing-slash-regex-polynomial-redos-codeql/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/trailing-slash-regex-polynomial-redos-codeql/</guid><description>末尾スラッシュを削るbase.replace(//+$/, &quot;&quot;)という正規表現が、先頭アンカー(^)を欠いていたためCodeQLのjs/polynomial-redos(high)に3箇所該当した。開始位置の探索とバックトラックが重なりO(n^2)になる。正規表現をやめて線形走査に置き換えて解消した。</description><pubDate>Tue, 15 Sep 2026 00:00:00 GMT</pubDate></item><item><title>pnpm --filter buildがModule not foundを93件出した原因</title><link>https://tech.rebounder.jp/posts/pnpm-filter-build-turbopack-module-not-found-monorepo-docker/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/pnpm-filter-build-turbopack-module-not-found-monorepo-docker/</guid><description>pnpm workspaceでpnpm --filter @scope/web buildを実行すると、web単体しかbuildされず依存パッケージのdistが未生成のままTurbopackが解決を試みてModule not foundが93件出る。フィルタに...を付けて依存先を先にbuildすると解消する。</description><pubDate>Mon, 14 Sep 2026 00:00:00 GMT</pubDate></item><item><title>is_current の降格→挿入で版が二度と発行できなくなる</title><link>https://tech.rebounder.jp/posts/postgres-publish-demote-then-insert-non-atomic-duplicate-key-permanently-stuck/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/postgres-publish-demote-then-insert-non-atomic-duplicate-key-permanently-stuck/</guid><description>契約書版の発行を「is_current降格→新版INSERT」という非原子な2手で実装すると、同時発行時に片方の更新が取り残され、以後の発行が duplicate key value violates unique constraint で恒久的に失敗する。max(version)導出の単発INSERTへの直し方。</description><pubDate>Mon, 14 Sep 2026 00:00:00 GMT</pubDate></item><item><title>技術ブログの計測にGA4ではなくCloudflare Web Analyticsを選んだ理由</title><link>https://tech.rebounder.jp/posts/cloudflare-web-analytics-not-ga4/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/cloudflare-web-analytics-not-ga4/</guid><description>AdSenseとCore Web Vitalsを二重に削らず、Cookie同意の記載も増やさないため、tech.rebounder.jpはGA4を使わずCloudflare Web Analyticsだけで運用している。方針を決めてから実装が追いつくまで2日分の計測を失った経緯も書く。</description><pubDate>Sun, 13 Sep 2026 00:00:00 GMT</pubDate></item><item><title>drizzle-kit generateは列追加のsnapshot放置で重複ALTERを再出力する</title><link>https://tech.rebounder.jp/posts/drizzle-kit-snapshot-manual-edit-avoids-duplicate-alter-regen/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/drizzle-kit-snapshot-manual-edit-avoids-duplicate-alter-regen/</guid><description>drizzleのsnapshotに列追加を手編集で反映せず放置すると、次のdrizzle-kit generateがIF NOT EXISTSの無いADD COLUMNを重複して出力し、適用済み環境でALTERが失敗する。</description><pubDate>Sun, 13 Sep 2026 00:00:00 GMT</pubDate></item><item><title>findUnmaskedPiiは逆マスク後だと辞書由来の復元値まで誤検知する</title><link>https://tech.rebounder.jp/posts/unmask-pii-check-false-positive-drops-correct-draft/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/unmask-pii-check-false-positive-drops-correct-draft/</guid><description>逆マスクで元表記に戻した後にPII検査すると、教員が書いた電話・メールなど辞書由来の正規復元値まで生PIIと誤検知し、正しい下書きを丸ごと破棄する。検査をマスク前に移すと検出力を保ったまま解消する。</description><pubDate>Sun, 13 Sep 2026 00:00:00 GMT</pubDate></item><item><title>staging環境をdestroyしたらGCSのNoSuchBucketで本番画像が404になった</title><link>https://tech.rebounder.jp/posts/gcs-bucket-default-url-staging-destroy-prod-404/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/gcs-bucket-default-url-staging-destroy-prod-404/</guid><description>本番の広告画像が突然404になった。原因は本番DBのmedia_urlに焼き込まれていた既定値がstagingのGCSバケットを指したままで、そのバケットをterraform destroyで撤去した瞬間に配信が壊れたことだった。</description><pubDate>Fri, 11 Sep 2026 00:00:00 GMT</pubDate></item><item><title>『an invalid form control is not focusable』で送信が無言停止した</title><link>https://tech.rebounder.jp/posts/multistep-form-hidden-required-field-blocks-submit-not-focusable/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/multistep-form-hidden-required-field-blocks-submit-not-focusable/</guid><description>1つのformに3ステップ分の入力欄をまとめ、非表示ステップをhidden属性で切り替えていた。前のステップのrequired欄が空だと、確認画面の送信ボタンを押しても何も起きない詰みになる。</description><pubDate>Thu, 10 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Resendクライアントをモジュール直下でnewするとNext.jsのビルドごと落ちる</title><link>https://tech.rebounder.jp/posts/resend-client-module-level-init-breaks-nextjs-build/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/resend-client-module-level-init-breaks-nextjs-build/</guid><description>モジュール直下でResendクライアントをnewすると、RESEND_API_KEYが無い環境で next build が &quot;resend_api_key is required&quot; を投げてビルド全体が落ちる。関数内で遅延初期化する直し方を書く。</description><pubDate>Thu, 10 Sep 2026 00:00:00 GMT</pubDate></item><item><title>supabase-jsの.range()は.order()無しで境界の行が重複・欠落する</title><link>https://tech.rebounder.jp/posts/postgrest-range-without-order-duplicate-drop-live-asset-deleted/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/postgrest-range-without-order-duplicate-drop-live-asset-deleted/</guid><description>supabase-jsの.range()によるOFFSET/LIMITページングは、.order()で順序を固定しないとページ境界で行が重複・欠落しうる。孤児オブジェクト掃除cronの参照集合が漏れ、生きた素材を誤って削除対象に含めかねなかった原因と直し方を書く。</description><pubDate>Wed, 09 Sep 2026 00:00:00 GMT</pubDate></item><item><title>2タブで完了した2本のPaymentIntent、負けた側のwebhookが与信を巻き戻す</title><link>https://tech.rebounder.jp/posts/stripe-duplicate-payment-intent-webhook-missing-pi-match-reverts-winner/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/stripe-duplicate-payment-intent-webhook-missing-pi-match-reverts-winner/</guid><description>Stripeのカード仮押さえで2タブ決済が二重にPaymentIntentを作ると、負けた側のcanceled/succeededイベントがPI idを照合しないUPDATEを通り、採用中の与信状態を書き換える。</description><pubDate>Wed, 09 Sep 2026 00:00:00 GMT</pubDate></item><item><title>supabase-jsのtry/catchは死んでいる。version凍結の根拠をerrorごと捨てていた</title><link>https://tech.rebounder.jp/posts/supabase-js-no-throw-contract-version-freeze-error-swallowed/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/supabase-js-no-throw-contract-version-freeze-error-swallowed/</guid><description>supabase-jsは通信/PostgREST失敗でもthrowせずdata:null,errorを返すため、dataだけ見るtry/catchのcatch節は発火しない。契約書テンプレートのversion凍結ロジックがerrorを捨て、一過性の読取失敗でも同意していない古い版を凍結しうる原因と直し方を書く。</description><pubDate>Wed, 09 Sep 2026 00:00:00 GMT</pubDate></item><item><title>read-merge-writeはFOR UPDATE無しでキーが消える</title><link>https://tech.rebounder.jp/posts/display-settings-read-merge-write-lost-update-without-lock/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/display-settings-read-merge-write-lost-update-without-lock/</guid><description>school_configsの相乗りキーを保存するServer Actionは、既存値のSELECTをFOR UPDATEで行ロックしていなかったため、並行保存でキー更新がlast-writer-winsで消えるロストアップデートが起きていた。原因と行ロックでの直し方を書く。</description><pubDate>Tue, 08 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Kotlinの?.let末尾のif/else-ifは式扱いでelse必須になる</title><link>https://tech.rebounder.jp/posts/kotlin-let-trailing-if-elseif-no-else-exhaustive-expression-error/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/kotlin-let-trailing-if-elseif-no-else-exhaustive-expression-error/</guid><description>Kotlinで?.letブロックの最後にelseの無いif/else-ifだけを置くと &quot;if must have both main and else branches if used as an expression&quot; でコンパイルが落ちる。原因と早期returnへの書き直し方。</description><pubDate>Tue, 08 Sep 2026 00:00:00 GMT</pubDate></item><item><title>SpeechRecognitionのnot-allowedとno-speechを出し分けてマイク無反応を直した</title><link>https://tech.rebounder.jp/posts/speechrecognition-not-allowed-benign-vs-serious-error-hint/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/speechrecognition-not-allowed-benign-vs-serious-error-hint/</guid><description>マイクの🎤ボタンがnot-allowedやaudio-captureのとき押しても無反応だった。全エラーをただ無視していたのが原因だが、no-speechのような良性コードまで警告を出すと今度は誤警告でうるさくなる。深刻なコードだけ拾う純関数に処理を集約して直した。</description><pubDate>Tue, 08 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Promise.allで同じ行を並行replace-saveするとlast-writer-winsで消える</title><link>https://tech.rebounder.jp/posts/editor-promise-all-last-writer-wins-duplicate-day/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/editor-promise-all-last-writer-wins-duplicate-day/</guid><description>AIの複数日まとめ編集が当日をtop-levelとdaysの両方に出すと、同じ(クラス,日付,セクション)行への並行replace-saveがPromise.all内でlast-writer-winsになり、盤面の一部セクションが消える。原因と、二重書き込みをスキップするガードでの直し方を書く。</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate></item><item><title>空文字のcontractIdがinvalid input syntax for type uuidを起こす</title><link>https://tech.rebounder.jp/posts/stripe-setup-mode-empty-contractid-invalid-uuid-postgres/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/stripe-setup-mode-empty-contractid-invalid-uuid-postgres/</guid><description>Stripeの会社レベルのカード登録（Setup Mode）はcontractIdを持たないが、呼び出し側の型がstring必須のままだったため空文字に変換して契約更新へ渡し、Postgresがinvalid input syntax for type uuidで拒否していた。</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Drizzleのupsert(onConflictDoUpdate)はCOALESCEが無いと直前の値をnullで潰す</title><link>https://tech.rebounder.jp/posts/drizzle-onconflictdoupdate-coalesce-last-known-good-null/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/drizzle-onconflictdoupdate-coalesce-last-known-good-null/</guid><description>そらまめ君の大気質データが一部だけnullで返る時間帯があり、Drizzleのupsert(onConflictDoUpdate)で素朴にsetすると、直前まで記録していた実測PM2.5やWBGTピーク値をnullで上書きしてしまう。原因とCOALESCEでの直し方。</description><pubDate>Sun, 06 Sep 2026 00:00:00 GMT</pubDate></item><item><title>CSPのframe-src欠落でYouTube埋め込みが全滅、視聴ログも無音で止まる</title><link>https://tech.rebounder.jp/posts/haiia-csp-missing-frame-src-blocks-youtube-breaks-watch-tracking/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/haiia-csp-missing-frame-src-blocks-youtube-breaks-watch-tracking/</guid><description>学習動画のCSPにframe-srcが無く、default-src &apos;self&apos;がYouTube埋め込みを全ブロックしていた。IFrame APIのwindow.YTも生えず、視聴時間の記録が静かに止まっていた。</description><pubDate>Sun, 06 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Server ActionsのbodySizeLimit変更だけでは足りず、エラー境界に落ちる</title><link>https://tech.rebounder.jp/posts/nextjs-server-actions-bodysizelimit-still-hits-error-boundary/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/nextjs-server-actions-bodysizelimit-still-hits-error-boundary/</guid><description>Next.jsのServer Actionsは既定で1MBを超えるとreturn前にthrowし、グローバルエラー境界に落ちる。bodySizeLimitを上げるだけでなく、クライアント・サーバー双方に総量ガードを入れて解消した。</description><pubDate>Sun, 06 Sep 2026 00:00:00 GMT</pubDate></item><item><title>cqw(container-query)は、DOM構造の変更で黙って効かなくなる</title><link>https://tech.rebounder.jp/posts/css-container-query-cqw-context-dependent-fails-silently/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/css-container-query-cqw-context-dependent-fails-silently/</guid><description>container-query単位(cqw)でtransform:scaleさせていた盤面プレビューが、周辺DOM構造の変更で.frameの幅が定まらなくなり、原寸のまま16:9枠に入って右と下が切れた。ResizeObserverで実幅を計測しwidthを明示する方式に直した。</description><pubDate>Fri, 04 Sep 2026 00:00:00 GMT</pubDate></item><item><title>buildSignagePayloadForClassを使わない盤面プレビューは自動ブロックが実機と食い違う</title><link>https://tech.rebounder.jp/posts/editor-preview-hand-built-payload-drifts-from-device-builder/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/editor-preview-hand-built-payload-drifts-from-device-builder/</guid><description>WYSIWYGエディタの盤面プレビューはbase(boardBase)を手組みし、news/trainStatus等の自動ブロックをnull固定していた。実機は単一ソースのbuilderで全ブロックを取得するため、実機と表示が違う結果になる。原因と直し方。</description><pubDate>Fri, 04 Sep 2026 00:00:00 GMT</pubDate></item><item><title>pdfjs-distのstandard_fontsがNext.js standaloneに同梱されない</title><link>https://tech.rebounder.jp/posts/pdfjs-dist-standard-fonts-nextjs-standalone-not-bundled/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/pdfjs-dist-standard-fonts-nextjs-standalone-not-bundled/</guid><description>pdfjs-distは標準フォントをfile://で動的読込するため、Next.jsのfile tracingが追跡できずstandaloneビルドに同梱漏れする。v6ではgetTextContent()がUnknownErrorExceptionで壊れる。設定と起動時assertで対処した。</description><pubDate>Fri, 04 Sep 2026 00:00:00 GMT</pubDate></item><item><title>送信ボタンをFormDataで判定しないとハイドレーション前は押せない</title><link>https://tech.rebounder.jp/posts/react-controlled-disabled-button-breaks-progressive-enhancement/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/react-controlled-disabled-button-breaks-progressive-enhancement/</guid><description>Reactでサーバーの状態からdisabled属性を制御すると、ハイドレーション前やJS失敗時にボタンが永久に無効で送信できない。署名フォームが送れなくなった原因と、required+常時有効化とFormData判定で直した経緯。</description><pubDate>Fri, 04 Sep 2026 00:00:00 GMT</pubDate></item><item><title>同一フィードのURL重複でON CONFLICT DO UPDATEが21000で全断した</title><link>https://tech.rebounder.jp/posts/postgres-on-conflict-do-update-cannot-affect-row-twice-feed-dedup/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/postgres-on-conflict-do-update-cannot-affect-row-twice-feed-dedup/</guid><description>1本のON CONFLICT DO UPDATEで複数記事をupsertするジョブが、同一フィードの同じURLで &quot;ON CONFLICT DO UPDATE command cannot affect row a second time&quot;（21000）となり、fail-softなcatchで無音skipしていた。</description><pubDate>Thu, 03 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Stripe webhook冪等台帳のINSERT失敗、23505以外も200で握り潰していた</title><link>https://tech.rebounder.jp/posts/stripe-webhook-ledger-insert-error-swallowed-as-duplicate/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/stripe-webhook-ledger-insert-error-swallowed-as-duplicate/</guid><description>Stripeのwebhookは冪等台帳stripe_eventsへのINSERT失敗を、理由を問わず二重配信の200 no-opとして返していた。UNIQUE制約違反(23505)以外のDB一時障害もこれに含まれるため、Stripeは成功と解釈して再送せず、イベントが恒久的に失われる。原因と直し方を書く。</description><pubDate>Thu, 03 Sep 2026 00:00:00 GMT</pubDate></item><item><title>turbo.jsonにpassThroughEnvが無いとテストが黙って全skipのままCIがgreenになる</title><link>https://tech.rebounder.jp/posts/turbo-passthroughenv-missing-rls-tests-silently-skipped/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/turbo-passthroughenv-missing-rls-tests-silently-skipped/</guid><description>turbo.jsonのtest taskにpassThroughEnvが無いと、CIにDATABASE_URLがあってもturboはそれをvitestへ渡さない。テストは未設定をdescribe.skipで検知するだけなのでCIはgreenのまま、RLSテスト24件が一度も実行されていなかった。</description><pubDate>Thu, 03 Sep 2026 00:00:00 GMT</pubDate></item><item><title>ポーリングだけDateが文字列化し、getTime is not a functionで盤面が落ちた</title><link>https://tech.rebounder.jp/posts/json-poll-response-date-string-gettime-not-a-function/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/json-poll-response-date-string-gettime-not-a-function/</guid><description>SSRの初期描画ではDateがそのまま復元されるのに、同じ画面の自動更新ポーリングだけres.json()経由でDateが文字列化する。ニュース日付整形が文字列に対し.getTime()を呼びTypeErrorで盤面ごとエラー画面に落ちた。JSON.parseのreviverで両方の描画経路を揃えて解消した。</description><pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate></item><item><title>setContentView前はinsetsControllerがnullでImmersiveが効かない</title><link>https://tech.rebounder.jp/posts/android-insetscontroller-null-before-setcontentview/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/android-insetscontroller-null-before-setcontentview/</guid><description>Android で setContentView() より前に window.insetsController を呼ぶと、DecorView 未確定で null が返り、hide() が動かずImmersiveモードが黙って効かない。呼び出し順序を setContentView 後へ移して直した。</description><pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate></item><item><title>キオスク端末の消灯がstartActivity1本頼りで、失敗すると朝まで点灯したままになる</title><link>https://tech.rebounder.jp/posts/android-kiosk-overlay-startactivity-can-silently-fail-leaving-screen-on/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/android-kiosk-overlay-startactivity-can-silently-fail-leaving-screen-on/</guid><description>常時起動のAndroidキオスク端末で夜間の黒画面をBlackScreenActivityへのstartActivity1回に頼ると、BAL制限やオーバーレイ権限(SYSTEM_ALERT_WINDOW)未許可でその呼び出しが失敗した瞬間、画面は消えないまま朝を迎える。</description><pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate></item><item><title>maybeSingleで1件決め打ちすると、複数行ヒットでPGRST116の404になる</title><link>https://tech.rebounder.jp/posts/supabase-maybesingle-multiple-rows-pgrst116-permanent-404/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/supabase-maybesingle-multiple-rows-pgrst116-permanent-404/</guid><description>署名の控えPDFを配信するAPIは一意制約が3列複合なのに、クエリは2列だけで絞り込んでmaybeSingle()に渡していた。同じ組で複数行が存在した瞬間PGRST116を返し、実在する控えが恒久404になっていた。</description><pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate></item><item><title>SECURITY DEFINER関数はPUBLIC EXECUTE既定でanonから直接呼べる</title><link>https://tech.rebounder.jp/posts/supabase-security-definer-function-default-public-execute-exposes-rpc/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/supabase-security-definer-function-default-public-execute-exposes-rpc/</guid><description>SECURITY DEFINERの書込RPCはPostgreSQLの既定でPUBLIC EXECUTEが付く。revokeしない限りSupabaseのPostgREST層を経由してanon/authenticatedロールから直接呼び出せる。実際に塞いだrevoke/grantの手順まで書く。</description><pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate></item><item><title>相乗りキーの設定行をロック無しで読んで→マージして→書くと、同時保存でキーが消える</title><link>https://tech.rebounder.jp/posts/colocated-config-key-lost-update-without-row-lock/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/colocated-config-key-lost-update-without-row-lock/</guid><description>1つのJSONB行に複数の設定キーを相乗りさせ、既存値を読んでスプレッドしてから書き戻すread-merge-write upsertは、その読み取りをSELECT ... FOR UPDATEで行ロックしない限り、並行更新と競合したとき相手が直前に書いたキーごと上書きして消す。原因と、行ロックでの直し方を書く。</description><pubDate>Sun, 30 Aug 2026 00:00:00 GMT</pubDate></item><item><title>学年はあるが学科は無い状態だけ「学科を追加」の導線が無かった</title><link>https://tech.rebounder.jp/posts/conditional-branch-hides-first-item-creation-entry-point-stuck-ui/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/conditional-branch-hides-first-item-creation-entry-point-stuck-ui/</guid><description>学校構成画面はisEmptyとhasDepartmentsの2つの真偽値で3状態に分岐し、条件分岐で最初の1件を作る導線が消えるUIの詰みが起きていた。学年はあるが学科が無い状態だけ「学科を追加」が無い。原因と直し方。</description><pubDate>Sun, 30 Aug 2026 00:00:00 GMT</pubDate></item><item><title>規約改定の再同意フォームがauto_renewをリセットしない</title><link>https://tech.rebounder.jp/posts/contract-reconsent-does-not-reset-auto-renew/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/contract-reconsent-does-not-reset-auto-renew/</guid><description>自動更新条項を削除した改定版の規約に再同意しても、自動更新フラグがtrueのまま残ることがある。原因はフラグを立てる関数がfalse→trueの一方向にしか書き込まない設計で、再同意（署名リセット）の側で明示的に倒さない限りtrueが残り続け、満了時に後継契約が自動生成・自動請求される。</description><pubDate>Sun, 30 Aug 2026 00:00:00 GMT</pubDate></item><item><title>transform:scaleで固定サイズに縮小表示していても、メディアクエリは実ビューポート幅で評価される</title><link>https://tech.rebounder.jp/posts/media-query-still-uses-real-viewport-inside-scaled-fixed-stage/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/media-query-still-uses-real-viewport-inside-scaled-fixed-stage/</guid><description>1280×720の固定ステージをtransform:scaleで縮小表示するプレビューが、@media(min-width)は縮小後ではなく実デバイスのビューポート幅で評価されるため、大型モニタでは大画面向けプロファイルが適用されてステージからはみ出した。</description><pubDate>Sun, 30 Aug 2026 00:00:00 GMT</pubDate></item><item><title>left:50%とwidth:fit-contentを組むとmax-widthが効かない</title><link>https://tech.rebounder.jp/posts/absolute-left-50-fit-content-max-width-never-applies/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/absolute-left-50-fit-content-max-width-never-applies/</guid><description>position:absoluteをleft:50%+width:fit-contentで中央寄せしたら、指定したmax-widthより手前で強制的に折り返された。shrink-to-fitのavailable widthがleftオフセット分だけ縮むのが原因。</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate></item><item><title>insetのbox-shadowで描いた縁取りが子要素の背景に隠れて消える</title><link>https://tech.rebounder.jp/posts/inset-box-shadow-ring-hidden-by-static-child-background/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/inset-box-shadow-ring-hidden-by-static-child-background/</guid><description>白い盤面の上でも暗幕の上でも見えるようにと縁取りをinset box-shadowで描いたら、入稿プレビューの背景を持つ子要素の下に隠れて消えました。insetのbox-shadowは要素自身の背景/ボーダー段で塗られるため、静的配置の子要素の背景に必ず負けるのが原因です。</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate></item><item><title>編集フォームが最新の選択肢一覧に無い選択を自動で間引き、無関係な保存で対象が黙って消えた</title><link>https://tech.rebounder.jp/posts/edit-form-prunes-selections-missing-from-stale-list-silent-data-loss/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/edit-form-prunes-selections-missing-from-stale-list-silent-data-loss/</guid><description>編集フォームは、v2から取得し直したモニタ一覧に無い選択IDを検知すると自動でselectedから間引いて上書きしていた。価格だけ直すつもりで保存すると、一覧の側の変動につられて対象モニタが黙って減る。原因と、警告表示+hiddenで送りサーバーに弾かせるfail-closedな直し方を書く。</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate></item><item><title>非数値のenv変数はNaNとして??をすり抜け、embeddingが0件・fetchが即abortになった</title><link>https://tech.rebounder.jp/posts/env-nan-parseint-nullish-coalescing-immediate-abort/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/env-nan-parseint-nullish-coalescing-immediate-abort/</guid><description>env変数が非数値だとNumber.parseIntはNaNを返す。truthyチェックと後段の?? 既定値の両方をすり抜け、embeddingは0件・fetchはsetTimeout(abort, NaN)で即中断され続けた。原因と直し方を書く。</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate></item><item><title>親ページの許可ロールだけ絞り込み、子コンポーネント内の別ロールガードを直し忘れて未捕捉の403例外を出した</title><link>https://tech.rebounder.jp/posts/parent-page-role-narrowed-child-component-gate-left-behind-forbidden-error/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/parent-page-role-narrowed-child-component-gate-left-behind-forbidden-error/</guid><description>効果ダッシュボードのrequireRoleをSYSTEM_ADMIN_ROLES専用に絞り込んだが、ページ内のAI効果コメントパネルが呼ぶServer ActionはPUBLISHER_ROLES gateのままで、未捕捉のForbiddenErrorをレビューで見つけて同コミット内で撤去した経緯を書く。</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate></item><item><title>決済成功後のDB反映失敗をカード失敗と誤認し、二重請求になりかけた</title><link>https://tech.rebounder.jp/posts/stripe-post-charge-db-failure-misdiagnosed-as-card-decline/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/stripe-post-charge-db-failure-misdiagnosed-as-card-decline/</guid><description>オフセッション課金でPaymentIntent作成の成否とDB反映(markContractPaid)の成否を同じtry/catchで扱うと、課金成立後の一過性DB書込エラーがカード失敗と誤診断され、課金済みのカードに対してさらに請求書フォールバックを発行し二重請求になる。原因と直し方を書く。</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate></item><item><title>監査ログのRLS policyがactor_user_id=NULLを許すと、乗っ取られたアカウントが操作痕跡を消せる</title><link>https://tech.rebounder.jp/posts/audit-log-rls-null-actor-allows-repudiation/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/audit-log-rls-null-actor-allows-repudiation/</guid><description>監査ログテーブルへのINSERTを許すRLS policyがactor_user_id IS NULLを無条件に許可していた。乗っ取られたテナント内アカウントがactor=NULLで自分の操作を記録すれば、追跡から逃れられる。system_adminだけNULLを許す例外設計に直した話。</description><pubDate>Thu, 27 Aug 2026 00:00:00 GMT</pubDate></item><item><title>stickyのtop:0が残ったままfixedにすると下部固定バーが全画面化する</title><link>https://tech.rebounder.jp/posts/css-fixed-inherited-top-zero-bottom-zero-fullscreen-stretch/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/css-fixed-inherited-top-zero-bottom-zero-fullscreen-stretch/</guid><description>sticky用のtop:0をリセットしないままposition:fixedへ切り替えると、bottom:0と両立してボックスがviewport全高にストレッチする。モバイルの下部固定タブバーが画面全体を覆って操作不能になった事故を、CSSの差分だけで直した記録。</description><pubDate>Thu, 27 Aug 2026 00:00:00 GMT</pubDate></item><item><title>配布パッケージの漏洩検査は、grepの対象パスがパッケージの半分しか見ていなかった</title><link>https://tech.rebounder.jp/posts/dist-sanitizer-denylist-grep-misses-new-internal-string/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/dist-sanitizer-denylist-grep-misses-new-internal-string/</guid><description>販売用パッケージのビルドに社内限定コメントを見つけるgrep検査を入れていたのに、配布物へ混入して買い手に指摘された。原因は検査語リストの不足ではなく、対象パスがパッケージの半分しか見ておらずすり抜けたこと。</description><pubDate>Thu, 27 Aug 2026 00:00:00 GMT</pubDate></item><item><title>新しい httpOnly cookie を追加してデプロイすると、ログイン済みユーザーだけ401になる</title><link>https://tech.rebounder.jp/posts/new-httponly-cookie-not-issued-until-relogin-after-deploy/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/new-httponly-cookie-not-issued-until-relogin-after-deploy/</guid><description>書き込みAPI専用のhttpOnly + HMAC署名cookieを新設してデプロイしたところ、デプロイ前からログイン中だった運営担当だけ、画面はログイン済みのまま一覧取得が401で失敗した。原因は新cookieがログイン時にしか配られないこと。401ハンドラで自動リロードして直した記録。</description><pubDate>Wed, 26 Aug 2026 00:00:00 GMT</pubDate></item><item><title>middlewareのmatcher除外に登録し忘れた公開ページが、匿名端末をログイン画面へ誤誘導していた</title><link>https://tech.rebounder.jp/posts/nextjs-middleware-matcher-missing-public-route-login-redirect/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/nextjs-middleware-matcher-missing-public-route-login-redirect/</guid><description>公開サイネージ表示は端末が__sessionを持たない匿名経路だが、middlewareのmatcher除外リストに登録し忘れていたため、そのままだと/loginへリダイレクトされ実機に到達できなかった。既存の/s/や/studentと同じnegative lookaheadにsignage/を足して解消した記録。</description><pubDate>Wed, 26 Aug 2026 00:00:00 GMT</pubDate></item><item><title>契約更新のたびに枠を複製し、旧行を終了し忘れると在庫定員が二重に消費される</title><link>https://tech.rebounder.jp/posts/renewal-successor-rows-without-retiring-predecessor-double-counts-capacity/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/renewal-successor-rows-without-retiring-predecessor-double-counts-capacity/</guid><description>サブスクリプションの自動更新バッチが後継契約へplacementsを複製する一方、元の行を終了扱いにしないと残り枠の集計が両方を数え続け、在庫定員が二重消費される。複製失敗時は元行を残す安全側の直し方。</description><pubDate>Wed, 26 Aug 2026 00:00:00 GMT</pubDate></item><item><title>ORDER BYの無いLIMIT 1が、複数テナントのstagingで別の校のadminを返す</title><link>https://tech.rebounder.jp/posts/dev-login-missing-orderby-returns-wrong-tenant-admin/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/dev-login-missing-orderby-returns-wrong-tenant-admin/</guid><description>dev-loginのschool_admin解決はORDER BYの無いSELECT LIMIT 1で書かれており、複数テナントのテストデータが増えるとPostgreSQLの行順に依存して意図しない学校のuidを返しうる状態だった。DEVLOGIN_TEST校を優先する決定的なORDER BYで直した経緯を書く。</description><pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Next.js の proxy.ts が API キー認証のエンドポイントもログイン画面へ飛ばしていた</title><link>https://tech.rebounder.jp/posts/nextjs-middleware-external-api-key-auth-redirected-to-login/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/nextjs-middleware-external-api-key-auth-redirected-to-login/</guid><description>Next.js の proxy.ts はセッション認証の除外パスに /api/health しか列挙しておらず、独自の API キー認証を持つ /api/v1/ と /api/mcp/ を後から追加した際に除外し忘れ、外部からのリクエストがログイン画面へリダイレクトされていた。原因と直し方を書く。</description><pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Supabase の update で未送信フィールドを `??` の既定値にすると既存の値が上書きされる</title><link>https://tech.rebounder.jp/posts/supabase-update-partial-field-nullish-coalesce-overwrite/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/supabase-update-partial-field-nullish-coalesce-overwrite/</guid><description>編集フォームに availability 欄が無いだけで、保存のたびに掲載中の枠が空きへ巻き戻っていた。原因は `val(formData.get(&quot;availability&quot;)) ?? &quot;空き&quot;` という書き方で、未送信フィールドを既存値ではなく常にデフォルト値として扱っていたこと。直し方まで書く。</description><pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate></item><item><title>セット割引の判定を「保有しているか」だけにすると、買い増すたびに再発する</title><link>https://tech.rebounder.jp/posts/bundle-discount-reapplied-on-every-purchase-without-granted-check/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/bundle-discount-reapplied-on-every-purchase-without-granted-check/</guid><description>まとめて保有すると自動適用されるセット割引を「対象を全部保有しているか」だけで判定していたため、買い増しのたびに何度も適用される冪等性のバグになっていた。契約テーブルに『既に付与済みか』を持たせて防いだ経緯。</description><pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate></item><item><title>ロックは効いているのに件数だけ二重になる。数えていたのは書き込みではなく「書くつもり」だった</title><link>https://tech.rebounder.jp/posts/for-update-count-intent-vs-actual-writes/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/for-update-count-intent-vs-actual-writes/</guid><description>FOR UPDATEで直列化したのに件数が合わない。TV死活チェッカのサマリがnewlyDown合計1のはずが2になるflakyテストの原因は、classificationの長さで数えて同時発火の敗者側まで二重計上していたこと。実書込件数を返す直し方。</description><pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate></item><item><title>仮パスワードの強制変更が直URLで素通りしていた。ガードを画面ごとに書くと必ず付け忘れる</title><link>https://tech.rebounder.jp/posts/forced-password-change-bypassed-by-direct-url/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/forced-password-change-bypassed-by-direct-url/</guid><description>must_change_passwordの広告主が/dashboard以外へ直URLでアクセスすると、強制パスワード変更を素通りできた。原因は強制リダイレクトが2画面にしか書かれておらず、チェックが画面ごとに散在していたこと。requireCustomer()に集約して直した記録。</description><pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate></item><item><title>RLSを有効にしても、TRUNCATE権限が残っていれば安全ではなかった</title><link>https://tech.rebounder.jp/posts/postgres-truncate-bypasses-rls-even-when-enabled/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/postgres-truncate-bypasses-rls-even-when-enabled/</guid><description>PostgreSQLのTRUNCATEはRLSをバイパスする。RLSを有効にしポリシーを0にしてもSupabaseの既定GRANTでanon/authenticatedにTRUNCATEが残り、テーブルを空にできた。実測に基づく直し方。</description><pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate></item><item><title>エラーメッセージを運用者向けの日本語にした副作用で、dead-letterから原因を辿れなくなった</title><link>https://tech.rebounder.jp/posts/dead-letter-error-humanized-loses-traceable-id/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/dead-letter-error-humanized-loses-traceable-id/</guid><description>配信の被覆検証は運営フォーム向けの日本語メッセージだけを返しており、それをdead-letterのlast_errorへ転用すると学校IDが失われ、ログからは原因の学校を特定できなくなっていた。検証結果に機械可読なcode/schoolsを足して分離した直し方を書く。</description><pubDate>Sat, 22 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Permissions-Policy: microphone=() は自オリジンの音声入力も塞ぐ</title><link>https://tech.rebounder.jp/posts/permissions-policy-microphone-self-blocks-web-speech/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/permissions-policy-microphone-self-blocks-web-speech/</guid><description>Permissions-Policy: microphone=() は「どのオリジンにも許可しない」という意味でselfを含まない。多層防御として追加した結果、自社アプリのWeb Speech APIによる音声入力がプロンプトすら出さずに全面遮断された。microphone=(self)へ変更して解消した経緯を書く。</description><pubDate>Sat, 22 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Checkout Session の期限を省くと、離脱した予約が24時間分の席を占有する</title><link>https://tech.rebounder.jp/posts/stripe-checkout-session-default-24h-expiry-holds-reservation-seat/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/stripe-checkout-session-default-24h-expiry-holds-reservation-seat/</guid><description>Stripe Checkout Session に expires_at を指定しないと既定で24時間有効になり、決済せず離脱した予約もその間ずっと定員を占有し続ける。予約サイトで実際に起きた事故と、Stripe が許す最短30分への短縮で解決した経緯。</description><pubDate>Sat, 22 Aug 2026 00:00:00 GMT</pubDate></item><item><title>streamObjectのabortでusage Promiseがunhandled rejectionになる</title><link>https://tech.rebounder.jp/posts/ai-sdk-streamobject-abort-unhandled-rejection/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/ai-sdk-streamobject-abort-unhandled-rejection/</guid><description>Vercel AI SDKのstreamObjectにAbortSignalを配線すると、中断時にresult.usage（完了後に解決するPromise）がrejectする。呼び出し元がその経路でdoneをawaitしていないと、誰にも拾われずNode.jsのunhandled rejectionになる。</description><pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Semgrep detect-non-literal-regexpの誤検知は、到達不能な分岐を型で消して直した</title><link>https://tech.rebounder.jp/posts/semgrep-non-literal-regexp-dead-branch-false-positive/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/semgrep-non-literal-regexp-dead-branch-false-positive/</guid><description>E2Eテストの`new RegExp(c.path.replace(...))`というフォールバック分岐がSemgrepのdetect-non-literal-regexpに引っかかりSASTが赤くなった。分岐自体は全ケースがallowUrlを持つため到達不能で、suppressせず型で分岐そのものを消して解消した話。</description><pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate></item><item><title>デプロイ後に無関係な機能が消えた。原因は分岐元が古いブランチだった</title><link>https://tech.rebounder.jp/posts/stale-branch-deploy-silently-reverts-merged-features/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/stale-branch-deploy-silently-reverts-merged-features/</guid><description>同じ手順でCloud Runのイメージタグを差し替えても、ビルド元のブランチの枝分かれ点が古いと、その後mainにマージ済みの機能はgit revertコミットを1つも作らずに本番から消える。デプロイの実体はgitの履歴ではなくタグの差し替えでしかないため、症状は無関係な2件の不具合として報告される。</description><pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate></item><item><title>YT.Playerでdivを置き換える埋め込み方式は、タイミング次第で黒画面のまま再生されない</title><link>https://tech.rebounder.jp/posts/youtube-iframe-player-div-replace-black-screen/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/youtube-iframe-player-div-replace-black-screen/</guid><description>YouTube IFrame APIでdiv要素をPlayerに渡して初期化する方式は、divがiframeに置き換わるまで画面に何も表示されず、タイミング次第で黒画面のまま再生が始まらないことがある。iframeをsrc付きで直接描画し、YT APIは後から紐づける方式に変えた経緯を書く。</description><pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate></item><item><title>唯一の呼出し元が消えたロール変更 seam を、それ自体が攻撃面として撤去する</title><link>https://tech.rebounder.jp/posts/dormant-privilege-escalation-seam-removed/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/dormant-privilege-escalation-seam-removed/</guid><description>使われなくなった権限変更関数を消し忘れると攻撃面になる。任意ロール・任意スクールIDをIdPのclaimへ書ける関数が、唯一の呼出し元が撤去されたあとも本番に残っていた。docstringの安全保証は呼出し元の存在に依存していた。</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate></item><item><title>pdf-lib + fontkit で生成した帳票PDFの電話番号がコピペで化ける</title><link>https://tech.rebounder.jp/posts/pdf-lib-fontkit-gsub-digit-garbling/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/pdf-lib-fontkit-gsub-digit-garbling/</guid><description>NotoSansJP を fontkit 経由で pdf-lib に埋め込むと、電話番号などの数字だけコピー・検索・pdftotext で化けることがある。原因は GSUB の文脈置換で、pdf-lib の ToUnicode CMap には既定グリフしか載らないためだった。</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate></item><item><title>フォームをkeyで再マウントすると、検証エラー直後の保存で入力値が既定値に戻る</title><link>https://tech.rebounder.jp/posts/react-key-remount-resets-uncontrolled-input/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/react-key-remount-resets-uncontrolled-input/</guid><description>Reactでkey再マウントするフォームは、defaultValueで渡した制御されていない入力がバリデーションエラー直後の再送信でも一緒にリセットされ、画面の値と違うデフォルト値に戻る値が保存される。原因と直し方。</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate></item><item><title>契約更新のバッチ処理で、後継行に外部キーを引き継ぐと同日中にステータスが巻き戻る</title><link>https://tech.rebounder.jp/posts/renewal-creative-id-revives-ended-placement/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/renewal-creative-id-revives-ended-placement/</guid><description>同日に走る複数のバッチ処理でステータスが元に戻る。契約更新バッチが枠(placements)を複製する際にcreative_idを新旧に残すと、同じcron run内の別バッチが元行を「申込済」へ巻き戻し、定員リークが再発する。</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate></item><item><title>マイグレーションファイルの連番が2つ重複していた</title><link>https://tech.rebounder.jp/posts/duplicate-migration-sequence-number/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/duplicate-migration-sequence-number/</guid><description>別々のfeatureブランチで作ったマイグレーションファイルが、どちらも0035番を使っていた。本番へは冪等なSQLとして両方適用され実害は無かったが、新規環境やstagingを連番順に流すと適用順序があいまいになる。衝突を警戒していたはずの側も、もう一方の存在には気づけなかった。</description><pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate></item><item><title>環境変数の既定値が staging バケットのままだと、destroy で本番画像が消える</title><link>https://tech.rebounder.jp/posts/env-default-bucket-leaks-across-environments/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/env-default-bucket-leaks-across-environments/</guid><description>seed スクリプトの環境変数に既定値（フォールバック）として他環境のバケット名を残していると、明示的に上書きしない限りその値がそのまま本番データベースに書き込まれる。staging を destroy した瞬間に本番の画像参照先ごと消えた実例と、原因・直し方・再発防止を書く。</description><pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate></item><item><title>フォームの一部だけ制御値にすると、保存失敗後の再送信で設定が黙って元に戻る</title><link>https://tech.rebounder.jp/posts/react-partial-controlled-fields-silent-revert/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/react-partial-controlled-fields-silent-revert/</guid><description>React 19 の &lt;form action&gt; は送信の成否に関わらず、制御していない入力を defaultValue へ戻します。一部の項目だけ制御値にしたフォームでは、検証エラーで戻った画面は制御外の項目だけが黙って元に戻り、フォームが無事に見えるぶん気づかず再送信してしまいます。</description><pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate></item><item><title>一部の設定にしか無い機能へのリンクを出しっぱなしにして502になった</title><link>https://tech.rebounder.jp/posts/unconditional-link-to-tenant-only-pdf-feature/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/unconditional-link-to-tenant-only-pdf-feature/</guid><description>申込書ページのPDF控えリンクは、特定の書式にしか対応していないPDF生成ルートを、対応・非対応を問わず全ユーザーに無条件で表示していた。非対応側の設定でリンクを踏むと、生成処理は失敗せず「対象外」を返しているのに、呼び出し元がそれを異常として扱い502になっていた。原因と直し方を書く。</description><pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate></item><item><title>CHECK 制約を張り替えるたび、別ブランチが足した値が消えていた</title><link>https://tech.rebounder.jp/posts/check-constraint-rewrite-drops-branch-value/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/check-constraint-rewrite-drops-branch-value/</guid><description>PostgreSQL の CHECK 制約を DROP して張り替える設計では、後から書いたマイグレーションが別ブランチで追加された値を知らないまま制約を書き直し、値ごと消してしまう。share_links.kind から receipt が消えた事故の原因と、和集合で冪等に復元する直し方。</description><pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate></item><item><title>23503 の外部キー違反が「競合しました」に化けて本番だけ全断した</title><link>https://tech.rebounder.jp/posts/fk-violation-masked-as-conflict/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/fk-violation-masked-as-conflict/</guid><description>system_admin による広告入稿が本番でだけ必ず失敗し、画面には「他の操作と競合しました」と出た。実際の原因は外部キー違反(23503)で、それを一意制約違反・検査制約違反と同じ扱いにするエラーハンドラが同じメッセージへ丸めていた。DBをモックしたテストは制約そのものを検証していなかった。</description><pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate></item><item><title>アプリ側のパスワード最小文字数がIdentity Platformの下限より緩くて本番だけ落ちた</title><link>https://tech.rebounder.jp/posts/idp-password-min-length-mismatch/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/idp-password-min-length-mismatch/</guid><description>アプリ側のパスワード最小文字数(4)がIdentity Platformの下限(6)より緩く、createUserがauth/invalid-passwordを返して本番だけ落ちた。IdPの拒否がcatchされずエラーバウンダリまで吹き上がっていた。</description><pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate></item><item><title>教員ログインを有効化しても画面に出ない、原因は force-dynamic 書き忘れの静的プリレンダ</title><link>https://tech.rebounder.jp/posts/nextjs-static-prerender-hides-flag-flip/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/nextjs-static-prerender-hides-flag-flip/</guid><description>認証を経ない公開ページに動的 API の呼び出しが無いと、Next.js はビルド時点の状態でそのルートを静的プリレンダし、CDN が s-maxage で長期キャッシュします。DB の値を後から変えても、force-dynamic を明示しない限り画面には反映されません。本番ヘッダーから原因を特定した手順を書きます。</description><pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate></item><item><title>UIでは編集を凍結していても、サーバー側が同じ条件を見ていなければ偽装POSTで書き換えられる</title><link>https://tech.rebounder.jp/posts/ui-freeze-not-enforced-server-side/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/ui-freeze-not-enforced-server-side/</guid><description>配信枠の編集画面はUIでは編集不可にしているのに、APIが検証しておらず直接POSTで書き換えられる状態だった。更新処理は「稼働中」しか見ておらず、買い切り直後で申込0件のタイミングだけ配信先を書き換えられた。</description><pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Androidの常駐サービスは、クラッシュせずに死ぬことがある</title><link>https://tech.rebounder.jp/posts/android-service-dies-without-crashing/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/android-service-dies-without-crashing/</guid><description>Androidのフォアグラウンドサービスは、クラッシュせず停止することがある。delayやバックオフ計算側の例外でwhile(true)ごと静かに抜け、アプリは生きたまま中身だけ止まる。成功時刻ベースの生存確認と強制再起動で検知・復帰させた設計。</description><pubDate>Mon, 17 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Cloud Run Job を初めて有効化すると SecretsAccessCheckFailed で落ちる</title><link>https://tech.rebounder.jp/posts/cloud-run-job-secret-iam-race/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/cloud-run-job-secret-iam-race/</guid><description>Terraform で Cloud Run Job と Secret Manager の accessor IAM を同じ apply で新規作成すると、IAM 権限が伝播する前に作成時の secret アクセス検証が走り job が tainted される。depends_on で順序を固定する恒久対応まで書く。</description><pubDate>Mon, 17 Aug 2026 00:00:00 GMT</pubDate></item><item><title>スキャンPDFかどうかを非空白文字数/ページで判定してGeminiに直送する</title><link>https://tech.rebounder.jp/posts/gemini-pdf-ocr-fallback-threshold/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/gemini-pdf-ocr-fallback-threshold/</guid><description>pdfjs-dist はテキストレイヤをそのまま返すため、スキャンPDFはほぼ空文字になる。1ページあたりの非空白文字数が閾値を下回ったときだけPDFバイトをGeminiへfile partとして直送しOCRへフォールバックする、閾値の決め方と画像との送り方の違いを実装から書く。</description><pubDate>Mon, 17 Aug 2026 00:00:00 GMT</pubDate></item><item><title>認証ミドルウェアが robots.txt をログインへリダイレクトする</title><link>https://tech.rebounder.jp/posts/nextjs-middleware-robots-redirect/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/nextjs-middleware-robots-redirect/</guid><description>未ログイン時にログイン画面へ飛ばすミドルウェアは、robots.txt や sitemap.xml も同じ扱いにしてしまいがちです。クローラは 307 を受け取り、Lighthouse の SEO 監査が落ちます。原因は2層あり、片方だけ直しても再発します。</description><pubDate>Mon, 17 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Astro 7 でコンテンツコレクションが3箇所同時に壊れる</title><link>https://tech.rebounder.jp/posts/astro-legacy-content-config/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/astro-legacy-content-config/</guid><description>Astro を上げたら LegacyContentConfigError でビルドが落ちます。設定ファイルの置き場所・loader の必須化・描画 API の3つが同時に変わっているためで、1つ直しても次が出ます。3つまとめて直す形を書きます。</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>drizzle-kit migrate は手書きの SQL を適用しない</title><link>https://tech.rebounder.jp/posts/drizzle-migrate-skips-sql/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/drizzle-migrate-skips-sql/</guid><description>マイグレーションは成功したのに RLS ポリシーも監査トリガも本番に無い。drizzle-kit migrate が流すのは drizzle が生成した DDL だけで、隣のディレクトリに置いた手書き SQL は黙って飛ばされる。確認 SQL と、両方を確実に流す形まで。</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>最初の開発ボードは何を作りたいかで決まる</title><link>https://tech.rebounder.jp/posts/first-dev-board/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/first-dev-board/</guid><description>最初の開発ボードの選び方。ESP32・ラズパイ（Raspberry Pi）・FPGAは守備範囲がまるで違う。通信する装置か、小さいコンピュータか、回路の学習か。3枚とも触った結果と、本番会場で通信が混線したときの対処。</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>GitHub Actions から GCP に繋ぐとき実際に出る3つのエラー</title><link>https://tech.rebounder.jp/posts/gcp-workload-identity-errors/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/gcp-workload-identity-errors/</guid><description>Workload Identity 連携は設定が3層に分かれ、どこが欠けても impersonation が失敗する。iam.serviceAccounts.getAccessToken の権限不足を含め、実際に出た3つのエラー文言を踏む順に並べ、どの層を見るかを書く。</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Gemini の思考トークンが出力上限を食い応答が空になる</title><link>https://tech.rebounder.jp/posts/gemini-thinking-budget-hang/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/gemini-thinking-budget-hang/</guid><description>会話AIが「考えています」のまま本番だけ固まる事故があった。原因は Gemini の思考トークンが maxOutputTokens の枠を食いつぶし、構造化出力が始まる前にトークンが尽きること。クライアント側の終端検知・サーバのストール中断・thinking budget=0 の三層で塞いだ形を書く。</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>気象庁APIの夕方発表をそのまま upsert すると今日の気温が消える</title><link>https://tech.rebounder.jp/posts/jma-evening-forecast-temp-null/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/jma-evening-forecast-temp-null/</guid><description>気象庁の天気予報APIは17時の夕方発表で本日分の気温だけを予報から落とす。ON CONFLICTでそのまま書き込むと、朝に取得していた気温がnullで上書きされ表示が「—」になる。原因と、COALESCEで気温だけ既存値を保持する直し方を書く。</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>FLAG_KEEP_SCREEN_ON を入れても画面が黒くなるのはスクリーンセーバ</title><link>https://tech.rebounder.jp/posts/keep-screen-on-daydream/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/keep-screen-on-daydream/</guid><description>常時表示させたい Android 端末で、FLAG_KEEP_SCREEN_ON もスリープ無効も入れたのに画面が黒くなる。最有力の原因はスクリーンセーバ（Daydream）で、しかも settings put は再起動で全部元に戻る。恒久化までの手順。</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Next.js が wasm パッケージをバンドルすると本番だけ壊れる</title><link>https://tech.rebounder.jp/posts/nextjs-wasm-bundling-broken/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/nextjs-wasm-bundling-broken/</guid><description>PDF生成用WASMライブラリがNext.jsにバンドルされ、本番だけpathの型エラーで壊れた。原因はバンドルするとwasmの相対パス解決が変わること。serverExternalPackagesで外部化し、素のrequireで読ませる直し方まで書く。</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>本番だけ SECURITY DEFINER 関数が効かないのは実行ロールのせい</title><link>https://tech.rebounder.jp/posts/security-definer-owner-role/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/security-definer-owner-role/</guid><description>CI では通るのに本番だけ SECURITY DEFINER 関数が期待どおり動かない。関数のオーナーはマイグレーションを実行したロールになるため、非特権ロールで流すと RLS をバイパスできず常に0行が返る。確認 SQL と是正手順、そして再発しない形まで。</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>動画の静止を ffmpeg で検出するとき、閾値はビット深度で変わる</title><link>https://tech.rebounder.jp/posts/static-frame-threshold-bitdepth/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/static-frame-threshold-bitdepth/</guid><description>tblend と signalstats で静止フレームを機械的に検出するときの落とし穴。YAVG の閾値は輝度のレンジに比例するため、12bit で使っていた 4.8 を 10bit の素材にそのまま当てると判定が丸ごと狂う。実測値と確認手順。</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>supabase-js の条件付き UPDATE は error を見ないと処理済み判定を誤る</title><link>https://tech.rebounder.jp/posts/supabase-update-error-swallowed/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/supabase-update-error-swallowed/</guid><description>Stripe決済の冪等化に使う条件付きUPDATEは、対象0件のとき data:null と error を両方返す。data だけ見て error を捨てると、一時的な書込失敗を「既に処理済み」と誤認し、入金を検知したのに領収書発行を永久にスキップする。throw して Stripe の再配信に載せる直し方まで書く。</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>terraform の enabled = false では環境を撤去できない</title><link>https://tech.rebounder.jp/posts/terraform-enabled-false-cannot-destroy/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/terraform-enabled-false-cannot-destroy/</guid><description>モジュールに enabled フラグを持たせた構成で、環境を畳もうと一括して false にすると Invalid template interpolation value で落ちます。module 呼び出しは評価され続けるため出力が null になるのが原因で、撤去は destroy でしか行えません。</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>AI コーディングツールを一通り使って落ち着いた使い分け</title><link>https://tech.rebounder.jp/posts/ai-coding-tools/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/ai-coding-tools/</guid><description>Claude Code・Cursor・Codex・Gemini を実際に使い分けた結果。複雑な開発とサッと作るものを分け、日常の相棒は別に置く。強いツールほどコストが溶けるという正直な体感も含めて。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>アイキャッチを画像生成で量産するプロンプトの型</title><link>https://tech.rebounder.jp/posts/ai-eyecatch-template/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/ai-eyecatch-template/</guid><description>毎回ゼロから考えず、主役を大きく・下部にタイトル帯・トーンを固定、の3点を骨格にして主役とタイトルだけ差し替える。日本語が崩れる限界と、偽の実機写真を作らない線引きも。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Cloud Run Job はイメージが凍る。直したのに直らない理由</title><link>https://tech.rebounder.jp/posts/cloud-run-job-image-frozen/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/cloud-run-job-image-frozen/</guid><description>ソースを直して commit しても Cloud Run Job には届かない。job が使うイメージは tag で固定されているため、bump して apply しない限り古いコードが動き続ける。実行前の確認手順と、その場をしのぐ env 上書きまで。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>3Dモデルをマウスでこねるのをやめてコードで書く</title><link>https://tech.rebounder.jp/posts/code-cad-3dprint/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/code-cad-3dprint/</guid><description>OpenSCAD と Python で寸法を数値で書き、形を数式で決める。パラメータを変えるだけで寸法違いが量産でき、git で差分管理もできる。作例2つと、STL を手書きするときの法線の罠。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>FPGA 入門ボードに DE10-Lite を選ぶ理由</title><link>https://tech.rebounder.jp/posts/de10-lite-fpga-intro/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/de10-lite-fpga-intro/</guid><description>スイッチ・LED・7セグが基板に載っているので、外付け配線なしで書いた回路がすぐ動く。文法が C に近く、結果が目に見える。入門で効くのはこの2点だった。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>DeepL と Whisper は地味に時間を生む</title><link>https://tech.rebounder.jp/posts/deepl-whisper/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/deepl-whisper/</guid><description>派手さはないが確実に効く2本。英語は書く前に日本語で書いて整えるほうが速く、文字起こしはローカルで動かせるとクラウドに送らずに済む。実装に組み込むならこの差が効く。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>個人開発のインフラを用途で使い分ける</title><link>https://tech.rebounder.jp/posts/dev-infra-choice/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/dev-infra-choice/</guid><description>Vercel・Firebase・Supabase・GCP をどう選ぶか。最初から全部を使いこなす必要はなく、手軽なほうから始めて必要になったら広げる順番のほうが、実際には早く進む。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>開発機の発熱とバッテリーは二択になる</title><link>https://tech.rebounder.jp/posts/dev-laptop-heat-battery/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/dev-laptop-heat-battery/</guid><description>ThinkPad X1 Carbon を開発機として使うと、涼しさと電池持ちが両立しない。電源モードの切り替えで一方を選ぶことになる。使う場所を先に決めれば、この二択は表に出なくなる。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>ESP32 のセンサ値を Web Serial でブラウザに出す</title><link>https://tech.rebounder.jp/posts/esp32-web-serial/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/esp32-web-serial/</guid><description>Arduino IDE のシリアルモニタは数字が流れるだけで見づらい。Next.js と Web Serial API でブラウザの計器盤にする構成と、セキュアコンテキストやユーザー操作起点といった制約のまとめ。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>同じアプリを Firebase と Supabase の両方で作った</title><link>https://tech.rebounder.jp/posts/firebase-to-supabase/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/firebase-to-supabase/</guid><description>個人開発のバックエンドで迷うなら、Firebase は立ち上げの速さ、Supabase は自由度で選ぶ。同じアプリを両方で作り直して見えた素直な住み分けと、乗り換える順番について。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>最初の3Dプリンタは組立済みと自動レベリングで選ぶ</title><link>https://tech.rebounder.jp/posts/first-3d-printer/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/first-3d-printer/</guid><description>入門で挫折する場所は造形ではなく、組み立てと水平出しにある。95%組立済みと完全自動レベリングを条件にすると、最初の1個を出すまでの距離が大きく縮む。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Google TV をキオスク化して数ヶ月運用した記録</title><link>https://tech.rebounder.jp/posts/googletv-kiosk-ops/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/googletv-kiosk-ops/</guid><description>Android 端末を24時間落ちないサイネージ専用機にする作業は、表示ではなく電源と権限の問題だった。Device Owner の前提条件、無言で死ぬ権限、コマンドで消せないタイマー、設定を黙って無視する機種まで。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>ロゴと名刺なら Figma で足りる</title><link>https://tech.rebounder.jp/posts/illustrator-to-figma/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/illustrator-to-figma/</guid><description>Figma は本来 UI のツールだが、ベクターなのでロゴや名刺のレベルなら普通に成立する。細かいパス仕事と印刷入稿では専用ツールに分があるという線引きも含めて。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Ollama でローカル LLM を動かして RAG を組む</title><link>https://tech.rebounder.jp/posts/local-llm-rag/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/local-llm-rag/</guid><description>外部 API にデータを投げたくない場面でローカル LLM は現実的な選択肢になる。Qwen を Ollama で動かして専門分野の RAG を組んだ構成と、モデルより検索側の設計が効くという結論。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>3Dプリントでサポートが外れないときに変える2箇所</title><link>https://tech.rebounder.jp/posts/orcaslicer-support/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/orcaslicer-support/</guid><description>OrcaSlicer 自体は初期設定でもきれいに出る。初心者が最初に折れるのはサポートで、ツリータイプにして密度を下げるだけで、造形物を傷つけずに外せるようになる。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Raspberry Pi 5 で顔認証を組んで速度の壁に当たった</title><link>https://tech.rebounder.jp/posts/pi5-face-recognition/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/pi5-face-recognition/</guid><description>face_recognition と CSV だけの最小構成で顔認証は動く。ただし1人あたり約15秒かかり、人数が増えると行列になる。動くことと実用になることの間にある距離の話。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Raspberry Pi Pico で力率計を自作する</title><link>https://tech.rebounder.jp/posts/pico-power-meter/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/pico-power-meter/</guid><description>力率は電圧と電流の位相差で決まる。クランプ式の非侵襲センサで電流波形を取り、Pico 側で計算する構成と、実際に一番詰まったのが測定原理ではなく通信だった話。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Quartus で最初に詰まるのは回路ではなく環境</title><link>https://tech.rebounder.jp/posts/quartus-first-traps/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/quartus-first-traps/</guid><description>USB Blaster が認識されない、ピン配置の漏れでコードは正しいのに動かない、7セグが0で点灯する。DE10-Lite と Quartus で最初に踏む3つと、実際に書いた Verilog 作例。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>サイネージ端末は Google TV か Raspberry Pi か</title><link>https://tech.rebounder.jp/posts/signage-android-vs-raspi/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/signage-android-vs-raspi/</guid><description>常時表示の端末を自作するとき、Android の Google TV と Raspberry Pi では設計思想が正反対になる。両方で組んで運用した結果と、24時間運用で共通して効いてくるストレージの話。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>SwitchBot 人感センサを Hub なしで BLE 直読みする</title><link>https://tech.rebounder.jp/posts/switchbot-ble-direct/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/switchbot-ble-direct/</guid><description>SwitchBot の人感センサは Hub とクラウドを前提に使うものだが、BLE アドバタイズを直接受信すればローカルだけで完結する。実装の要点3つと、位置情報権限が無いと無言で0件になる罠まで。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>タスク管理は入れる摩擦をゼロにすると続く</title><link>https://tech.rebounder.jp/posts/todoist-natural-language/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/todoist-natural-language/</guid><description>Todoist を AI から自然言語で操作できるようにしたら、タスク追加の手が止まらなくなった。貯める側と捌く側を分ける発想と、通知を見に行かずメールへ流す設計。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>ハードを触るなら開発機を物理的に分ける</title><link>https://tech.rebounder.jp/posts/two-laptops-hardware-dev/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/two-laptops-hardware-dev/</guid><description>ノートPCの2台持ちは贅沢ではなくリスク管理だった。ハードウェアを触る作業と壊れて困るデータを切り離す使い分け、シリアルチップのドライバとポートの都合。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Vercel で公開してから気づいた3つの落とし穴</title><link>https://tech.rebounder.jp/posts/vercel-deploy-traps/</link><guid isPermaLink="true">https://tech.rebounder.jp/posts/vercel-deploy-traps/</guid><description>Vercel へのデプロイ自体はつまずかない。問題はその先で、エイリアスが最新版を指さない、公開URLがログインを要求する、検索に載らない、の3点はドキュメントを読むだけでは見落とす。</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item></channel></rss>