feat: production deployment — Dockerfile, docker-compose, SPA serving, classic bot fights
- Add Dockerfile (multi-stage: build frontend + server, serve from single container) - Add docker-compose.yml for Portainer stack deployment - Server serves frontend SPA in production (static assets + SPA fallback) - Auto-run migrations and seed mock bots on server startup - DB path configurable via DB_PATH env var - Add "Fight a Classic Bot" button for instant mock bot matches - FIGHT button queues for real AI opponents Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
120250c01a
commit
6bf9fe27b3
@@ -11,6 +11,7 @@ const { pubkey, bot, profilePicUrl, isLoggedIn, hasExtension, isLoading, login,
|
||||
const step = ref<string>('login')
|
||||
const error = ref('')
|
||||
const isJoining = ref(false)
|
||||
const isFightingClassic = ref(false)
|
||||
const queueCount = ref(0)
|
||||
let pollHandle: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
@@ -173,6 +174,25 @@ async function fight() {
|
||||
isJoining.value = false
|
||||
}
|
||||
|
||||
async function fightClassicBot() {
|
||||
if (!bot.value || isFightingClassic.value) return
|
||||
isFightingClassic.value = true
|
||||
error.value = ''
|
||||
try {
|
||||
const res = await fetch(`/api/fights/mock/${bot.value.id}`, { method: 'POST' })
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
router.push(`/arena/${data.fightId}`)
|
||||
} else {
|
||||
const data = await res.json()
|
||||
error.value = data.error || 'Failed to start fight.'
|
||||
}
|
||||
} catch {
|
||||
error.value = 'Network error.'
|
||||
}
|
||||
isFightingClassic.value = false
|
||||
}
|
||||
|
||||
function handleSignOut() {
|
||||
logout()
|
||||
step.value = 'login'
|
||||
@@ -505,17 +525,46 @@ function handleSignOut() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Big fight button -->
|
||||
<button
|
||||
class="w-full py-5 bg-neon-pink/10 border-2 border-neon-pink text-neon-pink
|
||||
font-display font-black text-2xl tracking-[0.2em]
|
||||
hover:bg-neon-pink/20 transition-all neon-border-pink
|
||||
disabled:opacity-30 disabled:cursor-not-allowed"
|
||||
:disabled="isJoining"
|
||||
@click="fight"
|
||||
>
|
||||
{{ isJoining ? 'MATCHING...' : 'FIGHT' }}
|
||||
</button>
|
||||
<!-- Fight buttons -->
|
||||
<div class="space-y-3">
|
||||
<!-- Main fight button — real queue -->
|
||||
<button
|
||||
class="w-full py-5 bg-neon-pink/10 border-2 border-neon-pink text-neon-pink
|
||||
font-display font-black text-2xl tracking-[0.2em]
|
||||
hover:bg-neon-pink/20 transition-all neon-border-pink
|
||||
disabled:opacity-30 disabled:cursor-not-allowed"
|
||||
:disabled="isJoining || isFightingClassic"
|
||||
@click="fight"
|
||||
>
|
||||
{{ isJoining ? 'MATCHING...' : 'FIGHT' }}
|
||||
</button>
|
||||
<p class="font-mono text-[10px] text-text-muted text-center -mt-1">
|
||||
Queue up against a real AI bot
|
||||
</p>
|
||||
|
||||
<!-- Classic bot button — instant mock fight -->
|
||||
<button
|
||||
class="w-full py-4 bg-neon-purple/10 border-2 border-neon-purple/50 text-neon-purple
|
||||
font-display font-black text-base tracking-[0.15em]
|
||||
hover:bg-neon-purple/20 hover:border-neon-purple transition-all
|
||||
disabled:opacity-30 disabled:cursor-not-allowed
|
||||
flex items-center justify-center gap-3"
|
||||
:disabled="isJoining || isFightingClassic"
|
||||
@click="fightClassicBot"
|
||||
>
|
||||
<svg class="w-6 h-6 shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="4" y="4" width="16" height="12" rx="2" />
|
||||
<circle cx="9" cy="10" r="1.5" fill="currentColor" stroke="none" />
|
||||
<circle cx="15" cy="10" r="1.5" fill="currentColor" stroke="none" />
|
||||
<line x1="8" y1="20" x2="8" y2="16" />
|
||||
<line x1="16" y1="20" x2="16" y2="16" />
|
||||
</svg>
|
||||
{{ isFightingClassic ? 'STARTING...' : 'FIGHT A CLASSIC BOT' }}
|
||||
</button>
|
||||
<p class="font-mono text-[10px] text-text-muted text-center -mt-1">
|
||||
Instant match against a house bot
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Quick links -->
|
||||
<div class="mt-5 flex gap-2">
|
||||
|
||||
Reference in New Issue
Block a user