diff --git a/.github/used-prompts/deploying.md b/.github/used-prompts/deploying.md deleted file mode 100644 index aabe746..0000000 --- a/.github/used-prompts/deploying.md +++ /dev/null @@ -1,107 +0,0 @@ -## Overview - -Deploy `estus-shots` to the personal Fedora server manually—no CI/CD required. The application runs behind Nginx via a reverse proxy and is supervised by `systemd`. - -## Prerequisites - -- Fedora (server) with SSH access for a user that can `sudo` without a passwordless setup. -- Nim toolchain installed locally (for `nim`/`nimble`). -- Server already provisioned with Nim runtime dependencies. -- Existing Nginx site definition that proxies traffic to the `estus-shots` service port (defaults to `127.0.0.1:9000`). - -## One-time server setup - -1. Create deployment directories on the server: - ```fish - ssh user@server 'sudo mkdir -p /opt/estus-shots/bin /opt/estus-shots/config && sudo chown ${USER}:${USER} /opt/estus-shots -R' - ``` -2. Copy the `systemd` unit and enable it: - ```fish - printf '%s\n' "[Unit]" \ - "Description=estus-shots web service" \ - "After=network.target" \ - "" \ - "[Service]" \ - "Type=simple" \ - "ExecStart=/opt/estus-shots/bin/estus-shots" \ - "Restart=on-failure" \ - "RestartSec=5" \ - "User=www-data" \ - "WorkingDirectory=/opt/estus-shots" \ - "Environment=LOG_LEVEL=info" \ - "" \ - "[Install]" \ - "WantedBy=multi-user.target" \ - | ssh user@server 'sudo tee /etc/systemd/system/estus-shots.service' - - ssh user@server 'sudo systemctl daemon-reload && sudo systemctl enable estus-shots.service' - ``` -3. Ensure Nginx reverse proxy points to `127.0.0.1:9000` and reload it once configured: - ```fish - ssh user@server 'sudo systemctl restart nginx' - ``` - -## Deployment script - -Save the following as `scripts/deploy.fish` (or another preferred location) and make it executable with `chmod +x scripts/deploy.fish`. - -```fish -#!/usr/bin/env fish - -set -e - -set SERVER user@server -set TARGET_DIR /opt/estus-shots -set BIN_NAME estus-shots - -echo 'Building project locally (release)...' -nimble build -y - -echo 'Uploading binary...' -scp bin/$BIN_NAME $SERVER:$TARGET_DIR/bin/ - -echo 'Uploading static assets...' -scp -r src/static $SERVER:$TARGET_DIR/ - -echo 'Restarting services...' -ssh $SERVER 'sudo systemctl restart estus-shots.service' -ssh $SERVER 'sudo systemctl restart nginx' - -echo 'Deployment finished.' -``` - -> The script prompts for the SSH password and any required `sudo` password on the server. - -## Manual deployment steps - -1. Build the project locally: - ```fish - nimble build -y - ``` -2. Copy the new build output and static assets: - ```fish - scp bin/estus-shots user@server:/opt/estus-shots/bin/ - scp -r src/static user@server:/opt/estus-shots/ - ``` -3. Restart the service and, if needed, Nginx: - ```fish - ssh user@server 'sudo systemctl restart estus-shots.service' - ssh user@server 'sudo systemctl restart nginx' - ``` - -## Verification - -- Check service status: - ```fish - ssh user@server 'systemctl status estus-shots.service --no-pager' - ``` -- Review recent logs: - ```fish - ssh user@server 'journalctl -u estus-shots.service -n 50 --no-pager' - ``` - -## Troubleshooting tips - -- If the service fails, run it manually on the server to capture stdout/stderr: `bin/estus-shots`. -- Ensure SELinux contexts allow Nginx to proxy (`setsebool -P httpd_can_network_connect 1`). -- Validate reverse proxy config: `sudo nginx -t`. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c17a3ff --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# Estus Shots +Tracking tool for Dark Souls drinking games. + +## Game Rules +- One player actively plays the game. +- When a player dies, all must take a drink. +- The next player takes over. +- If a player beats a boss, the controller passes on, no drinks. + +## Features +- Track game progress across multiple games. +- Progress is tracked per game sessions. +- A Session is compoesed of multiple Events +- Events can be start, end, boss defeated, death, etc. +- Statistics are can be viewed for players, games and bosses. +- Players can be added, removed and edited. +- Games can be added, removed and edited. +- Bosses can be added, removed and edited. +- A penalty event happens when a player dies. +- The penalty event assigns a a dink to a player +- A typical penaly would look like this: + - 20:24 Player A dies to Boss B + - Player A drinks a shot of Drink A + - Player B drinks a shot of Drinnk B + - Player C drinks a shot of Dink A + diff --git a/internal/models/models.go b/internal/models/models.go new file mode 100644 index 0000000..3b8475e --- /dev/null +++ b/internal/models/models.go @@ -0,0 +1,79 @@ +package models + +import "time" + +// Player represents a participant in the drinking game. +type Player struct { + ID int `json:"id"` + Name string `json:"name"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +// Game represents a Dark Souls game variant. +type Game struct { + ID int `json:"id"` + Name string `json:"name"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +// Boss represents a boss in a Dark Souls game. +type Boss struct { + ID int `json:"id"` + Name string `json:"name"` + GameID int `json:"game_id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +// Drink represents a type of alcoholic beverage. +type Drink struct { + ID int `json:"id"` + Name string `json:"name"` + Type string `json:"type"` // e.g., "beer", "shot", "cocktail" + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +// EventType represents the type of event that occurred during a session. +type EventType string + +const ( + EventTypeStart EventType = "start" + EventTypeEnd EventType = "end" + EventTypeBossDefeated EventType = "boss_defeated" + EventTypeDeath EventType = "death" +) + +// Session represents a game session with multiple players. +type Session struct { + ID int `json:"id"` + GameID int `json:"game_id"` + StartedAt time.Time `json:"started_at"` + EndedAt *time.Time `json:"ended_at,omitempty"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +// Event represents an event that occurred during a session. +type Event struct { + ID int `json:"id"` + SessionID int `json:"session_id"` + EventType EventType `json:"event_type"` + PlayerID int `json:"player_id"` + BossID *int `json:"boss_id,omitempty"` + Timestamp time.Time `json:"timestamp"` + Notes string `json:"notes,omitempty"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +// PenaltyDrink represents a drink consumed as a penalty. +type PenaltyDrink struct { + ID int `json:"id"` + EventID int `json:"event_id"` + PlayerID int `json:"player_id"` + DrinkID int `json:"drink_id"` + CreatedAt time.Time `json:"created_at"` +} diff --git a/internal/server/server.go b/internal/server/server.go index 6d0d802..6eae33d 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -111,6 +111,30 @@ func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request) { data := AdminMenuBar() data.Title = "Admin Panel" s.renderTemplate(w, http.StatusOK, "admin.html", data) + case "/players": + data := DefaultMenuBar() + data.Title = "Players" + s.renderTemplate(w, http.StatusOK, "players.html", data) + case "/games": + data := DefaultMenuBar() + data.Title = "Games" + s.renderTemplate(w, http.StatusOK, "games.html", data) + case "/bosses": + data := DefaultMenuBar() + data.Title = "Bosses" + s.renderTemplate(w, http.StatusOK, "bosses.html", data) + case "/sessions": + data := DefaultMenuBar() + data.Title = "Sessions" + s.renderTemplate(w, http.StatusOK, "sessions.html", data) + case "/statistics": + data := DefaultMenuBar() + data.Title = "Statistics" + s.renderTemplate(w, http.StatusOK, "statistics.html", data) + case "/drinks": + data := DefaultMenuBar() + data.Title = "Drinks" + s.renderTemplate(w, http.StatusOK, "drinks.html", data) case "/counter": s.handleCounter(w, r) case "/time": diff --git a/internal/server/template_data.go b/internal/server/template_data.go index 64d4bb5..36b9382 100644 --- a/internal/server/template_data.go +++ b/internal/server/template_data.go @@ -40,22 +40,22 @@ func DefaultMenuBar() PageData { ShowClock: true, MenuGroups: []MenuGroup{ { - Label: "File", + Label: "Game", Items: []MenuItem{ - {Label: "New", URL: "#!"}, - {Label: "Open", URL: "#!"}, - {Label: "Save", URL: "#!"}, - {Label: "Save As", URL: "#!"}, + {Label: "Home", URL: "/"}, + {Label: "Sessions", URL: "/sessions"}, + {Label: "Statistics", URL: "/statistics"}, {IsDivider: true}, {Label: "Exit", URL: "#!"}, }, }, { - Label: "Edit", + Label: "Manage", Items: []MenuItem{ - {Label: "Cut", URL: "#!"}, - {Label: "Copy", URL: "#!"}, - {Label: "Paste", URL: "#!"}, + {Label: "Players", URL: "/players"}, + {Label: "Games", URL: "/games"}, + {Label: "Bosses", URL: "/bosses"}, + {Label: "Drinks", URL: "/drinks"}, }, }, { diff --git a/web/templates/bosses.html b/web/templates/bosses.html new file mode 100644 index 0000000..0ff7c5f --- /dev/null +++ b/web/templates/bosses.html @@ -0,0 +1,41 @@ +{{template "layout" .}} + +{{define "title"}}Bosses · Estus Shots{{end}} + +{{define "content"}} +
+{{end}} diff --git a/web/templates/drinks.html b/web/templates/drinks.html new file mode 100644 index 0000000..a94d5e7 --- /dev/null +++ b/web/templates/drinks.html @@ -0,0 +1,46 @@ +{{template "layout" .}} + +{{define "title"}}Drinks · Estus Shots{{end}} + +{{define "content"}} + +{{end}} diff --git a/web/templates/games.html b/web/templates/games.html new file mode 100644 index 0000000..5798d69 --- /dev/null +++ b/web/templates/games.html @@ -0,0 +1,35 @@ +{{template "layout" .}} + +{{define "title"}}Games · Estus Shots{{end}} + +{{define "content"}} + +{{end}} diff --git a/web/templates/players.html b/web/templates/players.html new file mode 100644 index 0000000..b8565a0 --- /dev/null +++ b/web/templates/players.html @@ -0,0 +1,35 @@ +{{template "layout" .}} + +{{define "title"}}Players · Estus Shots{{end}} + +{{define "content"}} + +{{end}} diff --git a/web/templates/sessions.html b/web/templates/sessions.html new file mode 100644 index 0000000..8c4893a --- /dev/null +++ b/web/templates/sessions.html @@ -0,0 +1,50 @@ +{{template "layout" .}} + +{{define "title"}}Sessions · Estus Shots{{end}} + +{{define "content"}} + +{{end}} diff --git a/web/templates/statistics.html b/web/templates/statistics.html new file mode 100644 index 0000000..8a4e422 --- /dev/null +++ b/web/templates/statistics.html @@ -0,0 +1,48 @@ +{{template "layout" .}} + +{{define "title"}}Statistics · Estus Shots{{end}} + +{{define "content"}} + +{{end}}