From a82eca4ef96c4f347e930553dff8ecf3a54d7c71 Mon Sep 17 00:00:00 2001 From: Stan Runge Date: Sun, 1 Mar 2026 02:22:39 +0100 Subject: [PATCH] add umami and seo tags --- docker-compose.yml | 34 ++++++++++ src/lib/components/Sidebar.svelte | 4 ++ src/routes/(app)/+page.svelte | 13 ++++ src/routes/(app)/leaderboard/+page.svelte | 9 +++ src/routes/(app)/mappools/+page.svelte | 9 +++ src/routes/(app)/mappools/[id]/+page.svelte | 13 ++++ src/routes/(app)/matches/+page.svelte | 9 +++ src/routes/(app)/matches/[id]/+page.svelte | 17 +++++ src/routes/(app)/privacy/+page.svelte | 71 +++++++++++++++++++++ src/routes/(app)/terms/+page.svelte | 64 +++++++++++++++++++ src/routes/+layout.svelte | 17 +++++ src/routes/sitemap.xml/+server.ts | 34 ++++++++++ static/robots.txt | 8 ++- 13 files changed, 300 insertions(+), 2 deletions(-) create mode 100644 src/routes/(app)/privacy/+page.svelte create mode 100644 src/routes/(app)/terms/+page.svelte create mode 100644 src/routes/+layout.svelte create mode 100644 src/routes/sitemap.xml/+server.ts diff --git a/docker-compose.yml b/docker-compose.yml index ac2cdad..f6b1fa9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,5 +42,39 @@ services: retries: 3 start_period: 10s + umami-db: + image: postgres:17 + restart: unless-stopped + environment: + POSTGRES_DB: umami + POSTGRES_USER: umami + POSTGRES_PASSWORD: ${UMAMI_DB_PASSWORD} + volumes: + - umamidata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U umami -d umami"] + interval: 10s + timeout: 5s + retries: 5 + + umami: + image: ghcr.io/umami-software/umami:postgresql-latest + restart: unless-stopped + depends_on: + umami-db: + condition: service_healthy + ports: + - "127.0.0.1:3001:3000" # Proxy via nginx at e.g. analytics.vash.software + environment: + DATABASE_URL: postgresql://umami:${UMAMI_DB_PASSWORD}@umami-db:5432/umami + APP_SECRET: ${UMAMI_APP_SECRET} + healthcheck: + test: ["CMD-SHELL", "wget -q -O /dev/null http://localhost:3000/api/heartbeat || exit 1"] + interval: 15s + timeout: 5s + retries: 5 + start_period: 30s + volumes: pgdata: + umamidata: diff --git a/src/lib/components/Sidebar.svelte b/src/lib/components/Sidebar.svelte index b8c5a7f..3bc2ecd 100644 --- a/src/lib/components/Sidebar.svelte +++ b/src/lib/components/Sidebar.svelte @@ -99,5 +99,9 @@ ⚙ Settings +
+ Terms + Privacy +
diff --git a/src/routes/(app)/+page.svelte b/src/routes/(app)/+page.svelte index 284393f..28e953e 100644 --- a/src/routes/(app)/+page.svelte +++ b/src/routes/(app)/+page.svelte @@ -1,5 +1,6 @@ + + Vash Esports — osu! Tournament Platform + + + + + + + + + + {#if !data.user}
diff --git a/src/routes/(app)/leaderboard/+page.svelte b/src/routes/(app)/leaderboard/+page.svelte index 0925fc4..73bb246 100644 --- a/src/routes/(app)/leaderboard/+page.svelte +++ b/src/routes/(app)/leaderboard/+page.svelte @@ -33,6 +33,15 @@ }; + + Leaderboard — Vash Esports + + + + + + +

Leaderboard

