Bump frontend VERSION to 1.0.9 Bump frontend VERSION to 1.0.9

- Update frontend/VERSION from 1.0.8 to 1.0.9 and add
  frontend/public/version.txt
- Write new version to frontend/public/version.txt during deploy
- Serve version.txt via nginx with caching (location /version.txt)
- Dockerfile.prod updated to copy public assets (incl. version.txt) to
  nginx
- Extend static asset rules to include txt files for caching
- Inject a version footer into public HTML pages and load version.txt on
  load
- Load Tailwind CSS via CDN on public pages and remove CSS stylesheet
  link tag
This commit is contained in:
2026-01-15 11:05:30 +01:00
parent 6e45db55ea
commit 4aef139135
15 changed files with 302 additions and 41 deletions

View File

@@ -134,6 +134,7 @@ update_version_file() {
print_header "Updating Version File"
local version_file="./frontend/VERSION"
local version_txt_file="./frontend/public/version.txt"
local current_version=""
# Check if version file exists
@@ -145,6 +146,7 @@ update_version_file() {
# Update version file with new version (strip 'v' prefix if present)
local new_version="${VERSION#v}"
echo "$new_version" > "$version_file"
echo "$new_version" > "$version_txt_file"
print_success "Updated version file to: $new_version"
}

View File

@@ -1,39 +1,11 @@
# Build stage - compile Tailwind CSS
FROM node:20-alpine AS builder
WORKDIR /app
# Copy package files
COPY package.json package-lock.json ./
# Install dependencies
RUN npm ci
# Copy source files
COPY css/ ./css/
COPY tailwind.config.js ./
# Build Tailwind CSS for production
RUN npm run build-css:prod
# Production stage
FROM nginx:alpine
# Copy compiled CSS from builder
COPY --from=builder /app/css/styles.css /app/css/styles.css
# Copy nginx configuration
COPY ./nginx.prod.conf /etc/nginx/nginx.conf
# Copy frontend files
# Copy frontend files (includes version.txt)
COPY ./public /usr/share/nginx/html
# Copy compiled CSS to nginx
COPY --from=builder /app/css/styles.css /usr/share/nginx/html/css/styles.css
# Copy version file
COPY ./VERSION /usr/share/nginx/html/version.txt
# Expose ports
EXPOSE 80 443

View File

@@ -1 +1 @@
1.0.8
1.0.9

View File

@@ -49,11 +49,18 @@ http {
# add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
# Handle static assets with caching
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|txt)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Version file endpoint
location = /version.txt {
access_log off;
expires 1h;
add_header Cache-Control "public, max-age=3600";
}
# Handle API proxy
location /api/ {
proxy_pass http://backend:3000;

View File

@@ -68,12 +68,19 @@ http {
}
# Rate limited static files
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|txt)$ {
limit_req zone=static burst=50 nodelay;
expires 1y;
add_header Cache-Control "public, immutable";
}
# Version file endpoint
location = /version.txt {
access_log off;
expires 1h;
add_header Cache-Control "public, max-age=3600";
}
# Main application routes
location / {
limit_req zone=static burst=10 nodelay;

View File

@@ -8,8 +8,8 @@
name="description"
content="Manage your Magic: The Gathering EDH/Commander decks"
/>
<link rel="stylesheet" href="/css/styles.css" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="h-full" x-data="commanderManager()">
<!-- Navigation Header -->
@@ -511,5 +511,39 @@
<script src="/js/app.js"></script>
<script src="/js/commanders.js"></script>
<script src="/js/footer-loader.js"></script>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-8 mt-12">
<div class="container mx-auto px-4 text-center">
<p class="text-gray-400">
EDH Stats Tracker - Track your Commander games with style
</p>
<p class="text-gray-500 text-sm mt-2">
Built with Fastify, SQLite, and Alpine.js
</p>
<p class="text-gray-600 text-xs mt-3" id="version-footer">
<!-- Version loaded dynamically -->
</p>
</div>
</footer>
<script>
// Load and display version in footer
(async function loadVersion() {
try {
const response = await fetch('/version.txt');
if (response.ok) {
const version = await response.text();
const versionEl = document.getElementById('version-footer');
if (versionEl) {
versionEl.textContent = `v${version.trim()}`;
}
}
} catch (error) {
console.debug('Version file not available');
}
})();
</script>
</body>
</html>

View File

@@ -8,8 +8,8 @@
name="description"
content="Track your Magic: The Gathering EDH/Commander games and statistics"
/>
<link rel="stylesheet" href="/css/styles.css" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="h-full" x-data="app()">
<!-- Navigation Header -->
@@ -406,5 +406,39 @@
<script src="/js/app.js"></script>
<script src="/js/stats-cards-loader.js"></script>
<script src="/js/footer-loader.js"></script>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-8 mt-12">
<div class="container mx-auto px-4 text-center">
<p class="text-gray-400">
EDH Stats Tracker - Track your Commander games with style
</p>
<p class="text-gray-500 text-sm mt-2">
Built with Fastify, SQLite, and Alpine.js
</p>
<p class="text-gray-600 text-xs mt-3" id="version-footer">
<!-- Version loaded dynamically -->
</p>
</div>
</footer>
<script>
// Load and display version in footer
(async function loadVersion() {
try {
const response = await fetch('/version.txt');
if (response.ok) {
const version = await response.text();
const versionEl = document.getElementById('version-footer');
if (versionEl) {
versionEl.textContent = `v${version.trim()}`;
}
}
} catch (error) {
console.debug('Version file not available');
}
})();
</script>
</body>
</html>

View File

@@ -8,8 +8,8 @@
name="description"
content="Log and track your Magic: The Gathering EDH/Commander games"
/>
<link rel="stylesheet" href="/css/styles.css" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="h-full" x-data="gameManager()">
<!-- Navigation Header -->
@@ -349,5 +349,39 @@
></script>
<script src="/js/games.js"></script>
<script src="/js/footer-loader.js"></script>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-8 mt-12">
<div class="container mx-auto px-4 text-center">
<p class="text-gray-400">
EDH Stats Tracker - Track your Commander games with style
</p>
<p class="text-gray-500 text-sm mt-2">
Built with Fastify, SQLite, and Alpine.js
</p>
<p class="text-gray-600 text-xs mt-3" id="version-footer">
<!-- Version loaded dynamically -->
</p>
</div>
</footer>
<script>
// Load and display version in footer
(async function loadVersion() {
try {
const response = await fetch('/version.txt');
if (response.ok) {
const version = await response.text();
const versionEl = document.getElementById('version-footer');
if (versionEl) {
versionEl.textContent = `v${version.trim()}`;
}
}
} catch (error) {
console.debug('Version file not available');
}
})();
</script>
</body>
</html>

View File

@@ -8,8 +8,8 @@
name="description"
content="Track your Magic: The Gathering EDH/Commander games and statistics"
/>
<link rel="stylesheet" href="/css/styles.css" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body
class="h-full flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8"
@@ -75,5 +75,39 @@
Alpine.data('indexApp', indexApp)
})
</script>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-8 mt-12">
<div class="container mx-auto px-4 text-center">
<p class="text-gray-400">
EDH Stats Tracker - Track your Commander games with style
</p>
<p class="text-gray-500 text-sm mt-2">
Built with Fastify, SQLite, and Alpine.js
</p>
<p class="text-gray-600 text-xs mt-3" id="version-footer">
<!-- Version loaded dynamically -->
</p>
</div>
</footer>
<script>
// Load and display version in footer
(async function loadVersion() {
try {
const response = await fetch('/version.txt');
if (response.ok) {
const version = await response.text();
const versionEl = document.getElementById('version-footer');
if (versionEl) {
versionEl.textContent = `v${version.trim()}`;
}
}
} catch (error) {
console.debug('Version file not available');
}
})();
</script>
</body>
</html>

