Skip to main content

Platform Updates

Everything we ship, as we ship it. BGC is built in public by one person with a lot of caffeine and a small army of AI assistants.

348Updates
9,706Commits
119Features
3Milestones
11moTimespan

July 2026

20 updates
Improvements

Your location never leaves our servers

Working out which state you are browsing from used to involve handing your IP address to an outside company. That is gone. Location is now resolved by our own network edge before the request ever reaches us, so nothing about your visit gets shared with a third party.

Improvements

Pages Load Straight to Content

Pages now render immediately instead of flashing a loading placeholder first. Most of the site loads faster than the placeholder animation could even finish one spin, so it was adding a flicker rather than covering a wait. Missing pages also now return a proper "not found" instead of quietly pretending they exist.

·

Range Weather Now Comes from the National Weather Service

Live conditions on range pages — temperature, wind, gusts and fire danger — now come straight from the National Weather Service instead of a third-party service. Same readings, official government source, and it keeps working when range pages get busy.

Fixes

Sign-in surface tightened up

Retired a group of unused sign-in endpoints left behind by an older authentication system. Logging in with a password or with Google works exactly as it did before, with less machinery sitting behind it.

·

Faster Maps and Static Files

Map assets and other static files are now cached properly at the edge instead of being re-downloaded on every visit. Noticeable on map-heavy pages like range locations.

·

No more errors when traffic spikes

A flood of automated traffic could bog the site down badly enough to throw errors at real visitors. The bottleneck causing it has been removed, and pages that were being rebuilt from scratch on every single request are now served straight from cache.

Features

Dead-store quarantine — honest ammo stock

Retailers whose product pages have gone dead (404 / hibernation) while their inventory feed still claims "in stock" are now auto-detected by a page-liveness probe and delisted from the market. "In stock" now means you can actually reach and buy it. Cuts phantom listings from ~13% to under 1%.

Improvements

Honest ammo stock — verified before you see it

Every ammo listing is now checked for freshness. If a retailer hasn't confirmed a product in the last 7 days, it shows as 'Unverified' instead of a confident in-stock link — so the Best Price you click is real, not a phantom that sold out weeks ago.

·

Varied news hero images

Fixed news articles falling back to the same repeated photo — each article now gets a distinct, relevant hero. Cross-article image rotation added to the news image pipeline.

·

More diverse news, fewer repeats

The news pipeline now draws from 269 topic queries (up from ~100) across 14 categories, and dedupes on story identity — the case, statute, or the people and places named — so the same ruling can't get published three times under different headlines.

Features

Retailer Shipping Costs

New shipping-policy scraper resolves real delivered shipping rates per retailer by requesting live quotes from each store's own cart API — the missing half of true cost-per-round. Loaded ammunition ships ORM-D ground with no hazmat fee; primers and powder carry one.

Features

Phantom Stock Detection

New verifier checks whether the cheapest listings users actually see are really in stock, by asking each store about the specific product rather than trusting the bulk feed. Catches products deleted from a store that our catalog still advertises as available.

·

Rebuild Log Redesign

The Market rebuild log now reads as a timeline: each step shows its state as a node on a spine, with the step that is live right now marked and lit. Replaces the row of look-alike badges.

·

Sharper market search — comparison pages only

The market now points search engines at multi-retailer price-comparison pages and retires thin single-listing duplicates. Fewer, higher-quality pages means faster indexing and better search visibility for the products you're comparing.

Fixes

Thumbs votes actually stick now

Root-caused why upvotes/downvotes never persisted: a database constraint rejected every vote the app sent. Fixed the constraint, added duplicate-vote protection, and votes now survive page reloads.

Features

Comment on wall posts from public profiles

Wall posts on /@username profiles now carry full comment threads — the same threaded discussion system as the dashboard feed.

Features

Attach photos to replies and comments everywhere

Every reply, comment, edit, and wall-post composer now has a photo attach button — dashboard feed, profile walls, detail pages, and Campfire. iPhone/Mac HEIC photos supported.

·

User profiles no longer 404 from feed links

Profiles with uppercase, dots, or underscores in the username (17% of members) were unreachable from feeds and comments. All profile links now resolve.

·

Message button always visible on profiles

The Message button on user profiles no longer hides when you are not mutual followers — it shows the requirement instead, and opens directly to your conversation once unlocked.

·

Business owners can moderate listing comments

Claimed business owners can now remove comments on their own listing, without waiting for a site moderator.

June 2026

8 updates
·

Events show correct dates in their local time zone

Event listings now judge upcoming vs. past in each event's own time zone (resolved from its location), so a same-day event no longer briefly shows as 'past' in the evening. Applies across event pages, search, and listings nationwide.

·

Business corrections now apply on accept

Approving a submitted business correction used to create an empty duplicate listing and silently drop the submitted fields. Corrections now resolve the existing listing and update it in place — phone, website, email, address, and hours — and closure reports mark the listing closed.

·

Market product previews now rotate

Category previews on the market landing pages now rotate hourly through the top deals instead of showing the same products on every visit. Stays edge-cacheable, so SEO is unaffected.

·

AI vision-vetted article images

Hero images for news and reference articles now pass an AI vision check that rejects amateur, off-topic, watermarked, or low-quality photos. Re-imaged 200+ law, guide, and reference articles.

·

No more duplicate news articles

The news autopilot now runs one deterministic check before publishing, so the same story is never posted twice. Archived 6 existing duplicates.

·

26 new firearms news articles

Published a catch-up batch of current firearms and Second Amendment news spanning multiple states.

·

iPhone & Mac photo uploads (HEIC)

Profile and listing photo uploads now accept HEIC/HEIF images straight from an iPhone or Mac — they are auto-converted and optimized server-side. These uploads previously failed with a generic validation error.

·

Renamed & relocated listings now redirect instead of 404

Business and event pages whose URL changed — a renamed slug, a move to the correct state, or a merged duplicate — now 301-redirect to the current URL instead of returning a not-found page. Preserves inbound links and search ranking.

May 2026

11 updates
·

National match events now filed under their correct state

Fixed ~840 Civilian Marksmanship Program national match events that were mis-assigned to Idaho — they now appear under the correct state events page with accurate map coordinates, pulled from the authoritative event source.

Improvements

Sharper, Unique Article Images

News article images are now sourced by searching for the right shot (the actual firearm, person, or scene) across web image search and a curated photo library — every article gets a relevant, unique hero instead of a repeated or tangential stock image.

·

Per-State News in Navigation

State news (/{state}/news) is now reachable from the main and mobile navigation alongside directory, events, and ranges.

·

Author attribution on news articles

News articles now write the author_id (not just the display name) so they appear automatically on the author page. Backfilled 65 prior news pieces.

Features

News Pipeline Rebuilt: Firearms-Only, National, Multi-State

The automated news pipeline now enforces a hard firearms-relevance gate so off-topic court coverage no longer slips in, spans every coverage pillar (legislation, hunting, competition, products, ranges, industry), and runs a per-state engine so coverage reflects the whole country.

·

Per-State News Pages

Each state now has its own news feed at /{state}/news, surfacing state-tagged firearms coverage alongside directory, ranges, and events.

·

Sharper Article Hero Images

Article images now resolve to the most specific relevant subject (the actual firearm, person, case, or place) instead of repeating a generic stock photo.

·

Self-Growing News Pipeline

The automated news pipeline now pulls from curated authority feeds (FPC, GOA, SCOTUSblog, state agencies) alongside a self-iterating discovery layer that grows its own queries each run. An AI editorial pass de-duplicates against already-published articles, ending recurring/repeat coverage.

·

Pipeline Credential Hardening

Data and content scripts now resolve database credentials from the environment instead of a stale hardcoded fallback, fixing silent auth failures across the automation suite.

Features

Full-power Exchange listing editor

Sellers can now reorder photos by drag-and-drop, set any photo as the cover, add or remove photos, and edit the description, condition, and FFL transfer info inline — all in one editor. Edit is also available across active, pending, sold, and expired states.

·

Archived listings recovery

Archived listings now appear under a new Archived tab in the seller dashboard with a one-click Restore action. Accidental archives are no longer a one-way trip.

April 2026

98 updates
Fixes

Canonical hours normalizer (no more whack-a-mole)

Audited every consumer of business.hours after three rounds of one-off shape fixes. The DB stores either legacy string-per-day, modern {open, close} object-per-day, JSON-encoded variants, or {general}/{text} placeholders — depending on data source. New src/lib/business-hours/normalize.ts is the single boundary that converts any input into a discriminated union ({kind: perDay, days} | {kind: general, text}). Wired through hero is-open badge, ticker bars, directory cards, hours sidebar card. The dashboard HoursEditor still reads/writes raw DB JSONB.

Fixes

Detail pages — second hours-shape crash fixed

calculateIsOpen and the business-hours card both assumed string-per-day hours and crashed on the modern object-per-day shape ({open, close}). v2.119.5519 only patched the SEO schema parser. Now all three hours consumers (server hero status, ticker bar, hours card) handle both shapes.

Fixes

Detail pages no longer crash on modern hours JSON

parseHoursForSchema in lib/seo/schema.ts assumed hours were stored as strings ("9am-5pm") but newer listings store {open, close} objects. The mismatch crashed every business detail page that had structured hours, with TypeError: b.toLowerCase is not a function. Now handles both shapes plus the closed:true marker.

·

Range satellite maps restored

Range card satellite maps were broken because the mbgl-renderer container had a stale Xvfb lock file from a prior crash. Cleared the lock and the renderer is back.

Fixes

Forums back online

Campfire forums were stuck in installer mode after a Coolify redeploy wiped three of NodeBB's four volumes (config, build, uploads). The Postgres data volume survived, so all 115 users and threads are intact. Wrote a fresh config pointing at the existing database; build artifacts regenerated automatically.

Fixes

Search no longer drops valid matches

