diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index ea3b49e..c3efb8a 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -82,6 +82,15 @@ jobs: - name: Frontend build run: | set -euo pipefail + base_version="$(node -p "require('./package.json').version")" + run_number="${GITHUB_RUN_NUMBER:-${GITEA_RUN_NUMBER:-0}}" + if [ "$run_number" != "0" ]; then + export VITE_BUILD_VERSION="${base_version}+build.${run_number}" + else + export VITE_BUILD_VERSION="${base_version}+local" + fi + export VITE_BUILD_DATE="$(date -u +%Y-%m-%d)" + echo "Building frontend version ${VITE_BUILD_VERSION}" npm ci npm run build working-directory: frontend @@ -109,8 +118,18 @@ jobs: id: meta run: | set -euo pipefail + version="$(node -p "require('./frontend/package.json').version")" + run_number="${GITHUB_RUN_NUMBER:-${GITEA_RUN_NUMBER:-0}}" + if [ "$run_number" != "0" ]; then + build_version="${version}+build.${run_number}" + else + build_version="${version}+local" + fi echo "sha=$(git rev-parse HEAD)" >> "$GITEA_OUTPUT" echo "short_sha=$(git rev-parse --short HEAD)" >> "$GITEA_OUTPUT" + echo "version=$version" >> "$GITEA_OUTPUT" + echo "build_version=$build_version" >> "$GITEA_OUTPUT" + echo "Deploying version ${build_version}" git log -1 --oneline - name: Verify production host layout @@ -140,6 +159,22 @@ jobs: chown -R "$dest_owner" /dest ' + - name: Write frontend build metadata + run: | + set -euo pipefail + build_date="$(date -u +%Y-%m-%d)" + docker run --rm \ + -e BUILD_VERSION="${{ steps.meta.outputs.build_version }}" \ + -e BUILD_DATE="${build_date}" \ + -v "${DEPLOY_APP_PATH}:/app" \ + alpine:latest \ + sh -lc ' + test -d /app/frontend + printf "VITE_BUILD_VERSION=%s\nVITE_BUILD_DATE=%s\n" "$BUILD_VERSION" "$BUILD_DATE" > /app/frontend/.env.production + echo "Frontend build metadata:" + cat /app/frontend/.env.production + ' + - name: Build Docker images run: | set -euo pipefail @@ -244,9 +279,11 @@ jobs: css_asset="$(printf "%s" "$index" | grep -Eo '/assets/index-[^"]+\.css' | head -n 1)" test -n "$js_asset" test -n "$css_asset" - curl -fsS --max-time 20 "${LIVE_URL}${js_asset}" >/dev/null + js_body="$(curl -fsS --max-time 20 "${LIVE_URL}${js_asset}")" + printf "%s" "$js_body" | grep -Fq "${{ steps.meta.outputs.build_version }}" curl -fsS --max-time 20 "${LIVE_URL}${css_asset}" >/dev/null echo "Frontend assets served: ${js_asset}, ${css_asset}" + echo "Frontend version verified: ${{ steps.meta.outputs.build_version }}" - name: Show production containers if: always() diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a2266f4..d9cc2fd 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "frontend", - "version": "0.0.0", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "frontend", - "version": "0.0.0", + "version": "0.1.0", "dependencies": { "@lucide/vue": "^1.20.0", "@primeuix/themes": "^2.0.3", diff --git a/frontend/package.json b/frontend/package.json index c46cb59..0b90d77 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "frontend", "private": true, - "version": "0.0.0", + "version": "0.1.0", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/components/admin/AdminReleaseNotesCard.vue b/frontend/src/components/admin/AdminReleaseNotesCard.vue new file mode 100644 index 0000000..cbbc0fc --- /dev/null +++ b/frontend/src/components/admin/AdminReleaseNotesCard.vue @@ -0,0 +1,157 @@ + + + diff --git a/frontend/src/lib/releaseNotes.ts b/frontend/src/lib/releaseNotes.ts new file mode 100644 index 0000000..ec4e010 --- /dev/null +++ b/frontend/src/lib/releaseNotes.ts @@ -0,0 +1,88 @@ +export type ReleaseChangeType = 'major' | 'feature' | 'fix' + +export interface ReleaseNoteItem { + type: ReleaseChangeType + title: string + description: string +} + +export interface VersionRule { + pattern: string + label: string + description: string +} + +export const semanticVersion = '0.1.0' +export const buildVersion = import.meta.env.VITE_BUILD_VERSION?.trim() || semanticVersion +export const buildDateLabel = import.meta.env.VITE_BUILD_DATE?.trim() || '26.06.2026' + +export const versionRules: VersionRule[] = [ + { + pattern: 'x.0.0', + label: 'Major Changes', + description: 'Grosse Umbauten, Breaking Changes oder Releases, die sich wie ein neues Kapitel anfuehlen.', + }, + { + pattern: '0.x.0', + label: 'Neue Features', + description: 'Neue Funktionen, groessere UI-Flows oder sichtbare Produktverbesserungen.', + }, + { + pattern: '0.0.x', + label: 'Minor & Bugfixes', + description: 'Kleine Verbesserungen, Bugfixes, Copy-Polish und unkritische Feinschliffe.', + }, +] + +export const releaseNotes: ReleaseNoteItem[] = [ + { + type: 'feature', + title: 'Twitch Login ist live', + description: 'Login und Account-Verknuepfung laufen jetzt ueber den offiziellen Twitch OAuth Flow.', + }, + { + type: 'feature', + title: 'Team-Accounts koennen Twitch verbinden', + description: 'Teammitglieder koennen ihren Account mit Twitch verknuepfen, wieder loesen und danach sauber ueber Twitch einsteigen.', + }, + { + type: 'feature', + title: 'Team-Status aktualisiert sich automatisch', + description: 'In der Teamverwaltung siehst du regelmaessig, wer online ist. Die Ansicht aktualisiert sich alle 30 Sekunden.', + }, + { + type: 'feature', + title: 'Moderation ist schneller bedienbar', + description: 'Reviewed Nominierungen und Risiko-Queues lassen sich angenehmer mit Pfeiltasten und Tastatur bedienen.', + }, + { + type: 'feature', + title: 'Admin-Bereiche wurden aufgeraeumt', + description: 'Jahre, Landingpage, Risiko, Team und Analytics sind kompakter, klarer gruppiert und weniger erschlagend.', + }, + { + type: 'feature', + title: 'User-Profil wurde repariert und ueberarbeitet', + description: 'Das Profil ist wieder ein echter Teil des Flows, inklusive Twitch-Verknuepfung und sauberem Account-Status.', + }, + { + type: 'feature', + title: 'Besseres Feedback beim Bearbeiten', + description: 'Buttons haben Animationen, Speichern/Bearbeiten gibt sichtbarere Rueckmeldung und Modals fuehlen sich stabiler an.', + }, + { + type: 'fix', + title: 'Dropdowns sehen wieder korrekt aus', + description: 'Das Dropdown-Design wurde stabilisiert und passt nun besser zum restlichen Admin-UI.', + }, + { + type: 'fix', + title: 'Backend, Auth und Sicherheit wurden gehaertet', + description: 'Sessions, Team-Rechte, Audit-Logs, Public Writes, Vote-Eindeutigkeit und Runtime-Settings wurden robuster gemacht.', + }, + { + type: 'fix', + title: 'Datenbank- und Deploy-Sicherheit verbessert', + description: 'Healthchecks, Migrationen, Seed-Verhalten und produktionsnahe Konfiguration sind klarer sichtbar und weniger fehleranfaellig.', + }, +] diff --git a/frontend/src/views/admin/AdminSettingsView.vue b/frontend/src/views/admin/AdminSettingsView.vue index ea783df..c09caac 100644 --- a/frontend/src/views/admin/AdminSettingsView.vue +++ b/frontend/src/views/admin/AdminSettingsView.vue @@ -5,6 +5,7 @@ import { onBeforeRouteLeave } from 'vue-router' import AdminOperationalSettingsCard from '../../components/admin/AdminOperationalSettingsCard.vue' import AdminPageHeader from '../../components/admin/AdminPageHeader.vue' +import AdminReleaseNotesCard from '../../components/admin/AdminReleaseNotesCard.vue' import AdminSeasonToolbar from '../../components/admin/AdminSeasonToolbar.vue' import AdminSettingsDatabaseCard from '../../components/admin/AdminSettingsDatabaseCard.vue' import AdminSettingsOverviewBoard from '../../components/admin/AdminSettingsOverviewBoard.vue' @@ -90,6 +91,8 @@ onBeforeUnmount(() => window.removeEventListener('beforeunload', handleBeforeUnl :content-completion="contentCompletion" /> + +