TL;DR: Single-pane view of every indie hacker asset (paste-ready content, products, roadmaps, audit results, revenue, ASC build state) auto-generated from filesystem + APIs. ~600 lines of Flask. Saves 30+ min/day of "what's the state of things" overhead.
The problem: too many silos
By Day 60 of my indie experiment I had:
- 50+ paste-ready dev.to articles in
reports/ - 23+ Substack newsletters
- 6 Gumroad SKUs
- 4 iOS apps with build state in ASC API
- 9 LIVE site pages
- 12 ops scripts
- 30+ commits across week
- 33 LIVE URLs to verify
Looking at all this required: 5 terminal windows, 3 browser tabs, 2 API calls, manual mental aggregation. ~30 min/day "checking state."
So I built a dashboard.
Architecture
Single Flask app, ~600 lines:
dashboard/
├── app.py # Flask routes
├── manifest_scan.py # YAML frontmatter aggregator
├── asc_api.py # Apple ASC JWT helper
├── gumroad_api.py # Gumroad REST client
├── verify_urls.py # HTTP 200 audit
├── revenue_state.py # cross-channel revenue aggregator
├── templates/
│ ├── index.html # 3-pane main view
│ ├── audit.html # URL audit table
│ └── revenue.html # revenue dashboard
└── data/
├── asc_status.json # cached, refreshed hourly
└── audit.json # cached, refreshed daily
The 3-pane main view
┌──────────────────┬──────────────────┬──────────────────┐
│ TODO │ User check items │ Quick run scripts│
│ (pending tasks) │ (manual actions) │ (run via button) │
├──────────────────┼──────────────────┼──────────────────┤
│ [Publish #51-56] │ [✓ Apple email?] │ [▶ daily_brief] │
│ [Reddit post] │ [✓ Gumroad sale?]│ [▶ asc_status] │
│ [B2B outreach] │ [✓ DM reply?] │ [▶ verify_urls] │
└──────────────────┴──────────────────┴──────────────────┘
3 panels, 3 actions. Not a Markdown viewer — it's a control panel.
Key endpoints
@app.route('/api/audit')
def audit_urls():
"""HTTP 200 verifier — runs across all LIVE assets"""
urls = scan_for_live_urls() # finds Gumroad/Substack/dev.to/Site URLs
results = []
for url in urls:
try:
r = requests.head(url, timeout=10, allow_redirects=True)
results.append({'url': url, 'status': r.status_code, 'ok': r.status_code == 200})
except Exception as e:
results.append({'url': url, 'status': 'ERR', 'ok': False, 'error': str(e)[:80]})
ok = sum(1 for r in results if r['ok'])
return jsonify({'total': len(results), 'ok': ok, 'fail': len(results) - ok, 'details': results})
@app.route('/api/revenue')
def revenue():
"""Aggregate revenue across all channels"""
return jsonify({
'gumroad': gumroad_total(),
'asc_iaps': asc_iap_total(),
'b2b_consulting': b2b_revenue_csv(),
'affiliates': affiliate_revenue(),
'total': sum_all(),
})
@app.route('/api/asc-status')
def asc_status():
"""Cached Apple ASC build state — refreshed hourly via cron"""
with open('data/asc_status.json') as f:
return jsonify(json.load(f))
Caching strategy
- Audit cache: 24h TTL (URLs rarely break in 24h)
- ASC build state cache: 1h TTL (build state refreshes via hourly cron)
- Gumroad sales cache: 5 min TTL (real-time enough for indie scale)
- Manifest scan: no cache, scans on every request (fast — 60 files in <100ms)
What this lets you do in 30 sec/morning
- Open dashboard
- Glance at 3 panes
- Click 1 button (e.g. "▶ daily_brief")
- See: "5 Gumroad SKUs LIVE, all 4 apps build VALID, 33/33 URLs OK, 0 stale assets, 1 user action pending: paste Reddit"
You don't need to remember. You don't need to check 5 different places. The dashboard is the truth.
What I'd skip if rebuilding
- Real-time WebSockets for revenue (overkill — polling is fine)
- Per-asset detail pages (just link to the file directly)
- Authentication (it's localhost — useless)
- Service-worker offline support (you'll always have wifi when you check)
What I'd keep:
- 3-pane layout (TODO / user / scripts)
- Frontmatter-driven asset list
- Click-to-run script buttons
- Caching for slow APIs
Source
Full Flask dashboard with all 6 endpoints + 3-pane view + caching:
AutoApp Dashboard ($39) is literally this dashboard. Drop-in for any indie hacker workflow with markdown content + API-aggregated state.
If you spend 30+ min/day "checking state" across silos, you have a dashboard-shaped problem. Cost: 4 hours of dev. Payback: 30 min/day = 4 hours / week.
Top comments (0)