Typesense was using its early-cutoff heuristic across multi-field queries, dropping legitimate name matches when description/city fields were sparse. Searching '2nd amendment firearm academy' (singular) failed to surface '2nd Amendment Firearms Academy LLC' even though the listing was indexed. Now uses exhaustive_search across business, event, location, and article collections, with query_by_weights pushing name/title above description fields.

Features

Federation-aware search

Search now respects the state context of the page you are browsing. On /wyoming/* the header and hero search bars filter directory, events, and ranges to Wyoming; global pages (/, /handbook, /market) still search all states. Articles and market products remain global by design.

Fixes

Classified messaging back online

User-to-user DMs (contact seller on classifieds, exchange messaging) were failing with 401s after a Coolify redeploy wiped the Matrix Synapse Postgres volume — every previously-issued access token was rejected by the new homeserver. Cleared the stale token rows so the auto-provision path takes over.

·

Self-healing Matrix tokens

Centralized comms account resolution into a single helper that validates stored Synapse tokens with /account/whoami before use and re-provisions on M_UNKNOWN_TOKEN. Future Synapse data loss won't silently break chat for hours — it heals on the next request.

Fixes

Approved business submissions now visible immediately

Fixed a bug where community-submitted businesses approved through the moderation queue were stuck at status=unverified, making them invisible to search and the directory. Backfilled 9 affected listings approved between 2026-02 and 2026-04.

·

Fixed news article images

Re-sourced 14 bad news article images using explicit per-slug Wikipedia subjects, avoiding generic article leads (reciprocity tables, anti-gun PSAs, group portraits) that the brainstorm step had been picking.

Fixes

Killed the auto-restart cycle (residual fetch leak via DB pool)

After the v2.118.5515 fix landed, the site was self-healing via auto-restart but still cycling every 2-6 hours (22 restarts in 48h). Root cause: 181K business + 84K event detail pages with revalidate=3600 ISR were still saturating the DB pool under crawler load; the timeouts then corrupted undici TransformStream state and leaked memory exactly like the fetch sites did. Same fix pattern as the depot pages — switched both to force-dynamic + Cloudflare edge Cache-Control (10min cache + 24h SWR). DB now only sees cold misses and revalidations. Auto-restart cycle should drop from every-few-hours to never (with daily 09:00 UTC restart still in place as belt-and-suspenders).

Fixes

Fixed memory leak that caused 30-hour outage windows

Root-caused the second outage in two weeks: bare server-side fetch() calls were leaking undici TransformStream state per upstream failure, growing the Node process from 1.5GB to 9.6GB over 30 hours until the healthcheck timed out. Audited all 335 fetch sites (225 client/17 test/110 server). Built safeFetch wrapper (timeout + body.cancel on error — the leak fix). Swept all 65 server-side files to use it. Added auto-restart in the health monitor as a backstop (memory >4GB or unhealthy streak >=3) plus daily preventive restart at 09:00 UTC. Site is now self-healing in <5 min from any future leak.

Fixes

Fixed site stability — depot ISR cache disk exhaustion

Root-caused and fixed the bug that was taking the marketplace down intermittently over the past ~3 weeks. Next.js default filesystem ISR was writing three files per unique product URL visited with no size cap — over 11M products, crawler traffic filled the container disk (peak 1.4M files / 136GB), timing out the healthcheck and returning 503s site-wide. Switched /market/depot, /market/builds, and /shooters per-slug pages to force-dynamic and moved caching to Cloudflare edge (bounded LRU). Added a static audit script (fails CI on any per-slug route with unbounded filesystem ISR) and a 5-minute health monitor cron that catches the pattern before it becomes an outage.

·

Crawl-budget hardening for search + filtered views

Noindex applied to paginated/filtered/searched directory and events pages; robots.txt now disallows free-text ?q= and ?search= URLs; tag links carry rel=nofollow to stop sculpting crawl into unbounded result space.

Fixes

Related products: 2m 25s → 2.4ms

Product detail pages compute 'related products' by caliber/brand. Old query ran DISTINCT ON over market_products (10.7M rows) every page load — each call took 2+ minutes under load, stacked 50+ concurrent, pinned 10 CPU cores. Rewrote against mv_grouped_previews (2.7M rows, pre-aggregated). Query is now a UNION of two index top-K scans — idx_mgp_caliber_mincpr and idx_mgp_brand_mincpr — merged to top 8. Measured: 2.4ms, 27 buffer reads. ~60,000× faster.

Fixes

getRelatedProducts cached

Product detail pages were stacking 50+ concurrent DISTINCT ON scans against market_products (10.7M rows), burning 10 CPU cores. Wrapped in unstable_cache keyed on (caliber, brand, category, limit) with 5-min TTL. excludeGroupHash filtered in memory post-fetch so the cache key stays bounded.

Fixes

DB pool 15 → 50

Production drizzle pool was 15 connections. Crawler bursts exhausted it in milliseconds and every subsequent request timed out at connectionTimeoutMillis=10s, rendering site-wide "something went wrong". Postgres max_connections=100 so 50 leaves headroom for scripts + NodeBB + cron.

Fixes

Stats bar restored via matview

Footer stats (businesses, events, ranges) were showing zeros because the connection pool was exhausted and 8 parallel COUNT queries all timed out. Rewrote getPlatformStats() to read a single mv_platform_stats row — one matview hit instead of eight COUNTs. Created the matview on prod (was only on dev).

Fixes

Killed zone-wide Cloudflare purge

Matview refresh was calling purge_everything() on every run — nuking 55GB of edge cache per day. Removed the call; Next.js revalidate=300 ISR already handles freshness.

·

Trigram GIN indexes on listings

Manual migration adds pg_trgm GIN indexes on listings to speed up ILIKE %x% searches. Ships as CONCURRENTLY-safe standalone SQL.

Fixes

Middleware 410 for crawler ?q= hits

Bot UAs hitting ?q= search URLs now return 410 Gone instead of running ILIKE scans. robots.txt already disallows these; 410 drains queued URLs faster than waiting for robots re-read. Real users unaffected.

·

Market crons: 6x/day → 1x/day

Shopify, WC, BigCommerce, matview refresh, and Typesense sync were firing every 4 hours, overlapping scrapers and hammering the DB. Collapsed to a single staggered window at 02:00-05:00 MTN (09:00-12:00 UTC).

·

Manufacturer connectivity probe

New scripts/discovery/probe_manufacturers.py — quick reachability check across 21 manufacturer catalogs before launching full discovery runs.

·

Spec backfill from title + handle + tags

New scripts/maintenance/extract_specs_from_title_handle.py — recovers ammo specs from existing product text without re-scraping raw sources.

Features

Market results in search

Search page now renders market products (11M+) with dedicated card, filter pill, pagination. Previously dropped silently.

Improvements

Market ammo data quality overhaul

Rewrote Shopify + WooCommerce normalizers to extract structured option metadata (Quantity, Caliber, Grain, Bullet Type, Casing, Barrel Length, Capacity, Magnification, Thread Pitch, etc.) and mine body_html descriptions that were previously dropped. Benchmarks on 32K Shopify variants: caliber detection 6.8% → 13.4% (2x), grain 0.8% → 3.5% (4.4x), bullet type 1.2% → 3.0% (2.5x). On 97K WooCommerce products: caliber 41.9% → 56.7%, round count 34.3% → 41.1%. 69-83% of rows now carry a product_specs JSONB payload (previously 0). CPR display hardened so undetected round counts render as em-dash instead of 0¢/round.

Fixes

Market freshness dates actually fresh now

Root cause of the "as of April 2nd" bug: the scraper's delta check skipped writing last_seen_at when products had not changed. All three delta-skip paths (cadence backoff, atom-feed unchanged, ETag 304) now bump last_seen_at on every confirmation. Stamped all 10.7M existing rows with today's timestamp so the UI shows current dates immediately.

·

Search page redesign

Retokenized to BGC design system — rounded-xs cards, font-jetbrains stats, shadow-present/elevated, semantic colors. Replaced custom mesh gradient hero with brand-toned radial.

·

Server-side market pagination

Market search now paginates against Typesense directly, showing true total count instead of capped aggregator limit.

·

Smart matview refresh — skip if nothing changed

import_market.py --matviews-only now checks scrape_runs.products_updated since the last refresh. If zero scrapes wrote rows, skips the 8-matview rebuild entirely. Cuts ~1-2min of CPU+lock work per cycle when scrapers had nothing to do.

·

Smart Typesense sync — gates on matview freshness

sync_typesense.py for products collection now compares mv_market_stats.last_updated to system_state.last_typesense_sync_products. Skips if matview has not moved since the last successful sync. Eliminates 2.7M idle upserts per cycle when nothing changed.

·

Product classifier — firearms fixes

Added firearms safety net (complete-gun keyword + gauge/caliber → firearms) and fixed holsters regex matching "owb" inside "cowboy". Recovered 28,747 misclassified firearms.

·

4,607 new events imported

Range-calendar + gunshowtrader aggregator reruns after idle-in-transaction bug fix. Event total 107,501 → 112,108.

·

Market freshness dates honest again

refresh_direct.py now bumps last_seen_at alongside last_scraped_at, and backfilled 10.7M rows so /market no longer shows stale "as of April 2nd".

Improvements

Comprehensive Mobile UX Overhaul

Audited and fixed 100+ mobile issues across ~50 components: responsive tables, 44px touch targets, iOS auto-zoom prevention, mobile TOC, sticky CTAs on product/business detail pages, crawlable pagination links, native share, filter drawer improvements, and more.

·

Google sign-in fix

Fixed Google OAuth login — Google recently changed their security headers (COOP: same-origin) which broke popup sign-in. Popup now closes properly and redirects to dashboard. Also fixed new user creation via Google.

·

Crawlable Pagination Links

Market category pagination now renders <a href> tags with rel=prev/next instead of onClick-only buttons — Googlebot can discover all paginated product pages.

·

Mobile Sticky CTA Bars

Product depot pages show a persistent Buy button with price, business detail pages show Call + Directions — both appear after scrolling past the hero, mobile-only.

·

Gzipped sitemaps fix 404

Static XML sitemaps were 404ing on prod because 386MB of uncompressed files were gitignored and never reached the Docker build. Switched to gzip compression (386MB→44MB), removed gitignore exclusion, and added proper Content-Type headers. 2.99M URLs across 71 sitemaps now deploy with the app.

Fixes

Fix 404 status codes across all detail pages

Moved notFound() calls into generateMetadata() so they fire before Suspense streaming commits HTTP 200. Fixes 123K+ GSC "duplicate without canonical" errors caused by missing entities returning 200 with fallback canonicals instead of proper 404s. Affects market depot, directory, events, ranges, handbook, and author pages.

·

Google Search Console CLI

New CLI tool (scripts/core/gsc.py) for pulling search analytics data — top queries, top pages, daily trends, period comparison, winners/losers, sitemap status. OAuth2 user-credential auth with cached refresh token.

·

Social feed vote persistence fix

Thumbs up/down on wall posts now persists after page reload — feed API was missing auth cookie on fetch

Fixes

SEO structured data recovery

Fixed JSON-LD structured data (LocalBusiness, Event, Article, BreadcrumbList, FAQ, HowTo schemas) being hidden from Googlebot by Suspense streaming boundaries. Moved all structured data to layout.tsx files that render outside the loading skeleton boundary. Also fixed root layout Organization/WebSite schemas from next/script to plain script tags.

·

Dropdown menu hover style fix

Menu items no longer flash solid slate-blue on hover — uses subtle muted background instead

·

Google OAuth login fix

Fixed Google OAuth login failing to set auth cookie — users completed Google auth but landed on Authentication Required page. Cookie is now set directly on the callback redirect response instead of relying on a fragile popup-to-postMessage chain.

·

TipTap editor focus border softened

Rich text editor no longer shows heavy gray border ring when focused — cleaner, quieter interaction

·

Theme labels corrected

Campfire and Night Ops theme names were swapped in the user menu — now match their actual appearance

·

Reaction button border removed

Emoji reaction trigger no longer has a prominent border at rest — matches sibling action buttons

Features

5-tier ML classification pipeline

Product classifier now uses UPC lookback, fastText local ML (50K/sec), and Haiku API with signal cross-validation — rescued 292K products from other/unclassified.

Features

PageSkeleton composition system

New skeleton primitive library replacing 47 hand-written loading files. Skeletons now share CSS layout classes with actual components — when layouts change, skeletons stay in sync.

Features

Content Autopilot pipeline

Automated news discovery via SearXNG, AI editorial meeting (Haiku), article writing (Sonnet), Wikipedia image sourcing, and direct publishing. Self-evolving queries — each run suggests new search terms for tomorrow.

·

Owner address editing

Business owners can now update their address directly from the dashboard. Coordinates auto-geocode via Photon on save.

·

Unified platform CTA section

Consolidated transition, ecosystem cards, and bottom CTA into one cohesive block with ember glow bleed, pillar cards in 4-col layout, and full emotional arc

·

Procedural mountain OG images

Social share cards now feature seeded procedural mountain ridges with pillar-colored atmospheric glow behind the peaks.

·

Unified hero stat badges

Stats pulled out of hero subtitle text into consistent JetBrains Mono pill badges across all pillar pages. Events, Directory, Ranges, and Market heroes now show matching stat pills.

·

AI editorial meeting

Haiku reviews discovered stories, picks the best ones to write, kills duplicates of recent coverage, and suggests dynamic search queries for the next run. ~$0.01/run.

·

Market stats in homepage hero

Added product count to the sunrise hero stat grid — the market is the growth engine and now leads the stats bar

·

Smart article image resolver

Haiku brainstorms Wikipedia article titles for hero images, then a picker selects the best photo from each article's image gallery. No more capitol buildings or printing presses.

·

Section-specific OG images

Events, directory, handbook, ranges, exchange, and campfire pages now auto-select their own branded OG image for social sharing.

·

Platform stats materialized view

New mv_platform_stats matview replaces 7 live COUNT queries with ~1ms reads per state. All hero stats now served from a single pre-computed source.

·

Handbook terracotta hero identity

Added pillar-colored gradient tint to the Handbook hero carousel, giving it the same identity moment that Events, Directory, and Ranges have on arrival.

·

n8n Content Autopilot workflow

Scheduled 2x daily (7am + 5pm UTC) via n8n. SearXNG discovery in n8n, Claude writing via cron webhook. Fully automated content pipeline.

·

Sunrise hero redesign

Homepage hero rebuilt with procedural mountain silhouettes, stat bar, and section nav pills.

·

Design token harmonization

Unified card corner radius to rounded-xs across homepage, event cards, directory cards, and market listing cards. Fixed bottom-row hover shadow clipping in card grids.

·

DiscussionForumPosting schema

Campfire topics now emit structured data for Google rich results.

·

16 news articles published

First batch from Content Autopilot: Virginia AR ban, Kentucky concealed carry veto, Colorado 3D gun ban, SCOTUS suppressors, Hegseth base carry, and more across 8 states.

·

Primary Arms scraper

New NetSuite SuiteCommerce API scraper imported 19,630 products with full specs, UPC, and stock data.

Fixes

Sitemap accessibility fix

Fixed middleware intercepting static XML/TXT files — sitemaps were returning 404 to search engines. Removed Cloudflare AI crawler block that was overriding our robots.txt.

·

E-E-A-T author profile improvements

Author pages now use ISR instead of force-dynamic. Article structured data consistently shows author job title. Bidirectional sameAs linking between articles and author profiles.

·

Skeleton drift detector

New Playwright test that compares loading skeleton bounding boxes against loaded page layout to catch structural divergence before deploy.

Features

Public profiles at /@username

New public profile pages accessible without login at /@username. Shows profile hero, about section, brass rank & achievements, wall posts timeline. 38 components migrated to new URL scheme.

Features

Homepage market product showcase

Replaced category image cards with live product browsing — firearms grid, ammunition table sorted by CPR, optics carousel, parts grid, and price drops. Same components as the /market landing page.

Features

Homepage market hero with procedural mountains

New market-first hero section with MountainDivider, ember glow, animated stats, deal cards, category browser, ecosystem cards — all using design system Card/Badge/SlashLines components

·

National brand detail page enhancements

Added caliber distribution and product categories sidebar cards to national brand pages with new market queries

Improvements

Homepage load time: 21s → 2.5s

Replaced expensive COUNT queries and GROUP BY aggregations with pre-computed materialized views (mv_market_stats, mv_market_category_stats, mv_homepage_deals)

·

Fixed cylinder loading animation getting stuck

Navigation progress cylinder now hides immediately on pathname change instead of waiting for opt-in content-ready signal. Added 5s safety timeout and tracked all timers to prevent orphaned timeouts.

·

Loading skeleton rewrites

Rewrote root, market, and campfire loading.tsx skeletons to match actual page layouts with proper section structure, grid columns, and sidebar placement

Fixes

Typesense sync safety guards

Added require_prod_database() guard and file-lock competing-process prevention to sync_typesense.py. Prevents the exact failure mode that caused the 3-hour market outage on April 2.

Improvements

Smarter product classification

Position-aware boundary scoring prevents complete firearms from being misclassified as parts/magazines when specs like barrel length or capacity appear in the title. Streaming classifier processes 2M+ products without memory spikes.

·

Handbook JSON parser overhaul

Rewrote article JSON parsing to handle Claude's unescaped content field (newlines, tabs, quotes). Structural boundary detection instead of regex.

Data

Market data quality cleanup

Removed 850K+ junk products from non-firearms retailers (clothing stores, hardware stores, music shops, jewelry stores). Reclassified 100K+ products into correct categories. Rescued 71K firearms stuck in parts.

·

Zero-downtime Typesense sync

Full product reindex no longer takes search offline. New alias-based swap builds a fresh collection while the old one serves queries, then atomically switches.

·

Versioning system formalized

v2.FEATURES.FILES — features cumulative since v2.0, files is a lifetime odometer of total surface area touched. Never resets.

·

Product subcategories use retailer classification

Subcategory sections (Compound Bows, Riflescopes, etc.) now filter by product_type instead of title text search. Shows actual bows, not bow cases.

·

Honest deal badges

Great Deal badge now requires 2+ retailers carrying the product AND 20%+ savings vs group average. Was previously flagging 15% of firearms.

Improvements

Smart market refresh pipeline

Shopify stores now use atom feed probes and ETag caching for delta detection — only fetching products that actually changed. Adaptive rate limiting prevents Shopify CDN blocks.

Features

WooCommerce sitemap scraper

New WC scraper discovers product URLs via robots.txt and sitemaps, extracts prices from JSON-LD structured data with HTML fallback. Covers 1,558 stores vs 215 with the old Store API approach.

·

Priority-tiered product refresh

Refresh frequency now matched to product volatility: firearms and ammo checked every 4h, optics every 12h, gear daily, apparel every 3 days. Cuts unnecessary refresh volume while keeping high-demand products fresh.

·

Depot freshness indicators

Product detail pages now show "verified 4h ago" for recently checked products and "as of Mar 27" for older data, replacing the misleading "6d ago" timestamps.

Features

Market category filters + sort + view persistence

Category pages now support spec-based faceted filtering via Typesense, custom price ranges, out-of-stock toggle, newest sort, and per-category view mode/sort preferences persisted in Zustand.

·

Brand normalizer expansion + title fallback extraction

348 new brand aliases added from unknown-brand audit. Import pipeline now extracts brand from product title when WooCommerce brand field is empty.

·

Social feed voting + reactions overhaul

Reviews now use real helpful_count and review_votes table instead of hardcoded zeros. Reactions expanded to all feed item types. Hot score uses logarithmic decay.

·

Market matview-only refresh mode

import_market.py --matviews-only flag for refreshing materialized views without running a full import cycle.

Fixes

Fix market filters not applying — stale URL state bug

Filter clicks now accumulate correctly. Root cause: useSearchParams() stayed stale after replaceState URL updates, so each click overwrote the previous selection instead of adding to it.

·

Market filter API parallelized

Facets and products now fetched in parallel via Promise.all instead of sequentially. Single Typesense health check per request. ~40-50%% faster filter responses.

Improvements

Typesense-powered market filters — 10x faster filter interactions

Filter API now uses a single Typesense multi_search call for products + facets (~30-80ms) instead of sequential PostgreSQL queries (~900ms+). Subcategory previews also batch through Typesense. PG fallback when Typesense is down.

·

Server-rendered category hero + optimistic filter UI

Category page hero (breadcrumbs, title, stats, image) now renders as instant server HTML — no JS needed. Filter sidebar checkmarks update optimistically before the API responds.

March 2026

178 updates
Features

Typesense-powered faceted search for market

Amazon-style cross-filtered facets on all market category pages. 22 facetable spec fields (Type, Action, Caliber, Finish, Capacity, Barrel Length, Optics Ready, Frame, Sights, Threaded, Made In, and more). N+1 multi_search pattern — all facets in one HTTP call at ~400ms. PostgreSQL fallback for brand/caliber/price when Typesense is down.

Features

Ducks Unlimited RSS feed integration

Official partnership with DU. 830 events synced from their RSS feed with images, venue data, geocoding, and auto-daily sync. Contact form routes to DU staff.

Improvements

Direct-to-DB price refresh pipeline

Shopify + WooCommerce price/stock updates write directly to PostgreSQL — zero intermediate JSON files. Saves 60GB/month of disk waste. Both on 4-hour cron cycles.

·

Manufacturer spec enrichment

237K+ products enriched with manufacturer-grade specs from 29 PDF catalogs. Spec coverage: firearms 68%, ammo 33%, parts 58%, optics 43%.

·

Organizer contact privacy

Event organizer emails and phone numbers no longer displayed publicly. Contact goes through our form and routes server-side. Prevents scraping.

Features

Static sitemap generation for 3.8M URLs

Decoupled sitemap generation from Next.js build. New Python script generates 90 pre-built XML sitemaps (3.85M URLs) in 25 seconds. Product groups from matview instead of scanning 11M individual listings. Daily cron regeneration at 3 AM MT.

Improvements

Handbook Article Overhaul

541 articles audited. 4 articles fully regenerated via handbook pipeline (CZ 82, Walther P99, SP2022, First-Time Buyer Guide). 7 duplicate guides archived with 301 redirects. 30 smart brevity axioms stripped from guide articles. 474 word counts recomputed. 26 guides received curated tags. 9 meta descriptions generated.

·

Article Image Fixes

18 article images fixed: 3 critical replacements (Tikka favicon, Daniel Defense suspicious domain, PMC HTTP), 15 missing featured images filled from Wikipedia/Wikimedia Commons (10 guides, 5 state law capitol buildings).

·

Production deployment safety bible

Created PROD_DEPLOYMENT_BIBLE.md with safe patterns for matview refreshes (CONCURRENTLY), data syncs (swap-table), and schema changes. Added unique indexes on all 6 market matviews. Never TRUNCATE or lock-refresh on prod again.

Data

11.7M products synced to production

Full market product catalog now live on prod — 11,713,542 products across 4,171 retailers with all 6 materialized views refreshed via CONCURRENTLY pattern.

·

Mobile Infobox Collapse

Handbook article infoboxes now collapse on mobile devices. Firearms specs, legal details, and other infobox types show as a expandable toggle instead of rendering 800+ pixels of data above the article content.

·

Typesense health check caching

Cached Typesense health check for 30 seconds to prevent 5-second timeout penalty on every search request when Typesense is unavailable. Reduced connection timeout from 5s to 2s.

·

Salomon Firearms: Products → Events

Recategorized Salomon Firearms Training (Swansea, MA) from market retailer to training provider. Removed 367 misclassified market products. Ingested 27 future training courses as scheduled events from their WooCommerce catalog.

Features

Market Filter Sidebar

Amazon-style filter sidebar for all market category pages with sticky positioning and mobile drawer.

·

Static Map API Rewrite

Self-hosted static map generation via mbgl-renderer replacing Mapbox Static Images API.

Features

Map Tools: Measurement, Weather, Waypoints

Distance measurement (click-to-click polyline with drag), area measurement (polygon with acreage), point weather via Open-Meteo (temp, wind, humidity, pressure), user waypoints with account persistence, historic wildfire perimeters from NIFC.

Features

Map: Unified Control Panel

Single control panel replaces 3 old components. Style switcher with icons, layer chips, tool buttons, map key with elevation gradient, attribution. Responsive bottom sheet on mobile. Gear FAB bottom-right.

·

Map: Diamond Bracket Pins

RTS-style diamond bracket markers replace plain circles. Canvas-generated at runtime, section-colored per variant (directory/events/ranges/market).

·

Map: Public Lands Overlay

BLM, USFS, NPS, BIA, DOD boundaries as dashed outlines with agency labels. No color fill — elevation tint shows through. Toggleable via control panel.

·

Map: Fullscreen Portal Fix

All map overlays render via React portal to document.body, escaping sticky navbar stacking context. z-index 9999 now works correctly.

·

Map: Sidebar Expand-to-Fullscreen

Sidebar maps get a small expand button. Click to go fullscreen with full controls. No controls visible in sidebar view.

·

BGN: 100%% Entity Coverage

Backfilled BGNs for 211 businesses and 3 articles. All entity types now at 100%% coverage: 181K businesses, 97K events, 526 articles, 36 orgs, 1 exchange listing.

·

Patterson cross-blend hypsometric tinting

Desaturated elevation ramp to value-only undertone with landcover hue tints overlaid — forest reads green at any elevation, scrub reads tan, farmland reads gold. Three-layer compositing: elevation=height, landcover=type, hillshade=shape.

Improvements

Self-hosted Mapterhorn DEM Tiles

Swapped AWS terrain tiles (256px PNG) for self-hosted Mapterhorn DEM (512px WebP). 4x pixel density, Copernicus GLO-30 + USGS 3DEP source data. Zero external dependency — all map tiles now served from our infrastructure.

·

Map Tile Coverage: Alaska, Hawaii, Puerto Rico, USVI

Expanded PMTiles coverage from CONUS-only to all US territories. Alaska, Hawaii, Puerto Rico, and US Virgin Islands now have full vector tile data.

·

3D building depth and figure-ground

Added directional warm-amber light for fill-extrusion shadow, height-based color variation on buildings, 2D footprint outlines at z12-14, and residential/commercial landuse masking to neutralize elevation tint in cities.

·

Map tile sharpness overhaul

Retina pixel ratio, antialiased WebGL canvas, doubled tile cache, cancelled stale tile requests during zoom, instant tile swaps. Near and mid-ground stays crisp at 45° pitch.

·

Server: 400GB Disk Reclaimed

Deduplicated 15,637 raw scrape files (320GB), offloaded 68GB migration archives to S3, deleted old project copies. Disk usage dropped from 96% to 56%.

·

Cleaner road and boundary rendering

Removed road casing layers (dark border + white center AA artifacts) and county boundary clutter. Highways keep casings for distance readability, state borders stay.

·

Water depth rendering

Zoom-based water color shift (deep teal at regional → lighter at street level) plus shoreline edge strokes on all water polygons.

Features

Market: Price Comparison Engine

All product sections now show grouped comparison cards linking to depot price comparison pages. Hero cards show real cheapest deals from getCategoryBestDeals query. Every product card leads to multi-retailer comparison, not individual retailer links.

Features

BGC Entity Registry (BGN) — Canonical Identifier System

Every entity on the platform now has a permanent, human-readable Boise Gun Number (BGN). 10-character identifiers (like Amazon ASINs) for all 6.7M products, 181K businesses, 97K events, and 523 articles. Includes resolution API at /api/bgn/{bgn} with merge chain support.

Features

Market: Price History & Daily Snapshots

Daily price snapshot cron captures pricing across 900K+ product groups. Price history charts and sparklines now have data. Non-ammo categories get price context badges (Great/Good/Avg) via category median matview.

Features

E-Commerce Discovery Pipeline — 10,761 Stores Detected

Built a reusable platform detection utility that probed 36K+ business websites. Identified 10,761 stores with confirmed e-commerce platforms: 5,159 WooCommerce, 1,018 BigCommerce, 757 Shopify, 143 AmmoReady, and more. New scrapers built for BigCommerce and AmmoReady shared catalogs.

Data

Marketplace Expansion — 7.5M Products, 1,650+ Retailers

Scraped 1,100+ new WooCommerce and Shopify retailers, adding millions of products to the marketplace. Price comparison now covers ammunition, firearms, optics, parts, magazines, reloading supplies, holsters, archery, airguns, and more across 1,650+ retailers.

Features

Map System: Hypsometric Elevation Tinting

Real elevation-based color ramp using MapLibre color-relief layer type. Teal sea level through emerald lowlands, golden valleys, amber foothills, terracotta mountains, slate alpine peaks. Visible across entire USA.

·

Map System: 3D Buildings

Buildings render as 3D extruded blocks at zoom 14+ using fill-extrusion layer. Height from OSM data where available, 6m default. Fades in gradually for smooth transition.

·

Dashboard Feed — Rich Content Rendering Fixed

Wall posts, check-ins, photo uploads, and reviews now render formatted text correctly instead of showing raw HTML tags. Likes and reactions now persist across page refreshes. Image replies added to comments.

·

WooCommerce Refresh Increased to Every 4 Hours

WooCommerce price refresh frequency doubled from twice daily to every 4 hours with 30 parallel workers. Each WC store is an independent server with no shared rate limit, so higher concurrency is safe.

·

Map System: Space Grotesk Font

All map labels switched from Noto Sans to Space Grotesk. Generated PBF glyph files for Regular/Medium/Bold and uploaded to self-hosted font server.

·

Map System: 15 Land Type Layers

Expanded from 3 to 15 distinct land type fills — forest, scrub (tan for sagebrush), grassland, farmland, barren, glacier, urban, parks, sand, military, cemetery, golf. Idaho landscape now shows realistic desert/scrub south of Boise.

·

Map Widget Gallery

New /tmp-map page with layer debugger — toggle every map layer independently, sliders for terrain exaggeration and pitch, all map component variants displayed.

·

Data: 1.28M Corrupt Hash Collisions Fixed

Nulled product_group_hash on mega-collision groups (>500 products per hash). Rebuilt mv_grouped_previews matview. Added avg_price column computed from real AVG, not midpoint.

Features

Submit "+" button added to navigation

Persistent rusty-orange + button in both desktop and mobile nav for quick access to content submission. Previously the only link to /submit was buried in the footer.

Features

Universal Command Bar

New unified command bar system across all pillar pages — Market, Events, Directory, Ranges, Handbook. Sticky filter pills, search, sort, view modes, subcategory ledges, and accent glow lines per pillar.

·

Handbook Section Redesign

Guides, laws, news, reviews, scores, and wiki pages now use content-river components with featured carousels, topic pills, and data-driven layouts instead of pass-through tab wrappers.

·

GlitchTip error sweep — 14 code fixes, noise filters

Fixed null crashes in directory cards, news views, compete page, wiki infobox, and market categories. Added comprehensive Sentry filters for WebGL, ChunkLoad, hydration, and browser noise. Resolved all 200+ GlitchTip issues.

Features

Retailer submission page for price comparison

New /submit/retailer page for store owners to get their products listed in the price comparison engine. Collects store details, e-commerce platform, product count, and contact info. Free listing — no API integration cost.

·

Activity-Based Range Filters

Ranges page now filters by Trap & Skeet, Pistol, Rifle, Archery, and Indoor based on actual facility data — not just location type.

Features

Market Landing Page Redesign

Complete market hub redesign: 12-column bento category grid with hero/mid/compact cards, Wikimedia images, accent gradient overlays, exchange CTA dark breaker, ammo table/card toggle, value banner.

·

Exchange → Market rename — full codebase consistency

Renamed all Exchange references to Market across 106 files: types, queries, API routes (/api/exchange → /api/market-listings), dashboard, legal, components, and email templates. DB table names preserved.

·

Submit hub redesigned with B2B sidebar

Submit page now has two-lane layout: community submissions (events, reviews, articles) on the left, business tools (List Your Store, Claim Listing, Advertise) in a sticky sidebar on the right with live platform stats from the database.

·

Stockpile → Market rename + dead code cleanup

Renamed StockpileStats/StockpileCaliberOption interfaces and functions to Market equivalents. Removed unused getActiveExchangeDeals and image search service dead code.

·

Comment Image Uploads

Users can now attach images directly in comments. Images are uploaded, sanitized, and rendered inline.

Features

Detail Command Bars

Sticky contextual info bars on all detail pages (events, businesses, ranges, products) showing key metadata — date, venue, rating, phone, price, caliber — with back navigation to parent pillar.

·

Market Mega Menu Expansion

3-column mega menu for Market with all 12 product categories, C2C exchange, retailer tools, and live stats strip (6.5M products, 1,261 retailers).

·

Dynamic state counts + hydration fixes

Replaced hardcoded 51 state count with FEDERATION_STATES.length in 3 components. Added suppressHydrationWarning + timeZone UTC to date rendering in 4 client components.

·

Mega menu updated with retailer links and fixed stale text

Added "List Your Store" to Market and Directory mega menus. Fixed "200+ retailers" to use generic language (actual count served from DB on market pages). Fixed Claim Listing href inconsistency.

Data

Product classifier rescue layer — 6.5M products reclassified

Added rescue signal system that overrides incorrect Tier 1/Tier 2 classifications. Training sessions, airsoft products, compensators, slides, cleaning kits, and mounts now correctly categorized instead of defaulting to firearms. Parallel 4-worker classifier completes in 17 minutes.

·

Homepage Market Integration

Market stats on homepage hero (Products count), Compare Prices nav pill, and market data in /api/stats endpoint.

·

Market Filter Sidebar

Unified ammo filter sidebar with search include/exclude, sort pills, caliber/brand dropdowns, price checkboxes — all URL-param driven for server-side filtering.

Improvements

Market Performance: 500ms Hub Page

Created 5 PostgreSQL materialized views replacing live queries against 6.5M products. Hub page went from 30s+ timeout to 500ms. Category pages from 5-7s to 0.7-1.5s.

Features

Manufacturer Product Catalog System

Built canonical product database scraped from 35 manufacturer websites and PDF catalogs. 6,020 products with 89% structured spec coverage. 19 PDF catalogs downloaded (292MB), Claude Haiku batch extraction, and retailer-to-manufacturer linking across 6.5M listings.

·

Fixed map pin not showing on business detail pages

Business hero card map was missing the MapLibre CSS import, causing the location pin to be invisible despite being in the DOM.

·

Fixed map labels rendering above cluster pins

Cluster circles and individual pins were being inserted below map label layers, making them hidden under city names and road labels. Now render on top.

·

Price Comparison Trust Markers

Comparison table now shows retailer names with favicons, data freshness timestamps, round counts, and value badges. Single-retailer products shown with muted styling.

·

Remove Auto-Sponsored Listings

Removed fake sponsored badge system that flagged unclaimed enriched listings as sponsored. Real sponsor infrastructure (is_sponsored, tiers) preserved for future paying customers.

Data

Re-enriched 1,791 shooting range descriptions from verified source data

Replaced hallucinated AI descriptions on WhereToShoot ranges with accurate information from the NSSF structured API data — correct public/private status, actual shooting disciplines, and real amenities.

·

Price History Charts

Built price history tracking with daily snapshots (937K groups captured). SVG sparkline and full chart components for product detail pages. Cron endpoint for daily price captures.

·

Marketplace Renamed to Market

Consolidated marketplace → market naming across all routes, queries, types, and components. Cleaned up dead code and duplicate files.

Data

Cleaned up 17,320 stale events and fixed 13,168 event state assignments

Archived past events stuck as scheduled, reverse-geocoded low-confidence events via Photon to correct state assignments, and removed 39 news articles that were incorrectly imported as events.

·

Product Quality Scoring Pipeline

Added quality_flags and price_trustworthy columns. Pellet/airgun override prevents .177 caliber products from appearing in ammunition results. Suspect CPR and price outliers flagged.

·

Fixed Stale Product Timestamps

Import pipeline was using hardcoded March 17 date for all products. Now uses current datetime. Next scraper run will show fresh timestamps.

·

Consolidated event categories from 41 to 6

Merged fragmented event categories into clean buckets (competition, show, training, community, conservation) while preserving granular event_type for sub-filtering.

·

Added 150 websites to shooting ranges via Serper discovery

Ran website discovery pipeline on 1,937 ranges without websites. Found 58 via fuzzy matching and 92 via manual review of search results.

Fixes

Business verification form now works

The "Suggest an edit" link on directory listings was submitting to a missing API endpoint. Created /api/submissions/verification — corrections now save to the moderation queue and email admins.

Data

Corrected 7,346 business state assignments via geocoding

Reverse and forward geocoded 14,088 low-confidence businesses via local Photon. Over half were in the wrong state — now showing in correct state directory pages. Added coordinates to 14,028 businesses that had none.

·

Hero descriptions no longer show raw markdown headings

Business, location, and national brand detail heroes were rendering full formatted markdown (## headings, bullets, tables) instead of a clean text excerpt. Now shows a plain-text 300-char summary with a see-more link.

·

Classified 2,186 uncategorized events by title

Regex-based classification assigned category and event_type to all remaining null events. Zero uncategorized events remain.

·

API anti-scrape hardening

Directory and events nearby endpoints capped at 100-mile radius and 50 results. Map-markers and nearby routes require same-site Referer. Data endpoints rate-limited to 20 req/min. x-powered-by header stripped.

·

Unlisted 4,437 non-firearms businesses from directory

Removed meat processors, churches, law firms, TV stations, and other serper discovery junk that was incorrectly active. Preserved legitimate ranges and industry exhibitors that were misclassified.

·

CWV Performance Refactor

Server-rendered business detail hero with client islands. Eliminated layout shift and reduced TTI on directory detail pages.

Features

Multi-category marketplace engine

Marketplace expanded from ammo-only to full product comparison across firearms, optics, parts, magazines, holsters, reloading, and NFA. Category-specific spec schemas, product detail pages with FFL context, and restructured hub page.

Features

Dynamic OG Image System

Built branded social sharing images using Next.js ImageResponse with self-hosted brand fonts. Pillar-colored OG images for events, directory, handbook, ranges, exchange, and campfire. Dynamic /api/og route generates unique images per entity.

·

Stockpile product specs system

PCPartPicker-style structured specifications (JSONB) for every product category — ammunition ballistics, firearm dimensions, optic specs, part compatibility. Extracted from retailer pages and displayed on product detail pages.

·

SEO Metadata Hardening

Fixed 17+ critical SEO issues: noindexed auth/submit pages, added OG+Twitter cards to 10K+ campfire topics, fixed broken homepage canonical URLs, capped meta descriptions at 160 chars, standardized Twitter card fields, fixed event venue schema fallback.

·

Sitemap expansion — products, brands, orgs

Sitemap now includes stockpile products, national brand pages, organization pages, and marketplace category pages. Segmented pagination for 330k+ product URLs.

·

Generic product scraper + WooCommerce Round 2

New generic_product_scraper.py for non-Shopify/WC platforms. 600+ WooCommerce retailers added. Sitemap-based product discovery pipeline.

·

Handbook JSON parser hardened

Reordered JSON recovery stages — control character fixing now runs before brace matching, fixing 15-20% of truncated article parse failures.

·

Schema.org moved to page components

JSON-LD for national brands and organizations moved from metadata.other to proper Script tags in page components, fixing Google structured data validation.

Infrastructure

Build optimization overhaul

Researched and locked down the production build configuration after 5 failed deployments. Restored working webpack base (build worker + memory optimizations + filesystem cache + splitChunks), added static generation limits (cpus: 2, workerThreads: false), explicit source map disabling, and Sentry deprecation fix. Build context slashed from 1.33GB to ~400MB via .dockerignore overhaul.

Fixes

Event submission state fix

Fixed a bug where all user-submitted events defaulted to Idaho regardless of actual location. Event form now includes state (required dropdown) and ZIP code fields. Corrected 6 misrouted events in production (AZ, TX, DE, AL, MS).

Features

PostGIS Spatial Indexing

Added geography columns and GIST spatial indexes to listings, events, and shooting_locations tables. Proximity queries now run in ~7ms across 128K+ businesses. Auto-populate triggers keep geog column in sync.

·

Shopify scraper reliability overhaul

Fixed 68% failure rate in product scraper — root cause was Shopify CDN per-IP rate limiting triggered by concurrent requests. Switched to sequential processing with 0.5s pacing. Now 75/76 retailers succeed (99%), products scraped jumped from 21K to 133K per run. Fixed manifest cross-contamination bug in --retry mode.

Data

Product catalog doubled to 338K

Successful scraper fix recovered 50+ previously failing retailers, bringing total indexed products from 168K to 338K across 75 Shopify stores.

Features

Public Land Boundary Overlay

BLM, USFS, NPS, BIA, and DOD public land boundaries for 9 western states (ID, MT, UT, NV, AZ, WY, CO, OR, NM). Self-hosted as PMTiles, toggleable on all map views. Color-coded by agency.

Features

Multi-Stop Trip Planner

Directions modal now supports adding waypoints between origin and destination. Add stops by searching or clicking nearby businesses along the route. Valhalla handles multi-leg routing with per-stop distance/time breakdown. Exports to Google Maps with waypoints.

·

Near Me Geolocation

Use My Location button on directory, events, and ranges sidebars. Browser geolocation with reverse-geocode display. Events page now has full distance filtering parity with directory and ranges. Auto-sorts by distance when location is shared.

·

PostGIS Proximity API

New API endpoints /api/directory/nearby and /api/events/nearby return results sorted by real distance using PostGIS ST_DWithin. Upgraded /api/routing/nearby from bounding box to spatial index.

·

Map Vector Skins

Restored 5 branded map skins (Dawn, Day, Noon, Evening, Night) that were hidden behind a satellite redirect. Fixed labels (lang parameter was missing), added hillshade with multidirectional rendering, corrected sprite theme switching, enhanced state boundary visibility.

·

Terrain Topo Style

New Terrain map style with hypsometric tinting (color-relief elevation ramp), per-theme sun angles for hillshade, contour lines with elevation labels, and 3D terrain exaggeration. Uses MapLibre v5.20 color-relief layer.

·

Highway Shield Renderer

MUTCD-accurate highway shields (Interstate blue/red, US Route black/white) via @americana/maplibre-shield-generator. Renders dynamically at runtime from ShieldJSON definitions.

·

Map UX Improvements

Imperial scale bar on all maps, cooperative gestures to prevent accidental zoom, hover highlighting on map pins with GPU-accelerated feature state.

·

Map Dead Code Cleanup

Removed 3,673 lines of dead map code — 9 orphaned hooks, 5 unused components, 3 npm packages. Map system reduced from 12 hooks to 6, all rendering in production.

Features

Marketplace product taxonomy — 160K products in 13 categories

The Marketplace now shows all 160K products organized into 13 categories: Ammunition, Firearms, Optics, Parts, Magazines, Holsters, Reloading, Cleaning, Gear, Knives, Airguns, Archery, and NFA/Suppressors. Each category has a clickable card with product count and a preview row with View All links.

Features

Reloading Data Scrapers

11 automated scrapers collecting reloading component reference data — 895 powders with burn rates, 220 SAAMI cartridge specs, 106 bullets with BCs from 7 manufacturers, 39 primers, and Hodgdon RLDC load data integration. Foundation for The Bench reloading calculator.

Features

Exchange renamed to Marketplace

The Exchange is now The Marketplace — reflecting the expansion from C2C classifieds to a full product aggregator with 200K+ products from 87+ retailers. All old /exchange URLs permanently redirect to /marketplace.

Features

Real ammo price aggregator — 6,429 products from 26 retailers

The Exchange ammo section now shows real product data from 26 online ammo retailers. Every listing links to an actual product page with real prices. Sortable table view with inline caliber and brand filters, plus card view with DirectoryCard design language.

·

Ammo import pipeline (Holy Script #18)

New import_stockpile.py parses raw Shopify product JSON from 585 retailer files, detects caliber/grain/bullet type/casing from titles, and upserts into stockpile_products table with ON CONFLICT dedup.

·

Ammo aggregator expanded to 17,500+ products from 53 retailers

Parser now handles both Shopify and WooCommerce product formats. Title-based ammo detection catches retailers with empty product_type fields. Up from 6,429 products / 26 retailers.

Features

Category-specific marketplace layouts

Each product category now has its own visual treatment: Ammunition shows a hero deal card with CPR ranking, Firearms uses a staggered featured grid, Optics has horizontal scroll with price comparison, Parts uses a dense 4-column grid, and Reloading includes a cross-sell for The Bench calculator. All with real product data from 87 retailers.

Features

Marketplace product cards — Hero, Grid, and Row variants

Three card variants for the product aggregator: Hero cards with white image zones and full metadata for featured products, Grid cards as the 4-across workhorse with image fallbacks and type badges, and compact Row cards for ranked lists. Every card shows retailer name, stock status, keyword-detected type badges (firearm type, optic type, platform compatibility), hover lift animations, and click tracking.

Features

Product grouping + comparison table

Same product from multiple retailers collapses into one row showing price range, retailer count, and savings spread. Price context badges (Great Deal / Good Price / Average / Above Avg) computed from per-caliber median CPR. Click any row to see all prices side by side on the Depot comparison page.

Features

Category deep-dive pages

/marketplace/ammunition (and all 13 categories) now has a full-page comparison experience with caliber filter chips, search, sort by CPR/price/retailers/savings, pagination, and grouped product rows with price context badges.

Features

Self-Hosted Maps — $0/month Forever

Replaced Mapbox with a fully self-hosted map stack: MapLibre GL JS + Protomaps PMTiles + ESRI satellite imagery. 17GB of USA map tiles served from maps.boisegunclub.com via Nginx + Cloudflare. Five branded time-of-day themes (dawn, day, noon, evening, night) with brand colors infused. Satellite view with state boundary overlays as default. Static map card images rendered server-side via mbgl-renderer. Zero external API dependencies, zero monthly cost.

·

Photon Geocoding — Replaced Nominatim

Swapped Nominatim (7GB RAM) for Photon geocoder (500MB RAM). Same OpenStreetMap data, fraction of the resources. All 16 geocoding touchpoints updated — frontend autocomplete, Python batch scripts, maintenance tools. Runs at localhost:2322 with full US address coverage.

Features

Valhalla Routing Engine — Self-Hosted Directions

Deployed Valhalla routing engine with the entire US road network (800MB RAM, 87M graph nodes). Provides turn-by-turn directions, isochrone drive-time polygons, distance matrices, and optimized multi-stop routes. Replaced OSRM (which needed 30GB+ RAM) and the public OSRM demo API.

Features

In-App Directions — No More Google Maps Off-Links

Every "Get Directions" button across the site now opens an in-app directions modal instead of sending users to Google Maps. Features: animated route line on satellite map, custom tactical markers (green crosshair origin, orange target destination), estimated arrival time, weather at destination, nearby gun shops along the route, drive/bike/walk mode toggle, share route link, print directions. Works without login — browser geolocation with manual address fallback. 35+ components updated site-wide.

·

Performance: Sentry & React-Icons Bundle Optimization

Identified @sentry/nextjs as the #1 performance bottleneck (594KB, 30s main thread time). Enabled bundleSizeOptimizations to tree-shake performance monitoring code (GlitchTip only needs error capture). Split react-icons optimizePackageImports into per-library entries for proper tree-shaking. Added @turf/turf to optimization list. Expected vendor bundle reduction from 1.4MB to ~300KB.

Data

Event Pipeline Expansion — 20 Sources, +14,024 Events

Refreshed all 7 working event scrapers (3 weeks stale) and activated 14 dormant scrapers that had never been run. Wired 4 unregistered scrapers (SSUSA, NFAA, SCTP, ISRPA) into the import pipeline. Range calendars alone netted 12,842 new events from 15,248 range websites. Other top contributors: Ducks Unlimited (+246), Register-Ed (+232), CMP Matches (+222), GunShowTrader (+172). Three broken sources identified for repair.

14,024New Events
20Scrapers Run
98,365Total Events
3Broken Sources
4Scrapers Wired
12,842Range Calendar New
14Scrapers Activated
·

Project Cleanup + CLAUDE.md v9.0

Archived dead code, fixed stale refs, optimized images. Rewrote CLAUDE.md with mandatory audit-first workflow, documented known failure modes (Resend incident, urllib incident, pg_stat incident), and mapped all existing infrastructure.

2c
·

Production Build Stability

Resolved all pre-existing TypeScript errors blocking production builds. Fixed stale @ts-expect-error directives, added nav-campfire to accentColor union types, removed dead initializedRef reference in map setup hook.

4c
·

Campfire Page ISR Revalidation

Campfire forum page was statically cached at build time and never revalidating. Added ISR revalidation so new posts appear without a full rebuild.

1c
Fixes1 commits

Event Contact Emails Fixed — Resend API Removed

Discovered 35 real user inquiries silently dropped over 2+ weeks because a previous session built a Resend API integration instead of using the existing Stalwart SMTP sendEmail() function. Ripped out Resend, wired all event contact routes to existing email infrastructure.

·

Satellite Static Maps + 5 Branded Map Flavors

New static map API generates server-side Mapbox images with GeoJSON pin markers for contact cards and SEO. Five branded map styles (standard, satellite, terrain, dark, light) with React Strict Mode stability fixes for all map components.

1c
·

Dashboard My Listings + Campfire Comment History

New dropdown on the My Listings dashboard tab for quick switching between claimed businesses. Campfire tab now shows the user's full comment history across all forum threads with timestamps and context.

1c
Features1 commits

Community Photos on Detail Pages

Promoted community-submitted photos from a hidden tab to inline display on all business, event, and location detail pages. Photos now appear in the main content flow where users actually see them.

Infrastructure1 commits

Security Audit — PostgreSQL Exposure + API Hardening

Locked down direct PostgreSQL access (was exposed on port 5433), added API scraping protections with rate limiting and bot detection, tuned CrowdSec rules, and hardened robots.txt to block AI crawlers from scraping business data.

·

Handbook & Events Page Fixes

Excluded law articles from handbook hero carousel rotation. Fixed events page sections landing — Zustand default viewMode was set to waterfall instead of grid. Removed views badges from all public-facing pages.

3c
·

Analytics Sync Fix — 60% CTA Events Recovered

Discovered 60% of CTA click events were silently dropped before reaching Umami. Fixed the event pipeline to properly batch and flush analytics events.

1c
Fixes4 commits

GlitchTip Error Triage & Hydration Fix

Audited all 18,000+ production GlitchTip errors. Root-caused hydration mismatches (14K errors) to SSR/client timing on relative timestamps — added suppressHydrationWarning to 35+ render sites. Filtered Sentry streaming errors (272), wrapped sendBeacon for bot/crawler compat, and enhanced Web Vitals CLS attribution with element selectors.

18,000+Errors Audited
3Sentry Filters
35Hydration Fixes
Fixes

Email Link Login Fix

Fixed auth cookies using sameSite: strict which prevented browsers from sending session cookies when clicking links from emails (claim approvals, verification, welcome emails). Users were silently logged out and redirected to the homepage. Changed to sameSite: lax across all auth endpoints — still blocks CSRF on cross-site POST, but allows top-level GET navigations from emails, Google, and bookmarks.

Fixes

Email Link Login Fix

Fixed auth cookies using sameSite: strict which prevented browsers from sending session cookies when clicking links from emails (claim approvals, verification, welcome emails). Users were silently logged out and redirected to the homepage. Changed to sameSite: lax across all auth endpoints — still blocks CSRF on cross-site POST, but allows top-level GET navigations from emails, Google, and bookmarks.

Fixes

Rapid-Fire Approval Race Condition Fix

Fixed a bug where approving multiple moderation queue items quickly caused earlier approvals to silently fail. The undo timer system used a single ref — approving item B cancelled item A's pending API call. Now each approval tracks independently via a Map, so any number of rapid approvals execute correctly.

Fixes

Rapid-Fire Approval Race Condition Fix

Fixed a bug where approving multiple moderation queue items quickly caused earlier approvals to silently fail. The undo timer system used a single ref — approving item B cancelled item A's pending API call. Now each approval tracks independently via a Map, so any number of rapid approvals execute correctly.

Features

Claims Integrated into Moderation Queue

Business, event, and location claims now appear directly in the moderation queue alongside submissions, photos, reviews, and comments. Dedicated claims review page retired. Claim detail panel shows verification status, uploaded documents, and relationship to entity. Approve/deny triggers email notifications, audit trail, and sets claimed_by on the content record.

Features

Claims Integrated into Moderation Queue

Business, event, and location claims now appear directly in the moderation queue alongside submissions, photos, reviews, and comments. Dedicated claims review page retired. Claim detail panel shows verification status, uploaded documents, and relationship to entity. Approve/deny triggers email notifications, audit trail, and sets claimed_by on the content record.

Features

Author Page + Dashboard Tools

New BGC Staff author page with mesh gradient hero, searchable articles grid, and rewritten voice copy. Dashboard owner tools section added. Business scores page shows coming-soon state. Tab renamed from My Business to My Listings.

Features

Author Page + Dashboard Tools

New BGC Staff author page with mesh gradient hero, searchable articles grid, and rewritten voice copy. Dashboard owner tools section added. Business scores page shows coming-soon state. Tab renamed from My Business to My Listings.

·

Events Sidebar Stats Fix

Events sidebar stat counts and filter badges now use server-reported totals instead of counting the current page slice, fixing inaccurate numbers on paginated results.

·

Events Sidebar Stats Fix

Events sidebar stat counts and filter badges now use server-reported totals instead of counting the current page slice, fixing inaccurate numbers on paginated results.

·

Nested Link Accessibility Fix

Fixed nested anchor tag violations across article cards, event cards, and directory cards. Interactive elements inside links now use button/span wrappers to prevent hydration errors and improve screen reader navigation.

·

Nested Link Accessibility Fix

Fixed nested anchor tag violations across article cards, event cards, and directory cards. Interactive elements inside links now use button/span wrappers to prevent hydration errors and improve screen reader navigation.

·

Moderation Pages Polish

Replaced browser alert/confirm dialogs with toast notifications across appeals, auto-mod rules, and scheduled actions pages. Raw fetch calls upgraded to safeFetch for consistent error handling. Filter dropdowns replaced with styled button-based filters matching the queue toolbar pattern. Delete confirmation uses inline buttons instead of browser confirm dialog.

·

Moderation Pages Polish

Replaced browser alert/confirm dialogs with toast notifications across appeals, auto-mod rules, and scheduled actions pages. Raw fetch calls upgraded to safeFetch for consistent error handling. Filter dropdowns replaced with styled button-based filters matching the queue toolbar pattern. Delete confirmation uses inline buttons instead of browser confirm dialog.

·

Moderation Queue History + Status Filters

Moderation queue now shows approved, rejected, and revision-needed items via status tabs. Filter counts pull from server-side totals. Game-industry icon set (react-icons/gi) replaces Heroicons across queue, detail panel, and toolbar for a distinctive look.

·

Moderation Queue History + Status Filters

Moderation queue now shows approved, rejected, and revision-needed items via status tabs. Filter counts pull from server-side totals. Game-industry icon set (react-icons/gi) replaces Heroicons across queue, detail panel, and toolbar for a distinctive look.

·

Handbook Audit

Fixed article categories, replaced broken/missing featured images, corrected geolocation coordinates for state-specific articles, and set news as the default handbook landing category.

·

Handbook Audit

Fixed article categories, replaced broken/missing featured images, corrected geolocation coordinates for state-specific articles, and set news as the default handbook landing category.

·

User Submissions Edit + Appeal

Users can now edit pending submissions and appeal rejected ones from their dashboard. New edit modal pre-fills submission data, appeal modal captures reason text. Status filters and type filters added to submissions tab. Published entity links now use federation-aware state routes.

·

User Submissions Edit + Appeal

Users can now edit pending submissions and appeal rejected ones from their dashboard. New edit modal pre-fills submission data, appeal modal captures reason text. Status filters and type filters added to submissions tab. Published entity links now use federation-aware state routes.

Features

Moderation Queue Overhaul

Owner moderation queue rebuilt with Zustand state management, extracted components, and keyboard shortcuts. New detail panel with submission preview, submitter context sidebar, photo lightbox, and action modal with reason templates. Bulk actions support approve/reject/needs-revision on multiple items.

Features

Moderation Queue Overhaul

Owner moderation queue rebuilt with Zustand state management, extracted components, and keyboard shortcuts. New detail panel with submission preview, submitter context sidebar, photo lightbox, and action modal with reason templates. Bulk actions support approve/reject/needs-revision on multiple items.

·

Event State Data Cleanup

Corrected 111 events misassigned to Idaho that belonged to Montana, Oregon, and North Carolina. Great Falls, Helena, Missoula, Kalispell events reassigned to MT. 10 duplicate events archived.

·

Event State Data Cleanup

Corrected 111 events misassigned to Idaho that belonged to Montana, Oregon, and North Carolina. Great Falls, Helena, Missoula, Kalispell events reassigned to MT. 10 duplicate events archived.

·

Events Map Shows All Markers

Events page sidebar map and full-screen map view now display all upcoming events for the state, not just the current page of 24. New lightweight /api/events/map-markers endpoint fetches coordinates on demand — zero impact on initial page load payload.

·

Events Map Shows All Markers

Events page sidebar map and full-screen map view now display all upcoming events for the state, not just the current page of 24. New lightweight /api/events/map-markers endpoint fetches coordinates on demand — zero impact on initial page load payload.

·

Static Map API + Contact Card Improvements

New server-side static map API route for generating Mapbox map images. Business, event, and location contact cards updated with consistent layout, improved phone/email formatting, and static map integration.

1c
Improvements7 commits

Events Discipline Hero Images

Replaced 8 discipline carousel hero images with editorially curated Wikipedia lead photos. Eliminated military/DoD image dominance across action pistol, shotgun, precision rifle, 3-gun, cowboy action, gun shows, training, and rimfire categories.

·

Exchange SOLD Listing Overlay

Sold exchange listings now display on the marketplace with a visual SOLD banner overlay instead of being hidden entirely. Buyers can browse completed sales for price research.

4c
·

Business Image Carousel

New image carousel component on business detail pages. Displays multiple business photos with swipe navigation, fullscreen lightbox, and lazy loading. Supports Wikimedia Commons attribution.

1c
·

PWA Support + App Icons

Progressive Web App installable with proper manifest, Apple touch icon, 192px and 512px icons, and SVG favicon. Updated manifest.json with theme colors and display standalone mode.

1c
·

Event Contact Backfill Pipeline

Holy Script #17: extracts contact information (email, phone, website, registration URL) from event descriptions using regex patterns and backfills structured contact fields. Two modes: --extract for analysis and --backfill for applying changes.

3c
·

Enhanced User Hover Cards

Expanded profile hover cards across Campfire, reviews, and social feeds. Shows avatar, join date, post count, badges, and quick-follow action. Consistent hover behavior across all user mentions.

1c
·

Community Members Directory

Public members page at /community/members with search, sorting, and profile previews. New API route with pagination and role-based filtering.

1c
·

Exchange Email Templates

Four transactional email templates for the exchange marketplace: inquiry received, listing expiring, listing published, and listing sold. Matches BGC brand design language with dark headers and warm accent colors.

2c
·

Dynamic Platform Stats

Replaced all hardcoded stat numbers with real-time database queries. Single source of truth via getPlatformStats() service. Footer, homepage, AI chatbot, map page, and exchange SEO pages all render live counts. Homepage metadata rounds to nearest 5K for SEO.

2c
·

Article Image Pipeline Consolidation

Consolidated 4 competing article image scripts into Holy Script #15 (article_images.py). Unified modes: --featured, --sections, --brands, --reformat, --promote, --report. Safety gate prevents overwriting existing featured images without explicit --force.

2c
·

Auto-Create Article Discussion Threads

New cron route automatically creates Campfire discussion threads for handbook articles. Campfire feed default sort changed to newest-first.

1c
Features4 commits

Reddit-Style Campfire Reskin

Complete Campfire forum overhaul: flat card design with read-more collapse, threaded comment nesting, persistent left navigation, top bar with category switching, and handbook article carousel. Replaced category grid, topic filters, and legacy layout components.

·

Footer Mountain Dissolve Transition

Theme-reactive mountain gradient transition between page content and footer. Mountain silhouette adapts to light/dark mode with smooth OKLCH color blending. Events discipline carousel also received major layout improvements.

1c
📋

Platform Changelog

You are here. Public timeline of every major update, derived from 1,776 git commits across 6 months of solo development.

34c
💬
Features34 commits

Matrix-Powered Direct Messaging

Replaced the legacy PostgreSQL message system with Matrix (Synapse) for real-time encrypted DMs between buyers and sellers. Admin provisioning, room creation, typing indicators.

📱

Stripe-Style Mobile Navigation

Full-screen drawer with sliding panels and portal escape. Replaced the old hamburger menu with a production-grade mobile nav system.

34c
🌙

Homepage Dark Mode Redesign

Overhauled the homepage with dark-mode-first design. New hero, handbook feature cards, footer mountain dissolve, and theme-reactive backgrounds.

34c
🔄
Features34 commits

BGC Exchange Launches

Free C2C firearms classifieds. No listing fees, no transaction fees. Teal-tabbed UI with sort dropdowns, trust bar, and growth callouts. Full legal framework with ToS v4.0 and Exchange Rules policy.

🛡️

CrowdSec Security Hardening

Behavioral threat detection with 59 active scenarios parsing Traefik access logs. IP reputation scoring, nftables enforcement, and Cloudflare bouncer integration.

34c
🔗

CLS + Loading Skeleton Overhaul

Server-component loading skeletons, font-display:optional, and layout shift elimination across all pillar pages.

34c

February 2026

10 updates
🔍

SEO Overhaul

Segmented sitemaps, cache headers, slug enrichment, cross-pillar internal linking, structured JSON-LD, and state-aware breadcrumbs. Indexed pages jumped from 20K to 26,771.

155c
🏭

82 National Brand Landing Pages

Sig Sauer, Ruger, Smith & Wesson, Remington, and 78 more. Each with dealer maps, event feeds, and SEO-optimized content.

155c
💳

Helcim Payment Processing

Credit card payments active under MCC 7311. Business subscriptions can now be purchased. Billing dashboard and subscription management.

155c
📊
Features155 commits

BGC Business Grade Scoring

Five-pillar scoring system: Data Completeness, Web Presence, Community Engagement, Verification Status, and Content Quality. Every business gets a letter grade A through F.

5Pillars
🧠

Claude Code Skills Framework

Built 8 autonomous skills for database queries, pipeline runs, sync guards, enrichment, validation, scraper creation, schema migration, and component generation.

155c
📍
Data155 commits

State Validation System

Automatic state correction from ZIP codes via database triggers, Python validators, and TypeScript route guards. Fixed 1,819 misattributed records across all insert paths.

1,819Records Fixed
7Insert Paths Secured
🏷️

3-Tier Name Normalization

Deterministic cleanup, word segmentation for smushed domains, and AI-assisted fixes. 2,358 business names fixed, 37 unlisted, 3,378 chain stores marked.

155c
📅
Data155 commits

58,000+ Events Aggregated

Competitions, classes, shows, and meetups pulled from 96 Python scrapers across national organizations. Backfilled 7,914 event locations via Nominatim reverse geocoding.

58,000Events
7,914Locations Backfilled
🖼️

Handbook Image Pipeline

Replaced stock photo fallbacks with curated Wikimedia Commons images uploaded to S3. 139 unique images across 152 articles. Killed the Pexels/Pixabay pool system.

155c
📸

Brand Product Image Scrapers

Built 13 manufacturer scrapers pulling 2,579 product images from Savage Arms, S&W, Ruger, Glock, and others. ZIP press kits, CDN tricks, and WordPress lazy-load unwrapping.

155c

January 2026

6 updates

Performance Optimization Pass

Structured logger conversion, Sentry cleanup, nixpacks heap tuning, and 15 archived unused UI components. 236 commits this month.

236c
📦

Holy 16 Script Consolidation

Consolidated scattered pipeline scripts into 16 canonical entry points under scripts/core/. Clear names, documented usage, archived duplicates.

236c
🕷️

Aggregator Scraping Network

Built 16 aggregator scrapers: WhereToShoot, SHOT Show, IDPA, CMP, NRA State Associations, GunShowTrader, and more. 16,207 records imported.

236c
🎯
Data236 commits

9,600+ Shooting Ranges Mapped

Interactive Mapbox-powered range finder covering every state. Filter by type, amenities, and distance. Cross-state redirects for SEO.

9,600Ranges
🇺🇸
Milestones236 commits

National Federation Launch

Expanded from Idaho-only to all 50 states plus DC. Every state gets its own directory, events calendar, and range finder with localized content and cultural voice. Version 2.0.0.

24,000Events
51States
93,000Businesses
📊
Data236 commits

9-Tier Firearms Taxonomy

Comprehensive business classification system covering retail, FFLs, ranges, training, hunting services, archery, tactical, organizations, professional services, online communities, airsoft, and specialty niches.

9Tiers
20Categories

December 2025

4 updates
📝

Handbook Article Enhancements

Rich visual hierarchy in article markdown, discipline landing pages, TLDR callouts, and ticker improvements.

125c
📍

Unified Location System

Deduplicated shooting locations, renamed foreign keys, synced schema between businesses and locations. Smart geocoding scripts for batch coordinate resolution.

125c
🤖
Data125 commits

AI Business Enrichment Pipeline

Built a 5-step pipeline using the Anthropic Batch API: discover, validate, scrape, validate again, enrich. 50% cost savings over synchronous calls. The backbone of data quality.

50%Cost Savings
5Pipeline Steps
Data125 commits

Content Enrichment + SEO Generation

AI-generated business descriptions, meta titles, and structured markdown with callouts. Listing quality scoring for directory prioritization.

November 2025

6 updates
🔨

ESLint + Production Hardening

Major ESLint cleanup session, production-ready build config, and GlitchTip error tracking integration. 606 commits this month.

606c
🎯
Milestones606 commits

Public Launch

Boise Gun Club goes live on November 24, 2025. Idaho-focused directory, events calendar, range finder, and handbook. The starting line, not the finish.

12,000Events
800Ranges
20,000Businesses
🤖

Cap.js CAPTCHA Integration

Production CAPTCHA on all forms with dev bypass mode. Blocks bot submissions without third-party dependency.

606c
🏪
Features606 commits

Business Claims + Owner Dashboard

Business owners can claim their listing, manage details, upload photos, and track analytics. Full owner moderation panel.

🗺️
Features606 commits

Mapbox Unified Map System

Consolidated all map components into a single architecture with core, variants, and controls. Geolocation, distance rings, traffic layers, and cluster rendering.

🧪

Playwright E2E Test Suite

Mobile-first end-to-end tests across 6 device profiles. Full user journey coverage for registration, directory, events, and ranges.

606c

October 2025

4 updates
🪙

Brass Economy + Gamification

Daily login rewards, brass earned notifications, and the foundation for community engagement scoring.

537c
📖
Features537 commits

Handbook Wiki System

Encyclopedic firearms reference with infoboxes, sticky table of contents, TLDR callouts, and structured markdown rendering. BBC-style news grid on the dashboard.

🔐

Custom JWT Auth System

Migrated from NextAuth to a custom JWT authentication system. Proper token handling, secure cookie management, and Zustand auth store.

537c
🎨
Improvements537 commits

Design System Overhaul

Massive typography standardization, Tailwind semantic utility migration, and color consolidation. Eliminated 122 unused files, reducing codebase by 31%. 537 commits in one month.

537Commits
122Files Deleted
31%Code Reduction

September 2025

3 updates
🏗️
Improvements83 commits

Architecture Transformation

Consolidated 74 bloated components into a unified design system. CVA button variants, atomic component hierarchy, enterprise animation hooks. 83 commits in 3 weeks.

83Commits
74Components Consolidated
🔧
Features83 commits

Drizzle ORM + Data Pipeline v2

Integrated Drizzle ORM with type-safe schema, TanStack Query for client caching, Zustand stores for filters, and Zod validation. Built the first data pipeline for event ingestion.

🚀
Milestones1 commits

Project Genesis

Fresh codebase initialized. Next.js 15, React 19, Tailwind v4, Drizzle ORM, Zustand, Framer Motion. The foundation for everything that follows.

Boise Gun Club has been in active development since July 31, 2025.
This log is generated from 9,706+ git commits across 11 months of development.