diff --git a/src/routes/(app)/mappools/+page.svelte b/src/routes/(app)/mappools/+page.svelte index d54b111..e91c78f 100644 --- a/src/routes/(app)/mappools/+page.svelte +++ b/src/routes/(app)/mappools/+page.svelte @@ -5,6 +5,15 @@ let creating = $state(false); + + Mappools — Vash Esports + + + + + + +
diff --git a/src/routes/(app)/mappools/[id]/+page.svelte b/src/routes/(app)/mappools/[id]/+page.svelte index a95bbff..cf61217 100644 --- a/src/routes/(app)/mappools/[id]/+page.svelte +++ b/src/routes/(app)/mappools/[id]/+page.svelte @@ -1,6 +1,7 @@ + + {data.pool.name} — Mappool | Vash Esports + + + + + + + + + +
diff --git a/src/routes/(app)/matches/+page.svelte b/src/routes/(app)/matches/+page.svelte index f0383ab..48be0a5 100644 --- a/src/routes/(app)/matches/+page.svelte +++ b/src/routes/(app)/matches/+page.svelte @@ -52,6 +52,15 @@ } + + Matches — Vash Esports + + + + + + +
diff --git a/src/routes/(app)/matches/[id]/+page.svelte b/src/routes/(app)/matches/[id]/+page.svelte index e97a53e..a21ae32 100644 --- a/src/routes/(app)/matches/[id]/+page.svelte +++ b/src/routes/(app)/matches/[id]/+page.svelte @@ -1,6 +1,7 @@ + + {ogTitle} + + + + + + + + + + {#snippet reinviteButton()}
{ diff --git a/src/routes/(app)/privacy/+page.svelte b/src/routes/(app)/privacy/+page.svelte new file mode 100644 index 0000000..d270cb8 --- /dev/null +++ b/src/routes/(app)/privacy/+page.svelte @@ -0,0 +1,71 @@ + + Privacy Policy — Vash Esports + + + +
+

Privacy Policy

+

Last updated: {new Date().getFullYear()}

+ +

1. Information We Collect

+

When you use Vash Esports, we collect:

+
    +
  • + osu! account data — your osu! username, user ID, and profile information + provided via osu! OAuth +
  • +
  • + Tournament data — match results, scores, and team membership you create or + participate in +
  • +
  • + Usage analytics — anonymized page views and interactions via Umami, a + privacy-focused analytics tool. No cookies are used and no personal data is collected. +
  • +
+ +

2. How We Use Your Information

+
    +
  • To provide and operate the Service (tournament management, matchmaking, scoring)
  • +
  • To display your username and profile in matches, leaderboards, and team pages
  • +
  • To communicate with you about your matches via osu! IRC
  • +
  • To improve the Service through aggregated analytics
  • +
+ +

3. Data Sharing

+

+ We do not sell or share your personal data with third parties, except as required by law. + osu! account data is obtained via osu!'s OAuth API and subject to + osu!'s Privacy Policy. +

+ +

4. Data Retention

+

+ Your account and tournament data are retained for as long as your account is active or as needed + to provide the Service. You may request deletion of your data by contacting us. +

+ +

5. Cookies

+

+ We use a single session cookie for authentication. Our analytics (Umami) are cookieless and do + not track you across sites. +

+ +

6. Your Rights (GDPR)

+

If you are in the EU/EEA, you have the right to:

+
    +
  • Access the personal data we hold about you
  • +
  • Request correction or deletion of your data
  • +
  • Object to or restrict processing of your data
  • +
  • Data portability
  • +
+

To exercise these rights, contact us at the address below.

+ +

7. Contact

+

+ For privacy questions or data requests, contact: + + contact@vash.software +

+
diff --git a/src/routes/(app)/terms/+page.svelte b/src/routes/(app)/terms/+page.svelte new file mode 100644 index 0000000..9b3bd23 --- /dev/null +++ b/src/routes/(app)/terms/+page.svelte @@ -0,0 +1,64 @@ + + Terms of Service — Vash Esports + + + +
+

Terms of Service

+

Last updated: {new Date().getFullYear()}

+ +

1. Acceptance of Terms

+

+ By accessing or using Vash Esports ("the Service"), you agree to be bound by these Terms of + Service. If you do not agree, do not use the Service. +

+ +

2. Use of the Service

+

+ Vash Esports is an osu! tournament management platform. You may use the Service only for lawful + purposes and in accordance with these Terms. You agree not to: +

+
    +
  • Use the Service in any way that violates applicable laws or regulations
  • +
  • Attempt to interfere with the proper functioning of the Service
  • +
  • Use the Service to harass, abuse, or harm other users
  • +
  • Attempt to gain unauthorized access to any part of the Service
  • +
+ +

3. Accounts

+

+ Access to the Service requires an osu! account. You are responsible for maintaining the + confidentiality of your account and for all activities that occur under it. +

+ +

4. Intellectual Property

+

+ The Service and its original content are owned by Vash Esports. osu! and related assets are + property of ppy Pty Ltd. Beatmap content belongs to their respective creators. +

+ +

5. Disclaimers

+

+ The Service is provided "as is" without warranties of any kind. We do not guarantee uptime or + uninterrupted access. Use the Service at your own risk. +

+ +

6. Limitation of Liability

+

+ To the fullest extent permitted by law, Vash Esports shall not be liable for any indirect, + incidental, or consequential damages arising from your use of the Service. +

+ +

7. Changes to Terms

+

+ We reserve the right to modify these Terms at any time. Continued use of the Service after + changes constitutes acceptance of the new Terms. +

+ +

8. Contact

+

+ For questions about these Terms, contact us at + + contact@vash.software. +

+
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte new file mode 100644 index 0000000..b19c8bb --- /dev/null +++ b/src/routes/+layout.svelte @@ -0,0 +1,17 @@ + + + + {#if umamiUrl && umamiId} + + + {/if} + + +{@render children()} diff --git a/src/routes/sitemap.xml/+server.ts b/src/routes/sitemap.xml/+server.ts new file mode 100644 index 0000000..822f31c --- /dev/null +++ b/src/routes/sitemap.xml/+server.ts @@ -0,0 +1,34 @@ +import type { RequestHandler } from './$types'; + +const ORIGIN = 'https://esports.vash.software'; + +const pages = [ + { url: '/', priority: '1.0', changefreq: 'daily' }, + { url: '/matches', priority: '0.8', changefreq: 'hourly' }, + { url: '/mappools', priority: '0.7', changefreq: 'daily' }, + { url: '/leaderboard', priority: '0.7', changefreq: 'daily' }, + { url: '/terms', priority: '0.3', changefreq: 'monthly' }, + { url: '/privacy', priority: '0.3', changefreq: 'monthly' } +]; + +export const GET: RequestHandler = () => { + const xml = ` + +${pages + .map( + (p) => ` + ${ORIGIN}${p.url} + ${p.changefreq} + ${p.priority} + ` + ) + .join('\n')} +`; + + return new Response(xml, { + headers: { + 'Content-Type': 'application/xml', + 'Cache-Control': 'max-age=3600' + } + }); +}; diff --git a/static/robots.txt b/static/robots.txt index b6dd667..7a74a78 100644 --- a/static/robots.txt +++ b/static/robots.txt @@ -1,3 +1,7 @@ -# allow crawling everything by default User-agent: * -Disallow: +Disallow: /api/ +Disallow: /admin +Disallow: /demo +Disallow: /settings + +Sitemap: https://esports.vash.software/sitemap.xml