Initial commit: Nexus Mission Control Platform

- ASP.NET Core 10 Backend (JWT Auth, Agent config API)
- Vue 3 Frontend (Dashboard, Team, Agents, Config Editor)
- PostgreSQL Database
- Docker Compose setup
- Mission Control Dashboard redesign
This commit is contained in:
Bao
2026-06-09 16:31:42 +02:00
commit eeb6174de0
248 changed files with 19706 additions and 0 deletions
+103
View File
@@ -0,0 +1,103 @@
import { defineStore } from 'pinia'
export interface AuthUser {
id: string
email: string
displayName: string
role: string
}
interface AuthPayload {
accessToken: string
expiresAt: string
user: AuthUser
}
let refreshInFlight: Promise<boolean> | null = null
export const useAuthStore = defineStore('auth', {
state: () => ({
accessToken: null as string | null,
expiresAt: null as string | null,
user: null as AuthUser | null,
initialized: false,
loading: false,
}),
getters: {
isAuthenticated: state => Boolean(state.accessToken && state.user),
},
actions: {
applySession(payload: AuthPayload) {
this.accessToken = payload.accessToken
this.expiresAt = payload.expiresAt
this.user = payload.user
},
clearSession() {
this.accessToken = null
this.expiresAt = null
this.user = null
},
async initialize() {
if (this.initialized) return this.isAuthenticated
this.initialized = true
return this.refresh()
},
async login(email: string, password: string) {
this.loading = true
try {
const response = await fetch('/api/v1/auth/login', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
})
if (!response.ok) {
if (response.status === 429) throw new Error('Too many attempts. Please wait one minute.')
throw new Error('Invalid email or password.')
}
this.applySession(await response.json() as AuthPayload)
} finally {
this.loading = false
}
},
async refresh(): Promise<boolean> {
if (refreshInFlight) return refreshInFlight
refreshInFlight = (async () => {
try {
const response = await fetch('/api/v1/auth/refresh', {
method: 'POST',
credentials: 'include',
})
if (!response.ok) {
this.clearSession()
return false
}
this.applySession(await response.json() as AuthPayload)
return true
} catch {
this.clearSession()
return false
} finally {
refreshInFlight = null
}
})()
return refreshInFlight
},
async logout() {
try {
await fetch('/api/v1/auth/logout', {
method: 'POST',
credentials: 'include',
headers: this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : undefined,
})
} finally {
this.clearSession()
}
},
},
})