From 29a0510192b5d2b60273776bc53a7a60c5c9759b Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 17 Feb 2026 22:48:22 +0200 Subject: [PATCH] docs: add Clients view and NavRail reorg implementation plan --- ...ients-view-navrail-reorg-implementation.md | 680 ++++++++++++++++++ 1 file changed, 680 insertions(+) create mode 100644 docs/plans/2026-02-17-clients-view-navrail-reorg-implementation.md diff --git a/docs/plans/2026-02-17-clients-view-navrail-reorg-implementation.md b/docs/plans/2026-02-17-clients-view-navrail-reorg-implementation.md new file mode 100644 index 0000000..0040ffc --- /dev/null +++ b/docs/plans/2026-02-17-clients-view-navrail-reorg-implementation.md @@ -0,0 +1,680 @@ +# Clients View & NavRail Reorganization Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Add a Clients management view with billing details and reorder the NavRail into a logical workflow. + +**Architecture:** Backend-first approach — migrate the database schema, update Rust structs/queries, expand the TypeScript store, then build the frontend view and update navigation. The Clients.vue view follows the same card-grid + dialog pattern established by Projects.vue. + +**Tech Stack:** Tauri v2 (Rust + SQLite), Vue 3 Composition API, Tailwind CSS v4 with @theme tokens, Lucide icons, Pinia stores, vue-router + +--- + +### Task 1: Database migration — add new columns to clients table + +**Files:** +- Modify: `src-tauri/src/database.rs:1-118` + +**Step 1: Add ALTER TABLE statements after the existing table creation** + +After the `CREATE TABLE IF NOT EXISTS clients` block (line 13), add 5 `ALTER TABLE ADD COLUMN` statements. These use `ALTER TABLE ... ADD COLUMN` which is safe to re-run because SQLite will error on duplicate columns — wrap each in a closure that ignores "duplicate column" errors. + +Add this code after line 13 (after the `?;` that closes the clients CREATE TABLE): + +```rust +// Migrate clients table — add new columns (safe to re-run) +let migration_columns = [ + "ALTER TABLE clients ADD COLUMN company TEXT", + "ALTER TABLE clients ADD COLUMN phone TEXT", + "ALTER TABLE clients ADD COLUMN tax_id TEXT", + "ALTER TABLE clients ADD COLUMN payment_terms TEXT", + "ALTER TABLE clients ADD COLUMN notes TEXT", +]; +for sql in &migration_columns { + match conn.execute(sql, []) { + Ok(_) => {} + Err(e) => { + let msg = e.to_string(); + if !msg.contains("duplicate column") { + return Err(e); + } + } + } +} +``` + +**Step 2: Build to verify migration compiles** + +Run: `cd src-tauri && cargo check` +Expected: compiles with no errors + +**Step 3: Commit** + +```bash +git add src-tauri/src/database.rs +git commit -m "feat: add migration for new client billing columns" +``` + +--- + +### Task 2: Expand Rust Client struct and update all CRUD queries + +**Files:** +- Modify: `src-tauri/src/commands.rs:6-99` (Client struct + 4 commands) +- Modify: `src-tauri/src/commands.rs:382-457` (export_data) + +**Step 1: Expand the Client struct** + +Replace the existing `Client` struct (lines 7-12) with: + +```rust +#[derive(Debug, Serialize, Deserialize)] +pub struct Client { + pub id: Option, + pub name: String, + pub email: Option, + pub address: Option, + pub company: Option, + pub phone: Option, + pub tax_id: Option, + pub payment_terms: Option, + pub notes: Option, +} +``` + +**Step 2: Update `get_clients` query (line 62)** + +Replace the SELECT and row mapping: + +```rust +let mut stmt = conn.prepare( + "SELECT id, name, email, address, company, phone, tax_id, payment_terms, notes FROM clients ORDER BY name" +).map_err(|e| e.to_string())?; +let clients = stmt.query_map([], |row| { + Ok(Client { + id: Some(row.get(0)?), + name: row.get(1)?, + email: row.get(2)?, + address: row.get(3)?, + company: row.get(4)?, + phone: row.get(5)?, + tax_id: row.get(6)?, + payment_terms: row.get(7)?, + notes: row.get(8)?, + }) +}).map_err(|e| e.to_string())?; +``` + +**Step 3: Update `create_client` INSERT (line 77-80)** + +```rust +conn.execute( + "INSERT INTO clients (name, email, address, company, phone, tax_id, payment_terms, notes) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)", + params![client.name, client.email, client.address, client.company, client.phone, client.tax_id, client.payment_terms, client.notes], +).map_err(|e| e.to_string())?; +``` + +**Step 4: Update `update_client` UPDATE (line 87-89)** + +```rust +conn.execute( + "UPDATE clients SET name = ?1, email = ?2, address = ?3, company = ?4, phone = ?5, tax_id = ?6, payment_terms = ?7, notes = ?8 WHERE id = ?9", + params![client.name, client.email, client.address, client.company, client.phone, client.tax_id, client.payment_terms, client.notes, client.id], +).map_err(|e| e.to_string())?; +``` + +**Step 5: Update `export_data` clients query (lines 386-397)** + +Replace the clients block inside `export_data`: + +```rust +let clients = { + let mut stmt = conn.prepare("SELECT id, name, email, address, company, phone, tax_id, payment_terms, notes FROM clients").map_err(|e| e.to_string())?; + let rows: Vec = stmt.query_map([], |row| { + Ok(serde_json::json!({ + "id": row.get::<_, i64>(0)?, + "name": row.get::<_, String>(1)?, + "email": row.get::<_, Option>(2)?, + "address": row.get::<_, Option>(3)?, + "company": row.get::<_, Option>(4)?, + "phone": row.get::<_, Option>(5)?, + "tax_id": row.get::<_, Option>(6)?, + "payment_terms": row.get::<_, Option>(7)?, + "notes": row.get::<_, Option>(8)? + })) + }).map_err(|e| e.to_string())?.collect::, _>>().map_err(|e| e.to_string())?; + rows +}; +``` + +**Step 6: Build to verify everything compiles** + +Run: `cd src-tauri && cargo check` +Expected: compiles with no errors + +**Step 7: Commit** + +```bash +git add src-tauri/src/commands.rs +git commit -m "feat: expand Client struct with billing fields and update all queries" +``` + +--- + +### Task 3: Expand TypeScript Client interface in the Pinia store + +**Files:** +- Modify: `src/stores/clients.ts:5-10` + +**Step 1: Add new optional fields to the Client interface** + +Replace the existing `Client` interface (lines 5-10) with: + +```typescript +export interface Client { + id?: number + name: string + email?: string + address?: string + company?: string + phone?: string + tax_id?: string + payment_terms?: string + notes?: string +} +``` + +No other changes needed — the store's `createClient`, `updateClient`, `fetchClients` all pass/receive `Client` objects, so the new fields flow through automatically. + +**Step 2: Verify the frontend builds** + +Run: `npm run build` +Expected: builds with no errors + +**Step 3: Commit** + +```bash +git add src/stores/clients.ts +git commit -m "feat: expand Client interface with billing fields" +``` + +--- + +### Task 4: Add /clients route to the router + +**Files:** +- Modify: `src/router/index.ts` + +**Step 1: Add the clients route** + +Insert the clients route between the `/timer` and `/projects` routes (between lines 16 and 17): + +```typescript +{ + path: '/clients', + name: 'Clients', + component: () => import('../views/Clients.vue') +}, +``` + +The full routes array will now be: `/` (Dashboard), `/timer` (Timer), `/clients` (Clients), `/projects` (Projects), `/entries` (Entries), `/reports` (Reports), `/invoices` (Invoices), `/settings` (Settings). + +**Step 2: Commit** + +```bash +git add src/router/index.ts +git commit -m "feat: add /clients route" +``` + +--- + +### Task 5: Reorder NavRail and add Clients entry + +**Files:** +- Modify: `src/components/NavRail.vue` + +**Step 1: Add `Users` to the Lucide import** + +Replace the import block (lines 6-13) with: + +```typescript +import { + LayoutDashboard, + Clock, + Users, + FolderKanban, + List, + BarChart3, + FileText, + Settings +} from 'lucide-vue-next' +``` + +**Step 2: Reorder the navItems array** + +Replace the `navItems` array (lines 19-27) with the new workflow order: + +```typescript +const navItems = [ + { name: 'Dashboard', path: '/', icon: LayoutDashboard }, + { name: 'Timer', path: '/timer', icon: Clock }, + { name: 'Clients', path: '/clients', icon: Users }, + { name: 'Projects', path: '/projects', icon: FolderKanban }, + { name: 'Entries', path: '/entries', icon: List }, + { name: 'Invoices', path: '/invoices', icon: FileText }, + { name: 'Reports', path: '/reports', icon: BarChart3 }, + { name: 'Settings', path: '/settings', icon: Settings } +] +``` + +Note: Invoices moved before Reports (bill clients, then analyze). + +**Step 3: Verify the frontend builds** + +Run: `npm run build` +Expected: builds with no errors (will warn about missing Clients.vue — that's fine, it's lazy-loaded) + +**Step 4: Commit** + +```bash +git add src/components/NavRail.vue +git commit -m "feat: reorder NavRail and add Clients entry" +``` + +--- + +### Task 6: Create Clients.vue — card grid, empty state, and base layout + +**Files:** +- Create: `src/views/Clients.vue` + +**Step 1: Create the Clients view** + +Create `src/views/Clients.vue` following the Projects.vue pattern exactly. The view has: + +- Header with "Clients" title and "+ Add" button +- Card grid (1-3 columns responsive) showing: name (bold), company subtitle (if set), email (tertiary) +- Hover reveals edit/delete icons (same SVG icons as Projects.vue) +- Empty state with `Users` icon, "No clients yet" message, and "Create Client" CTA +- Create/Edit dialog with two sections: + - **Contact Info**: Name (required), Email, Phone, Address (textarea) + - **Billing Details** (collapsible): Company, Tax ID, Payment Terms, Notes (textarea) +- Delete confirmation dialog (same pattern as Projects) + +```vue +