Both compute per-group aggregates; the difference is what survives. GROUP BY answers 'one line per shop'; a window answers 'each repair, with its shop's average next to it' — comparisons like mins - AVG(mins) OVER (…) are only possible in the second shape. The mirror failures: needing row-level detail after a GROUP BY (it's gone), or SUMming a windowed aggregate as if it were grouped (it repeats per row).
SELECT shop, AVG(mins) AS avg_mins FROM repairs GROUP BY shop ORDER BY shop;
SELECT shop, mins, mins - AVG(mins) OVER ( PARTITION BY shop ) AS vs_avg FROM repairs ORDER BY shop, mins;
GROUP BY collapsed the repairs to one row per shop, so the per-repair detail was gone — a window PARTITION keeps every repair with its shop's average attached.
GROUP BY for one-row-per-group outputs; a window for row-plus-context; never aggregate a window's output without re-grouping deliberately.