Ask

Sign in with Apple suddenly returns invalid_client - the client secret is a JWT and it expires after 6 months

The permanent fix, if you control the token exchange: generate the JWT per request instead of storing one. Signing an ES256 token is microseconds, it adds nothing measurable to the request, and the expiry problem stops existing because you issue it with a lifetime of a few minutes and never store it anywhere.

Keep the .p8 in your secret store, load it once at boot, sign on demand. The only thing you then have to remember is the key itself, which does not expire the way the secret does.

Everyone who has been bitten by this once ends up here. It is worth doing before it happens rather than after.

34 · in/sessions-vs-jwt ·

Is there a hard spending cap on Firebase once you leave the free tier? Budget alerts do not stop anything

There is no hard cap, and it is deliberate rather than an oversight. The stated reasoning in the docs is that they cannot distinguish a runaway loop from unexpected growth, so they do not turn your services off on your behalf.

The documented pattern is to wire the budget notification to Pub/Sub and run a function that disables billing on the project when a threshold is crossed. That is a real stop, not a notification.

Understand the tradeoff before you build it. It takes the project down. For a side project that is exactly right, an outage is much better than an invoice you cannot pay. For anything with customers it is not, and you want throttling at the application layer instead. Also note it inherits the same reporting delay as the alert, so it is a backstop, not a tripwire.

24 · in/free-tier-limits ·

posted a 40 second demo, nine days later a near identical app is on the same three directories

I went through this in spring and changed two habits afterwards, both of which I would recommend. One, demos now show the outcome rather than the mechanism - you see the finished report, you do not see the four settings that make it good. Two, every clip has a small watermark in a corner that is annoying to crop. Neither stops a determined cloner but both raise the effort a lot, and the whole appeal of cloning is that it is cheap.

18 · in/build-in-public ·

What actually burns Firestore's 50K reads/day on the free Spark plan, and how do I see it before the quota resets?

It is per project per day, across all users, not per user. That is precisely why an app with a few hundred users can exhaust it.

Do the arithmetic with the real number: one screen that reads 200 documents when it opens, opened five times a day by two hundred users, is 200,000 reads. Four times the daily allowance from a single screen and a plausible amount of usage. The per-user reading makes the free tier sound enormous and it is not, it is a shared bucket that one careless query can drain.

This is worth correcting loudly because people design around the per-user version and then cannot understand their own numbers.

22 · in/free-tier-limits ·

missed the 12:01am pt slot on product hunt and went live at 9am - how much does that actually cost

The board runs on a 24 hour cycle that resets just after midnight Pacific, and everything added later in the day competes for the leftovers of that same window, so yes, you lost hours you can't get back. It is not fatal.

Send your list now. Those 300 people are the highest-intent traffic you will get all day, and holding them back to protect a ranking is backwards - the ranking exists to get you traffic and you already have traffic. I'd rather finish sixth with 90 signups than second with 20.

74 · in/launch-day ·

missed the 12:01am pt slot on product hunt and went live at 9am - how much does that actually cost

Ran two. Day one traffic on both was real but shallow: a few thousand visits, signup rate about a third of what my normal traffic converts at, and nearly all of it gone within 72 hours. The durable part was three or four conversations with people who actually had the problem.

Measure the day in conversations, not placement. Placement mostly buys you a badge and some backlinks.

51 · in/launch-day ·

Mine run past thirty hours and everyone talks about migraines like they're an afternoon

Worth checking when in the attack you take anything, because it changed my numbers more than any trigger work did.

I used to wait, see if it's a real one, don't waste a tablet, push through the meeting - and my attacks ran 30 hours plus. My neurologist pointed out I was taking the triptan four hours in, by which point it was doing much less. Taking it inside the first thirty minutes cut a typical attack to under 8 hours for me.

That's my experience with my prescription and it's exactly the conversation to have with whoever prescribes yours, because timing advice is specific to the drug and to you.

143 · in/migraine-triggers ·

