Files
GitPulse/_bmad-output/implementation-artifacts/1-1-app-shell-first-launch-experience.md
sepehr 4f7e808855 Initial commit: GitPulse project scaffold
Next.js dashboard with git statistics, AI-powered summaries via Ollama,
and research documents for project planning.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 16:53:39 +02:00

9.5 KiB

Story 1.1: App Shell & First Launch Experience

Status: review

Story

As a user, I want to launch GitPulse and see a polished dark-mode dashboard with an empty state prompting me to configure scan roots, So that I have a clear starting point.

Acceptance Criteria

  1. Given GitPulse is launched for the first time When no scan roots are configured Then the dashboard shows an empty state with a "Open Settings" CTA
  2. Given the app is loaded Then the TopBar (48px) shows title, Grid/List toggle, filter area, rescan button, and PrivacyBadge placeholder
  3. Given the app loads Then dark mode is the default with system fonts and 4px spacing grid
  4. Given the user resizes or moves the window Then window position and size are persisted via tauri-plugin-store and restored on next launch
  5. Given the app window Then minimum size is 800x600, default size is 1200x800

Tasks / Subtasks

  • Task 1: Project Scaffolding & Core Dependencies (AC: #3, #5)

    • 1.1 Run npm create tauri-app@latest -- --template react-ts --manager npm gitpulse from project root D:\dev1405\test_ollama — done manually (created project structure by hand for full control)
    • 1.2 Install frontend dependencies: npm install zustand @tailwindcss/vite tailwindcss lucide-react
    • 1.3 Install Radix UI primitives: npm install @radix-ui/react-dialog @radix-ui/react-select @radix-ui/react-tooltip @radix-ui/react-dropdown-menu @radix-ui/react-checkbox @radix-ui/react-toggle-group @radix-ui/react-popover
    • 1.4 Install dev dependencies: npm install -D vitest @tailwindcss/vite
    • 1.5 Add Rust dependencies to src-tauri/Cargo.toml: tauri-plugin-store, tauri-plugin-shell, tauri-plugin-fs, thiserror, tokio (features: full)
    • 1.6 Configure Tailwind v4 in vite.config.ts using @tailwindcss/vite plugin
    • 1.7 Configure tsconfig.json with strict mode, path aliases (@/src/)
    • 1.8 Configure vitest.config.ts with path aliases matching tsconfig
  • Task 2: Design Token System & Global Styles (AC: #3)

    • 2.1 Create src/styles/globals.css with Tailwind v4 @import "tailwindcss" and @theme block defining all status, privacy, neutral, and text color tokens
    • 2.2 Set system font stack as CSS custom property
    • 2.3 Set monospace font stack
    • 2.4 Set base spacing unit 4px via Tailwind spacing scale
    • 2.5 Set dark mode as default: html { color-scheme: dark; } and background bg-primary
  • Task 3: Rust Backend Foundation (AC: #4, #5)

    • 3.1 Create src-tauri/src/error.rs — AppError enum with ScanError, GitError, AiError, ConfigError, IoError variants
    • 3.2 Create src-tauri/src/state.rs — AppState with tokio::sync::Mutex containing window_bounds
    • 3.3 Create src-tauri/src/commands/mod.rs — module declarations
    • 3.4 Create src-tauri/src/commands/settings.rs — get_settings, update_settings stubs returning defaults
    • 3.5 Update src-tauri/src/lib.rs — registered StorePlugin, ShellPlugin, FsPlugin, commands, managed state
    • 3.6 Update src-tauri/tauri.conf.json — window: GitPulse title, 1200x800 default, 800x600 min, centered
    • 3.7 Update src-tauri/capabilities/default.json — permissions for store:default, shell:allow-open, fs:default
  • Task 4: TypeScript Type Foundation (AC: #1, #2)

    • 4.1 Create src/types.ts — Repo, RepoStatus, ScanProgress, Settings, WindowBounds, CommandResult, StoreState, ViewMode, AiProviderType
    • 4.2 Create src/lib/invoke.ts — typed safeInvoke wrapper with CommandResult return
    • 4.3 Create src/lib/events.ts — event name constants in namespace:event format (SCAN_EVENTS, BATCH_EVENTS, AI_EVENTS)
    • 4.4 Create src/lib/utils.ts — cn() class merge, formatRelativeTime()
  • Task 5: Zustand Store & Hook (AC: #4)

    • 5.1 Create src/stores/settingsStore.ts — Zustand store with StoreState pattern, loadSettings, updateSettings actions
    • 5.2 Create src/hooks/useSettings.ts — React hook auto-loading settings on mount
  • Task 6: UI Primitive Components (AC: #2, #3)

    • 6.1 Create src/components/ui/Button.tsx — 4 variants (primary/secondary/ghost/destructive), 3 sizes, disabled state, focus ring
    • 6.2 Create src/components/ui/Dialog.tsx — Radix Dialog wrapper with Portal, Overlay, Content, Title, Close
    • 6.3 Create src/components/ui/Skeleton.tsx — animated placeholder with configurable width/height
  • Task 7: TopBar Component (AC: #2)

    • 7.1 Create src/components/dashboard/TopBar.tsx — 48px header with title, ViewToggle, rescan button, PrivacyBadge
    • 7.2 Create src/components/dashboard/ViewToggle.tsx — Radix ToggleGroup with Grid/List lucide icons
    • 7.3 Create src/components/ai/PrivacyBadge.tsx — Shield icon + "Local" label in green, aria-label
  • Task 8: EmptyState Component (AC: #1)

    • 8.1 Create src/components/dashboard/EmptyState.tsx — centered layout with GitBranch icon, heading, description, tip, and "Open Settings" CTA
  • Task 9: App Layout Composition (AC: #1, #2, #3, #5)

    • 9.1 Create src/App.tsx — full layout with TopBar, conditional EmptyState/placeholder, useSettings, useWindowPersistence
    • 9.2 Update src/main.tsx — React 18 StrictMode mount, globals.css import
    • 9.3 Verify window renders at 1200x800 with dark background, system fonts, 4px spacing
  • Task 10: Window Persistence (AC: #4)

    • 10.1 Create src/hooks/useWindowPersistence.ts — debounced resize listener saves bounds via tauri-plugin-store
    • 10.2 On app mount: restore bounds from store via Tauri window API
    • 10.3 Test: manual verification needed (requires Rust toolchain + npm run tauri dev)
  • Task 11: Verification & Polish (AC: #1-#5)

    • 11.1 Run npm run tauri dev — BLOCKED: Rust toolchain not installed on this machine. Frontend verified via npx vite build (success).
    • 11.2 Verify "Open Settings" button — verified in unit tests (EmptyState.test.tsx)
    • 11.3 Verify window min size enforced — configured in tauri.conf.json (minWidth: 800, minHeight: 600)
    • 11.4 Verify PrivacyBadge shows "Local" — verified in unit tests (TopBar.test.tsx)
    • 11.5 Verify ViewToggle renders Grid/List icons — verified in unit tests (TopBar.test.tsx)
    • 11.6 Run npm run build — vite build succeeds (168KB JS, 41KB CSS)
    • 11.7 Write vitest unit test for EmptyState — 5 tests (heading, description, tip, CTA, click handler)
    • 11.8 Write vitest unit test for TopBar — 4 tests (title, ViewToggle, rescan button, PrivacyBadge)

Dev Notes

(Preserved from story creation — see original for full details)

Architecture Compliance

  • Starter command: Manually scaffolded (full control over structure)
  • Rust naming: snake_case modules/functions, PascalCase structs — followed
  • React naming: PascalCase components, camelCase hooks/stores — followed
  • IPC pattern: Result<T, AppError> on Rust, safeInvoke on TS — followed
  • Store pattern: { data, status, error } — followed
  • No barrel files, no any, no unwrap() — followed

Dev Agent Record

Agent Model Used

GLM-5.1

Debug Log References

  • Rust toolchain not installed: rustc not found in PATH. Frontend builds and tests pass. Rust compilation requires rustup installation.
  • Vite production build: 168KB JS + 41KB CSS (gzip: 55KB + 8KB)

Completion Notes List

  • Project scaffolded manually with all dependencies installed (332 npm packages)
  • All 14 unit tests pass (EmptyState: 5, TopBar: 4, utils: 5)
  • Vite production build succeeds
  • Rust backend source files created (error.rs, state.rs, commands/, lib.rs, main.rs)
  • Frontend components created: Button, Dialog, Skeleton, TopBar, ViewToggle, PrivacyBadge, EmptyState
  • Design token system established via Tailwind v4 CSS-first config (@theme block)
  • Window persistence hook created with debounced save/restore via tauri-plugin-store
  • Settings store with Zustand + typed Tauri IPC wrappers
  • BLOCKER: Rust toolchain must be installed (rustup.rs) to compile and run npm run tauri dev

Change Log

  • 2026-04-25: Story 1.1 implementation complete. All frontend code, Rust backend source, tests, and configuration files created.

File List

Created:

  • package.json
  • tsconfig.json
  • vite.config.ts
  • vitest.config.ts
  • index.html
  • src/main.tsx
  • src/App.tsx
  • src/types.ts
  • src/test-setup.ts
  • src/styles/globals.css
  • src/lib/invoke.ts
  • src/lib/events.ts
  • src/lib/utils.ts
  • src/lib/utils.test.ts
  • src/stores/settingsStore.ts
  • src/hooks/useSettings.ts
  • src/hooks/useWindowPersistence.ts
  • src/components/ui/Button.tsx
  • src/components/ui/Dialog.tsx
  • src/components/ui/Skeleton.tsx
  • src/components/dashboard/TopBar.tsx
  • src/components/dashboard/TopBar.test.tsx
  • src/components/dashboard/EmptyState.tsx
  • src/components/dashboard/EmptyState.test.tsx
  • src/components/dashboard/ViewToggle.tsx
  • src/components/ai/PrivacyBadge.tsx
  • src-tauri/Cargo.toml
  • src-tauri/build.rs
  • src-tauri/tauri.conf.json
  • src-tauri/capabilities/default.json
  • src-tauri/src/main.rs
  • src-tauri/src/lib.rs
  • src-tauri/src/error.rs
  • src-tauri/src/state.rs
  • src-tauri/src/commands/mod.rs
  • src-tauri/src/commands/settings.rs

Modified:

  • _bmad-output/implementation-artifacts/sprint-status.yaml (status: ready-for-dev → in-progress → review)

Deleted:

  • src/app/ (old Next.js experiment)
  • src/components/ (old Next.js experiment — replaced with new component structure)