CoinGuard
In progressDjango storefront selling hardware crypto wallets, built for buyers most payment rails will not serve.
Problem
The product is itself a security device, and the buyers are largely people mainstream payment processors decline. That means supporting Stripe, PayPal, Zarinpal, and on-chain payment side by side — four rails with four different failure modes — while the storefront stays trustworthy enough that somebody will hand it a shipping address for the device that will hold their keys.
Approach
One order state machine sits behind every payment gateway, so adding a rail is an adapter rather than a second branch through checkout. The whole stack ships as containers behind Nginx, which terminates TLS with automatically renewed Let's Encrypt certificates, and separate dev and production compose files keep the two from drifting into each other.
- Django 4.2
- PostgreSQL
- Gunicorn
- Tailwind CSS
- Docker Compose
- Nginx
- Stripe / PayPal / Zarinpal
Architecture & security decisions
Architecture
- Nginx terminates TLS and serves static assets; Gunicorn runs the application behind it, never exposed directly
- Separate dev and production compose files, so a local convenience cannot accidentally ship
- Multiple payment gateways behind one checkout flow rather than one code path per provider
- Automated deployment and monitoring scripts, so a release is repeatable rather than remembered
Security
- CSRF protection on every state-changing form; sessions hardened rather than left at defaults
- Parameterised queries throughout — no SQL assembled from strings
- Uploads validated on the way in, since a storefront that accepts files accepts whatever it does not check
- HSTS, X-Frame-Options, and X-Content-Type-Options set at the edge, with HTTP redirected to HTTPS
- Payment details tokenised rather than stored; role-based access control on the admin surface
- Security events audit-logged, so an incident has a record to read rather than a guess