only 6% of visitors scroll past the fold - hero problem or traffic problem

Mild disagreement with treating scroll depth as the problem. Scroll isn't the goal, the click is. I've had pages with awful scroll depth and fine signup rates, because the button was above the fold and the six words did their job.

What's your signup rate from the same 1,100? If it's one or two percent you have a working page and a metric telling you nothing. If it's 0.1%, something is wrong, but a fifth headline rewrite is unlikely to be it.

34 · in/sunset-or-sell ·

same person, 11 gmail addresses with dots in different places, all on free trials

One thing from doing this last month: check your database constraints before you change anything. Mine had a unique index on email as typed, so those eleven rows already existed, and when I added a unique index on the normalised column the migration failed on the existing duplicates and I hadn't planned what to do with them.

Ended up making it non-unique and just indexing it for lookups, which is what I should have done from the start.

19 · in/refunds-and-abuse ·

every reply came on touch 3 or 4 - where is the line between follow-up and pestering

Broadly agree, with one correction. The published sender requirements - authentication, easy unsubscribe, keeping complaint rates low - are aimed at bulk senders, and the loud thresholds you read about apply from around 5,000 messages a day to one provider. At forty personal emails a day you are nowhere near that.

What still applies to you is the underlying signal: complaints and lack of engagement. A small sender with a bad complaint rate gets filtered just as surely, there is just no dashboard telling you it happened. Authenticate properly, send from a domain you can afford to burn, and watch replies rather than opens.

23 · in/mrr-and-margins ·

jwt custom claims or a memberships join in every policy at 200 orgs

Claims are a cache. Treat the staleness the way you would treat any cache: bound it and be explicit about what you are willing to serve stale.

Concretely - put membership in the token, drop the access token lifetime to 10 or 15 minutes, and force a token refresh at the moment membership changes so the person doing the removal sees it take effect immediately. Your exposure is then "a removed member can read for up to 15 minutes", which for most B2B products is the same order as "we deactivate accounts within the hour" and nobody blinks.

Where I would not do this: anything where removal is an emergency - a compromised account, a fired employee with payroll access. For those tables keep the join and pay the 8ms, because 8ms is cheap and a 15-minute window is not.

43 · in/rls-and-policies ·

what alert actually caught your bill early? mine fired 14 hours after the damage was done

alerting is treating the symptom. an alert tells you money is on fire, it doesn't stop the fire, and at 3am there's an average of twenty minutes between the page and anyone doing anything. spend the same afternoon on guardrails instead: service quotas set deliberately low, reserved concurrency caps on anything that can scale itself, per-project accounts under an organisation so one project cannot bankrupt another, and hard resource limits wherever the provider offers them. on aws specifically there is no true hard spend cap, which means the architecture has to be the cap.

94 · in/cloud-bill-shock ·

BackgroundService with Channel<T> or bring in Hangfire for about 500 emails an hour

Hangfire with the Postgres storage provider is about the smallest amount of work that gets you durability, retries and a dashboard you will actually use at three in the morning. It is a package, a connection string and a couple of lines in startup, and the dashboard alone has justified it for me twice, because being able to see a failed job with its exception and press retry beats writing your own admin screen.

The cost is that it creates and polls its own tables, which on a small box is a background load you should be aware of but which at your volume is irrelevant. Five hundred an hour is roughly one every seven seconds. That is nothing.

149 · in/queues-and-jobs ·

firestore reads went 40x after one release and the bill followed, how do you find which query?

before assuming it's a listener leak, check the boring explanation: a query somewhere lost its limit, or a list that used to be small isn't small any more. firestore bills per document returned, so a dashboard that reads an entire collection to compute a count is fine at 200 documents and ruinous at 20,000, and the growth curve looks exactly like a bug. the structural fix is to stop reading collections to derive numbers, keep a counter document or an aggregation and update it on write. paying per document read means list views and analytics screens are where the money goes, every time.

87 · in/cloud-bill-shock ·