View File

@@ -8,7 +8,7 @@
name="description"
content="Login to track your Magic: The Gathering EDH/Commander games"
/>
<link rel="stylesheet" href="/css/styles.css" />
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body
class="h-full flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8"
@@ -298,5 +298,39 @@
}
}
</script>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-8 mt-12">
<div class="container mx-auto px-4 text-center">
<p class="text-gray-400">
EDH Stats Tracker - Track your Commander games with style
</p>
<p class="text-gray-500 text-sm mt-2">
Built with Fastify, SQLite, and Alpine.js
</p>
<p class="text-gray-600 text-xs mt-3" id="version-footer">
<!-- Version loaded dynamically -->
</p>
</div>
</footer>
<script>
// Load and display version in footer
(async function loadVersion() {
try {
const response = await fetch('/version.txt');
if (response.ok) {
const version = await response.text();
const versionEl = document.getElementById('version-footer');
if (versionEl) {
versionEl.textContent = `v${version.trim()}`;
}
}
} catch (error) {
console.debug('Version file not available');
}
})();
</script>
</body>
</html>

View File

@@ -8,7 +8,7 @@
name="description"
content="Create a new account to track your Magic: The Gathering EDH/Commander games"
/>
<link rel="stylesheet" href="/css/styles.css" />
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body
class="h-full flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8"
@@ -463,5 +463,39 @@
src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"
></script>
<script src="/js/auth.js"></script>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-8 mt-12">
<div class="container mx-auto px-4 text-center">
<p class="text-gray-400">
EDH Stats Tracker - Track your Commander games with style
</p>
<p class="text-gray-500 text-sm mt-2">
Built with Fastify, SQLite, and Alpine.js
</p>
<p class="text-gray-600 text-xs mt-3" id="version-footer">
<!-- Version loaded dynamically -->
</p>
</div>
</footer>
<script>
// Load and display version in footer
(async function loadVersion() {
try {
const response = await fetch('/version.txt');
if (response.ok) {
const version = await response.text();
const versionEl = document.getElementById('version-footer');
if (versionEl) {
versionEl.textContent = `v${version.trim()}`;
}
}
} catch (error) {
console.debug('Version file not available');
}
})();
</script>
</body>
</html>

