Add PostgreSQL analytics dashboard prototype and realistic sample data
This commit is contained in:
47
mockups/sample_report.py
Normal file
47
mockups/sample_report.py
Normal file
@@ -0,0 +1,47 @@
|
||||
"""Read-only checks and a compact report for the generated sample histories."""
|
||||
import math
|
||||
|
||||
from database import connect
|
||||
|
||||
|
||||
def report():
|
||||
with connect() as conn:
|
||||
for game in conn.execute("SELECT id,name FROM games WHERE properties->>'sampleVersion'='2' ORDER BY id").fetchall():
|
||||
gid=game['id']
|
||||
summary=conn.execute('''WITH counts AS(SELECT player_id,count(*) n FROM sessions WHERE game_id=%s GROUP BY player_id)
|
||||
SELECT count(*) players,100.0*count(*) FILTER(WHERE n=1)/count(*) one_session FROM counts''',(gid,)).fetchone()
|
||||
minutes=conn.execute('SELECT avg(extract(epoch FROM ended_at-started_at))/60 minutes FROM sessions WHERE game_id=%s',(gid,)).fetchone()['minutes']
|
||||
returns=[]
|
||||
for day in [1,7,30]:
|
||||
row=conn.execute('''SELECT 100.0*count(*) FILTER(WHERE EXISTS(SELECT 1 FROM sessions s
|
||||
WHERE s.game_id=p.game_id AND s.player_id=p.id AND (s.started_at AT TIME ZONE 'UTC')::date=(p.first_seen AT TIME ZONE 'UTC')::date+%s)) / nullif(count(*),0) rate
|
||||
FROM players p WHERE p.game_id=%s AND (p.first_seen AT TIME ZONE 'UTC')::date+%s<current_date''',(day,gid,day)).fetchone()
|
||||
returns.append(float(row['rate']))
|
||||
spending=conn.execute('''SELECT player_id,sum(unit_price_robux*quantity) total FROM product_sales
|
||||
WHERE game_id=%s AND unit_price_robux>0 GROUP BY player_id ORDER BY total DESC''',(gid,)).fetchall()
|
||||
total=sum(r['total'] for r in spending)
|
||||
top_share=100*sum(r['total'] for r in spending[:max(1,math.ceil(len(spending)*.01))])/total
|
||||
bad_sales=conn.execute('''SELECT count(*) n FROM product_sales p JOIN sessions s ON s.game_id=p.game_id AND s.id=p.session_id
|
||||
WHERE p.game_id=%s AND (p.purchased_at<s.started_at OR p.purchased_at>s.ended_at)''',(gid,)).fetchone()['n']
|
||||
overlaps=conn.execute('''WITH ordered AS(SELECT started_at,lag(ended_at) OVER(PARTITION BY player_id ORDER BY started_at) previous_end
|
||||
FROM sessions WHERE game_id=%s) SELECT count(*) n FROM ordered WHERE started_at<previous_end''',(gid,)).fetchone()['n']
|
||||
bad_balances=conn.execute('''SELECT count(*) n FROM player_snapshots WHERE game_id=%s AND data ? 'cash'
|
||||
AND (data->>'cash')::numeric<>(data->>'cashEarned')::numeric-(data->>'cashSpent')::numeric''',(gid,)).fetchone()['n']
|
||||
bad_snapshots=conn.execute('''SELECT count(*) n FROM player_statistics WHERE game_id=%s AND latest_data IS NOT NULL
|
||||
AND ((latest_data->>'robux')::numeric<>robux_recorded OR (latest_data->>'purchases')::numeric<>products_bought)''',(gid,)).fetchone()['n']
|
||||
assert returns[0]>returns[1]>returns[2], (game,returns)
|
||||
assert 3<float(minutes)<30, (game,minutes)
|
||||
assert summary['one_session']>50, (game,summary)
|
||||
assert len(spending)<summary['players']*.1, (game,len(spending))
|
||||
assert top_share>10, (game,top_share)
|
||||
assert bad_sales==0, (game,bad_sales)
|
||||
assert overlaps==0, (game,overlaps)
|
||||
assert bad_balances==0, (game,bad_balances)
|
||||
assert bad_snapshots==0, (game,bad_snapshots)
|
||||
print(f"{game['name']}: {summary['players']:,} players | one session {summary['one_session']:.1f}% | average session {minutes:.1f} min")
|
||||
print(f" D1/D7/D30: {' / '.join(f'{r:.2f}%' for r in returns)} | payers {len(spending):,} ({100*len(spending)/summary['players']:.1f}%) | top 1% payer revenue share {top_share:.1f}%")
|
||||
print('Sample distribution and timeline checks passed.')
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
report()
|
||||
Reference in New Issue
Block a user