<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>Rebounder Tech Blog</title><description>Field notes from the production systems operated by Rebounder Inc., written by the engineers who run them.</description><link>https://tech.rebounder.jp/</link><language>en</language><item><title>cqw Fails Silently When the DOM Around It Changes</title><link>https://tech.rebounder.jp/en/posts/css-container-query-cqw-context-dependent-fails-silently/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/css-container-query-cqw-context-dependent-fails-silently/</guid><description>A board preview scaled with container-query units stopped resolving when a DOM change left .frame&apos;s width undetermined, so it rendered at full size and clipped.</description><pubDate>Fri, 04 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Hand-Built Preview Payload Drifts From the Device</title><link>https://tech.rebounder.jp/en/posts/editor-preview-hand-built-payload-drifts-from-device-builder/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/editor-preview-hand-built-payload-drifts-from-device-builder/</guid><description>The class editor&apos;s board preview hand-built its base and pinned automatic blocks to null. The device builds every block from one source, so the two disagreed.</description><pubDate>Fri, 04 Sep 2026 00:00:00 GMT</pubDate></item><item><title>pdfjs-dist standard_fonts Missing From standalone</title><link>https://tech.rebounder.jp/en/posts/pdfjs-dist-standard-fonts-nextjs-standalone-not-bundled/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/pdfjs-dist-standard-fonts-nextjs-standalone-not-bundled/</guid><description>pdfjs-dist loads its standard fonts dynamically over file://, so Next.js file tracing cannot follow it and the standalone build ships without them.</description><pubDate>Fri, 04 Sep 2026 00:00:00 GMT</pubDate></item><item><title>A disabled Submit Button Dies Before Hydration</title><link>https://tech.rebounder.jp/en/posts/react-controlled-disabled-button-breaks-progressive-enhancement/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/react-controlled-disabled-button-breaks-progressive-enhancement/</guid><description>Driving the disabled attribute from server state left the button permanently disabled before hydration or when JS failed, making the signing form unsubmittable.</description><pubDate>Fri, 04 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Duplicate URLs in a Feed Break ON CONFLICT DO UPDATE</title><link>https://tech.rebounder.jp/en/posts/postgres-on-conflict-do-update-cannot-affect-row-twice-feed-dedup/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/postgres-on-conflict-do-update-cannot-affect-row-twice-feed-dedup/</guid><description>A news job upserting several articles in one ON CONFLICT DO UPDATE failed with Postgres 21000 on duplicate URLs, and a fail-soft catch skipped it silently.</description><pubDate>Thu, 03 Sep 2026 00:00:00 GMT</pubDate></item><item><title>A Ledger INSERT Failure Swallowed as a Duplicate</title><link>https://tech.rebounder.jp/en/posts/stripe-webhook-ledger-insert-error-swallowed-as-duplicate/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/stripe-webhook-ledger-insert-error-swallowed-as-duplicate/</guid><description>The Stripe webhook returned a 200 no-op for any ledger INSERT failure, so a transient DB fault lost the event permanently: Stripe never retried it.</description><pubDate>Thu, 03 Sep 2026 00:00:00 GMT</pubDate></item><item><title>maybeSingle() Throws PGRST116 on a Too-Loose Filter</title><link>https://tech.rebounder.jp/en/posts/supabase-maybesingle-multiple-rows-pgrst116-permanent-404/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/supabase-maybesingle-multiple-rows-pgrst116-permanent-404/</guid><description>An evidence-PDF API filtered on 2 of 3 unique-key columns, then called maybeSingle(). Once a second row existed for that pair, real data started returning 404.</description><pubDate>Thu, 03 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Missing passThroughEnv Skips Tests While CI Stays Green</title><link>https://tech.rebounder.jp/en/posts/turbo-passthroughenv-missing-rls-tests-silently-skipped/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/turbo-passthroughenv-missing-rls-tests-silently-skipped/</guid><description>Without passThroughEnv, turbo won&apos;t forward CI&apos;s DATABASE_URL to vitest. A describe.skip guard hides the gap, so CI stayed green while 24 RLS tests never ran.</description><pubDate>Thu, 03 Sep 2026 00:00:00 GMT</pubDate></item><item><title>Only the Poll Stringifies Date: getTime Is Not a Function</title><link>https://tech.rebounder.jp/en/posts/json-poll-response-date-string-gettime-not-a-function/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/json-poll-response-date-string-gettime-not-a-function/</guid><description>SSR restores Date as a Date, but the same screen&apos;s polling gets a string from res.json(). Calling .getTime() on it took the whole board down.</description><pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate></item><item><title>insetsController Is null Before setContentView</title><link>https://tech.rebounder.jp/en/posts/android-insetscontroller-null-before-setcontentview/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/android-insetscontroller-null-before-setcontentview/</guid><description>window.insetsController returns null before setContentView() because the DecorView is not resolved yet. hide() never runs and immersive mode silently fails.</description><pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate></item><item><title>One startActivity Is Not Enough to Blank a Kiosk Screen</title><link>https://tech.rebounder.jp/en/posts/android-kiosk-overlay-startactivity-can-silently-fail-leaving-screen-on/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/android-kiosk-overlay-startactivity-can-silently-fail-leaving-screen-on/</guid><description>An always-on Android kiosk that blanks its screen with one startActivity stays lit all night when BAL limits or a missing SYSTEM_ALERT_WINDOW block the call.</description><pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate></item><item><title>SECURITY DEFINER Functions Are PUBLIC EXECUTE</title><link>https://tech.rebounder.jp/en/posts/supabase-security-definer-function-default-public-execute-exposes-rpc/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/supabase-security-definer-function-default-public-execute-exposes-rpc/</guid><description>A SECURITY DEFINER write RPC gets PUBLIC EXECUTE by PostgreSQL default. Without a revoke, anon can call it directly through Supabase&apos;s PostgREST layer.</description><pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate></item><item><title>read-merge-write Without FOR UPDATE Loses Keys</title><link>https://tech.rebounder.jp/en/posts/colocated-config-key-lost-update-without-row-lock/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/colocated-config-key-lost-update-without-row-lock/</guid><description>Several settings keys share one JSONB row. Read, spread, write back without SELECT ... FOR UPDATE and a concurrent save overwrites the key the other just wrote.</description><pubDate>Sun, 30 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Only One Branch Had No Way to Add the First Item</title><link>https://tech.rebounder.jp/en/posts/conditional-branch-hides-first-item-creation-entry-point-stuck-ui/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/conditional-branch-hides-first-item-creation-entry-point-stuck-ui/</guid><description>The school structure screen branches three ways on two booleans, and the state with grades but no departments had no way to add a department at all.</description><pubDate>Sun, 30 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Re-consent to Revised Terms Does Not Reset auto_renew</title><link>https://tech.rebounder.jp/en/posts/contract-reconsent-does-not-reset-auto-renew/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/contract-reconsent-does-not-reset-auto-renew/</guid><description>A customer re-consents to terms without the auto-renewal clause, yet auto_renew stays true. The flag is only ever written false to true.</description><pubDate>Sun, 30 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Media Queries See the Real Viewport in a Scaled Stage</title><link>https://tech.rebounder.jp/en/posts/media-query-still-uses-real-viewport-inside-scaled-fixed-stage/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/media-query-still-uses-real-viewport-inside-scaled-fixed-stage/</guid><description>A 1280x720 stage shrunk with transform:scale still evaluates @media against the real viewport, so a large monitor applies the big-screen profile.</description><pubDate>Sun, 30 Aug 2026 00:00:00 GMT</pubDate></item><item><title>left:50% With width:fit-content Makes max-width Never Apply</title><link>https://tech.rebounder.jp/en/posts/absolute-left-50-fit-content-max-width-never-applies/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/absolute-left-50-fit-content-max-width-never-applies/</guid><description>An absolute plate centred with left:50% and width:fit-content wrapped long before its max-width. Shrink-to-fit subtracts the left offset from available width.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate></item><item><title>An inset box-shadow Ring Hides Behind a Child Background</title><link>https://tech.rebounder.jp/en/posts/inset-box-shadow-ring-hidden-by-static-child-background/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/inset-box-shadow-ring-hidden-by-static-child-background/</guid><description>A ring drawn with inset box-shadow vanished under a child with its own background. inset shadows paint at the background stage, below static children.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate></item><item><title>The Edit Form Pruned Selections It Could Not See</title><link>https://tech.rebounder.jp/en/posts/edit-form-prunes-selections-missing-from-stale-list-silent-data-loss/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/edit-form-prunes-selections-missing-from-stale-list-silent-data-loss/</guid><description>The edit form silently dropped selected IDs missing from a refetched monitor list, so saving just a price change could shrink the targeted monitors.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A Non-Numeric env Becomes NaN and Slips Past ??</title><link>https://tech.rebounder.jp/en/posts/env-nan-parseint-nullish-coalescing-immediate-abort/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/env-nan-parseint-nullish-coalescing-immediate-abort/</guid><description>A non-numeric env makes Number.parseInt return NaN. It passes the truthy check and the ?? default alike, so embeddings ran zero and fetch aborted instantly.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Narrowing a Page&apos;s Roles Left the Action&apos;s Gate</title><link>https://tech.rebounder.jp/en/posts/parent-page-role-narrowed-child-component-gate-left-behind-forbidden-error/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/parent-page-role-narrowed-child-component-gate-left-behind-forbidden-error/</guid><description>The dashboard&apos;s requireRole was narrowed to system admins while a panel&apos;s Server Action kept its publisher gate, producing an uncaught ForbiddenError.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A Post-Charge DB Failure Read as a Card Decline</title><link>https://tech.rebounder.jp/en/posts/stripe-post-charge-db-failure-misdiagnosed-as-card-decline/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/stripe-post-charge-db-failure-misdiagnosed-as-card-decline/</guid><description>Handle PaymentIntent creation and the DB write in one try/catch and a transient write error after the charge succeeds gets diagnosed as a card failure.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate></item><item><title>RLS Allowing actor_user_id NULL Erases Audit Trails</title><link>https://tech.rebounder.jp/en/posts/audit-log-rls-null-actor-allows-repudiation/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/audit-log-rls-null-actor-allows-repudiation/</guid><description>The audit log INSERT policy allowed actor_user_id IS NULL for any role. A compromised tenant account could log its actions as actor=NULL and escape the trail.</description><pubDate>Thu, 27 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A Leftover sticky top:0 Makes a fixed Bar Fill the Screen</title><link>https://tech.rebounder.jp/en/posts/css-fixed-inherited-top-zero-bottom-zero-fullscreen-stretch/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/css-fixed-inherited-top-zero-bottom-zero-fullscreen-stretch/</guid><description>Switching to position:fixed without clearing the sticky top:0 leaves top and bottom both set, stretching the box to the full viewport height.</description><pubDate>Thu, 27 Aug 2026 00:00:00 GMT</pubDate></item><item><title>The Leak Check Only Grepped Half the Package</title><link>https://tech.rebounder.jp/en/posts/dist-sanitizer-denylist-grep-misses-new-internal-string/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/dist-sanitizer-denylist-grep-misses-new-internal-string/</guid><description>A build script grepped the distribution package for internal wording. Internal text shipped anyway: the grep path covered only part of the package.</description><pubDate>Thu, 27 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A New httpOnly Cookie 401s Only Already-Logged-In Users</title><link>https://tech.rebounder.jp/en/posts/new-httponly-cookie-not-issued-until-relogin-after-deploy/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/new-httponly-cookie-not-issued-until-relogin-after-deploy/</guid><description>A write-only httpOnly HMAC cookie shipped and only staff logged in before the deploy got 401s, while the UI still showed them signed in.</description><pubDate>Wed, 26 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A Public Route Missing From the middleware matcher</title><link>https://tech.rebounder.jp/en/posts/nextjs-middleware-matcher-missing-public-route-login-redirect/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/nextjs-middleware-matcher-missing-public-route-login-redirect/</guid><description>The public signage page is anonymous — no __session. Left out of the middleware matcher&apos;s exclusion list, every device was redirected to /login instead.</description><pubDate>Wed, 26 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Duplicating a Placement Without Ending the Old One</title><link>https://tech.rebounder.jp/en/posts/renewal-successor-rows-without-retiring-predecessor-double-counts-capacity/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/renewal-successor-rows-without-retiring-predecessor-double-counts-capacity/</guid><description>The renewal batch duplicates placements for the successor contract. Without ending the original row, the remaining-capacity sum keeps counting both.</description><pubDate>Wed, 26 Aug 2026 00:00:00 GMT</pubDate></item><item><title>LIMIT 1 Without ORDER BY Returns Another Tenant</title><link>https://tech.rebounder.jp/en/posts/dev-login-missing-orderby-returns-wrong-tenant-admin/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/dev-login-missing-orderby-returns-wrong-tenant-admin/</guid><description>dev-login resolved a school_admin with a SELECT LIMIT 1 and no ORDER BY, so as multi-tenant test data grows it can return a uid from an unintended school.</description><pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate></item><item><title>proxy.ts Redirected API-Key Endpoints to the Login Page</title><link>https://tech.rebounder.jp/en/posts/nextjs-middleware-external-api-key-auth-redirected-to-login/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/nextjs-middleware-external-api-key-auth-redirected-to-login/</guid><description>Next.js proxy.ts listed only /api/health as exempt from session auth, so /api/v1/ and /api/mcp/ with their own API key auth were redirected to the login page.</description><pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate></item><item><title>?? Defaults Overwrite Fields the Form Never Sent</title><link>https://tech.rebounder.jp/en/posts/supabase-update-partial-field-nullish-coalesce-overwrite/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/supabase-update-partial-field-nullish-coalesce-overwrite/</guid><description>An edit form without an availability field rolled live slots back to vacant on every save. val(formData.get(...)) ?? default treats unsent as the default.</description><pubDate>Tue, 25 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Holding-Only Checks Reapply a Bundle Discount</title><link>https://tech.rebounder.jp/en/posts/bundle-discount-reapplied-on-every-purchase-without-granted-check/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/bundle-discount-reapplied-on-every-purchase-without-granted-check/</guid><description>A bundle discount decided purely by whether the buyer holds every member reapplied on each further purchase. A granted-history check fixed it.</description><pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate></item><item><title>The Lock Held; the Count Counted Intent, Not Writes</title><link>https://tech.rebounder.jp/en/posts/for-update-count-intent-vs-actual-writes/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/for-update-count-intent-vs-actual-writes/</guid><description>A flaky test where newlyDown summed to 2 instead of 1 was not the DB rows but the summary. FOR UPDATE serialised the writes; the count used the classification.</description><pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A Temp-Password Guard Written Per Page Leaks by URL</title><link>https://tech.rebounder.jp/en/posts/forced-password-change-bypassed-by-direct-url/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/forced-password-change-bypassed-by-direct-url/</guid><description>A must_change_password advertiser could skip the forced change by going to any page but /dashboard by direct URL. The guard lived per page, not in one place.</description><pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate></item><item><title>RLS On Is Not Safe While TRUNCATE Is Granted</title><link>https://tech.rebounder.jp/en/posts/postgres-truncate-bypasses-rls-even-when-enabled/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/postgres-truncate-bypasses-rls-even-when-enabled/</guid><description>chat_knowledge had RLS enabled and zero policies, yet Supabase&apos;s default grants left TRUNCATE on anon/authenticated. TRUNCATE is not subject to RLS at all.</description><pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Humanising an Error Message Cost the Dead-Letter Its Trace</title><link>https://tech.rebounder.jp/en/posts/dead-letter-error-humanized-loses-traceable-id/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/dead-letter-error-humanized-loses-traceable-id/</guid><description>Coverage validation returned only admin-form Japanese. Reusing it as the dead-letter last_error dropped the school ID, so logs could not name the cause.</description><pubDate>Sat, 22 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Permissions-Policy: microphone=() Blocks Your Own Origin Too</title><link>https://tech.rebounder.jp/en/posts/permissions-policy-microphone-self-blocks-web-speech/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/permissions-policy-microphone-self-blocks-web-speech/</guid><description>Permissions-Policy: microphone=() allows no origin at all, blocking our own Web Speech API voice input with no permission prompt. Fixed with microphone=(self).</description><pubDate>Sat, 22 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Omitting expires_at Holds a Seat for 24 Hours</title><link>https://tech.rebounder.jp/en/posts/stripe-checkout-session-default-24h-expiry-holds-reservation-seat/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/stripe-checkout-session-default-24h-expiry-holds-reservation-seat/</guid><description>A Stripe Checkout Session with no expires_at defaults to 24 hours, and a booking abandoned without paying keeps occupying capacity that whole time.</description><pubDate>Sat, 22 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Aborting streamObject Leaves usage as an Unhandled Rejection</title><link>https://tech.rebounder.jp/en/posts/ai-sdk-streamobject-abort-unhandled-rejection/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/ai-sdk-streamobject-abort-unhandled-rejection/</guid><description>Wiring an AbortSignal into the Vercel AI SDK&apos;s streamObject makes result.usage reject on abort. If the caller returns without awaiting done, nothing catches it.</description><pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Fixing a detect-non-literal-regexp False Positive</title><link>https://tech.rebounder.jp/en/posts/semgrep-non-literal-regexp-dead-branch-false-positive/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/semgrep-non-literal-regexp-dead-branch-false-positive/</guid><description>An E2E fallback, new RegExp(c.path.replace(...)), tripped Semgrep&apos;s detect-non-literal-regexp. The branch was unreachable, so we deleted it with a type.</description><pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A Stale Branch Deploy Silently Reverted Features</title><link>https://tech.rebounder.jp/en/posts/stale-branch-deploy-silently-reverts-merged-features/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/stale-branch-deploy-silently-reverts-merged-features/</guid><description>Swapping a Cloud Run image tag by the usual steps removes features merged to main since the build branch diverged — without a single git revert commit.</description><pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate></item><item><title>YT.Player Replacing a div Can Leave a Black Screen</title><link>https://tech.rebounder.jp/en/posts/youtube-iframe-player-div-replace-black-screen/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/youtube-iframe-player-div-replace-black-screen/</guid><description>Initialising the YouTube IFrame API by handing it a div shows nothing until that div becomes an iframe, and depending on timing playback never starts.</description><pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Removing a Role-Change Seam With No Callers Left</title><link>https://tech.rebounder.jp/en/posts/dormant-privilege-escalation-seam-removed/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/dormant-privilege-escalation-seam-removed/</guid><description>A function that writes any role and any school ID into IdP claims stayed in the repo with zero production callers after its only caller was removed.</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Phone Numbers Garble When Copied From a pdf-lib PDF</title><link>https://tech.rebounder.jp/en/posts/pdf-lib-fontkit-gsub-digit-garbling/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/pdf-lib-fontkit-gsub-digit-garbling/</guid><description>Embedding NotoSansJP through fontkit into pdf-lib garbles digits on copy and pdftotext. GSUB picks glyphs the ToUnicode CMap has no entry for.</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Remounting a Form by key Resets Uncontrolled Inputs</title><link>https://tech.rebounder.jp/en/posts/react-key-remount-resets-uncontrolled-input/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/react-key-remount-resets-uncontrolled-input/</guid><description>With &lt;form key={formGen}&gt; remounting on every submit, inputs given only defaultValue reset on the resubmit right after a validation error, saving the default.</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Carrying a creative_id Revived an Ended Placement</title><link>https://tech.rebounder.jp/en/posts/renewal-creative-id-revives-ended-placement/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/renewal-creative-id-revives-ended-placement/</guid><description>The renewal batch copies a placement row and keeps creative_id on both. Another batch in the same cron run uses that key to roll the ended row back to booked.</description><pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Two Migrations Claimed the Same Sequence Number</title><link>https://tech.rebounder.jp/en/posts/duplicate-migration-sequence-number/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/duplicate-migration-sequence-number/</guid><description>Two feature branches both created migration 0035. Both applied to production as idempotent SQL, but a fresh database run in order has no guaranteed sequence.</description><pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A staging Default in env Deleted Production Images</title><link>https://tech.rebounder.jp/en/posts/env-default-bucket-leaks-across-environments/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/env-default-bucket-leaks-across-environments/</guid><description>Leave another environment&apos;s bucket as an env var&apos;s fallback and that value gets written into the production database, vanishing the day staging is destroyed.</description><pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Half-Controlled Forms Silently Revert on Resubmit</title><link>https://tech.rebounder.jp/en/posts/react-partial-controlled-fields-silent-revert/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/react-partial-controlled-fields-silent-revert/</guid><description>React 19&apos;s &lt;form action&gt; resets uncontrolled inputs to defaultValue whether it succeeded or not. Control only some fields and the rest revert silently.</description><pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Linking Everyone to a Tenant-Only Feature Gave 502</title><link>https://tech.rebounder.jp/en/posts/unconditional-link-to-tenant-only-pdf-feature/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/unconditional-link-to-tenant-only-pdf-feature/</guid><description>The application page always showed a PDF copy link to a route implemented for one tenant type only. The other side got a 502, though nothing had failed.</description><pubDate>Wed, 19 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A CHECK Rewrite Erased Another Branch&apos;s Value</title><link>https://tech.rebounder.jp/en/posts/check-constraint-rewrite-drops-branch-value/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/check-constraint-rewrite-drops-branch-value/</guid><description>Rewriting a PostgreSQL CHECK constraint with DROP then ADD silently removes values another branch added. share_links.kind lost receipt, with no migration error.</description><pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A 23503 FK Violation Disguised as a Conflict</title><link>https://tech.rebounder.jp/en/posts/fk-violation-masked-as-conflict/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/fk-violation-masked-as-conflict/</guid><description>An operator ad submission failed every time in production, showing &quot;conflicted with another operation&quot;. The real cause was a foreign key violation, 23503.</description><pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate></item><item><title>auth/invalid-password: App Allowed Shorter Passwords</title><link>https://tech.rebounder.jp/en/posts/idp-password-min-length-mismatch/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/idp-password-min-length-mismatch/</guid><description>A 4-5 char password passed app validation, then Identity Platform rejected it as auth/invalid-password, uncaught: an error boundary, not a form error.</description><pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A Missing force-dynamic Froze a Flag Flip Behind Static HTML</title><link>https://tech.rebounder.jp/en/posts/nextjs-static-prerender-hides-flag-flip/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/nextjs-static-prerender-hides-flag-flip/</guid><description>Enabling teacher login changed nothing on screen. With no dynamic API call, Next.js prerendered the route at build time and the CDN cached it for a year.</description><pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A UI Freeze Without a Server Check Is Not a Freeze</title><link>https://tech.rebounder.jp/en/posts/ui-freeze-not-enforced-server-side/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/ui-freeze-not-enforced-server-side/</guid><description>The edit screen froze its inputs when a slot was live or bought out, but the update path only checked live. A forged POST could rewrite targeting in between.</description><pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate></item><item><title>An Android Foreground Service Can Die Without Crashing</title><link>https://tech.rebounder.jp/en/posts/android-service-dies-without-crashing/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/android-service-dies-without-crashing/</guid><description>Guarding only pollOnce() is not enough. An exception in delay or the backoff calculation exits while(true) quietly, stopping the work while the app lives on.</description><pubDate>Mon, 17 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Enabling a Cloud Run Job Fails With SecretsAccessCheckFailed</title><link>https://tech.rebounder.jp/en/posts/cloud-run-job-secret-iam-race/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/cloud-run-job-secret-iam-race/</guid><description>Creating a Cloud Run Job and its secret accessor IAM in one Terraform apply taints the job: creation-time validation runs before IAM propagates.</description><pubDate>Mon, 17 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Routing Scanned PDFs to Gemini by Chars per Page</title><link>https://tech.rebounder.jp/en/posts/gemini-pdf-ocr-fallback-threshold/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/gemini-pdf-ocr-fallback-threshold/</guid><description>pdfjs-dist returns the text layer as-is, so a scanned PDF comes back near-empty. Below a per-page character threshold, send the bytes to Gemini as a file part.</description><pubDate>Mon, 17 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Auth Middleware Redirects robots.txt to the Login Page</title><link>https://tech.rebounder.jp/en/posts/nextjs-middleware-robots-redirect/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/nextjs-middleware-robots-redirect/</guid><description>Middleware that sends unauthenticated users to /login tends to treat robots.txt the same way. Crawlers get a 307 and the Lighthouse SEO audit fails.</description><pubDate>Mon, 17 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Astro 7 Breaks Content Collections in Three Places</title><link>https://tech.rebounder.jp/en/posts/astro-legacy-content-config/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/astro-legacy-content-config/</guid><description>Upgrading Astro fails with LegacyContentConfigError. Three things changed at once: where the config file lives, the required loader, and the render API.</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>drizzle-kit migrate Does Not Apply Hand-Written SQL</title><link>https://tech.rebounder.jp/en/posts/drizzle-migrate-skips-sql/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/drizzle-migrate-skips-sql/</guid><description>Migrations succeed but RLS policies and audit triggers are missing in production. drizzle-kit migrate runs only drizzle-generated DDL.</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Your First Dev Board Depends on What You&apos;ll Build</title><link>https://tech.rebounder.jp/en/posts/first-dev-board/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/first-dev-board/</guid><description>ESP32, Raspberry Pi and FPGA cover completely different ground. A thing that communicates, a small computer, or learning circuits — that is the choice.</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Three Errors You Actually Hit Connecting Actions to GCP</title><link>https://tech.rebounder.jp/en/posts/gcp-workload-identity-errors/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/gcp-workload-identity-errors/</guid><description>Workload Identity Federation splits configuration across three layers and impersonation fails if any is missing. The three real errors, in order.</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Gemini Thinking Tokens Eat maxOutputTokens</title><link>https://tech.rebounder.jp/en/posts/gemini-thinking-budget-hang/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/gemini-thinking-budget-hang/</guid><description>A chat AI hung on &quot;thinking&quot; in production only. Gemini&apos;s thinking tokens eat the maxOutputTokens budget, so the response ends empty before output starts.</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>The JMA Evening Update Nulls Today&apos;s Temperature</title><link>https://tech.rebounder.jp/en/posts/jma-evening-forecast-temp-null/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/jma-evening-forecast-temp-null/</guid><description>Japan&apos;s JMA forecast API drops today&apos;s temperature in the 17:00 update. Upsert it straight through and the morning&apos;s value is overwritten with null.</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>FLAG_KEEP_SCREEN_ON Ignored: It&apos;s the Screensaver</title><link>https://tech.rebounder.jp/en/posts/keep-screen-on-daydream/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/keep-screen-on-daydream/</guid><description>An always-on Android display still goes black with FLAG_KEEP_SCREEN_ON set. The most likely cause is the screensaver, and settings put resets on every reboot.</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Next.js Bundling a wasm Package Breaks Only in Production</title><link>https://tech.rebounder.jp/en/posts/nextjs-wasm-bundling-broken/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/nextjs-wasm-bundling-broken/</guid><description>A WASM library for PDF generation got bundled by Next.js and broke in production with a path type error. Bundling changes how the wasm relative path resolves.</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>SECURITY DEFINER Fails in Production: the Executing Role</title><link>https://tech.rebounder.jp/en/posts/security-definer-owner-role/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/security-definer-owner-role/</guid><description>CI passes but production gets nothing from a SECURITY DEFINER function. The owner is whoever ran the migration, and it cannot bypass RLS.</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>The Still-Frame Threshold Depends on Bit Depth</title><link>https://tech.rebounder.jp/en/posts/static-frame-threshold-bitdepth/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/static-frame-threshold-bitdepth/</guid><description>Detecting still frames with tblend and signalstats: the YAVG threshold scales with luma range, so 4.8 from 12-bit material breaks entirely on 10-bit.</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A Conditional UPDATE Needs error, Not Just data</title><link>https://tech.rebounder.jp/en/posts/supabase-update-error-swallowed/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/supabase-update-error-swallowed/</guid><description>A conditional UPDATE returns data:null with error when it matches nothing. Read data alone and a transient write failure looks like &quot;already processed&quot;.</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>terraform enabled = false Cannot Tear Down an Env</title><link>https://tech.rebounder.jp/en/posts/terraform-enabled-false-cannot-destroy/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/terraform-enabled-false-cannot-destroy/</guid><description>With an enabled flag on every module, flipping them all to false to fold an environment fails with Invalid template interpolation value. Only destroy works.</description><pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate></item><item><title>How I Settled on Splitting AI Coding Tools</title><link>https://tech.rebounder.jp/en/posts/ai-coding-tools/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/ai-coding-tools/</guid><description>Results from actually splitting work between Claude Code, Cursor, Codex and Gemini: complex development, quick builds, and a separate everyday companion.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>A Prompt Template for Mass-Producing Thumbnails</title><link>https://tech.rebounder.jp/en/posts/ai-eyecatch-template/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/ai-eyecatch-template/</guid><description>Rather than starting over each time: subject large, title band at the bottom, tone fixed. Swap only the subject and the title. Where Japanese text breaks down.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Cloud Run Jobs Freeze Their Image</title><link>https://tech.rebounder.jp/en/posts/cloud-run-job-image-frozen/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/cloud-run-job-image-frozen/</guid><description>You fixed the code, committed, and re-ran the job. Nothing changed. The image is pinned in the job definition until you bump the tag and apply.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Writing 3D Models as Code Instead of Mouse Work</title><link>https://tech.rebounder.jp/en/posts/code-cad-3dprint/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/code-cad-3dprint/</guid><description>Write dimensions as numbers in OpenSCAD and Python and let equations decide the shape. Change a parameter for a new size, and diff the design in git.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Why I Chose the DE10-Lite as a First FPGA Board</title><link>https://tech.rebounder.jp/en/posts/de10-lite-fpga-intro/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/de10-lite-fpga-intro/</guid><description>Switches, LEDs and a 7-segment display are on board, so a circuit runs with no external wiring, and the syntax is close to C. Those two are what helped.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>DeepL and Whisper Quietly Save Time</title><link>https://tech.rebounder.jp/en/posts/deepl-whisper/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/deepl-whisper/</guid><description>Neither is flashy, but both work. English is faster if you draft in Japanese first, and transcription run locally never leaves the machine.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Splitting Personal-Project Infrastructure by Use</title><link>https://tech.rebounder.jp/en/posts/dev-infra-choice/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/dev-infra-choice/</guid><description>How to choose between Vercel, Firebase, Supabase and GCP. Starting with the easy end and widening when you need to actually moves faster.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Heat and Battery Are a Choice on a Dev Laptop</title><link>https://tech.rebounder.jp/en/posts/dev-laptop-heat-battery/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/dev-laptop-heat-battery/</guid><description>Using a ThinkPad X1 Carbon for development, cool running and battery life do not coexist. The power mode makes you pick one.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Putting ESP32 Sensor Data in the Browser With Web Serial</title><link>https://tech.rebounder.jp/en/posts/esp32-web-serial/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/esp32-web-serial/</guid><description>The Arduino IDE serial monitor is just numbers scrolling past. Here is the Next.js and Web Serial API setup that turns it into a browser dashboard.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Building the Same App on Firebase and Supabase</title><link>https://tech.rebounder.jp/en/posts/firebase-to-supabase/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/firebase-to-supabase/</guid><description>Choosing a backend for a personal project: Firebase for speed to launch, Supabase for freedom. What rebuilding the same app on both made plain.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Pick a First 3D Printer on Assembly and Levelling</title><link>https://tech.rebounder.jp/en/posts/first-3d-printer/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/first-3d-printer/</guid><description>What defeats beginners is not printing but assembly and bed levelling. Requiring 95% pre-assembled and automatic levelling shortens the road to a first print.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Running a Google TV Kiosk for Several Months</title><link>https://tech.rebounder.jp/en/posts/googletv-kiosk-ops/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/googletv-kiosk-ops/</guid><description>Making an Android device into signage that never falls over is a power and permissions problem, not a display one. Device Owner, silent failures, timers.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Figma Is Enough for a Logo and a Business Card</title><link>https://tech.rebounder.jp/en/posts/illustrator-to-figma/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/illustrator-to-figma/</guid><description>Figma is a UI tool by design, but being vector it holds up perfectly well at the level of a logo or a business card. Where the dedicated tool still wins.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Running a Local LLM with Ollama and Building RAG</title><link>https://tech.rebounder.jp/en/posts/local-llm-rag/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/local-llm-rag/</guid><description>Where you would rather not send data to an external API, a local LLM is realistic. Running Qwen on Ollama, and why retrieval matters more than the model.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Two Settings to Change When Supports Won&apos;t Come Off</title><link>https://tech.rebounder.jp/en/posts/orcaslicer-support/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/orcaslicer-support/</guid><description>OrcaSlicer prints well on defaults. What breaks beginners is supports: switch to tree type and lower the density, and they peel off without damage.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Face Recognition on a Raspberry Pi 5 Hits a Speed Wall</title><link>https://tech.rebounder.jp/en/posts/pi5-face-recognition/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/pi5-face-recognition/</guid><description>face_recognition plus a CSV file is enough to make face recognition work. But it takes about 15 seconds per person, and a queue forms as soon as numbers grow.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Building a Power Factor Meter With a Raspberry Pi Pico</title><link>https://tech.rebounder.jp/en/posts/pico-power-meter/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/pico-power-meter/</guid><description>Power factor comes from the phase difference between voltage and current. A clamp sensor gets the waveform and the Pico does the maths.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>What Stops You First in Quartus Is the Setup</title><link>https://tech.rebounder.jp/en/posts/quartus-first-traps/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/quartus-first-traps/</guid><description>The programmer is not recognised, correct code does nothing because a pin assignment is missing, and the 7-segment lights on 0. Three first traps.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Google TV or Raspberry Pi for a Signage Device</title><link>https://tech.rebounder.jp/en/posts/signage-android-vs-raspi/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/signage-android-vs-raspi/</guid><description>For an always-on display, Google TV and a Raspberry Pi take opposite design philosophies. Results from running both, and the storage that matters.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Reading a SwitchBot Motion Sensor Over BLE Directly</title><link>https://tech.rebounder.jp/en/posts/switchbot-ble-direct/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/switchbot-ble-direct/</guid><description>SwitchBot&apos;s motion sensor assumes a Hub and the cloud, but receiving its BLE advertisements directly keeps it all local. Three points and one silent trap.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Task Management Sticks When Entry Has No Friction</title><link>https://tech.rebounder.jp/en/posts/todoist-natural-language/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/todoist-natural-language/</guid><description>Once Todoist could be driven from an AI in natural language, tasks started accumulating without stopping work. Splitting the storing side from the doing side.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Separate the Machine You Touch Hardware With</title><link>https://tech.rebounder.jp/en/posts/two-laptops-hardware-dev/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/two-laptops-hardware-dev/</guid><description>Carrying two laptops was risk management, not luxury. Serial-chip drivers and ports, and separating work that can break things from data you cannot lose.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item><item><title>Three Vercel Traps I Hit After Going Live</title><link>https://tech.rebounder.jp/en/posts/vercel-deploy-traps/</link><guid isPermaLink="true">https://tech.rebounder.jp/en/posts/vercel-deploy-traps/</guid><description>Deploying to Vercel is the easy part. The alias not following the newest build, the public URL demanding a login, and not appearing in search are what you miss.</description><pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate></item></channel></rss>