View File

@@ -8,8 +8,8 @@
name="description"
content="Live round counter for Magic: The Gathering EDH/Commander games"
/>
<link rel="stylesheet" href="/css/styles.css" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="h-full flex flex-col" x-data="roundCounterApp()">
<!-- Navigation Header -->
@@ -217,5 +217,39 @@
></script>
<script src="/js/round-counter.js"></script>
<script src="/js/footer-loader.js"></script>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-8 mt-12">
<div class="container mx-auto px-4 text-center">
<p class="text-gray-400">
EDH Stats Tracker - Track your Commander games with style
</p>
<p class="text-gray-500 text-sm mt-2">
Built with Fastify, SQLite, and Alpine.js
</p>
<p class="text-gray-600 text-xs mt-3" id="version-footer">
<!-- Version loaded dynamically -->
</p>
</div>
</footer>
<script>
// Load and display version in footer
(async function loadVersion() {
try {
const response = await fetch('/version.txt');
if (response.ok) {
const version = await response.text();
const versionEl = document.getElementById('version-footer');
if (versionEl) {
versionEl.textContent = `v${version.trim()}`;
}
}
} catch (error) {
console.debug('Version file not available');
}
})();
</script>
</body>
</html>

View File

@@ -8,9 +8,9 @@
name="description"
content="View detailed statistics for your EDH/Commander games"
/>
<link rel="stylesheet" href="/css/styles.css" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="h-full" x-data="statsManager()">
<!-- Navigation Header -->
@@ -175,5 +175,39 @@
<script src="/js/stats.js"></script>
<script src="/js/stats-cards-loader.js"></script>
<script src="/js/footer-loader.js"></script>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-8 mt-12">
<div class="container mx-auto px-4 text-center">
<p class="text-gray-400">
EDH Stats Tracker - Track your Commander games with style
</p>
<p class="text-gray-500 text-sm mt-2">
Built with Fastify, SQLite, and Alpine.js
</p>
<p class="text-gray-600 text-xs mt-3" id="version-footer">
<!-- Version loaded dynamically -->
</p>
</div>
</footer>
<script>
// Load and display version in footer
(async function loadVersion() {
try {
const response = await fetch('/version.txt');
if (response.ok) {
const version = await response.text();
const versionEl = document.getElementById('version-footer');
if (versionEl) {
versionEl.textContent = `v${version.trim()}`;
}
}
} catch (error) {
console.debug('Version file not available');
}
})();
</script>
</body>
</html>

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EDH Stats - Application Status</title>
<link rel="stylesheet" href="/css/styles.css" />
<script src="https://cdn.tailwindcss.com"></script>
<style>
.status { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
.success { color: #10b981; background: #d4edda; padding: 20px; border-radius: 8px; margin: 10px 0; }

View File

@@ -0,0 +1 @@
1.0.9