On the mainnet, how long does it take for me to get the receipt for the transaction? Is it sane to make the user wait on the same page after clicking the onBuy button with a loading wheel until the receipt arrives? If not, what's the conventional way to deal with this?
When you send a transaction, you will get the transaction hash pretty quickly. However, the receipt is only returned once the transaction is mined. The length of time it takes to have your transaction mined varies greatly depending on how much you're willing to pay for gas (can be several seconds for very high gas prices or can be several hours if you're paying < 10 Gwei). You can get an idea by using Ropsten/Rinkeby (the test networks will probably be faster than MainNet). Chances are (and based on the system you're describing), it won't be reasonable to have your user wait.
I don't know if there is a "conventional" way to deal with this. You can provide the user with your own confirmation number (or use the transaction hash as the confirmation number), send an email when the transaction is mined, push a notification if on a mobile app, etc. If you present the user with some sort of confirmation number based on the transaction hash, you'll have to decide how you want to resolve cases when the transaction fails.
Is my DB structure a reasonable way to connect to the blockchain? I am worried about data integrity (i.e. having to sync address field between my internal DB and the blockchain) but I find it useful to store the blockchain data inside the internal DB, and read mostly from the internal DB instead of the blockchain.
This is purely an opinion, so take this with a grain of salt. I try to avoid having duplicate data, but if you're going to have multiple persistence layers you'll probably need to maintain some sort of referential integrity between them. So, it's certainly ok to store ids and addresses.
The part of your question that confuses me is why do you prefer to read mostly from the DB? Have you tried measuring the latency of using a fully sync'ed node on your server and retrieving data from your contract through constant
functions? I would test that first before duplicating my data. In your case, I would look to use the blockchain to store purchases while using the DB just for inventory management. But, that's based on very little knowledge of you business case.