Change to static skin catalog population

This commit is contained in:
bob
2026-05-29 18:36:17 -05:00
parent 6f3c0175cd
commit b51f1d9f5f
26 changed files with 3063 additions and 370 deletions

37
db/02_readonly_role.sql Normal file
View File

@@ -0,0 +1,37 @@
-- ============================================================
-- CS2 Skin Tracker — read-only reporting/BI role
-- Run as a superuser (e.g. postgres) OR as skintracker_app,
-- connected to the skintracker database. Safe to re-run.
--
-- Replace the password placeholder before running.
-- This role can SELECT every table in the skintracker schema
-- (existing and future) and nothing else: no INSERT/UPDATE/
-- DELETE, no DDL, no access to other schemas.
-- ============================================================
-- 1. Login role, guarded so the script is idempotent.
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'skintracker_readonly') THEN
CREATE ROLE skintracker_readonly WITH LOGIN PASSWORD 'change-me-readonly-password';
END IF;
END
$$;
-- 2. Allow the role to connect to the database and resolve names
-- in the skintracker schema by default.
GRANT CONNECT ON DATABASE skintracker TO skintracker_readonly;
GRANT USAGE ON SCHEMA skintracker TO skintracker_readonly;
ALTER ROLE skintracker_readonly SET search_path = skintracker;
-- 3. Read access to every existing table/view in the schema.
GRANT SELECT ON ALL TABLES IN SCHEMA skintracker TO skintracker_readonly;
-- 4. Read access to tables the app role creates LATER (e.g. new
-- migrations). Without this, future tables would not be visible.
-- Must name the role that OWNS new objects — that is skintracker_app.
ALTER DEFAULT PRIVILEGES FOR ROLE skintracker_app IN SCHEMA skintracker
GRANT SELECT ON TABLES TO skintracker_readonly;
-- 5. Belt-and-braces: ensure the role can never write to public either.
REVOKE CREATE ON SCHEMA public FROM skintracker_readonly;

82
db/03_catalog_audit.sql Normal file
View File

@@ -0,0 +1,82 @@
-- ============================================================
-- CS2 Skin Tracker — catalog audit (read-only)
-- Run against the skintracker database as any role with SELECT
-- (e.g. skintracker_readonly). Pure SELECTs, safe to re-run.
--
-- Purpose: sanity-check the weapon/glove skin catalog for the
-- gaps that break tradeup math and pricing joins.
-- ============================================================
SET search_path = skintracker;
-- 1. Totals — quick scale check.
SELECT 'skins' AS table, count(*) FROM skins
UNION ALL SELECT 'weapons', count(*) FROM weapons
UNION ALL SELECT 'collections', count(*) FROM collections
UNION ALL SELECT 'skin_collections', count(*) FROM skin_collections
UNION ALL SELECT 'skin_conditions', count(*) FROM skin_conditions;
-- 2. Orphan skins: belong to NO collection/container.
-- Expected: only "Howl" (Contraband, removed from its collection).
SELECT s.id, s.slug, s.name, s.rarity
FROM skins s
LEFT JOIN skin_collections sc ON sc.skins_id = s.id
WHERE sc.skins_id IS NULL
ORDER BY s.name;
-- 3. Missing float bounds.
-- Expected: only Vanilla (default) knives, which have no wear range.
SELECT s.id, s.slug, s.name, s.float_min, s.float_max
FROM skins s
WHERE s.float_min IS NULL OR s.float_max IS NULL
ORDER BY s.name;
-- 4. Rarity hygiene: any nulls/blanks, and the distribution.
SELECT coalesce(nullif(rarity, ''), '<empty/null>') AS rarity, count(*)
FROM skins
GROUP BY 1
ORDER BY 2 DESC;
-- 5. Inverted or out-of-range float bounds (should return 0 rows).
SELECT id, slug, name, float_min, float_max
FROM skins
WHERE float_min > float_max OR float_min < 0 OR float_max > 1;
-- 6. Duplicate slugs (unique index should keep this empty).
SELECT slug, count(*)
FROM skins
GROUP BY slug
HAVING count(*) > 1;
-- 7. Collection type split (expect only Collection / Container).
SELECT coalesce(type, '<null>') AS type, count(*)
FROM collections
GROUP BY 1
ORDER BY 2 DESC;
-- 8. Skins with no weapon link (should return 0 rows).
SELECT s.id, s.slug
FROM skins s
LEFT JOIN weapons w ON w.id = s.weapon_id
WHERE w.id IS NULL;
-- 9. Skin count per weapon type — confirms only weapon/glove items.
-- Note: Zeus x27 (type "Equipment") skins ARE valid catalog/tradeup items.
SELECT w.type, count(s.id) AS skins
FROM weapons w
LEFT JOIN skins s ON s.weapon_id = w.id
GROUP BY w.type
ORDER BY skins DESC;
-- 10. StatTrak / Souvenir availability.
SELECT
sum(CASE WHEN stat_trak_available THEN 1 ELSE 0 END) AS stattrak,
sum(CASE WHEN souvenir_available THEN 1 ELSE 0 END) AS souvenir,
count(*) AS total
FROM skins;
-- 11. true_float split (capped range vs full 0.01.0; null = unknown bounds).
SELECT coalesce(true_float::text, '<null>') AS true_float, count(*)
FROM skins
GROUP BY 1
ORDER BY 2 DESC;