chore: remove duplicate copies of the site, download center and installers (WS-C)
The landing page, download pages, invite page, assetlinks and installers existed in two or three places; only site/ and the Forgejo feed are served. - apps/api-server/wwwroot: delete the stale site build, download/invite pages, .well-known copy, legacy static admin and 1.0.0 binaries. The API no longer serves static files (UseStaticFiles/fallbacks and the apk/zip blocker removed); the Next admin is the only admin UI. - Delete 19 tracked installers/packages (~568 MiB) under site/public/releases, apps/web/public/releases and wwwroot/releases; .gitignore blocks them. - apps/web: delete the download/releases pages, desktop-release.ts, the download.html and assetlinks copies, and the accept-invite page (invites are only issued to the site's /accept-invite/). e2e specs call the /app base path and check the /download redirect instead. - scripts: delete the retired release/NAS site scripts, drop the web target from sync-version, and check assetlinks in site/public only. - Delete the unused Dockerfile.admin (apps/admin/Dockerfile is used). Policy: docs/REFACTOR_POLICY.md Wave 3, W3-5 and W3-6.
This commit is contained in:
parent
b6fe588a7c
commit
cd9d199dbf
53 changed files with 43 additions and 3278 deletions
|
|
@ -124,12 +124,12 @@ test.describe('Billing provider and Payple DOM flow', () => {
|
|||
})
|
||||
})
|
||||
|
||||
await page.goto('/login')
|
||||
await page.goto('/app/login')
|
||||
await page.getByPlaceholder('user@studio.com').fill(email)
|
||||
await page.getByPlaceholder('••••••••').fill(password)
|
||||
await page.getByRole('button', { name: '로그인', exact: true }).click()
|
||||
await page.waitForURL(/\/dashboard/, { timeout: 15_000 })
|
||||
await page.goto('/billing')
|
||||
await page.goto('/app/billing')
|
||||
|
||||
await expect(page.getByTestId('billing-current-tier')).toHaveText('FREE')
|
||||
await expect(page.getByTestId('billing-current-provider')).toContainText('없음')
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ test.describe('Dashboard, dictionary and command Supabase parity', () => {
|
|||
let otherId = ''
|
||||
|
||||
async function login(page: import('@playwright/test').Page): Promise<void> {
|
||||
await page.goto('/login')
|
||||
await page.goto('/app/login')
|
||||
await page.getByPlaceholder('user@studio.com').fill(ownerEmail)
|
||||
await page.getByPlaceholder('••••••••').fill(password)
|
||||
await page.getByRole('button', { name: '로그인', exact: true }).click()
|
||||
|
|
@ -146,7 +146,7 @@ test.describe('Dashboard, dictionary and command Supabase parity', () => {
|
|||
|
||||
test('dictionary uses RLS CRUD, filters, pagination, duplicate protection and optimistic rollback', async ({ page }) => {
|
||||
await login(page)
|
||||
await page.goto('/dictionary')
|
||||
await page.goto('/app/dictionary')
|
||||
await expect(page.getByText('CUSTOM DICTIONARY')).toBeVisible()
|
||||
await expect(page.getByText(foreignDictionaryWord)).toHaveCount(0)
|
||||
await expect(page.getByText(oldestWord)).toHaveCount(0)
|
||||
|
|
@ -237,7 +237,7 @@ test.describe('Dashboard, dictionary and command Supabase parity', () => {
|
|||
expect(bootstrapA.data).toHaveLength(4)
|
||||
expect(bootstrapB.data).toHaveLength(4)
|
||||
await bootstrapClient.auth.signOut({ scope: 'local' })
|
||||
await page.goto('/commands')
|
||||
await page.goto('/app/commands')
|
||||
await expect(page.getByText('SYNCED COMMANDS (4)')).toBeVisible()
|
||||
await expect(page.getByText('Translate to English', { exact: true }).first()).toBeVisible()
|
||||
await expect(page.getByText('BUILT-IN · READ ONLY').first()).toBeVisible()
|
||||
|
|
|
|||
|
|
@ -90,13 +90,13 @@ test.describe('History Supabase SSOT', () => {
|
|||
})
|
||||
|
||||
test('session, RLS, search, favorite, pagination, detail and mutation rollback work end-to-end', async ({ page }) => {
|
||||
await page.goto('/login')
|
||||
await page.goto('/app/login')
|
||||
await page.getByPlaceholder('user@studio.com').fill(ownerEmail)
|
||||
await page.getByPlaceholder('••••••••').fill(password)
|
||||
await page.getByRole('button', { name: '로그인', exact: true }).click()
|
||||
await page.waitForURL(/\/dashboard/, { timeout: 15_000 })
|
||||
|
||||
await page.goto('/history')
|
||||
await page.goto('/app/history')
|
||||
await expect(page.getByText('TRANSCRIPTION HISTORY')).toBeVisible()
|
||||
await expect(page.getByText(foreignTitle)).toHaveCount(0)
|
||||
await expect(page.getByTestId(`history-card-${oldestId}`)).toHaveCount(0)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { SITE_URLS } from '@d3ro/core/web-urls';
|
||||
|
||||
const SCREENSHOT_DIR = path.resolve('C:/Users/encep/.gemini/antigravity/brain/bbff18a3-721d-4c43-989f-1d6964e15be7/screenshots');
|
||||
|
||||
|
|
@ -21,9 +22,9 @@ test.describe.serial('Extreme Red Team - Cycle 4: Web Console & Public Surfaces'
|
|||
});
|
||||
});
|
||||
|
||||
test('RT-14: Web Public Hub - /login, /download, /releases & /accept-invite', async ({ page }) => {
|
||||
test('RT-14: Web Public Hub - /login and the /download redirect to the landing site', async ({ page }) => {
|
||||
// 1. Test /login
|
||||
await page.goto('/login');
|
||||
await page.goto('/app/login');
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
|
||||
await expect(page.getByText(/D3RO[- ]VOICE/i)).toBeVisible({ timeout: 10000 });
|
||||
|
|
@ -35,49 +36,10 @@ test.describe.serial('Extreme Red Team - Cycle 4: Web Console & Public Surfaces'
|
|||
path: path.join(SCREENSHOT_DIR, 'rt14_01_web_login.png'),
|
||||
});
|
||||
|
||||
// 2. Test /download
|
||||
await page.goto('/download');
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
|
||||
await expect(page.getByText(/OFFICIAL STABLE RELEASE|D3RO Voice Desktop 1.1.0/i).first()).toBeVisible({ timeout: 10000 });
|
||||
await expect(page.getByText(/Windows|macOS/i).first()).toBeVisible();
|
||||
|
||||
const primaryDownloadBtn = page.getByRole('link', { name: /Download for Windows/i });
|
||||
await expect(primaryDownloadBtn).toBeVisible();
|
||||
await expect(primaryDownloadBtn).toHaveAttribute('href', '/releases/1.1.0/D3RO-Voice-Setup-1.1.0-x64.exe');
|
||||
await expect(primaryDownloadBtn).toHaveAttribute('download', 'D3RO-Voice-Setup-1.1.0-x64.exe');
|
||||
|
||||
const cardDownloadBtn = page.getByRole('link', { name: /Download Setup \(\.exe\)/i });
|
||||
await expect(cardDownloadBtn).toBeVisible();
|
||||
await expect(cardDownloadBtn).toHaveAttribute('href', '/releases/1.1.0/D3RO-Voice-Setup-1.1.0-x64.exe');
|
||||
|
||||
// Verify static release asset HTTP availability
|
||||
const releaseHead = await page.request.head('/releases/1.1.0/D3RO-Voice-Setup-1.1.0-x64.exe');
|
||||
expect(releaseHead.status()).toBe(200);
|
||||
expect(Number(releaseHead.headers()['content-length'])).toBeGreaterThan(100000000);
|
||||
|
||||
// Screenshot download
|
||||
await page.screenshot({
|
||||
path: path.join(SCREENSHOT_DIR, 'rt14_02_web_download.png'),
|
||||
});
|
||||
|
||||
// 3. Test /releases
|
||||
await page.goto('/releases');
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
|
||||
await expect(page.getByText(/OFFICIAL STABLE RELEASE|D3RO Voice Desktop 1.1.0/i).first()).toBeVisible({ timeout: 10000 });
|
||||
await expect(page.getByRole('link', { name: /Download for Windows/i })).toBeVisible();
|
||||
|
||||
// Screenshot releases
|
||||
await page.screenshot({
|
||||
path: path.join(SCREENSHOT_DIR, 'rt14_03_web_releases.png'),
|
||||
});
|
||||
|
||||
// 4. Test /accept-invite
|
||||
await page.goto('/accept-invite?token=red-team-bogus-token');
|
||||
await page.waitForLoadState('domcontentloaded');
|
||||
|
||||
await expect(page.getByText(/TEAM INVITE|초대/i).first()).toBeVisible({ timeout: 10000 });
|
||||
// 2. /download lives only on the landing site; the web app just redirects there.
|
||||
const downloadRes = await page.request.get('/app/download', { maxRedirects: 0 });
|
||||
expect([307, 308]).toContain(downloadRes.status());
|
||||
expect(downloadRes.headers()['location']).toBe(SITE_URLS.download);
|
||||
|
||||
expect(uncaughtExceptions).toEqual([]);
|
||||
});
|
||||
|
|
@ -98,7 +60,7 @@ test.describe.serial('Extreme Red Team - Cycle 4: Web Console & Public Surfaces'
|
|||
];
|
||||
|
||||
for (const route of protectedRoutes) {
|
||||
await page.goto(route);
|
||||
await page.goto(`/app${route}`);
|
||||
await page.waitForURL(/\/login/, { timeout: 10000 });
|
||||
expect(page.url()).toContain('/login');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,36 +10,31 @@ import { test, expect } from '@playwright/test'
|
|||
|
||||
test.describe('Smoke: unauthenticated access', () => {
|
||||
test('루트(/)는 /login으로 리다이렉트된다 (Supabase 미설정 시)', async ({ page }) => {
|
||||
await page.goto('/')
|
||||
await page.goto('/app')
|
||||
await page.waitForURL(/\/login/, { timeout: 10000 })
|
||||
expect(page.url()).toContain('/login')
|
||||
})
|
||||
|
||||
test('/login 페이지가 로드되고 D3RO VOICE 로고가 표시된다', async ({ page }) => {
|
||||
await page.goto('/login')
|
||||
await page.goto('/app/login')
|
||||
await expect(page.getByText(/D3RO[- ]VOICE/i)).toBeVisible({ timeout: 10000 })
|
||||
})
|
||||
|
||||
test('/login에 Google/GitHub OAuth 버튼이 보인다', async ({ page }) => {
|
||||
await page.goto('/login')
|
||||
await page.goto('/app/login')
|
||||
await expect(page.getByRole('button', { name: /Google/i })).toBeVisible()
|
||||
await expect(page.getByRole('button', { name: /GitHub/i })).toBeVisible()
|
||||
})
|
||||
|
||||
test('/dashboard는 미로그인 시 /login으로 리다이렉트', async ({ page }) => {
|
||||
await page.goto('/dashboard')
|
||||
await page.goto('/app/dashboard')
|
||||
await page.waitForURL(/\/login/, { timeout: 10000 })
|
||||
expect(page.url()).toContain('/login')
|
||||
})
|
||||
|
||||
test('/meetings도 미로그인 시 /login으로 리다이렉트', async ({ page }) => {
|
||||
await page.goto('/meetings')
|
||||
await page.goto('/app/meetings')
|
||||
await page.waitForURL(/\/login/, { timeout: 10000 })
|
||||
expect(page.url()).toContain('/login')
|
||||
})
|
||||
|
||||
test('/accept-invite?token=bogus는 페이지 로드 (에러 메시지 표시)', async ({ page }) => {
|
||||
await page.goto('/accept-invite?token=bogus')
|
||||
await expect(page.getByText(/TEAM INVITE/i)).toBeVisible({ timeout: 10000 })
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue