From afda2ae565716973d4611ce1eb306c690fe9589b Mon Sep 17 00:00:00 2001 From: bikram dey <62688713+modhack2003@users.noreply.github.com> Date: Fri, 16 Oct 2026 17:35:44 +0530 Subject: [PATCH 1/3] Implement portfolio accessibility, discovery, availability and content recovery backlog --- .github/workflows/checks.yml | 32 ++++ .gitignore | 4 + README.md | 9 +- SETUP.md | 4 + docs/portfolio-improvements.md | 50 +++++ docs/security-insights.md | 4 +- e2e/portfolio.spec.ts | 156 +++++++++++++++ jest.config.js | 1 + jest.setup.js | 7 + package-lock.json | 63 +++++++ package.json | 7 +- playwright.config.ts | 19 ++ prisma/schema.prisma | 27 +++ public/social-preview.jpg | Bin 0 -> 153249 bytes scripts/check-content.ts | 21 +++ scripts/measure-mobile.cjs | 35 ++++ scripts/seed-e2e.ts | 21 +++ scripts/test-database.ts | 7 + scripts/test-insights.ts | 9 +- scripts/test-recovery.ts | 82 ++++++++ src/app/api/admin/backup/route.ts | 37 ++++ src/app/api/admin/history/route.ts | 55 ++++++ src/app/api/import/linkedin/route.ts | 6 +- .../api/site-audio/__tests__/route.test.ts | 4 +- src/app/blog/[slug]/page.tsx | 21 +-- src/app/blog/page.tsx | 96 ++++------ src/app/globals.css | 9 + src/app/layout.tsx | 24 +-- src/app/page.tsx | 4 +- src/app/robots.ts | 6 + src/app/sitemap.ts | 14 ++ src/components/admin/admin-shell.tsx | 2 +- src/components/admin/collection-editor.tsx | 2 +- src/components/admin/dashboard.tsx | 7 +- src/components/admin/history-panel.tsx | 90 +++++++++ src/components/admin/insights-panel.tsx | 2 +- src/components/cyber/experience-gate.tsx | 178 ++++++------------ src/components/cyber/not-found-screen.tsx | 2 +- src/components/cyber/primitives.tsx | 9 +- src/components/cyber/repo-object-stage.tsx | 2 +- src/components/cyber/scroll-circle.tsx | 6 +- src/components/cyber/sharingan.tsx | 2 +- src/components/sections/blog.tsx | 4 +- src/components/sections/bounty-client.tsx | 6 +- src/components/sections/hero.tsx | 6 +- src/components/sections/projects.tsx | 19 +- src/components/shadow-shell.tsx | 2 +- src/lib/__tests__/blog-list.test.ts | 19 ++ src/lib/__tests__/content-recovery.test.ts | 23 +++ src/lib/__tests__/security-insights.test.ts | 3 +- src/lib/blog-list.ts | 31 +++ src/lib/content-history.ts | 139 ++++++++++++++ src/lib/content-recovery.ts | 90 +++++++++ src/lib/portfolio-data.ts | 22 +-- src/lib/prisma.ts | 7 +- src/lib/security-insights.ts | 4 + src/lib/seo.ts | 14 ++ src/middleware.ts | 29 +-- 58 files changed, 1285 insertions(+), 269 deletions(-) create mode 100644 docs/portfolio-improvements.md create mode 100644 e2e/portfolio.spec.ts create mode 100644 playwright.config.ts create mode 100644 public/social-preview.jpg create mode 100644 scripts/check-content.ts create mode 100644 scripts/measure-mobile.cjs create mode 100644 scripts/seed-e2e.ts create mode 100644 scripts/test-database.ts create mode 100644 scripts/test-recovery.ts create mode 100644 src/app/api/admin/backup/route.ts create mode 100644 src/app/api/admin/history/route.ts create mode 100644 src/app/robots.ts create mode 100644 src/app/sitemap.ts create mode 100644 src/components/admin/history-panel.tsx create mode 100644 src/lib/__tests__/blog-list.test.ts create mode 100644 src/lib/__tests__/content-recovery.test.ts create mode 100644 src/lib/blog-list.ts create mode 100644 src/lib/content-history.ts create mode 100644 src/lib/content-recovery.ts create mode 100644 src/lib/seo.ts diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 26abaee..f00e8be 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -36,4 +36,36 @@ jobs: run: npx tsx scripts/test-insights.ts env: INSIGHTS_TEST_DATABASE_URL: mongodb://127.0.0.1:27017/studio_insights_test?replicaSet=rs0 + - name: Verify transactional content recovery with MongoDB + run: npm run test:recovery + env: + RECOVERY_TEST_DATABASE_URL: mongodb://127.0.0.1:27017/studio_recovery_test?replicaSet=rs0 + - name: Seed synthetic browser-test content + run: npx tsx scripts/seed-e2e.ts + env: + E2E_DATABASE_URL: mongodb://127.0.0.1:27017/studio_e2e_test?replicaSet=rs0 + - name: Create browser-test indexes + run: npx prisma db push --skip-generate + env: + DATABASE_URL: mongodb://127.0.0.1:27017/studio_e2e_test?replicaSet=rs0 + - name: Verify content check refuses an unavailable database + run: | + if DATABASE_URL='' npm run content:check; then + echo 'Content check unexpectedly accepted an unavailable database' + exit 1 + fi - run: npm run build + env: + DATABASE_URL: mongodb://127.0.0.1:27017/studio_e2e_test?replicaSet=rs0 + - run: npx playwright install --with-deps chromium + - run: npm run test:e2e + env: + E2E_DATABASE_URL: mongodb://127.0.0.1:27017/studio_e2e_test?replicaSet=rs0 + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: browser-test-results + path: | + playwright-report/ + test-results/ + retention-days: 7 diff --git a/.gitignore b/.gitignore index 2b8632d..3c24219 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,7 @@ firestore-debug.log /src/generated/prisma !.env.example + +# Browser test output +/playwright-report/ +/test-results/ diff --git a/README.md b/README.md index e08b379..91adf3b 100644 --- a/README.md +++ b/README.md @@ -268,9 +268,12 @@ The admin console, first login and day‑to‑day content workflow are covered i 1. Import the repo in Vercel. The Next.js preset is picked up automatically. 2. Add the variables above under **Settings → Environment Variables**. -3. Deploy. `postinstall` generates the Prisma client during the build. -4. Once, from your machine, run `DATABASE_URL="" npm run db:push` to create the collections and indexes. -5. Log in, set a new PIN in **Security**, then press **GitHub → Sync now**. +3. From your machine, run `DATABASE_URL="" npm run db:push` to create the collections and indexes, including content history. +4. For a new database, use the local admin console (`npm run dev`) to save your real profile (name, title and bio) and at least one project or visible repository. Existing populated installations can skip this step. Do not seed example content into production. +5. Deploy. `postinstall` generates Prisma; `prebuild` verifies the content/database before a release. A failed check keeps the previous successful deployment active. +6. Log in, set a new PIN in **Security**, then press **GitHub → Sync now**. + +See [availability, admin recovery and browser tests](docs/portfolio-improvements.md) for Trash, revisions, backup limits and test commands. > [!TIP] > Seeing `Server selection timeout` or `bad auth`? In Atlas, open **Network Access** to Vercel (for example `0.0.0.0/0`), and check that the database name is part of `DATABASE_URL`. diff --git a/SETUP.md b/SETUP.md index a0a52eb..ebab5d9 100644 --- a/SETUP.md +++ b/SETUP.md @@ -46,3 +46,7 @@ npm test # unit tests npm run typecheck npm run lint ``` + +## Content availability and recovery + +Builds now require a reachable, populated database to avoid releasing an empty portfolio. See [portfolio improvements](docs/portfolio-improvements.md) for the content check, schema/index setup, admin Trash/history, backup limits, and browser tests. diff --git a/docs/portfolio-improvements.md b/docs/portfolio-improvements.md new file mode 100644 index 0000000..b57c029 --- /dev/null +++ b/docs/portfolio-improvements.md @@ -0,0 +1,50 @@ +# Portfolio backlog: selected October improvements + +Implements issue #20 items 1, 2, 4–10. The Naruto/cyber design remains. Authentication changes and portfolio case-study content are separate work. + +## Publishing and availability + +- The 90-day archive job targets only slugs in the durable Security Insights import ledger. Original write-ups, including older posts discussing CVEs, are preserved. Imported content is archived reversibly. +- `npm run build` first runs `content:check`. A working database, a populated public profile (name/title/bio), and at least one visible project/repository are required. A connection failure or incomplete source data fails the release; Vercel keeps the previous successful deployment. No demo data is inserted by this check. +- Home-page database errors now fail static generation/revalidation rather than silently generating an empty portfolio. Runtime ISR can retain its last successful page. This protects releases; it does not make dynamic pages available during a database outage. +- The blog reads 12 summaries per page, never whole article bodies in listing queries. Search matches titles/excerpts case-insensitively; tag filtering matches an exact tag. GET forms and pagination URLs preserve filters and work without client-side JavaScript. + +## Accessibility and mobile projects + +The entrance dialog is static and defaults to safe mode before paint. It has no loading delay or flicker. Keyboard focus starts on Safe Mode, remains in the dialog, and moves to the page's main content on dismissal. Escape selects safe mode. Reduced-motion preferences override a stored glitch choice and update when the OS setting changes. Storage-denied browsing still works. + +Shared reveals, text decoding, parallax and tilt honor the same mode; existing WebGL viewport pausing and reduced-motion fallbacks remain. Mobile grid and list cards expose Source/Visit, Demo (when present), and Details links as siblings of selection buttons, without nesting interactive elements. Keyboard selection updates the preview too. + +## Search discovery and fonts + +- Canonical URLs use the public production origin. Home-page Person and article BlogPosting JSON-LD escape content-controlled markup. Articles include publication/modification metadata and a social image. +- `/sitemap.xml` includes only public pages/published articles. `/robots.txt` and noindex headers exclude API/admin/decoy paths. Filtered searches are noindex, follow. +- The four existing font families remain. Requested weights drop from 15 to 9; Japanese UI labels use a 106-glyph subset. When adding Japanese labels, extend the `text=` subset in layout.tsx. Google Fonts still uses `display=swap` and preconnects. +- `scripts/measure-mobile.cjs` records LCP, CLS, observed long-task blocking, TTFB, font bytes, page errors and overflow using Chromium Pixel 7 emulation, 4× CPU slowdown, 1.6 Mbps download and 150 ms latency. Results are laboratory measurements against synthetic local data, not real-user Core Web Vitals or a production speed guarantee. + +## Admin history, Trash and backups + +Open **History & recovery** in the real admin console. New writes to profile, projects, skills, certificates, education, experience, CTFs, GitHub repositories, blog, bounty findings and audio settings store full before/after revisions in the same Mongo transaction as the content edit. Automatic content syncs are recorded too. Existing records have no historical revisions until their next write. Actor labels are session-token hash prefixes or `automation`; raw session tokens are never logged. + +Deleting these content records sets optional `deletedAt`; normal reads/counts exclude both newly deleted records and retain compatibility with older Mongo documents that omit the field. Trash shows retained records by collection. Review a revision, compare current/before/after, and explicitly restore a side. If the record changed since review, restoration fails with 409. Every restore creates a new undo revision; conflicting writes or a failed audit insert roll back the transaction. + +The **Download content backup** action exports the 11 content collections (including drafts/Trash/private bounty details) plus the import deduplication ledger. The upload path validates the entire file in a dry run before enabling restore. Restore merges by durable ID, keeps records absent from the file, rejects unique-field/singleton conflicts and records every overwrite. It is atomic; it never partially restores a file. + +Limits: 3 MB / 1,000 records per content backup. Credentials, sessions, login attempts, inbox messages, client requests and old revision history are excluded. Uploaded photos/resumes are URL references, not copied media binaries. Keep downloaded files private. Use the database provider's separate backups and media retention for full disaster recovery or larger datasets. Content history itself is retained without automatic pruning. + +Schema changes: optional `deletedAt` on the 11 content models and a new `ContentRevision` collection with indexes. Run the normal `npx prisma db push` deployment/schema setup to create its indexes; existing content fields need no data rewrite. Prisma generation remains the existing install step. + +## Reproduce verification + +The integration scripts refuse any URL except their exact localhost disposable database. They never fall back to `DATABASE_URL`. + +1. Start a local MongoDB 7 replica set on port 27017 named `rs0`. +2. `npm ci`; `npm run typecheck`; `npm run lint`; `npm test -- --runInBand`. +3. Set `RECOVERY_TEST_DATABASE_URL=mongodb://127.0.0.1:27017/studio_recovery_test?replicaSet=rs0`; run `npm run test:recovery`. +4. Set `INSIGHTS_TEST_DATABASE_URL=mongodb://127.0.0.1:27017/studio_insights_test?replicaSet=rs0`; run `npx tsx scripts/test-insights.ts`. +5. Set `E2E_DATABASE_URL=mongodb://127.0.0.1:27017/studio_e2e_test?replicaSet=rs0`; run `npx tsx scripts/seed-e2e.ts`. +6. Set `DATABASE_URL` to that same e2e database; run `npx prisma db push --skip-generate` and `npm run build`. +7. `npx playwright install --with-deps chromium`; `npm run test:e2e`. The runner starts the production server, uses a fixture PIN, and tests desktop/mobile against real APIs and Mongo. Each browser project resets only synthetic test data, preserving indexes. Screenshots/traces are retained on failure. +8. To measure mobile performance, start the production server on port 3100 with the e2e database and run `node scripts/measure-mobile.cjs`. `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` can select an already installed Chromium. + +CI performs the database integrations and all 12 browser scenarios. Missing-database release refusal is checked explicitly. CI stores browser failure artifacts for seven days. diff --git a/docs/security-insights.md b/docs/security-insights.md index 2f7d985..d039b23 100644 --- a/docs/security-insights.md +++ b/docs/security-insights.md @@ -7,7 +7,7 @@ Uses the official CISA KEV JSON mirror. No AI key, paid scheduler, or publishing - First successful run publishes up to eight briefs from the preceding 30 days, distributed across weeks. Existing manual CVE coverage is skipped. - Subsequent runs publish at most three new briefs per UTC day. Past-month imports also publish automatically. The publishing approval switch has been removed. - On the first successful sync after this update, existing unpublished imported briefs from the past 90 days publish automatically. Archived posts and manual drafts are excluded. Later syncs preserve editorial changes, including deliberate unpublishing. -- Every successful sync archives blog posts older than 90 days using their publication date, or creation date for drafts without a publication date. Archived content is retained in the database and admin blog list, marked with `archivedAt`, and hidden from the homepage, `/blog`, and individual public post URLs. Nothing is permanently deleted. +- Every successful sync archives imported briefs older than 90 days using their publication date, or creation date for drafts without a publication date. Archived content is retained in the database and admin blog list, marked with `archivedAt`, and hidden from the homepage, `/blog`, and individual public post URLs. Nothing is permanently deleted. - Admin → Blog: daily collection switch, Sync now, Import past month, last success and errors. The manual editor still controls manually authored posts. - A shared ten-minute MongoDB lease prevents concurrent cron/admin imports. Automatic retries have a twenty-minute cooldown. The endpoint runs for at most five minutes. Paused collection also pauses automatic archiving; Sync now can still run it. - Stable slugs and a durable CVE ledger prevent duplicates, preserve edits, and keep deleted imported posts from returning. @@ -23,3 +23,5 @@ Daily collection and publishing are enabled by default. Existing pause settings ## Verification Unit tests cover source validation, date windows, budgets, automatic publishing, deletion tracking, lease skips, failures, admin authentication and cron authentication. CI runs `scripts/test-insights.ts` against a disposable MongoDB replica set to verify atomic concurrency, persisted caps, automatic backfill publishing, legacy documents with missing fields, one-time draft release, retained archived content, deletion tracking and editorial preservation. It cannot connect to production. + +Retention applies only to slugs recorded in InsightImport. Original write-ups are never selected by the 90-day automatic archive. diff --git a/e2e/portfolio.spec.ts b/e2e/portfolio.spec.ts new file mode 100644 index 0000000..4849828 --- /dev/null +++ b/e2e/portfolio.spec.ts @@ -0,0 +1,156 @@ +import { execFileSync } from 'node:child_process'; +import { expect, test, type Page } from '@playwright/test'; + +test.beforeAll(() => { execFileSync(process.execPath, ['node_modules/tsx/dist/cli.mjs', 'scripts/seed-e2e.ts'], { env: process.env }); }); + +async function calmVisit(page: Page, path = '/') { + await page.addInitScript(() => { localStorage.setItem('nd-experience-mode', 'safe'); localStorage.setItem('nd-theme-muted-v1', 'true'); }); + await page.goto(path, { waitUntil: 'domcontentloaded' }); +} +async function login(page: Page) { + await calmVisit(page, '/bikram'); + const pin = page.getByLabel('Admin PIN'); + await expect(pin).toBeFocused(); // the login effect confirms hydration before typing + await pin.fill('84627193'); + await expect(page.getByRole('button', { name: 'Authorize', exact: true })).toBeEnabled(); + await page.getByRole('button', { name: 'Authorize', exact: true }).click(); + await expect(page.getByRole('heading', { name: 'Admin console' })).toBeVisible(); +} +async function section(page: Page, name: string, id: string) { + const picker = page.getByRole('combobox', { name: 'Section', exact: true }); + if (await picker.isVisible()) await picker.selectOption(id); + else await page.getByRole('navigation', { name: 'Admin sections' }).getByRole('button', { name: new RegExp(`^${name}(?: \\d+)?$`) }).click(); +} + +test('calm entrance, focus trap, Escape and preference persistence', async ({ page }) => { + await page.emulateMedia({ reducedMotion: 'no-preference' }); + await page.goto('/'); + const dialog = page.getByRole('dialog', { name: 'Choose your experience' }); + await expect(dialog).toBeVisible(); + await expect(page.locator('html')).toHaveClass(/safe-mode/); + await expect(page.getByRole('button', { name: 'Use safe mode', exact: true })).toBeFocused(); + await page.keyboard.press('Shift+Tab'); + await expect(page.getByRole('button', { name: 'Enable glitch effect' })).toBeFocused(); + await page.keyboard.press('Tab'); + await expect(page.getByRole('button', { name: 'Use safe mode', exact: true })).toBeFocused(); + await page.keyboard.press('Escape'); + await expect(dialog).not.toBeVisible(); + await expect(page.locator('main')).toBeFocused(); + await page.reload(); + await expect(dialog).not.toBeVisible(); + await page.emulateMedia({ reducedMotion: 'reduce' }); + await expect(page.locator('html')).toHaveClass(/safe-mode/); +}); + +test('reduced motion wins over an earlier glitch choice', async ({ page }) => { + await page.addInitScript(() => localStorage.setItem('nd-experience-mode', 'glitch')); + await page.goto('/'); + await expect(page.locator('html')).toHaveClass(/safe-mode/); + await expect(page.getByRole('dialog')).not.toBeVisible(); +}); + +test('navigation and project selection work with direct mobile links', async ({ page }, info) => { + await calmVisit(page); + if (info.project.name === 'mobile') { + await page.getByRole('button', { name: 'Open menu' }).click(); + await page.getByRole('dialog').getByRole('link', { name: /Projects/ }).click(); + await expect(page.getByRole('dialog')).not.toBeVisible(); + await expect(page.getByRole('link', { name: 'Source: fixture-repo', exact: true })).toHaveAttribute('href', 'https://github.com/example/fixture'); + await expect(page.getByRole('link', { name: 'Demo: fixture-repo', exact: true })).toHaveAttribute('href', 'https://example.com/demo'); + await page.getByRole('link', { name: 'Details: Browser fixture toolkit', exact: true }).click(); + } else { + await page.locator('header nav').getByRole('link', { name: /Projects/ }).click(); + await page.getByRole('button', { name: /project \/ 02 Browser fixture toolkit/ }).click(); + } + await expect(page.locator('#project-preview')).toContainText('Browser fixture toolkit'); + await expect(page.locator('#project-preview a').filter({ hasText: 'View Project' })).toHaveAttribute('href', 'https://example.com/toolkit'); + await expect(page.locator('body')).toHaveJSProperty('scrollWidth', await page.locator('body').evaluate(node => node.clientWidth)); +}); + +test('blog search, exact tags, pagination, details and SEO', async ({ page, request }) => { + await calmVisit(page, '/blog'); + await expect(page.getByRole('status')).toHaveText('15 articles · Page 1 of 2'); + await expect(page.locator('main a[href^="/blog/browser-article-"]')).toHaveCount(12); + await page.getByRole('link', { name: 'Next page' }).click(); + await expect(page.getByRole('status')).toHaveText('15 articles · Page 2 of 2'); + await page.getByLabel('Search articles').fill('Cryptography'); + await page.getByLabel('Tag', { exact: true }).fill('Crypto'); + await page.getByRole('button', { name: 'Search', exact: true }).click(); + await expect(page.getByRole('status')).toHaveText('7 articles · Page 1 of 1'); + await expect(page.locator('main')).not.toContainText('Private browser draft'); + await page.locator('main a[href^="/blog/browser-article-"]').first().click(); + await expect(page.locator('article')).toContainText('Synthetic article'); + await expect(page.locator('link[rel="canonical"]')).toHaveAttribute('href', /https:\/\/bikram-cyber.vercel.app\/blog\/browser-article-/); + expect(await page.locator('script[type="application/ld+json"]').first().textContent()).toContain('BlogPosting'); + const sitemap = await request.get('/sitemap.xml'); + expect(sitemap.status()).toBe(200); expect(await sitemap.text()).not.toContain('private-browser-draft'); + expect(await (await request.get('/robots.txt')).text()).toContain('Disallow: /api/'); + const privatePage = await request.get('/bikram'); + expect(privatePage.headers()['x-robots-tag']).toContain('noindex'); +}); + +test('contact form submits to the real API and saves to admin inbox', async ({ page }, info) => { + await calmVisit(page, '/#contact'); + await page.getByLabel('Name', { exact: true }).fill('Browser Tester'); + await page.getByRole('textbox', { name: 'Email', exact: true }).fill('browser@example.com'); + const subject = `Browser contact ${info.project.name}`; + await page.getByLabel('Subject', { exact: true }).fill(subject); + await page.getByLabel('Message', { exact: true }).fill('Synthetic local browser message to verify the actual persistence flow.'); + await page.getByRole('button', { name: 'Send Message' }).click(); + await expect(page.getByRole('heading', { name: 'Message Sent!' })).toBeVisible(); + await login(page); await section(page, 'Inbox', 'inbox'); + await expect(page.getByText(subject, { exact: true })).toBeVisible(); +}); + +test('admin create, publish, trash, restore, backup and revoked-session handling', async ({ page, request }, info) => { + expect((await request.get('/api/admin/history')).status()).toBe(401); + expect((await request.get('/api/admin/backup')).status()).toBe(401); + await login(page); + await page.reload(); + await expect(page.getByRole('heading', { name: 'Admin console' })).toBeVisible(); + await section(page, 'Blog', 'blog'); + const title = `Recovery article ${info.project.name}`; + const slug = `recovery-article-${info.project.name}`; + await page.getByRole('button', { name: 'New post', exact: true }).click(); + await page.getByLabel('Title *', { exact: true }).fill(title); + await page.getByLabel('URL slug', { exact: true }).fill(slug); + await page.getByLabel('Content (Markdown)', { exact: true }).fill('## Recovery test\n\nA real browser-created article.'); + await page.getByRole('button', { name: /^Save$/ }).click(); + const row = page.locator('li').filter({ has: page.getByRole('button', { name: `Edit ${title}`, exact: true }) }); + await expect(row).toContainText('Draft'); + expect((await page.request.get(`/blog/${slug}`)).status()).toBe(404); + await row.getByRole('button', { name: `Edit ${title}`, exact: true }).click(); + await page.getByRole('switch', { name: 'Published', exact: true }).click(); + await page.getByRole('button', { name: /^Save$/ }).click(); + await expect(row).toContainText('Published'); + const article = await page.request.get(`/blog/${slug}`); + expect(article.status()).toBe(200); expect(await article.text()).toContain('A real browser-created article.'); + page.on('dialog', dialog => dialog.accept()); + await row.getByRole('button', { name: `Delete ${title}`, exact: true }).click(); + await expect(row).toHaveCount(0); + expect((await page.request.get(`/blog/${slug}`)).status()).toBe(404); + await section(page, 'History & recovery', 'history'); + await page.getByRole('button', { name: 'Trash', exact: true }).click(); + const deletedRow = page.locator('li').filter({ has: page.getByText(title, { exact: true }) }); + await expect(deletedRow).toHaveCount(1); + await deletedRow.getByRole('button', { name: 'Review version', exact: true }).click(); + await page.getByRole('button', { name: 'Restore before version', exact: true }).click(); + await expect(page.getByRole('status').filter({ hasText: 'Version restored' })).toBeVisible(); + expect((await page.request.get(`/blog/${slug}`)).status()).toBe(200); + const downloadPromise = page.waitForEvent('download'); + await page.getByRole('button', { name: 'Download content backup' }).click(); + const download = await downloadPromise; + const stream = await download.createReadStream(); const chunks: Buffer[] = []; + for await (const chunk of stream!) chunks.push(Buffer.from(chunk)); + const backup = Buffer.concat(chunks); + const parsed = JSON.parse(backup.toString()); expect(parsed.format).toBe('own-verse-content'); expect(parsed.collections.AdminCredential).toBeUndefined(); + await page.getByLabel('Choose content backup', { exact: true }).setInputFiles({ name: 'content.json', mimeType: 'application/json', buffer: backup }); + await expect(page.getByText(/records validated. No changes applied/)).toBeVisible(); + await page.getByRole('button', { name: 'Restore validated backup', exact: true }).click(); + await expect(page.getByRole('status').filter({ hasText: 'records restored.' })).toBeVisible(); + // Revoke via the real endpoint while keeping the dashboard mounted. + expect((await page.request.post('/api/admin/logout')).ok()).toBe(true); + await page.getByRole('button', { name: 'Refresh history', exact: true }).click(); + await expect(page.getByLabel('Admin PIN')).toBeVisible(); + await expect(page.getByRole('status').filter({ hasText: 'session expired' })).toBeVisible(); +}); diff --git a/jest.config.js b/jest.config.js index 73b7978..aff43a7 100644 --- a/jest.config.js +++ b/jest.config.js @@ -11,6 +11,7 @@ const customJestConfig = { testEnvironment: 'jsdom', // the standalone build copies package.json into .next/, which Jest's haste map reports as a name collision modulePathIgnorePatterns: ['/.next/'], + testPathIgnorePatterns: ['/node_modules/', '/e2e/'], moduleNameMapper: { '^@/(.*)$': '/src/$1', }, diff --git a/jest.setup.js b/jest.setup.js index c44951a..132bb28 100644 --- a/jest.setup.js +++ b/jest.setup.js @@ -1 +1,8 @@ import '@testing-library/jest-dom' + +// Shared browser media API used by the consent/reduced-motion hook. +if (typeof window !== 'undefined') Object.defineProperty(window, 'matchMedia', { writable: true, value: jest.fn(query => ({ + matches: false, media: query, onchange: null, + addEventListener: jest.fn(), removeEventListener: jest.fn(), + addListener: jest.fn(), removeListener: jest.fn(), dispatchEvent: jest.fn(), +})) }); diff --git a/package-lock.json b/package-lock.json index eeac02d..a5f9fd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,6 +56,7 @@ "zod": "^4.4.3" }, "devDependencies": { + "@playwright/test": "^1.58.2", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.0", "@types/jest": "^30.0.0", @@ -3167,6 +3168,22 @@ "url": "https://opencollective.com/pkgr" } }, + "node_modules/@playwright/test": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz", + "integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@prisma/client": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.14.0.tgz", @@ -11700,6 +11717,52 @@ "pathe": "^2.0.3" } }, + "node_modules/playwright": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", + "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.58.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", + "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", diff --git a/package.json b/package.json index abd589b..bfa51b5 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,11 @@ "prisma:seed": "tsx prisma/seed.ts", "postinstall": "prisma generate", "db:push": "prisma db push", - "github:sync": "tsx scripts/sync-github.ts" + "github:sync": "tsx scripts/sync-github.ts", + "content:check": "tsx scripts/check-content.ts", + "prebuild": "npm run content:check", + "test:e2e": "playwright test", + "test:recovery": "tsx scripts/test-recovery.ts" }, "dependencies": { "@hookform/resolvers": "^5.9.1", @@ -63,6 +67,7 @@ "zod": "^4.4.3" }, "devDependencies": { + "@playwright/test": "^1.58.2", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.0", "@types/jest": "^30.0.0", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..a66c642 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,19 @@ +import { defineConfig, devices } from '@playwright/test'; +import { testDatabase } from './scripts/test-database'; + +const database = testDatabase('e2e'); +export default defineConfig({ + testDir: './e2e', fullyParallel: false, workers: 1, retries: process.env.CI ? 1 : 0, + timeout: 60000, expect: { timeout: 10000 }, + reporter: process.env.CI ? [['list'], ['html', { open: 'never' }]] : 'list', + use: { baseURL: 'http://127.0.0.1:3100', contextOptions: { reducedMotion: 'reduce' }, trace: 'retain-on-failure', screenshot: 'only-on-failure', + launchOptions: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH ? { executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH, args: ['--no-sandbox'] } : {} }, + projects: [ + { name: 'desktop', use: { ...devices['Desktop Chrome'], viewport: { width: 1440, height: 1000 } } }, + { name: 'mobile', use: { ...devices['Pixel 7'], defaultBrowserType: 'chromium' } }, + ], + webServer: { + command: 'npm run start -- -p 3100', url: 'http://127.0.0.1:3100', reuseExistingServer: false, timeout: 120000, + env: { DATABASE_URL: database, ADMIN_PIN: '84627193', GITHUB_USERNAME: 'modhack2003' }, + }, +}); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index afd65ac..5d848dc 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -11,6 +11,7 @@ generator client { // were created before it existed keep loading. model PersonalData { + deletedAt DateTime? id String @id @default(auto()) @map("_id") @db.ObjectId name String title String @@ -26,6 +27,7 @@ model PersonalData { } model Project { + deletedAt DateTime? id String @id @default(auto()) @map("_id") @db.ObjectId title String description String @@ -34,6 +36,7 @@ model Project { } model Skill { + deletedAt DateTime? id String @id @default(auto()) @map("_id") @db.ObjectId languages String[] tools String[] @@ -41,6 +44,7 @@ model Skill { } model Certificate { + deletedAt DateTime? id String @id @default(auto()) @map("_id") @db.ObjectId name String issuer String @@ -49,6 +53,7 @@ model Certificate { } model Education { + deletedAt DateTime? id String @id @default(auto()) @map("_id") @db.ObjectId institution String degree String @@ -56,6 +61,7 @@ model Education { } model Experience { + deletedAt DateTime? id String @id @default(auto()) @map("_id") @db.ObjectId company String role String @@ -69,6 +75,7 @@ model Experience { } model CtfEvent { + deletedAt DateTime? id String @id @default(auto()) @map("_id") @db.ObjectId name String organizer String @@ -81,6 +88,7 @@ model CtfEvent { } model GitHubRepository { + deletedAt DateTime? id String @id @default(auto()) @map("_id") @db.ObjectId githubId Int @unique // GitHub repository ID name String @@ -119,6 +127,7 @@ model GitHubRepository { } model BlogPost { + deletedAt DateTime? id String @id @default(auto()) @map("_id") @db.ObjectId title String slug String @unique @@ -135,6 +144,7 @@ model BlogPost { /// A reported vulnerability shown in the public Hall of Fame. /// When privateProgram is true the program name and link never leave the server. model BountyFinding { + deletedAt DateTime? id String @id @default(auto()) @map("_id") @db.ObjectId title String program String @@ -275,6 +285,7 @@ model InsightImport { /// Shared site-wide playback settings; public visitors can only mute their theme. model SiteAudioConfig { + deletedAt DateTime? id String @id @map("_id") music Float @default(0.75) dialogue Float @default(1) @@ -284,3 +295,19 @@ model SiteAudioConfig { fadeSeconds Float @default(4) enabledDialogueIds String[] } + +/// Append-only content revisions, including reversible trash operations. +model ContentRevision { + id String @id @default(auto()) @map("_id") @db.ObjectId + model String + recordId String + action String + actor String + label String + before Json? + after Json? + createdAt DateTime @default(now()) + + @@index([model, recordId, createdAt]) + @@index([createdAt]) +} diff --git a/public/social-preview.jpg b/public/social-preview.jpg new file mode 100644 index 0000000000000000000000000000000000000000..04382fbf196b577cf1a656f6f69bf9cc31bfe14a GIT binary patch literal 153249 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˖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%0DG9qVk^j__(%Z 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 literal 0 HcmV?d00001 diff --git a/scripts/check-content.ts b/scripts/check-content.ts new file mode 100644 index 0000000..16a18e3 --- /dev/null +++ b/scripts/check-content.ts @@ -0,0 +1,21 @@ +import { PrismaClient } from '@prisma/client'; + +const db = new PrismaClient(); +async function main() { +try { + if (!process.env.DATABASE_URL) throw new Error('DATABASE_URL is required to build public content.'); + const active = { OR: [{ deletedAt: null }, { deletedAt: { isSet: false } }] }; + const [profile, projects, repos] = await Promise.all([ + db.personalData.findFirst({ where: active, select: { name: true, title: true, bio: true } }), + db.project.count({ where: active }), + db.gitHubRepository.count({ where: { AND: [active, { displayInPortfolio: true }] } }), + ]); + if (!profile?.name.trim() || !profile.title.trim() || !profile.bio.trim() || projects + repos < 1) throw new Error('Public content is incomplete: a named profile, title, bio and at least one project/repository are required.'); + console.log(`Content check passed: profile and ${projects + repos} projects/repositories are available.`); +} catch { + console.error('Content check failed. Build stopped to preserve the current deployment. Verify DATABASE_URL, database access, and a populated public profile with at least one project/repository.'); + process.exitCode = 1; +} finally { await db.$disconnect(); } + +} +void main(); diff --git a/scripts/measure-mobile.cjs b/scripts/measure-mobile.cjs new file mode 100644 index 0000000..6759f73 --- /dev/null +++ b/scripts/measure-mobile.cjs @@ -0,0 +1,35 @@ +/* Run after building and starting the synthetic e2e server, never against production. */ +const { chromium, devices } = require('@playwright/test'); +const fs = require('node:fs/promises'); +(async () => { + const browser = await chromium.launch({ executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH || undefined, args: ['--no-sandbox'] }); + try { + const context = await browser.newContext({ ...devices['Pixel 7'], reducedMotion: 'reduce' }); + const page = await context.newPage(); + const session = await context.newCDPSession(page); + await session.send('Network.enable'); + await session.send('Network.emulateNetworkConditions', { offline: false, latency: 150, downloadThroughput: 200000, uploadThroughput: 93750 }); + await session.send('Emulation.setCPUThrottlingRate', { rate: 4 }); + const fonts = new Map(); + session.on('Network.responseReceived', event => { if (event.type === 'Font') fonts.set(event.requestId, { url: event.response.url, bytes: 0 }); }); + session.on('Network.loadingFinished', event => { if (fonts.has(event.requestId)) fonts.get(event.requestId).bytes = event.encodedDataLength; }); + await page.addInitScript(() => { + localStorage.setItem('nd-experience-mode', 'safe'); localStorage.setItem('nd-theme-muted-v1', 'true'); + window.__mobileMetrics = { lcp: 0, cls: 0, tbt: 0 }; + new PerformanceObserver(list => { for (const entry of list.getEntries()) window.__mobileMetrics.lcp = entry.startTime; }).observe({ type: 'largest-contentful-paint', buffered: true }); + new PerformanceObserver(list => { for (const entry of list.getEntries()) if (!entry.hadRecentInput) window.__mobileMetrics.cls += entry.value; }).observe({ type: 'layout-shift', buffered: true }); + new PerformanceObserver(list => { for (const entry of list.getEntries()) window.__mobileMetrics.tbt += Math.max(0, entry.duration - 50); }).observe({ type: 'longtask', buffered: true }); + }); + const errors = []; + page.on('pageerror', error => errors.push(error.message)); + await page.goto('http://127.0.0.1:3100/', { waitUntil: 'domcontentloaded', timeout: 60000 }); + await page.waitForFunction(() => document.fonts.status === 'loaded', { timeout: 20000 }).catch(() => {}); + await page.waitForTimeout(3000); + const metrics = await page.evaluate(() => ({ ...window.__mobileMetrics, navigation: performance.getEntriesByType('navigation').map(n => ({ ttfb: n.responseStart, domContentLoaded: n.domContentLoadedEventEnd })), fontStatus: document.fonts.status, safeMode: document.documentElement.classList.contains('safe-mode'), overflow: document.documentElement.scrollWidth > innerWidth })); + const result = { conditions: 'Chromium Pixel 7 emulation, 4x CPU slowdown, 1.6 Mbps down / 150 ms latency; synthetic local data; laboratory observation, not field Core Web Vitals', ...metrics, fontRequests: fonts.size, fontBytes: [...fonts.values()].reduce((sum, font) => sum + font.bytes, 0), errors }; + await fs.mkdir('test-results', { recursive: true }); + await fs.writeFile('test-results/mobile-performance.json', JSON.stringify(result, null, 2)); + await page.screenshot({ path: 'test-results/mobile-home.png', fullPage: true }); + console.log(JSON.stringify(result, null, 2)); + } finally { await browser.close(); } +})().catch(error => { console.error(error); process.exitCode = 1; }); diff --git a/scripts/seed-e2e.ts b/scripts/seed-e2e.ts new file mode 100644 index 0000000..0887d0d --- /dev/null +++ b/scripts/seed-e2e.ts @@ -0,0 +1,21 @@ +import { Prisma, PrismaClient } from '@prisma/client'; +import { testDatabase } from './test-database'; + +const db = new PrismaClient({ datasourceUrl: testDatabase('e2e') }); +async function seed() { + // Exact allowlisted localhost URL checked above, and only synthetic fixture data is written. + for (const model of Prisma.dmmf.datamodel.models) await db.$runCommandRaw({ delete: model.name, deletes: [{ q: {}, limit: 0 }] }); + await db.personalData.create({ data: { name: 'Bikram Dey', title: 'Cybersecurity Analyst & Penetration Tester', bio: 'Synthetic browser test profile. Not production content.', github: 'https://github.com/modhack2003', linkedin: '', email: 'test@example.com', resumeUrl: '', bountyProfiles: [] } }); + await db.project.createMany({ data: [ + { title: 'Browser fixture scanner', description: 'A local-only test project.', tags: ['Security'], link: 'https://example.com/scanner' }, + { title: 'Browser fixture toolkit', description: 'Another test project.', tags: ['Testing'], link: 'https://example.com/toolkit' }, + ] }); + const now = new Date(); + await db.gitHubRepository.create({ data: { githubId: 1, name: 'fixture-repo', fullName: 'fixture/fixture-repo', description: 'Synthetic repository', htmlUrl: 'https://github.com/example/fixture', cloneUrl: 'https://github.com/example/fixture.git', language: 'TypeScript', topics: ['Security'], customTags: [], stargazersCount: 1, forksCount: 0, createdAt: now, updatedAt: now, pushedAt: now, size: 1, defaultBranch: 'main', visibility: 'public', displayInPortfolio: true, homepage: 'https://example.com/demo' } }); + await db.skill.create({ data: { languages: ['Python'], tools: ['Nmap'], areas: ['Web Security'] } }); + await db.blogPost.createMany({ data: Array.from({ length: 15 }, (_, i) => ({ title: `Browser article ${String(i + 1).padStart(2, '0')}`, slug: `browser-article-${i + 1}`, excerpt: i % 2 ? 'Cryptography field notes' : 'Web security field notes', content: `## Browser test\n\nSynthetic article ${i + 1}.`, tags: [i % 2 ? 'Crypto' : 'Web'], published: true, publishedAt: new Date(now.getTime() - i * 60000) })) }); + await db.blogPost.create({ data: { title: 'Private browser draft', slug: 'private-browser-draft', excerpt: 'Must not leak', content: 'Private draft text', tags: [], published: false } }); + await db.gitHubSyncState.create({ data: { id: 'github', username: 'modhack2003', lastSuccess: now, lastAttempt: now } }); + console.log('Synthetic browser fixtures seeded in disposable studio_e2e_test.'); +} +seed().finally(() => db.$disconnect()).catch(error => { console.error(error); process.exitCode = 1; }); diff --git a/scripts/test-database.ts b/scripts/test-database.ts new file mode 100644 index 0000000..7679faf --- /dev/null +++ b/scripts/test-database.ts @@ -0,0 +1,7 @@ +/** Test scripts never accept production database URLs, including through fallback env vars. */ +export function testDatabase(name: 'e2e' | 'recovery') { + const env = name === 'e2e' ? 'E2E_DATABASE_URL' : 'RECOVERY_TEST_DATABASE_URL'; + const url = process.env[env]; + if (url !== `mongodb://127.0.0.1:27017/studio_${name}_test?replicaSet=rs0`) throw new Error(`Set ${env} to the disposable localhost studio_${name}_test replica-set URL.`); + return url; +} diff --git a/scripts/test-insights.ts b/scripts/test-insights.ts index da7a7f8..f7c12f3 100644 --- a/scripts/test-insights.ts +++ b/scripts/test-insights.ts @@ -29,6 +29,8 @@ async function main() { _id: { $oid: '000000000000000000000001' }, title: 'Old post', slug: 'old-post', excerpt: '', content: 'Retain me', tags: [], published: true, publishedAt: { $date: oldDate.toISOString() }, createdAt: { $date: oldDate.toISOString() }, updatedAt: { $date: oldDate.toISOString() }, }] }); + await db.blogPost.create({ data: { title: 'Old imported brief', slug: 'old-import', excerpt: '', content: 'Retain imported content', tags: [], published: true, publishedAt: oldDate } }); + await db.insightImport.create({ data: { id: 'CVE-2026-99999', postSlug: 'old-import', sourceDate: oldDate } }); const recent = await db.blogPost.findFirstOrThrow({ where: { published: true } }); await db.blogPost.update({ where: { id: recent.id }, data: { published: false, publishedAt: null } }); await db.insightSyncState.update({ where: { id: 'security-insights' }, data: { publishingMigratedAt: null, autoPublish: false } }); @@ -36,8 +38,11 @@ async function main() { assert.equal(migration.archived, 1); assert.equal(migration.published, 1); const old = await db.blogPost.findUniqueOrThrow({ where: { slug: 'old-post' } }); - assert.equal(old.published, false); - assert.ok(old.archivedAt); + assert.equal(old.published, true, 'manual write-ups must survive retention'); + assert.equal(old.archivedAt, null); + const archived = await db.blogPost.findUniqueOrThrow({ where: { slug: 'old-import' } }); + assert.equal(archived.published, false); + assert.ok(archived.archivedAt); assert.equal(old.content, 'Retain me'); assert.equal(await db.insightImport.count({ where: { postSlug: edited.slug } }), 1); await db.blogPost.update({ where: { id: recent.id }, data: { published: false } }); diff --git a/scripts/test-recovery.ts b/scripts/test-recovery.ts new file mode 100644 index 0000000..e121201 --- /dev/null +++ b/scripts/test-recovery.ts @@ -0,0 +1,82 @@ +import assert from 'node:assert/strict'; +import { PrismaClient } from '@prisma/client'; +import { createContentClient, contentTransaction, restoreData, CONTENT_MODELS } from '../src/lib/content-history'; +import { checksum, exportBackup, importBackup, restoreRevision, validateBackup } from '../src/lib/content-recovery'; +import { testDatabase } from './test-database'; + +const raw = new PrismaClient({ datasourceUrl: testDatabase('recovery') }); +const db = createContentClient(raw); +async function main() { + await raw.$runCommandRaw({ dropDatabase: 1 }); + // Create the revision collection/index before transactions (Mongo cannot create collections in all transaction contexts). + await raw.$runCommandRaw({ create: 'ContentRevision' }); + await raw.$runCommandRaw({ createIndexes: 'BlogPost', indexes: [{ key: { slug: 1 }, name: 'BlogPost_slug_key', unique: true }] }); + const project = await db.project.create({ data: { title: 'Version one', description: 'Original', tags: [] } }); + await db.project.update({ where: { id: project.id }, data: { title: 'Version two' } }); + assert.equal(await raw.contentRevision.count(), 2); + await db.project.deleteMany({ where: { id: project.id } }); + assert.equal(await db.project.count(), 0, 'trash must disappear from public/admin reads'); + assert.equal(await db.project.findUnique({ where: { id: project.id } }), null); + assert.ok((await raw.project.findUniqueOrThrow({ where: { id: project.id } })).deletedAt, 'soft deletion must retain original content'); + const deletion = await raw.contentRevision.findFirstOrThrow({ where: { action: 'deleted' } }); + let current = await raw.project.findUnique({ where: { id: project.id } }); + await restoreRevision(raw, deletion.id, 'before', checksum(current), 'test-admin'); + assert.equal((await db.project.findUniqueOrThrow({ where: { id: project.id } })).title, 'Version two'); + await assert.rejects(restoreRevision(raw, deletion.id, 'before', checksum(current), 'test-admin'), /changed/); + // A failing audit insert must roll back its corresponding content edit. + const failing = new Proxy(raw, { get(target, key) { + if (key !== '$transaction') return Reflect.get(target, key); + return (work: (tx: object) => unknown) => raw.$transaction(tx => work(new Proxy(tx, { get(inner, property) { + if (property === 'contentRevision') return { create: () => { throw new Error('forced audit failure'); } }; + return Reflect.get(inner, property); + } })) as never); + } }); + await assert.rejects(createContentClient(failing).project.update({ where: { id: project.id }, data: { title: 'Must roll back' } }), /forced audit failure/); + assert.equal((await raw.project.findUniqueOrThrow({ where: { id: project.id } })).title, 'Version two'); + // The LinkedIn path shares its existing transaction and logs each write once. + await raw.$transaction(async tx => { const client = contentTransaction(tx, 'test-import'); await client.project.create({ data: { title: 'Imported', description: '', tags: [] } }); }); + assert.equal(await raw.contentRevision.count({ where: { actor: 'test-import' } }), 1); + await db.personalData.create({ data: { name: 'Test Operator', title: 'Test', bio: 'Fixture', github: '', linkedin: '', email: 'test@example.com', resumeUrl: '', bountyProfiles: [] } }); + await db.skill.create({ data: { languages: ['Python'], tools: [], areas: [] } }); + await db.blogPost.create({ data: { title: 'Published test', slug: 'published-test', excerpt: '', content: 'Safe content', tags: ['Test'], published: true, publishedAt: new Date() } }); + await db.bountyFinding.create({ data: { title: 'Private finding', program: 'Hidden Program', privateProgram: true } }); + await db.siteAudioConfig.create({ data: { id: 'site-audio', enabledDialogueIds: [] } }); + await raw.insightImport.create({ data: { id: 'CVE-2026-12345', postSlug: 'published-test', sourceDate: new Date() } }); + await db.certificate.create({ data: { name: 'Test certificate', issuer: 'Fixture', year: 2026 } }); + await db.education.create({ data: { institution: 'Fixture university', degree: 'Test degree', duration: '2026' } }); + await db.experience.create({ data: { company: 'Fixture company', role: 'Test role', startDate: new Date() } }); + await db.ctfEvent.create({ data: { name: 'Fixture CTF', organizer: 'Fixture', date: new Date(), categories: ['Web'] } }); + await db.gitHubRepository.create({ data: { githubId: 1, name: 'fixture', fullName: 'fixture/test', htmlUrl: 'https://github.com/example/test', cloneUrl: 'https://github.com/example/test.git', topics: [], customTags: [], createdAt: new Date(), updatedAt: new Date(), pushedAt: new Date(), size: 1, defaultBranch: 'main', visibility: 'public' } }); + const backup = await exportBackup(raw); + const prepared = validateBackup(JSON.parse(JSON.stringify(backup))); + assert.throws(() => validateBackup({ ...backup, collections: { ...backup.collections, AdminCredential: [] } }), /supported/); + assert.throws(() => restoreData('Project', { id: project.id, title: 'Bad', description: '', tags: [], deletedAt: 'not-a-date' }), /Invalid/); + const beforeRows = await raw.project.findMany(); + // Simulate a fresh content database by removing only the exact test collections. + for (const model of CONTENT_MODELS) { + const collection = model; + await raw.$runCommandRaw({ delete: collection, deletes: [{ q: {}, limit: 0 }] }); + } + await raw.insightImport.deleteMany(); + await importBackup(raw, prepared, 'test-recovery'); + assert.equal(await raw.project.count(), beforeRows.length); + for (const model of CONTENT_MODELS) { + const delegate = (raw as unknown as Record }>)[model[0].toLowerCase() + model.slice(1)]; + assert.ok(await delegate.count(), `${model} must round-trip`); + } + current = await raw.project.findUnique({ where: { id: project.id } }); + assert.equal(current?.title, 'Version two'); + assert.equal(await raw.insightImport.count(), 1); + assert.equal((await db.bountyFinding.findFirstOrThrow()).privateProgram, true); + assert.equal((await db.siteAudioConfig.findUniqueOrThrow({ where: { id: 'site-audio' } })).music, 0.75); + assert.ok(await raw.contentRevision.count({ where: { action: 'backup-restored' } })); + assert.equal(await raw.adminCredential.count(), 0); + // A conflicting slug rolls back every earlier row from the same backup. + const copy = JSON.parse(JSON.stringify(backup)); + copy.collections.Project[0].title = 'Must not persist'; + copy.collections.BlogPost[0].id = '000000000000000000000099'; + await assert.rejects(importBackup(raw, validateBackup(copy), 'test-conflict')); + assert.equal((await raw.project.findUniqueOrThrow({ where: { id: project.id } })).title, 'Version two'); + console.log('Content recovery Mongo integration passed: atomic history, audit failure rollback, soft delete, stale restore rejection, import history, backup round trip, private content, ledger, and conflicting restore rollback.'); +} +main().finally(() => raw.$disconnect()).catch(error => { console.error(error); process.exitCode = 1; }); diff --git a/src/app/api/admin/backup/route.ts b/src/app/api/admin/backup/route.ts new file mode 100644 index 0000000..caca1d8 --- /dev/null +++ b/src/app/api/admin/backup/route.ts @@ -0,0 +1,37 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { rawPrisma } from '@/lib/prisma'; +import { requireAdminSession } from '@/lib/admin-auth'; +import { jsonError, revalidatePublic } from '@/lib/api'; +import { contentActor } from '@/lib/content-history'; +import { exportBackup, importBackup, MAX_BACKUP_BYTES, validateBackup } from '@/lib/content-recovery'; + +export const dynamic = 'force-dynamic'; +export const maxDuration = 60; +export async function GET(request: NextRequest) { + const denied = await requireAdminSession(request); if (denied) return denied; + try { + const backup = await exportBackup(rawPrisma); + return NextResponse.json(backup, { headers: { 'Cache-Control': 'private, no-store', 'Content-Disposition': `attachment; filename="own-verse-content-${new Date().toISOString().slice(0, 10)}.json"` } }); + } catch { return jsonError('Could not export content. Check the database connection and the 1,000-record / 3 MB backup limits.', 503); } +} +export async function POST(request: NextRequest) { + const denied = await requireAdminSession(request); if (denied) return denied; + if (Number(request.headers.get('content-length')) > MAX_BACKUP_BYTES) return jsonError('Backup too large (max 3 MB).', 413); + let prepared; + try { + // Bound the stream as well as Content-Length; a client can omit that header. + const reader = request.body?.getReader(); if (!reader) return jsonError('Backup required', 400); + const chunks: Uint8Array[] = []; let bytes = 0; + try { for (;;) { const { value, done } = await reader.read(); if (done) break; bytes += value.byteLength; if (bytes > MAX_BACKUP_BYTES) return jsonError('Backup too large (max 3 MB).', 413); chunks.push(value); } } + finally { await reader.cancel(); } + const body = JSON.parse(Buffer.concat(chunks).toString('utf8')); + // Dry-run validates every record before making the restore button available. + prepared = validateBackup(body); + } catch { return jsonError('Invalid content backup. No records were changed.', 400); } + if (request.nextUrl.searchParams.get('preview') === 'true') return NextResponse.json({ records: prepared.count, collections: prepared.collections.map(({ model, rows }) => ({ model, count: rows.length })) }, { headers: { 'Cache-Control': 'private, no-store' } }); + try { + const result = await importBackup(rawPrisma, prepared, await contentActor()); + revalidatePublic(); + return NextResponse.json(result, { headers: { 'Cache-Control': 'private, no-store' } }); + } catch { return jsonError('Restore failed and was rolled back. Check for conflicting unique fields or database availability.', 409); } +} diff --git a/src/app/api/admin/history/route.ts b/src/app/api/admin/history/route.ts new file mode 100644 index 0000000..5b37e55 --- /dev/null +++ b/src/app/api/admin/history/route.ts @@ -0,0 +1,55 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { rawPrisma } from '@/lib/prisma'; +import { requireAdminSession } from '@/lib/admin-auth'; +import { handleError, jsonError, OBJECT_ID, readJson, revalidatePublic } from '@/lib/api'; +import { contentActor, contentDelegate, isContentModel } from '@/lib/content-history'; +import { checksum, RecoveryConflict, restoreRevision } from '@/lib/content-recovery'; + +export const dynamic = 'force-dynamic'; +const headers = { 'Cache-Control': 'private, no-store' }; +export async function GET(request: NextRequest) { + const denied = await requireAdminSession(request); if (denied) return denied; + try { + const id = request.nextUrl.searchParams.get('id'); + if (id) { + if (!OBJECT_ID.test(id)) return jsonError('Invalid revision id', 400); + const revision = await rawPrisma.contentRevision.findUnique({ where: { id } }); + if (!revision || !isContentModel(revision.model)) return jsonError('Revision not found', 404); + const current = await contentDelegate(rawPrisma, revision.model).findFirst({ where: { id: revision.recordId } }); + return NextResponse.json({ revision, current, expected: checksum(current) }, { headers }); + } + const model = request.nextUrl.searchParams.get('model'); + if (model && !isContentModel(model)) return jsonError('Invalid collection', 400); + const page = Math.max(1, Math.min(10000, Number(request.nextUrl.searchParams.get('page')) || 1)); + if (request.nextUrl.searchParams.get('trash') === 'true') { + if (!model || !isContentModel(model)) return jsonError('Choose a trash collection', 400); + const delegate = contentDelegate(rawPrisma, model); + const where = { deletedAt: { not: null } }; + const [rows, total] = await Promise.all([delegate.findMany({ where, orderBy: { deletedAt: 'desc' }, skip: (Math.floor(page) - 1) * 30, take: 30 }), delegate.count({ where })]); + const items = await Promise.all(rows.map(async row => { + const revision = await rawPrisma.contentRevision.findFirst({ where: { model, recordId: row.id, action: 'deleted' }, orderBy: { createdAt: 'desc' }, select: { id: true } }); + return { id: revision?.id ?? '', model, recordId: row.id, action: 'deleted', actor: '', label: String(row.title ?? row.name ?? model), createdAt: row.deletedAt }; + })); + return NextResponse.json({ items, total, page: Math.floor(page) }, { headers }); + } + const where = model ? { model } : {}; + const [items, total] = await Promise.all([ + rawPrisma.contentRevision.findMany({ where, orderBy: [{ createdAt: 'desc' }, { id: 'desc' }], skip: (Math.floor(page) - 1) * 30, take: 30, select: { id: true, model: true, recordId: true, action: true, actor: true, label: true, createdAt: true } }), + rawPrisma.contentRevision.count({ where }), + ]); + return NextResponse.json({ items, total, page: Math.floor(page) }, { headers }); + } catch (error) { return handleError(error, 'Content history'); } +} +export async function POST(request: NextRequest) { + const denied = await requireAdminSession(request); if (denied) return denied; + const body = await readJson(request) as { id?: string; side?: string; expected?: string } | undefined; + if (!body?.id || !OBJECT_ID.test(body.id) || !['before', 'after'].includes(body.side ?? '') || !/^[a-f0-9]{64}$/.test(body.expected ?? '')) return jsonError('Invalid restore request', 400); + try { + await restoreRevision(rawPrisma, body.id, body.side as 'before' | 'after', body.expected!, await contentActor()); + revalidatePublic(); + return NextResponse.json({ success: true }, { headers }); + } catch (error) { + if (error instanceof RecoveryConflict) return jsonError(error.message, 409); + return handleError(error, 'Content restore'); + } +} diff --git a/src/app/api/import/linkedin/route.ts b/src/app/api/import/linkedin/route.ts index 5fa6070..bd32667 100644 --- a/src/app/api/import/linkedin/route.ts +++ b/src/app/api/import/linkedin/route.ts @@ -1,5 +1,6 @@ +import { contentTransaction, contentActor } from '@/lib/content-history'; import { NextRequest, NextResponse } from 'next/server'; -import { prisma } from '@/lib/prisma'; +import { prisma, rawPrisma } from '@/lib/prisma'; import { requireAdminSession } from '@/lib/admin-auth'; import { handleError, jsonError, readJson, revalidatePublic } from '@/lib/api'; import { importLinkedIn, parseLinkedInExport } from '@/lib/linkedin-import'; @@ -44,9 +45,10 @@ export async function POST(request: NextRequest) { overwriteProfile: body.overwriteProfile !== false, }; // A preview never writes; a real import commits all sections together. + const actor = await contentActor(); const summary = options.dryRun ? await importLinkedIn(prisma, parsed, options) - : await prisma.$transaction((tx) => importLinkedIn(tx, parsed, options), { timeout: 45_000 }); + : await rawPrisma.$transaction((tx) => importLinkedIn(contentTransaction(tx, actor), parsed, options), { timeout: 45_000 }); if (!summary.dryRun) revalidatePublic(); return NextResponse.json({ success: true, summary }); } catch (error) { diff --git a/src/app/api/site-audio/__tests__/route.test.ts b/src/app/api/site-audio/__tests__/route.test.ts index cff2b8f..91dffa2 100644 --- a/src/app/api/site-audio/__tests__/route.test.ts +++ b/src/app/api/site-audio/__tests__/route.test.ts @@ -21,10 +21,10 @@ test('public read returns defaults before the first admin save; writes require a }); test('admin saves a durable singleton; a separate public read receives the saved settings only', async () => { const config = { ...DEFAULT_AUDIO_SETTINGS, music: 0.3, intervalSeconds: 35, enabledDialogueIds: [] }; - jest.mocked(prisma.siteAudioConfig.upsert).mockResolvedValue({ id: 'site-audio', ...config }); + jest.mocked(prisma.siteAudioConfig.upsert).mockResolvedValue({ id: 'site-audio', deletedAt: null, ...config }); expect((await PUT(req(config))).status).toBe(200); expect(prisma.siteAudioConfig.upsert).toHaveBeenCalledWith({ where: { id: 'site-audio' }, update: config, create: { id: 'site-audio', ...config } }); - jest.mocked(prisma.siteAudioConfig.findUnique).mockResolvedValue({ id: 'site-audio', ...config }); + jest.mocked(prisma.siteAudioConfig.findUnique).mockResolvedValue({ id: 'site-audio', deletedAt: null, ...config }); expect(await (await GET()).json()).toEqual(config); }); test.each([{ music: 2 }, { intervalSeconds: 0 }, { fadeSeconds: -1 }, { enabledDialogueIds: ['external'] }, { enabledDialogueIds: ['pain', 'pain'] }, { src: 'https://example.com/file.mp3' }])('rejects malformed settings %o', async patch => { diff --git a/src/app/blog/[slug]/page.tsx b/src/app/blog/[slug]/page.tsx index 53212d3..587ff92 100644 --- a/src/app/blog/[slug]/page.tsx +++ b/src/app/blog/[slug]/page.tsx @@ -1,24 +1,19 @@ +import { cache } from 'react'; +import { jsonLd, publicMetadata, SITE_URL } from '@/lib/seo'; import Link from 'next/link'; import { notFound } from 'next/navigation'; import { ArrowLeft } from 'lucide-react'; import { HeaderNav } from '@/components/header-nav'; import { Markdown } from '@/lib/markdown'; import { prisma } from '@/lib/prisma'; -import { getHiddenSections, isBuildPhase, readTime } from '@/lib/portfolio-data'; +import { getHiddenSections, readTime } from '@/lib/portfolio-data'; export const revalidate = 60; export const dynamicParams = true; type Props = { params: Promise<{ slug: string }> }; -async function getPost(slug: string) { - try { - return await prisma.blogPost.findFirst({ where: { slug, published: true } }); - } catch (error) { - if (isBuildPhase()) return null; - throw error; - } -} +const getPost = cache((slug: string) => prisma.blogPost.findFirst({ where: { slug, published: true } })); export async function generateStaticParams() { return []; @@ -27,8 +22,9 @@ export async function generateStaticParams() { export async function generateMetadata({ params }: Props) { const { slug } = await params; const post = await getPost(slug); - if (!post) return { title: 'Not found' }; - return { title: `${post.title} | Blog`, description: post.excerpt || undefined }; + if (!post) return { title: 'Not found', robots: { index: false, follow: false } }; + const metadata = publicMetadata(`${post.title} | Bikram Dey`, post.excerpt, `/blog/${encodeURIComponent(post.slug)}`); + return { ...metadata, openGraph: { ...metadata.openGraph, type: 'article', publishedTime: post.publishedAt?.toISOString(), modifiedTime: post.updatedAt.toISOString(), authors: ['Bikram Dey'], tags: post.tags } }; } export default async function BlogPostPage({ params }: Props) { @@ -43,7 +39,8 @@ export default async function BlogPostPage({ params }: Props) { return (