117 Commits

Author SHA1 Message Date
aa5ca7ff31 Add keyboard event listeners to close Terms of Service modal
Some checks failed
Build and Publish Docker Images / Build and Push Docker Images (push) Failing after 17s
2026-04-14 07:50:41 +02:00
08cdf1a795 Update version.txt 2026-04-14 07:35:45 +02:00
6a6411accd Update version to 2.4.2 and refine input styles
Bump version to 2.4.2.

Adjust date input appearance and positioning.
Tighten spacing on dashboard stats cards.
Update footer padding.
2026-04-14 07:28:38 +02:00
e541b10f3f feat: implement pagination and query filter for commanders list
Some checks failed
Build and Publish Docker Images / Build and Push Docker Images (push) Failing after 2m15s
2026-04-13 09:19:31 +02:00
f5b0caf194 Add Terms of Service modal to registration flow
Add a modal with EDH Stats Tracker's Terms of Service and Privacy
Policy. The modal is triggered by a link next to the "I agree" checkbox.
It includes an "I Agree" button to validate acceptance and a close
button. The modal is dismissed on click outside or via the dedicated
buttons, ensuring a seamless user experience for new registrations.
2026-04-12 20:49:45 +02:00
fc309738f4 chore: bump version to 2.3.6 and improve profile form validation
Bump version to 2.3.6 in package.json files.

Enhance password validation regex to provide specific error messages for
lowercase, uppercase, and numeric requirements instead of generic
messages.

