The problem is coupling schema changes to the deploy while old code is still live. Fix: backward-compatible (expand/contract) migrations decoupled from app deploy; add the column nullable, backfill in a separate throttled step, drop the old in a later release.
#ci-cd#database#laravel
Eliminate the long-lived AWS keys in GitHub Secrets. With OIDC, make GitHub Actions an identity provider in AWS IAM; create a role whose trust policy is scoped to your repo/branch; the workflow gets short-lived STS credentials at runtime — no secret stored anywhere.
#ci-cd#security#infrastructure
A 1.2GB image ships your whole build toolchain to production — slow and a big attack surface. Multi-stage builds fix both: for Go, the final stage can be `scratch`/distroless (a few MB); for PHP, target `fpm-alpine` + `vendor/`. Run as non-root.
#ci-cd#docker#infrastructure
Local state + 3 people = corruption and races. Move state to a remote backend: S3 (versioned, encrypted) for the state file, DynamoDB for state locking. A lock is taken before any apply, so a second apply waits. Per-environment state and applies from CI.
#ci-cd#infrastructure#terraform
The symlink flip is atomic but not enough; OPcache keys on file path and the `current` path never changes, so workers keep serving old bytecode. Fix: flip the symlink, then gracefully reload PHP-FPM (not restart), and `opcache_reset` if needed. With Octane, code lives in memory so `octane:reload` is mandatory.
#ci-cd#laravel#deploy
100M rows/day in plain MySQL fails: the B-tree index and full-table aggregates don't fit in RAM. If you think in SQL and need aggregation, TimescaleDB (hypertables + continuous aggregates + compression) is the low-friction win. InfluxDB only if you want a separate metrics stack.
#data#postgresql#scaling
A blocking `ALTER TABLE` locks 20M rows. Do expand/contract: add new columns nullable, have the code write both old and new (dual-write), backfill history in throttled batches + verify, switch reads to the new schema, then drop the old. Each step is independently deployable and reversible.
#data#postgresql#ci-cd
Storing scores as plain strings and sorting in the app is O(N log N) per read over millions of keys. Use a Sorted Set (ZSET): `ZADD` updates in O(log N), `ZREVRANGE 0 99` returns the top 100 already sorted, `ZREVRANK` gives a rank in O(log N). It stays ordered as you write, so reads are near-constant.
#data#redis#performance
Try the cheapest version first: add a read replica and move reporting there — that usually ends the locking. Adopt full CQRS only when query shapes diverge too much for one schema; sync the models event-driven with the outbox pattern, don't dual-write, and accept eventual consistency.
#data#architecture#elasticsearch
Don't reach for MongoDB just because attributes vary — that's the NoSQL trap. Keep the relational core (products, prices, orders) in PostgreSQL, put the variable attributes in a GIN-indexed `JSONB` column. Your reporting need alone argues against splitting into Mongo.
#data#architecture#postgresql