예전 배포본(HEAD)의 상세 기능을 새 아키텍처(인증=.NET 백엔드, 데이터=Supabase) 위에 실데이터로 복원. 예전 HEAD는 서명 쿠키를 거부하고 위조 쿠키는 통과시키는 인증 결함이 있었고, 삭제된 페이지 다수는 백엔드 호출 0인 하드코딩 목업이었음. 인증/세션 - 로그인 이메일 전용화(username 폐지), 에러 키별 안내 메시지 - ADMIN_COOKIE_SECURE 옵션: TLS 없는 LAN HTTP 배포에서 Secure 쿠키 유실로 로그인이 유지되지 않던 문제 해결 (login/logout route, admin-session, compose, .env.example) - Supabase 미설정 시 우아한 저하: isSupabaseAdminConfigured + UnavailableAdminPanel 기능 복원 (실데이터) - Release Hub: Forgejo API 실데이터(다운로드 수/SHA-256 체크섬/릴리스 이력) - Ad Monetization: 데스크톱 미디에이션 10개 어댑터 로스터(fail-closed) + ad_reward_claims 통계 - License Issuer: 서버사이드 Ed25519 서명(/api/admin/license, super_admin 전용), 개인키는 ADMIN_LICENSE_PRIVATE_KEY env로만, 발급 감사를 .NET AdminAuditEntries에 기록 - Service Models: STT 7종/LLM 5종 프리셋 드롭다운 + 자동채움 - 대시보드 ARR/MRR KPI: Supabase 구독 실집계(티어 월단가 기반) - 사용자 상세 티어별 기능 배지(pro_plus 조건부) .NET - SuperAdminOnly 정책 추가, /api/admin/license-audit 엔드포인트, LicenseAuditDto
57 lines
2.2 KiB
JavaScript
57 lines
2.2 KiB
JavaScript
import { createClient } from '@supabase/supabase-js'
|
|
|
|
const action = process.argv[2]
|
|
const url = process.env.D3RO_LOCAL_SUPABASE_URL?.trim() ?? ''
|
|
const serviceRoleKey = process.env.D3RO_LOCAL_SUPABASE_SERVICE_ROLE_KEY?.trim() ?? ''
|
|
if (!url.startsWith('http://127.0.0.1:55321') || serviceRoleKey.length < 20) {
|
|
throw new Error('D3RO local Supabase service credentials are required')
|
|
}
|
|
|
|
const client = createClient(url, serviceRoleKey, {
|
|
auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false }
|
|
})
|
|
const adminEmail = 'admin.browser.e2e@example.com'
|
|
const targetEmail = 'customer.browser.e2e@example.com'
|
|
|
|
async function matchingUsers() {
|
|
const { data, error } = await client.auth.admin.listUsers({ page: 1, perPage: 1000 })
|
|
if (error) throw error
|
|
return data.users.filter((user) => user.email === adminEmail || user.email === targetEmail)
|
|
}
|
|
|
|
async function cleanup() {
|
|
const users = await matchingUsers()
|
|
const ids = users.map((user) => user.id)
|
|
if (ids.length === 0) return
|
|
await client.from('audit_log').delete().in('admin_id', ids)
|
|
await client.from('admin_operation_requests').delete().in('actor_id', ids)
|
|
for (const user of users) await client.auth.admin.deleteUser(user.id)
|
|
}
|
|
|
|
if (action === 'cleanup') {
|
|
await cleanup()
|
|
console.log('admin browser fixture cleaned')
|
|
} else if (action === 'setup') {
|
|
await cleanup()
|
|
const admin = await client.auth.admin.createUser({
|
|
email: adminEmail,
|
|
password: 'Admin-browser-e2e-strong-password!',
|
|
email_confirm: true,
|
|
app_metadata: { role: 'super_admin' },
|
|
user_metadata: { name: 'Browser E2E Admin' }
|
|
})
|
|
if (admin.error) throw admin.error
|
|
const target = await client.auth.admin.createUser({
|
|
email: targetEmail,
|
|
password: 'Customer-browser-e2e-strong-password!',
|
|
email_confirm: true,
|
|
app_metadata: { role: 'user' },
|
|
user_metadata: { name: 'Browser E2E Customer' }
|
|
})
|
|
if (target.error) throw target.error
|
|
const roleUpdate = await client.from('profiles').update({ role: 'super_admin' }).eq('id', admin.data.user.id)
|
|
if (roleUpdate.error) throw roleUpdate.error
|
|
console.log(`admin browser fixture ready target=${target.data.user.id}`)
|
|
} else {
|
|
throw new Error('Expected setup or cleanup')
|
|
}
|