Initial commit: Brachnha Insight project setup

- Next.js 14+ with App Router and TypeScript
- Tailwind CSS and ShadCN UI styling
- Zustand state management
- Dexie.js for IndexedDB (local-first data)
- Auth.js v5 for authentication
- BMAD framework integration

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Max
2026-01-26 12:28:43 +07:00
commit 3fbbb1a93b
812 changed files with 150531 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
import { expect } from '@playwright/test';
import { test } from '../support/fixtures/offline.fixture';
test.describe('Offline Action Queueing', () => {
test('should enqueue SAVE_DRAFT action when offline', async ({ offlineControl, page }) => {
// GIVEN: App is loaded
await page.goto('/');
await page.waitForFunction(() => (window as any).db !== undefined && (window as any).DraftService !== undefined, { timeout: 10000 });
// GIVEN: App goes offline
await offlineControl.goOffline(page.context());
// WHEN: DraftService.saveDraft is called (Service Integration)
await page.evaluate(async () => {
// @ts-ignore
await window.DraftService.saveDraft({
title: 'Offline Draft',
content: 'Content written offline',
tags: [],
createdAt: Date.now(),
status: 'draft',
sessionId: 'test-session'
});
});
// THEN: 'syncQueue' table has 1 item
const queueCount = await page.evaluate(async () => {
// @ts-ignore
return await window.db.syncQueue.count();
});
expect(queueCount).toBe(1);
const firstItem = await page.evaluate(async () => {
// @ts-ignore
return await window.db.syncQueue.orderBy('createdAt').first();
});
expect(firstItem.action).toBe('saveDraft');
expect(firstItem.payload.draftData.title).toBe('Offline Draft');
});
test('should enqueue DELETE_ENTRY action when offline', async ({ offlineControl, page }) => {
// GIVEN: App is loaded and has an entry
await page.goto('/');
await page.waitForFunction(() => (window as any).db !== undefined && (window as any).DraftService !== undefined, { timeout: 10000 });
// Setup entry
const draftId = await page.evaluate(async () => {
// @ts-ignore
const id = await window.db.drafts.add({
title: 'To Delete',
content: 'Delete me',
tags: [],
createdAt: Date.now(),
status: 'draft',
sessionId: 'test-session'
});
return id;
});
await offlineControl.goOffline(page.context());
// WHEN: DraftService.deleteDraft is called
await page.evaluate(async (id) => {
// @ts-ignore
await window.DraftService.deleteDraft(id);
}, draftId);
// THEN: SyncQueue has delete action
const lastItem = await page.evaluate(async () => {
// @ts-ignore
return await window.db.syncQueue.orderBy('createdAt').last();
});
expect(lastItem.action).toBe('deleteDraft');
expect(lastItem.payload.draftId).toBe(draftId);
});
});