Add a delete confirmation modal to the profile page with a button that
disables if the user has typed a different username, preventing
accidental
2026-04-12 16:19:47 +02:00
983d9b1597 Add archived state for commanders across all layers (#3)
* Add archived state for commanders across all layers

* Add `tick` import and smooth scrollIntoView to commander and game edit
flows

Replace `setTimeout` with `await tick()` when scrolling forms into view.
Update `startEdit` functions in `/commanders` and `/games` to use the
new `tick` import. Replace hardcoded 100ms timeout with `tick` and
ensure `bind:this` is applied to form elements before scrolling.

* Add `tick` import and smooth scrollIntoView to commander and game edit
flows

Replace `setTimeout` with `await tick()` when scrolling forms into view.
Update `startEdit` functions in `/commanders` and `/games` to use the
new `tick` import. Replace hardcoded 100ms timeout with `tick` and
ensure `bind:this` is applied to form elements before scrolling.

* Add cache control headers for version.txt and handle HTML files
explicitly

* Refactor buttons to use icon-button component

Update Start/Stop/Reset controls to use the new `icon-button` class.
Replace text-only buttons with a consistent pattern of SVG icon followed
by a `<span>` label. Add corresponding CSS rules for `.icon-button`
and `.btn-icon` to ensure proper spacing and sizing.

* feat: change reset button icon and bump version

- Update reset button SVG to a circular arrow icon
- Decrease reset icon size to 1.15rem
- Bump version to 2.3.2 in static file

* Add support for displaying archived commanders count
Bump application version to 2.3.3
Refine round counter button disabled state and styling

* Add color icon assets and update version number

feat: Add color icon assets (W, U, B, R, G, C) and increment version to
2.3.4

* Add color icon assets and update version number

feat: Add color icon assets (W, U, B, R, G, C) and increment version to
2.3.4

* Update color assets from SVG to PNG and refresh image files

Replace all `.svg` color icons (W, U, B, R, G, C) with corresponding
`.png` files. Add new asset `timer.png` and `commanders.png`. Remove
`round_timer.png`, `stats.png`, and `logs.png`. Replace `logs.png` with
an updated version. Bump version number from 2.3.4 to 2.3.5.

* Update commander profile card styling and replace placeholder icons

```
Update commander profile card styling and replace placeholder icons

- Revert white background and padding for the main container
- Increase icon chip dimensions to 90% width and height
- Remove border and inset shadow from color chip icons
- Replace generic SVG placeholders (B, C, G, R, U, W) with new designs
  ```

* Update footer to remove version prefix and add commander images
2026-04-12 15:37:17 +02:00
de1eb635d6 Bump package versions to 2.2.5 2026-04-11 20:24:49 +02:00
76b8cb3199 feat: Complete SvelteKit frontend migration and update deployment
checklists

SVELTE_MIGRATION.md --- Text
1 # Svelte Migration Progress
2
3 ## 🎉 MIGRATION COMPLETE!
4
5 All pages have been successfully migrated from Alpine.js to SvelteKit!
The application is fully functional, tested, and ready for deployment.
6
7 **Final Build Status**:  Production build successful (tested on
2026-04-10)
8
9 ##  Completed
10
11 ### 1. Project Setup
12 -  Installed SvelteKit and dependencies (@sveltejs/kit,
@sveltejs/adapter
2026-04-11 20:17:29 +02:00
4822e03ab4 Migrate frontend from Alpine.js to SvelteKit and update documentation
Migrated the frontend from Alpine.js to SvelteKit with shared UI stores.
Updated the project structure to use SvelteKit primitives for routing,
state management, and form handling. Added a new round counter component
and updated the project root to use a single Dockerfile. Updated
dependencies including Alpine.js, Vite, and SvelteKit. Refined CSS and
configuration files for the new frontend stack.
2026-04-11 20:12:45 +02:00
2c0cd01ab2 Update version to 2.2.0 and migrate to session-based cookies
*   Bump backend package version to `2.2.0` in `package.json` and
    `package-lock.json`.
*   Replace local storage token management with secure HTTP-only
    cookies.
    *   Added cookie options to `@fastify/cookie` plugin configuration
        in `server.js` (request-time parsing, strict same-site,
        production enforcement).
    *   Updated `auth.js` routes to use `reply.setCookie` and
        `reply.clearCookie` instead of manual token handling.
    *   Added `request.headers.authorization` pre-handling hook to
        inject cookie tokens into the Authorization header for route
        handlers.
*   Updated `frontend/src/lib/stores/auth.js`:
    *   Switched token storage logic to rely solely on cookies via the
        browser (`credentials: 'include'`).
    *   Removed `localStroage` and `sessionStor`ge usage for the auth
        token.
    *   Refactored login/register flow to call `markAuthenticated()`
        immediately upon success.
    *   Updated logout to clear the backend cookie via
        `/api/auth/logout` and reset store state.
    *   Modified `checkRegistrationConfig` and other store methods to
        handle state updates correctly without local storage
        persistence.
*   Removed `localStroage` and `sessionStor`ge references from the
    frontend register page UI and validation logic.
    Update version to 2.2.0 and migrate to session-based cookies

Replace JWT token storage with HTTP-only session cookies in the backend.
Add `/session` endpoint to verify cookie-based authentication and remove
reliance on localStorage for client-side token management. Update
frontend auth store to handle cookies via `credentials: include` and
refresh tokens on 401 errors.
2026-04-11 20:08:29 +02:00
24510001b5 Refactor Commander card layout and delete dialog
- Convert `label` element to `p` tag with `text-sm` class
- Restructure color identity section from single flex to multi-column
  grid
- Add `tabindex="-1"` to dialog overlay for proper keyboard focus
  management
- Add `on:keydown` handler to dialog overlay to prevent default key
  actions
- Improve delete dialog spacing and typography
2026-04-11 19:13:35 +02:00
e3c421a52e Refactor pagination logic in game list and bump version
</think>

Refactor pagination logic in game list and bump version
2026-04-11 13:20:38 +02:00
4310d9a1c4 Update publish.yml 2026-04-11 13:01:58 +02:00
20baba9a5f Update GitHub Actions delete-packag-versions workflow
Change the package-name input from referencing environment variables
directly to using env.PR and env.PROJECT_NAME references for the backend
and frontend workflows.
2026-04-11 12:56:06 +02:00
81ea4244af Update publish.yml 2026-04-11 12:53:57 +02:00
5ca10f3b0e Fix typo in build and push frontend job name
Update context and Dockerfile path for frontend builds
2026-04-11 12:51:52 +02:00
b84ac04396 Update version to 2.2.3 and refactor commander data loading
- Fetch and map statistics for each commander in /api/stats/commanders
- Merge commander lists with their corresponding stats using commanderId
- Remove unnecessary text diff artifacts from static version file
2026-04-11 11:47:34 +02:00
def4ddabb7 Update publish.yml 2026-04-11 10:51:17 +02:00
d69a14d80b Migrate frontend to SvelteKit with comprehensive deployment (#2)
* Migrate frontend to SvelteKit with comprehensive deployment
documentation

- Create new SvelteKit project structure with routing, stores, and
  components
- Implement complete authentication system with auth store and protected
  routes
- Build all application pages: Home, Login, Register, Dashboard, Games,
  Stats, Commanders, Profile, and Round Counter
- Configure Vite, TailwindCSS, PostCSS, and Nginx for production
  deployment
- Add Dockerfile.svelte for containerized builds with multi-stage
  optimization
- Create comprehensive SVELTE_DEPLOYMENT.md and SVELTE_MIGRATION.md
  guides
- Update deployment scripts and package dependencies for SvelteKit
  ecosystem

* feat: Add user authentication and game tracking pages to EDH Stats
Tracker

* Migrate frontend to SvelteKit and update Docker configuration

- Replace Alpine.js with SvelteKit for improved DX and hot module
  replacement
- Switch frontend service to `Dockerfile.dev` with volume mounts and
  Vite dev server
- Update `docker-compose.yml` to map ports 5173 and use
  `http://localhost:5173` for CORS
- Add `Dockerfile.svelte` for production static builds
- Configure Vite proxy to target `http://backend:3000` in containers and
  `localhost:3002` locally
- Migrate existing components to new routes and update authentication
  store logic
- Add Chart.js integration to stats page and handle field name mapping
  for forms
- Include static assets (`fonts/Beleren-Bold.ttf`) and update deployment
  scripts
- Document migration status, testing checklist, and known minor issues
  in guides

* Refactor frontend state properties from snake_case to camelCase

This commit standardizes frontend property access across Dashboard,
Games, and Stats pages.
Changes include:
- Renaming API data fields (e.g., `commanderName`, `playerCount`,
  `winRate`).
- Updating `startEdit` logic to normalize mixed snake_case/camelCase
  inputs.
- Replacing template literals like `_player_won` with camelCase
  versions.
- Consistent usage of `totalGames` and `wins` instead of snake_case
  variants.

* Update version to 2.1.12 and refactor commander management

- Upgrade application version to 2.1.12
- Add Footer component and include in all pages
- Refactor `/commanders` page to fetch commanders and stats separately
- Fix commander API endpoint to load all commanders instead of only
  those with stats
- Add stats merging logic to calculate wins, win rate, and avg rounds
- Split add/edit command logic into shared `loadCommanders` function
- Fix color toggle logic to work with both new and editing command modes
- Update API methods for update requests to send `PUT` for existing
  commanders
- Enhance commander delete functionality with proper API response
  handling
- Refactor dashboard and stats pages to reuse shared data loading logic
- Add chart cleanup on destroy for both dashboard and stats pages
- Implement Chart.js for Win Rate by Color and Player Count charts
- Reorganize round counter component state and timer functions
- Add localStorage persistence for round counter with pause/resume
  support
- Update game log page to integrate footer component

* Refactor auth store and backend to use stable user ID

*   Backend: Switch user lookup from username to ID in auth routes to
    maintain stability across username changes.
*   Frontend: Update user store to reflect ID-based updates.
*   UI: Refactor user menu Svelte component to use ID-based user data.
*   Profile: Switch profile page to use ID-based user data for
    validation and state management.

* format date formatting options consistently across dashboard and games
pages

* format date formatting options consistently across dashboard and games
pages

* Refactor card action buttons to use icons with semantic text

- Switch "Edit" and "Delete" button text to SVG icons in `commanders`
  and `games` pages
- Update icon colors and font styles to match standard design tokens
  (indigo/red, bold text)
- Improve responsive spacing by adding `lg:grid-cols-3`

* grids
- Clarify hover states and titles for better UX accessibility
  Bump application versions to 2.2.0 and update deployment configuration

* Convert `+page.svelte` to use template strings for multiline strings and
fix syntax errors.

* Update static version to 2.2.2 and tighten nginx cache headers
2026-04-11 10:42:46 +02:00
2b69a07cf6 Update deploy.sh 2026-04-10 13:58:34 +02:00
fe9adb97fa Change cache lifetime for JS files to 1 day
- Update `nginx.prod.conf` to reduce JS file expiration from 1 year to 1
  day
- Clear `edh-round-counter-state` from `localStorage` on game load
- Bump version from 2.1.10 to 2.1.12
2026-04-10 12:31:24 +02:00
58def0c006 Filter zero-win entries and apply pastel palette 2026-02-22 22:02:51 +01:00
b1e6f9a561 Bump version to 2.1.8 in backend and frontend 2026-01-23 10:19:51 +01:00
a2b9827279 Fix security vulnerability: validate auth tokens with backend
SECURITY FIX:
- Removed unsafe client-side only token check
- Added server-side token validation via /api/auth/me endpoint
- Prevents tokens spoofed in localStorage from granting access
- Only redirects if token is verified as valid by backend

How it works:
- When user visits login/register page with token in storage
- auth-check.js makes API call to /api/auth/me with token
- Backend JWT middleware verifies token signature and expiration
- If valid, user is redirected to dashboard
- If invalid/expired, token is cleared and user stays on login page
- If network error, user stays on login page (no redirect)
2026-01-23 09:45:34 +01:00
0a95fe95b6 Add auth redirect for logged-in users on login/register pages
- Check for authentication token on page load
- If user is already logged in, redirect to dashboard
- Prevents logged-in users from seeing login/register forms
- Applies to both login.html and register.html
2026-01-23 09:43:59 +01:00
6f0f156bd3 Update dashboard nav and bump version
- Add Round timer to header and sidebar navigation
- Replace Dashboard with Commanders and include Round timer
- Remove Quick Actions from dashboard
- Bump version to 2.1.4
2026-01-23 08:35:51 +01:00
06c9ff6ed6 fix: add continue-on-error to image cleanup steps
- Image cleanup steps will now continue on error instead of failing the workflow
- This handles the case where packages don't exist yet or aren't found
- Keeps workflow from breaking on first cleanup attempt
- Maintains proper YAML formatting and indentation
2026-01-20 15:47:18 +01:00
b7ebd7cf23 Clean up old container images in publish workflow 2026-01-20 15:45:13 +01:00
6f4e5996aa Bump versions; add 404 page; enable TOS modal 2026-01-20 14:55:51 +01:00
87a86c55fc Format logs, bump version, update Traefik config
- Reformat logging calls in server.js for readability
- Bump API version from 1.0.0 to 2.1.2
- Update Traefik labels; switch TLS certresolver to
  letsencrypt-cloudflare
2026-01-20 14:55:51 +01:00
df8495a9b5 Format logs, bump version, update Traefik config
- Reformat logging calls in server.js for readability
- Bump API version from 1.0.0 to 2.1.2
- Update Traefik labels; switch TLS certresolver to
  letsencrypt-cloudflare
2026-01-19 19:29:37 +01:00
1fdc55afa1 Add max user registration limit
- Parse MAX_USERS from env in registrationConfig
- Count total users with new UserRepository.countUsers()
- Enforce registration cap in the signup flow
- Expose MAX_USERS in docker-compose and env example
- Bump frontend version to 2.1.2
2026-01-18 16:42:42 +01:00
5e3b71a015 Load env vars, update seeds, tweak frontend 2026-01-18 16:15:39 +01:00
3c25450972 Improve API pagination and seed compatibility 2026-01-18 15:56:11 +01:00
779dfd173c Refactor change-password and add delete account
- Harden /change-password with JWT guard and per-hour rate limit
- Validate current and new passwords, and update password on success
- Replace previous password-change flow with a streamlined
  delete-account path
- Implement /me DELETE to permanently remove user data and respond with
  success
- Add frontend delete account flow: profile.js handles deletion, modal
  UI, and token-based API call
- Extend profile.html with a Danger Zone and a Delete Account modal
- Update register.html: link to Terms of Service now points to /tos.html
  and opens in a new tab
2026-01-18 15:29:10 +01:00
23cfde1f78 Enforce parameter validation and pagination in API 2026-01-18 14:46:54 +01:00
6d2345bee7 Expand game query filters and update UI assets
- Backend: extend filters with dateFrom/dateTo, won, roundsMin/Max and
  colors; implement color identity using jsonb and order by date with
  limit/offset.
- Frontend: adjust slideshow spacing in index.html and include new
  images; bump version to 2.0.5.
2026-01-18 14:23:21 +01:00
cc4ecd0ce1 Expand game query filters and update UI assets
- Backend: extend filters with dateFrom/dateTo, won, roundsMin/Max and
  colors; implement color identity using jsonb and order by date with
  limit/offset.
- Frontend: adjust slideshow spacing in index.html and include new
  images; bump version to 2.0.5.
2026-01-18 14:07:44 +01:00
bb0fb42631 refactor: improve slideshow layout and navigation
- Added padding to top and bottom of image container (pt-12 pb-12)
- Removed 'Slide X of 4' counter text
- Moved Previous/Next buttons to left/right sides of image as arrow icons
- Arrow buttons have hover effects (gray background)
- Play/Pause button repositioned to top-right corner
- Dot indicators remain at the bottom
- Used SVG arrows for cleaner, more professional look
- Improved spacing and visual hierarchy
- Better responsive design on all screen sizes
2026-01-18 13:53:23 +01:00
3caab40653 fix: remove non-existent preview.png from slideshow
- Slideshow was trying to load preview.png which doesn't exist
- Removed duplicate/missing image reference
- Now slideshow displays only 4 actual images:
  1. Commanders management
  2. Game logging
  3. Round timer
  4. Statistics
- Fixes first and last slide being the same
- All images now exist and display correctly
2026-01-18 13:49:16 +01:00
956d64f642 feat: add automatic slideshow gallery to landing page
- Created slideshow component with 5 feature images
- Auto-scrolls through images every 3 seconds
- Manual controls: Previous, Play/Pause, Next buttons
- Dot indicators for quick navigation between slides
- Smooth fade transitions between slides
- Shows slide counter (e.g., '1 of 5')
- Images featured:
  1. Dashboard with KPI cards
  2. Commander management interface
  3. Game logging form
  4. Round timer functionality
  5. Statistics and analytics
- Responsive design works on all screen sizes
- Includes descriptive alt text for accessibility
2026-01-18 13:47:07 +01:00
e38d0e36a9 feat: add dashboard preview image to landing page
- Added preview.png screenshot showing dashboard features
- Displays KPI cards (Total Games, Win Rate, Active Decks, Avg Rounds)
- Shows Recent Games and Top Commanders sections
- Includes action buttons (Start Round Counter, Log Game, View
  Statistics)
- Added descriptive text explaining the dashboard functionality
- Updated tech stack mention (SQLite -> PostgreSQL)
- Improved landing page with visual example of the application
2026-01-18 13:41:12 +01:00
de829d4b06 Update docker-compose volumes and remove init-db
- Bump frontend version from 2.0.2 to 2.0.4
- Add scripts:ro and backups volumes in deployment and compose
- Remove backend/init-db mount from docker-compose
2026-01-18 13:09:56 +01:00
4986c4f6b8 feat: add complete password requirements to registration form
- Display all 5 backend password validation requirements
- Added: minimum 8 characters (existing)
- Added: maximum 100 characters
- Added: at least one lowercase letter
- Added: at least one uppercase letter
- Added: at least one number
- Each requirement shows real-time validation with green checkmark
- Requirements match exactly with backend/src/utils/validators.js

feat: add Traefik labels to frontend container

- Enable Traefik auto-discovery for frontend service
- Configure HTTP routing with Host rule
- Setup both web (HTTP) and websecure (HTTPS) entrypoints
- Configure load balancer backend port (80)
- Include optional TLS/Let's Encrypt configuration
- Change edh.example.com to your actual domain

feat: configure production compose file to use Traefik network

- Generated docker-compose.prod.deployed.yml now uses traefik-network
- Frontend service joined to both edh-stats-network and traefik-network
- Added Traefik labels for routing and TLS configuration
- traefik-network configured as external (must be created by Traefik)
- Removed external ports from frontend (Traefik handles routing)
- Updated setup instructions to mention Traefik prerequisites
- Changed TLS to enabled by default in production

refactor: remove frontend port exposure and Traefik labels from dev compose

- Removed port 8081 exposure from development docker-compose.yml
- Removed Traefik labels from development environment
- Development compose now simple and focused on local testing
- Production compose (via deploy.sh) handles Traefik routing via DNS
- Frontend only accessible through backend API in development
- Cleaner separation: dev is simple, prod uses Traefik

Switch Postgres data to host path and bump version Update Traefik rule,
expose port, bump version

feat: add database migration script for PostgreSQL

- Created migrate-database.sh script for exporting/importing databases
- Supports source and target database configuration via CLI options
- Validates connections before migration
- Verifies data integrity after import (table and row counts)
- Can skip import and just export to file for manual restore
- Supports Docker Compose container names
- Includes comprehensive error handling and user prompts
- Added DATABASE_MIGRATION.md documentation with usage examples
- Handles common scenarios: dev→prod, backups, restore
- Security considerations for password handling

refactor: simplify migration script to run directly in PostgreSQL container

- Removed network/remote host configuration (no longer needed)
- Script now runs inside PostgreSQL container with docker compose exec
- Simplified to use only source-db, target-db, output-file, skip-import options
- No external dependencies - uses container's pg_dump and psql
- Much simpler usage: docker compose exec postgres /scripts/migrate-database.sh
- Updated documentation with container-based examples
- Added real-world integration examples (daily backups, deployments, recovery)
- Includes troubleshooting and access patterns for backup files

feat: mount scripts directory into PostgreSQL container

- Added ./scripts:/scripts:ro volume mount to postgres service
- Makes migrate-database.sh and other scripts accessible inside container
- Read-only mount for security (scripts can't be modified inside container)
- Allows running: docker compose exec postgres /scripts/migrate-database.sh
- Scripts are shared between host and container for easy access

docs: clarify that migration script must run as postgres user

- Added -u postgres flag to all docker compose exec commands
- Explains why postgres user is required (PostgreSQL role authentication)
- Created shell alias for convenience
- Updated all scenarios and examples
- Updated troubleshooting section
- Clarifies connection issues related to user authentication

feat: save database backups to host by default

- Added ./backups volume mount to postgres container
- Changed default backup location from /tmp to /backups
- /backups is mounted to ./backups on host for easy access
- Script automatically creates /backups directory if needed
- Updated help and examples with -u postgres flag
- Summary now shows both container and host backup paths
- Backups are immediately available on host machine
- No need for docker cp to retrieve backups

feat: add --skip-export flag for import-only database operations

- Allows importing from existing backup files without re-exporting
- Added validate_backup_file() function to check backup existence
- Updated main() to handle import-only mode with proper validation
- Updated summary output to show import-only mode details
- Updated help text with import-only example
- Prevents using both --skip-import and --skip-export together

docs: update database migration guide for import-only mode

- Document new --skip-export flag for import-only operations
- Add example for quick restore from backup without re-export
- Update command options table with mode combinations
- Update all scenarios and examples to use /backups mount
- Clarify file location and volume mounting (./backups on host)
- Add Scenario 5 for quick restore from backup
- Simplify examples and fix container paths

feat: clear existing data before importing in migration script

- Added clear_database() function to drop all tables, views, and sequences
- Drops and recreates public schema with proper permissions
- Ensures clean import without data conflicts
- Updated warning message to clarify data deletion
- clear_database() called before import starts
- Maintains database integrity and grants

docs: update migration guide to explain data clearing on import

- Clarify that existing data is deleted before import
- Explain the drop/recreate schema process
- Add notes to scenarios about data clearing
- Document the import process sequence
- Update version to 2.2

fix: remove verbose flag from pg_dump to prevent SQL syntax errors

- Removed -v flag from pg_dump export command
- Verbose output was being included in SQL file as comments
- These comments caused 'syntax error at or near pg_dump' errors during import
- Backup files will now be clean SQL without pg_dump metadata comments

docs: document pg_dump verbose output fix and troubleshooting

- Added troubleshooting section for pg_dump syntax errors
- Noted that v2.3 fixes this issue
- Directed users to create new backups if needed
- Updated version to 2.3
- Clarified file location is /backups/

docs: add critical warning about using migration script for imports

- Added prominent warning against using psql directly with -f flag
- Explained why direct psql causes 'relation already exists' errors
- Added troubleshooting section for these errors
- Emphasized that script handles data clearing automatically
- Clear examples of wrong vs right approach

fix: remove pg_dump restrict commands that block data import

- Added clean_backup_file() function to remove \restrict and \unrestrict
- pg_dump adds these security commands which prevent data loading
- Script now automatically cleans backup files before importing
- Removes lines starting with \restrict or \unrestrict
- Ensures all data (users, games, commanders) imports successfully
- Called automatically during import process

docs: add troubleshooting for pg_dump restrict commands blocking imports

- Document the \restrict and \unrestrict security commands issue
- Explain why they block data from being imported
- Show that migration script v2.4+ removes them automatically
- Update version to 2.4
- Add detailed troubleshooting section for empty imports
2026-01-18 13:09:53 +01:00
e7d6c67c39 fix: show specific validation error messages instead of generic 'Invalid input data'
- Backend now returns first validation error message in 'message' field
- Both POST and PUT commander endpoints updated
- Frontend fallback to handle either message or details array format
- Users now see 'Select at least one color' instead of generic error
- Improved error response consistency across all validation errors
2026-01-17 21:29:10 +01:00
1a81a6d191 fix: correct indentation in deploy.sh docker-compose generation
- Fixed docker-compose.prod.deployed.yml YAML indentation
- postgres service now uses consistent 2-space indents
- db-migrate, backend, and frontend services properly aligned as siblings
- All healthcheck, deploy, and networks sections correctly indented
- Fixed comment indentation in file header
- Fixed print_summary() function echo statement indentation
2026-01-17 21:22:19 +01:00
1956a09560 fix: add error message display to edit commander modal
- Added error display section to edit modal form
- Ensures validation errors are visible when updating commander
- Matches error display styling of add commander form
- JavaScript error parsing already in place for validation details
2026-01-17 21:19:27 +01:00
b7306a963a Migration from SQlite3 to PostgreSQL (#1)
* Migrate from SQLite to PostgreSQL for dev and prod environments

- Replace better-sqlite3 with pg library in backend
- Update database.js to use PostgreSQL connection pooling
- Convert migrations.sql to PostgreSQL syntax with proper triggers and constraints
- Convert seeds.sql to PostgreSQL syntax with JSONB for colors and ON CONFLICT handling
- Update docker-compose.yml with PostgreSQL service and db-migrate container
- Update deploy.sh to generate production docker-compose with PostgreSQL configuration
- Configure environment variables for database connection (DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD)

* Update database models to use PostgreSQL async API

- Convert User.js from better-sqlite3 to PostgreSQL async queries
  - Use parameterized queries with ,  placeholders
  - Update all methods to use async/await
  - Use result.rowCount instead of result.changes
  - Use result.rows[0].id for RETURNING clause results

- Convert Commander.js from better-sqlite3 to PostgreSQL async queries
  - Implement proper async methods with pg library
  - Update JSONB color handling (no longer needs JSON.parse/stringify)
  - Use ILIKE for case-insensitive search instead of LIKE
  - Use proper numeric casting for win rate calculations

- Convert Game.js from better-sqlite3 to PostgreSQL async queries
  - All query methods now properly async
  - Update boolean handling (true/false instead of 1/0)
  - Use ILIKE for case-insensitive commander name search
  - Use RETURNING clause instead of lastInsertRowid

All models now use dbManager.query(), dbManager.get(), and dbManager.all() methods

* Add PostgreSQL cleanup and repository pattern for improved DB abstraction

Database Improvements:
- Fix migrate.js to use async PostgreSQL API with proper error handling
- Update .env.example to reflect PostgreSQL configuration variables
- Update GitHub Actions workflow to generate production docker-compose with PostgreSQL

Architectural Improvements:
- Create base Repository class providing common CRUD operations
- Implement UserRepository for user-specific database operations
- Implement CommanderRepository for commander-specific database operations
- Implement GameRepository for game-specific database operations
- All repositories use parameterized queries to prevent SQL injection
- Centralized database access patterns for better maintainability

Benefits:
- Cleaner separation of concerns (repositories handle data access)
- Reusable repository pattern can be extended for new entities
- Better error handling and transaction support
- Improved code organization and maintainability
- All database queries now properly handle PostgreSQL async operations

* Add comprehensive PostgreSQL migration documentation

- Complete migration summary with before/after comparison
- Detailed changes to each component
- Architecture improvements and benefits
- Repository pattern explanation
- Quick start guide for development and production
- Deployment instructions
- Testing guidelines
- Verification checklist

* Fix Docker build: update package-lock.json and npm syntax

- Run npm install to update package-lock.json with pg dependencies
- Replace deprecated --only=production with --omit=dev (npm 7+)
- Resolves Docker build error about missing pg packages in lock file

* Add migration status document

- Executive summary of completed migration
- Detailed commits history with verification
- Architecture before/after comparison
- Deployment instructions (dev & prod)
- Testing procedures
- Performance characteristics
- Troubleshooting guide
- Rollback instructions (if needed)
- Final sign-off for production readiness

* Add comprehensive deployment checklist

- Pre-deployment verification checklist
- Development deployment step-by-step guide
- Production deployment procedures
- Rollback instructions for emergency cases
- Monitoring and maintenance procedures
- Common issues and solutions
- Performance monitoring commands
- Sign-off checklist for deployment readiness

* Fix PostgreSQL user authentication in docker-compose

- Use postgres superuser instead of creating custom user
- Add init-db script directory for database initialization
- Update docker-compose to mount init scripts
- Simplify credentials: use 'postgres' user for dev
- Update .env.example with correct default credentials
- Health check now uses postgres user

This resolves the 'role edh_user does not exist' error on container startup.
The postgres superuser can create and manage databases and migrations.

* Add Docker Compose testing guide

- Prerequisites checklist
- Step-by-step startup instructions
- Service verification procedures
- API and database testing commands
- Frontend verification steps
- Troubleshooting guide for common issues
- Cleanup procedures
- Expected results checklist

* Fix PostgreSQL password authentication - use correct default user

- Remove incorrect POSTGRES_USER setting (defaults to postgres)
- Set POSTGRES_PASSWORD=edh_password for the default postgres user
- Set POSTGRES_DB=edh_stats to create database automatically
- Update db-migrate and backend services to use password: edh_password
- Update .env.example with correct credentials

PostgreSQL Docker image automatically creates the 'postgres' superuser
when POSTGRES_PASSWORD is set. This resolves the authentication error.

* Add final verification document for completed migration

- Complete migration status verification
- All issues resolved checklist
- Final commit log with all 10 commits
- Quick start command for docker-compose
- Development credentials reference
- Complete list of deliverables
- Documentation index
- Ready-to-deploy status confirmation

* Fix PostgreSQL initialization and SQL migration execution

- Fix 01-init.sql: Remove invalid MySQL syntax and rely on POSTGRES_DB for database creation
- Fix database.js: Execute entire migration/seed SQL files as single queries instead of splitting by semicolon
  This prevents issues with multi-statement SQL constructs (functions, views, triggers)
- Fix docker-compose.yml: Add listen_addresses=* to allow connections from Docker network containers
  and add PGPASSWORD to healthcheck for proper password authentication

All services now start successfully:
- PostgreSQL accepts connections from Docker network
- Migrations run without errors
- Seed data is properly inserted
- Backend API starts and health checks pass
- Database schema with tables, views, and triggers created correctly

* Fix production docker-compose configuration in deploy.sh

- Add listen_addresses=* to PostgreSQL command for Docker network connectivity
- Use 'postgres' superuser instead of DB_USER variable (matches development setup)
- Fix PostgreSQL healthcheck to include PGPASSWORD environment variable
- Fix frontend healthcheck to check root path instead of non-existent /health endpoint
- Add resource limits to frontend container for consistency
- Update .env documentation to reflect correct PostgreSQL user

* Fix DB_USER configuration consistency

- Change default DB_USER in database.js from 'edh_user' to 'postgres'
- Aligns with .env.example, docker-compose.yml, and deploy.sh
- Add clarifying comment in .env.example explaining superuser requirement
- DB_USER must be a superuser to run migrations and create schema objects

The PostgreSQL superuser 'postgres' is created automatically by the Docker image
and has the necessary privileges for all application operations.

* Add DB_SEED environment variable to toggle automatic seeding

- Add DB_SEED environment variable to db-migrate service (default: false)
- Update migrate.js to check DB_SEED and automatically seed if enabled
- Fix seeds.sql ON CONFLICT clauses and sequence resets to use dynamic MAX(id)
- Seeds can now be triggered by setting DB_SEED=true in docker-compose or .env
- Add documentation to .env.example explaining DB_SEED option
- Update deploy.sh to support DB_SEED in production configuration

This allows developers to quickly populate test data during development
without manual seeding commands, while keeping it opt-in for clean databases.

* Fix Commander model: properly convert colors array to JSON for JSONB storage

- Convert JavaScript arrays to JSON strings before inserting into JSONB column
- Add ::jsonb type cast in SQL queries for explicit JSONB conversion
- Handle both array and string inputs in create() and update() methods
- Fixes 'invalid input syntax for type json' error when creating/updating commanders

The pg library doesn't automatically convert JS arrays to JSON, so we must
stringify them before passing to PostgreSQL. The ::jsonb cast ensures proper
type conversion in the database.

* Fix JSON parsing in routes: PostgreSQL JSONB is already parsed

PostgreSQL's pg library automatically parses JSONB columns into JavaScript objects.
The routes were incorrectly calling JSON.parse() on already-parsed JSONB data,
which would fail or cause errors.

Fixed in:
- backend/src/routes/commanders.js (3 occurrences)
- backend/src/routes/games.js (3 occurrences)
- backend/src/routes/stats.js (1 occurrence)

Changed from: JSON.parse(colors) or JSON.parse(commander_colors)
Changed to: colors || [] or commander_colors || []

This matches how the models already handle JSONB data correctly.

* Fix seeds.sql: correct bcrypt hash for password123

The previous bcrypt hash was incorrect and did not match 'password123'.
Generated the correct hash using bcryptjs with 12 rounds.

Correct credentials for seeded test users:
  - Username: testuser
    Password: password123

  - Username: magictg
    Password: password123

This allows developers to login to the application with seeded data.

* Fix stats routes: convert from SQLite to PostgreSQL async methods

- Replace db.prepare().get() with await dbManager.get()
- Replace db.prepare().all() with await dbManager.all()
- Update parameterized query placeholders from ? to $1, $2, etc
- Change boolean comparisons from 'won = 1' to 'won = TRUE' for PostgreSQL
- Remove unnecessary db.initialize() calls
- Both /api/stats/overview and /api/stats/commanders now working correctly

* Fix games routes: remove SQLite boolean conversions and unnecessary JSON parsing

- Remove boolean-to-integer conversion (was converting true/false to 1/0)
- Remove JSON.parse() on JSONB colors column (PostgreSQL pg driver already parses JSONB)
- Fix in both POST create response and PUT update response
- Colors array now correctly returned as already-parsed JavaScript array
- Boolean fields now correctly returned as native boolean type

* Fix frontend: remove JSON.parse() on colors from API responses

- colors field is now pre-parsed array from PostgreSQL JSONB
- Simplified stats.html line 124: remove JSON.parse(stat.colors)
- Simplified dashboard.html line 279: remove defensive type checking for colors
- Frontend now properly handles colors as JavaScript arrays

* Simplify: remove defensive type checking for commanderColors in
dashboard

- game.commanderColors is always an array from PostgreSQL JSONB
- Changed from complex ternary to simple: game.commanderColors || []

* feat: improve environment variable handling in docker-compose and .env.example

- Add RATE_LIMIT_WINDOW and RATE_LIMIT_MAX to .env.example (commented for now)
- Update docker-compose.yml to use environment variables with defaults
  - All DB_* variables now use default format
  - NODE_ENV, JWT_SECRET, CORS_ORIGIN, LOG_LEVEL, ALLOW_REGISTRATION now respect env vars
  - DB_SEED now uses environment variable
- Improves flexibility for development, testing, and production deployments
- Maintains backward compatibility with defaults
- Reduces hardcoded values and increases configurability

* fix: use DB_PASSWORD environment variable in postgres healthcheck

- PGPASSWORD in healthcheck was hardcoded to 'edh_password'
- Changed to use ${DB_PASSWORD:-edh_password} for consistency
- Ensures healthcheck respects DB_PASSWORD environment variable
- Fixes issue where custom DB_PASSWORD would cause healthcheck to fail

* fix: make PostgreSQL external port configurable via DB_PORT

- Changed postgres port mapping from hardcoded '5432:5432' to '${DB_PORT:-5432}:5432'
- Allows users to expose PostgreSQL on different external port via DB_PORT env variable
- Internal container port remains 5432 (unchanged)
- Enables non-standard port usage in constrained environments
- Maintains backward compatibility with default of 5432

* fix: update production docker-compose template in deploy.sh for environment variables

Changes to generated docker-compose.prod.deployed.yml:

Postgres Service:
- Added configurable external port: ${DB_PORT:-5432}:5432
- Ensures port mapping respects DB_PORT environment variable

DB-Migrate Service:
- DB_HOST: postgres -> ${DB_HOST:-postgres}
- DB_PORT: 5432 -> ${DB_PORT:-5432}
- DB_USER: postgres -> ${DB_USER:-postgres}
- Maintains configuration consistency with development

Backend Service:
- DB_HOST: postgres -> ${DB_HOST:-postgres}
- DB_PORT: 5432 -> ${DB_PORT:-5432}
- DB_USER: postgres -> ${DB_USER:-postgres}
- LOG_LEVEL: warn -> ${LOG_LEVEL:-warn}
- Removed hardcoded RATE_LIMIT_* variables (not used yet)
- All variables now properly parameterized

Documentation:
- Updated .env example to include DB_USER, LOG_LEVEL, DB_SEED
- Better guidance for production deployment

Ensures production deployments have same flexibility as development

* fix: update GitHub Actions workflow for PostgreSQL and environment variables

Postgres Service:
- POSTGRES_USER: edh_user -> postgres (matches .env.example and deploy.sh)
- POSTGRES_PASSWORD: change-this-in-production -> edh_password (matches .env.example)
- Added ports configuration: ${DB_PORT:-5432}:5432 (allows external access)
- Fixed healthcheck to use PGPASSWORD and proper variable syntax

DB-Migrate Service:
- DB_HOST: postgres -> ${DB_HOST:-postgres}
- DB_PORT: 5432 -> ${DB_PORT:-5432}
- DB_USER: edh_user -> postgres
- DB_PASSWORD: change-this-in-production -> edh_password
- Added DB_SEED=${DB_SEED:-false}

Backend Service:
- DB_HOST: postgres -> ${DB_HOST:-postgres}
- DB_PORT: 5432 -> ${DB_PORT:-5432}
- DB_USER: edh_user -> postgres
- DB_PASSWORD: change-this-in-production -> edh_password
- JWT_SECRET: removed unsafe default (must be provided)
- LOG_LEVEL: warn -> ${LOG_LEVEL:-warn}

Ensures GitHub Actions workflow is consistent with:
- docker-compose.yml (development)
- deploy.sh (production script)
- .env.example (configuration template)

* feat: implement global rate limiting and request/response logging

- Added rateLimitConfig to jwt.js with configurable window (minutes) and max requests
- Integrated global rate limiting into server.js using RATE_LIMIT_WINDOW and RATE_LIMIT_MAX env vars
- Default: 100 requests per 15 minutes (overridable via environment)
- Added request/response logging hooks for debugging (logged at debug level)
- Logs include method, URL, IP, status code, and duration
- Updated .env.example to document rate limiting configuration

* docs: update README for PostgreSQL migration and new features

- Updated intro to mention PostgreSQL instead of SQLite
- Added rate limiting and request logging features to infrastructure
  section
- Updated Technology Stack to reflect PostgreSQL and rate-limiting
- Revised environment variables section with PostgreSQL config
- Added Custom Environment Variables section with examples
- Expanded Database section with PostgreSQL-specific details
- Added Tips & Common Operations for PostgreSQL management
- Updated Recent Changes to document Session 3 migration work
- Updated Development Notes for async database operations
- Added JSONB field documentation

* security: remove exposed PostgreSQL port from docker-compose

PostgreSQL no longer needs to be exposed to the host since:
- Backend container accesses postgres via internal Docker network
- DB_PORT=5432 is only for internal container connections, not port mapping
- Removes unnecessary attack surface in production

Changes:
- Removed 'ports:' section from postgres service in docker-compose.yml
- Removed port mapping from production deploy.sh template
- Clarified DB_PORT usage in .env.example (internal only)
- Added DB_USER to .env.example with explanation

Security Impact:
- PostgreSQL only accessible within Docker network
- Reduced container exposure to host network
- More secure production deployments

Tested:
- All services start successfully
- Backend connects to postgres via internal network
- Login works, database queries successful
- Frontend accessible on 8081, Backend on 3002

* refactor: remove hardcoded DB_PORT, use PostgreSQL standard port 5432

Simplified database configuration by removing configurable DB_PORT since
PostgreSQL always runs on standard port 5432:

Changes:
- Updated backend/src/config/database.js to hardcode port 5432
- Removed DB_PORT from all docker-compose services
- Removed DB_PORT from production deploy.sh template
- Updated .env.example with clearer documentation
- Clarified that port 5432 is not configurable

Benefits:
- Simpler configuration (fewer environment variables)
- Standard PostgreSQL port is expected behavior
- Reduced configuration surface area
- Still flexible: can adjust DB_HOST for different database servers

Tested:
- All services start successfully
- Database connections work via internal Docker network
- User authentication functional
- API endpoints respond correctly

* docs: update README to reflect DB_PORT removal and configuration simplification

Updated documentation to reflect latest changes:
- Removed DB_PORT from environment variables section (port 5432 is standard)
- Added note that PostgreSQL port is not configurable
- Clarified connection details (port 5432 is standard, not configurable)
- Updated project structure: postgres_data instead of database
- Added deployment script to project structure
- Updated Recent Changes section with configuration simplification details
- Added DB_SEED documentation to environment variables
- Improved clarity on which settings are configurable vs. standard

Emphasizes the security and simplicity improvements from removing
unnecessary port configuration.

* Remove migration docs and init scripts

* refactor: migrate routes from models to repositories

Replaced all data access layer calls in routes from Model classes to Repository classes.

Changes:
- auth.js: Now uses UserRepository instead of User model
  * User.create() → UserRepository.createUser()
  * User.findByUsername() → UserRepository.findByUsername()
  * User.findById() → UserRepository.findById()
  * User.verifyPassword() → UserRepository.verifyPassword()
  * User.updatePassword() → UserRepository.updatePassword()
  * User.updateUsername() → UserRepository.updateUsername()
  * User.updateProfile() → UserRepository.updateProfile()

- commanders.js: Now uses CommanderRepository instead of Commander model
  * Commander.create() → CommanderRepository.createCommander()
  * Commander.findByUserId() → CommanderRepository.getCommandersByUserId()
  * Commander.search() → CommanderRepository.searchCommandersByName()
  * Commander.findById() → CommanderRepository.findById()
  * Commander.update() → CommanderRepository.updateCommander()
  * Commander.delete() → CommanderRepository.deleteCommander()
  * Commander.getStats() → CommanderRepository.getCommanderStats()
  * Commander.getPopular() → CommanderRepository.getPopularCommandersByUserId()

- games.js: Now uses GameRepository instead of Game model
  * Game.findByUserId() → GameRepository.getGamesByUserId()
  * Game.findById() → GameRepository.getGameById()
  * Game.create() → GameRepository.createGame()
  * Game.update() → GameRepository.updateGame()
  * Game.delete() → GameRepository.deleteGame()
  * Game.exportByUserId() → GameRepository.exportGamesByUserId()

Benefits:
 Clean separation of concerns (routes vs data access)
 Better testability (can mock repositories)
 More maintainable (database logic centralized)
 Consistent patterns across all data access
 Easier to add caching or logging layers

Testing:
✓ All syntax checks pass
✓ Authentication working
✓ Commanders endpoint returning 5 commanders
✓ Games endpoint returning 16 games
✓ All endpoints functional

* refactor: remove unused model classes

Models (User, Commander, Game) have been fully replaced by their
corresponding Repository classes. All functionality is preserved in
the repositories with no loss of capability or breaking changes.

Deleted files:
- User.js (136 lines)
- Commander.js (195 lines)
- Game.js (204 lines)

Total: ~535 lines of unused code removed

Benefits:
 Cleaner codebase - no duplicate data access logic
 Single source of truth - repositories handle all data access
 Better maintainability - clear separation of concerns
 No confusion - developers only use repositories
 Follows DRY principle - no code duplication

Testing:
✓ All routes verified to use repositories only
✓ All endpoints tested and working
✓ Authentication (8 endpoints)
✓ Commanders (7 endpoints)
✓ Games (6 endpoints)
✓ Stats (read-only)

No breaking changes - all functionality identical to before.

* Configure DB env defaults and add health checks

- Use DB_USER, DB_PASSWORD, and DB_NAME with defaults in deploy.sh and
  docker-compose.yml
- Replace wget-based health check with curl to /health in the frontend
  service
- Remove listen_addresses configuration from Postgres in
  deploy/docker-compose
- Delete frontend/public/status.html

* Return camelCase game data and richer responses

* Add validation utilities and stricter schemas

* Update commanders.html
2026-01-17 21:14:10 +01:00
aca34942b7 Consolidate into version.txt for deployment and frontent 2026-01-17 10:58:24 +01:00