diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000..96cc8b6
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,7 @@
+{
+ "recommendations": [
+ "eamodio.gitlens"
+ ]
+}
+
+
diff --git a/README.md b/README.md
index 3f27d18..87a4e82 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,12 @@
-

+

- # Focal Finance Tracker
+ # FinanceMate
A modern, privacy-focused expense tracking Progressive Web App (PWA) with AI-powered receipt scanning.

-[](https://focal.creative-geek.tech)
[]()
@@ -34,8 +33,8 @@ A modern, privacy-focused expense tracking Progressive Web App (PWA) with AI-pow
```bash
# Clone repository
-git clone https://github.com/Creative-Geek/Focal.git
-cd Focal
+git clone https://github.com/yourusername/FinanceMate.git
+cd FinanceMate
# Install dependencies
pnpm install
@@ -101,8 +100,8 @@ Built with [React](https://react.dev), [Cloudflare](https://cloudflare.com), [sh
-**[Live Demo](https://focal.creative-geek.tech)** • **[Documentation](docs/DEVELOPMENT.md)** • **[Report Bug](https://github.com/Creative-Geek/Focal/issues)**
+**[Documentation](docs/DEVELOPMENT.md)** • **[Report Bug](https://github.com/yourusername/FinanceMate/issues)**
-Made with ❤️ by Creative Geek
+Track smarter, spend better 💙
diff --git a/e2e/user-flow.spec.ts b/e2e/user-flow.spec.ts
new file mode 100644
index 0000000..6f58d9f
--- /dev/null
+++ b/e2e/user-flow.spec.ts
@@ -0,0 +1,142 @@
+import { test, expect } from '@playwright/test';
+
+test.describe('User Flow', () => {
+ test('should allow user to login and see dashboard', async ({ page }) => {
+ // Mock login API
+ await page.route('**/api/auth/login', async route => {
+ await route.fulfill({
+ status: 200,
+ contentType: 'application/json',
+ body: JSON.stringify({ token: 'fake-jwt-token', user: { id: 1, email: 'test@example.com' } }),
+ });
+ });
+
+ // Mock expenses API (empty list initially)
+ await page.route('**/api/expenses', async route => {
+ await route.fulfill({
+ status: 200,
+ contentType: 'application/json',
+ body: JSON.stringify([]),
+ });
+ });
+
+ // Mock User API if needed (often checked on load)
+ await page.route('**/api/auth/me', async route => {
+ await route.fulfill({
+ status: 200,
+ contentType: 'application/json',
+ body: JSON.stringify({ id: 1, email: 'test@example.com' }),
+ });
+ });
+
+ await page.goto('/login');
+
+ // Fill login form
+ await page.getByLabel('Email').fill('test@example.com');
+ await page.getByLabel('Password').fill('password123');
+ await page.getByRole('button', { name: 'Sign in' }).click();
+
+ // Verify redirect to dashboard
+ await expect(page).toHaveURL('/');
+ await expect(page.getByText('Current Balance')).toBeVisible();
+ });
+
+ test('should allow adding an expense', async ({ page }) => {
+ // Mock APIs
+ await page.route('**/api/auth/me', async route => {
+ await route.fulfill({
+ status: 200,
+ contentType: 'application/json',
+ body: JSON.stringify({ id: 1, email: 'test@example.com' }),
+ });
+ });
+
+ await page.route('**/api/expenses', async route => {
+ if (route.request().method() === 'GET') {
+ await route.fulfill({
+ status: 200,
+ contentType: 'application/json',
+ body: JSON.stringify([]),
+ });
+ } else if (route.request().method() === 'POST') {
+ await route.fulfill({
+ status: 201,
+ contentType: 'application/json',
+ body: JSON.stringify({ id: 101, amount: 50, description: 'Lunch', date: new Date().toISOString() }),
+ });
+ }
+ });
+
+ // Bypass login by setting token (if app checks localstorage on load)
+ // Or just re-login. Re-login is safer with mocks.
+ await page.route('**/api/auth/login', async route => {
+ await route.fulfill({
+ status: 200,
+ contentType: 'application/json',
+ body: JSON.stringify({ token: 'fake-jwt-token', user: { id: 1, email: 'test@example.com' } }),
+ });
+ });
+
+ await page.goto('/login');
+ await page.getByLabel('Email').fill('test@example.com');
+ await page.getByLabel('Password').fill('password123');
+ await page.getByRole('button', { name: 'Sign in' }).click();
+ await expect(page).toHaveURL('/');
+
+ // Add Expense interaction
+ // Assuming there is a button to add expense.
+ // I need to know the UI. Usually a "+" button or "Add Expense".
+ // I will check the dashboard code or guess.
+ // Based on README images, there's likely an "Add Expense" button.
+
+ // For now, I'll pause there or look for the button.
+ // Let's assume there is an "Add Expense" button text or label.
+ // I'll wait for selector or just generic text.
+
+ // Looking at AddExpenseMenu.tsx might help knowing the trigger.
+ // But I'll write the test up to login for now and verify, then refine.
+ // Actually, I should write the full test if possible.
+ // I'll check AddExpenseMenu.tsx content quickly in next step if needed, but I'll write a basic check first.
+
+ const addBtn = page.getByRole('button', { name: /add expense/i });
+ await expect(addBtn).toBeVisible();
+ await addBtn.click();
+
+ // Choose Manual Entry
+ await page.getByRole('button', { name: /manual entry/i }).click();
+
+ // Fill form
+ await page.locator('#merchant').fill('Coffee Shop');
+ await page.locator('#total').fill('5.50');
+ // Date defaults to today usually, but let's leave it or fill it if key
+
+ // Select Category (shadcn select)
+ await page.getByRole('combobox').click();
+ await page.getByRole('option', { name: 'Food & Drink' }).click();
+
+ // Mock Save API
+ await page.route('**/api/expenses', async route => {
+ // Handle both GET (refresh) and POST (save)
+ if (route.request().method() === 'GET') {
+ await route.fulfill({
+ status: 200,
+ contentType: 'application/json',
+ body: JSON.stringify([{ id: 101, amount: 5.5, total: 5.5, merchant: 'Coffee Shop', category: 'Food & Drink', date: new Date().toISOString(), currency: 'USD' }]),
+ });
+ } else if (route.request().method() === 'POST') {
+ await route.fulfill({
+ status: 201,
+ contentType: 'application/json',
+ body: JSON.stringify({ success: true, data: { id: 101 } }),
+ });
+ }
+ });
+
+ // Click Save
+ await page.getByRole('button', { name: /save expense/i }).click();
+
+ // Verify expense appears (via GET mock)
+ await expect(page.getByText('Coffee Shop')).toBeVisible();
+ await expect(page.getByText('$5.50')).toBeVisible();
+ });
+});
diff --git a/index.html b/index.html
index 029d135..51f42ad 100644
--- a/index.html
+++ b/index.html
@@ -1,93 +1,57 @@
-
-
-
-
-
-
-
- Focal: AI-Powered Expense Tracker & Receipt Scanner
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+ FinanceMate: AI Expense Tracker
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+