# PyCharter UI

Next.js App Router + TypeScript + Tailwind CSS + shadcn/ui application for PyCharter.

This codebase is designed as a **reusable template** for other projects (e.g. PyStator). The directory structure, core components, and utility layer are generic and domain-agnostic; domain-specific features live in clearly isolated directories.

## Features

- **Next.js 16 App Router** with static export
- **TypeScript** (strict mode)
- **Tailwind CSS** with shadcn/ui component library
- **Centralized API client** with error handling, auth, and type safety
- **Authentication** with session management and public route support
- **Modular component architecture** with layout, common, and domain directories

## Quick Start

```bash
# Install npm dependencies
npm install

# Start development server
npm run dev
# or
pycharter ui dev

# Build for production
npm run build
```

The UI is available at `http://localhost:3000`. Configure the API server URL in Settings.

## Project Structure

```
src/
├── app/                        # Next.js App Router pages
│   ├── layout.tsx              # Root layout (ErrorBoundary + AppShell)
│   ├── page.tsx                # Home page
│   ├── loading.tsx             # Global loading state
│   ├── error.tsx               # Global error handler
│   ├── login/page.tsx          # Login page
│   ├── settings/page.tsx       # Settings page
│   ├── contracts/page.tsx      # [domain] Contract management
│   ├── editor/page.tsx         # [domain] Schema editor
│   ├── validation/page.tsx     # [domain] Validation workspace
│   ├── etl/page.tsx            # [domain] ETL workspace
│   ├── quality/page.tsx        # [domain] Quality reports
│   ├── options/page.tsx        # [domain] Metadata entities
│   └── documentation/page.tsx  # [domain] API docs
│
├── components/
│   ├── layout/                 # [core] App shell, navigation, page structure
│   │   ├── AppShell.tsx        #   AuthProvider + Navigation + main wrapper
│   │   ├── Navigation.tsx      #   Top nav bar with route links
│   │   ├── AuthGuard.tsx       #   Route-level auth protection
│   │   ├── ApiUnavailableBanner.tsx
│   │   ├── PageHeader.tsx      #   Page title + description + actions
│   │   ├── PageContainer.tsx   #   Standard page wrapper (max-width or full-height)
│   │   └── ResizableWorkspaceLayout.tsx
│   ├── common/                 # [core] Shared, reusable UI pieces
│   │   ├── ErrorBoundary.tsx
│   │   ├── ErrorDisplay.tsx
│   │   ├── LoadingSpinner.tsx  #   LoadingSpinner, PageLoading, CardSkeleton, TableSkeleton
│   │   ├── TruncatedId.tsx
│   │   └── ContractCombobox.tsx
│   ├── ui/                     # [core] shadcn/ui primitives (auto-generated)
│   ├── sidebar/                # [core] Collapsible sidebar
│   ├── contracts/              # [domain] Contract CRUD modals and tables
│   ├── schemas/                # [domain] Schema editor components
│   ├── validation/             # [domain] Validation workspace panels
│   ├── etl/                    # [domain] ETL workspace panels
│   └── metadata/               # [domain] Metadata entity modal
│
├── lib/
│   ├── api.ts                  # [core] API client: fetch helpers, ApiError, getApiErrorMessage
│   ├── auth-storage.ts         # [core] Token persistence (localStorage)
│   ├── constants.ts            # [core] APP_NAME, ROUTES, auth constants
│   ├── settings.ts             # [core] User settings persistence
│   ├── utils.ts                # [core] cn(), formatDate(), debounce(), downloadBlob()
│   ├── types/                  # Type definitions organized by domain
│   │   ├── index.ts            #   Central re-exports
│   │   ├── auth.ts             #   AuthMeResponse, AuthLoginResponse
│   │   ├── contract.ts         #   Contract, ContractData, etc.
│   │   ├── etl.ts              #   EtlRunResponse
│   │   └── validation.ts       #   ValidationResponse, etc.
│   └── schema-editor/          # [domain] Schema editor types and utilities
│
├── hooks/
│   ├── useApiQuery.ts          # [core] Generic data-fetching hook
│   ├── useFieldUpdater.ts      # [domain] Schema editor field update hook
│   ├── useContracts.ts         # [domain] Thin wrapper: fetch contracts
│   ├── useSchemas.ts           # [domain] Thin wrapper: fetch schemas
│   └── useAutoValidation.ts    # [domain] Debounced validation hook
│
└── contexts/
    └── AuthContext.tsx          # [core] Auth state, login/logout, session management
```

Items marked **[core]** are generic infrastructure suitable for any project. Items marked **[domain]** are PyCharter-specific.

## How to Use as a Template

### 1. Add a New Page

Create `src/app/my-feature/page.tsx`:

```tsx
'use client';

import { PageContainer, PageHeader } from '@/components/layout';

export default function MyFeaturePage() {
  return (
    <PageContainer>
      <PageHeader
        title="My Feature"
        description="Description of the feature"
        actions={<Button>Action</Button>}
      />
      {/* Page content */}
    </PageContainer>
  );
}
```

For workspace-style pages (full height with resizable panels):

```tsx
<PageContainer fullHeight>
  {/* workspace content */}
</PageContainer>
```

### 2. Add a New Domain Component Group

Create `src/components/my-domain/` with an `index.ts` barrel file:

```
components/my-domain/
├── MyComponent.tsx
├── MyOtherComponent.tsx
└── index.ts
```

### 3. Customize Navigation Routes

Edit `src/lib/constants.ts` to add routes, then update `src/components/layout/Navigation.tsx` to include the new link.

### 4. Fetch Data from the API

Use the `useApiQuery` hook for standard fetch patterns:

```tsx
import { useApiQuery } from '@/hooks/useApiQuery';
import { api } from '@/lib/api';

function MyComponent() {
  const { data, loading, error, refetch } = useApiQuery(
    () => api.myEndpoint.list(),
    [],               // initial value
    'Failed to load',  // fallback error message
  );
}
```

Or use `getApiErrorMessage()` for inline error handling:

```tsx
import { api, getApiErrorMessage } from '@/lib/api';

try {
  await api.myEndpoint.create(data);
} catch (err) {
  setError(getApiErrorMessage(err, 'Failed to create'));
}
```

## Key Conventions

- **Named exports only** -- no `export default` for components (pages use `export default` per Next.js convention)
- **Barrel files** (`index.ts`) in each component directory
- **Import from barrels** -- `import { X } from '@/components/common'` rather than deep paths
- **`PageContainer`** wraps every page for consistent layout
- **`getApiErrorMessage()`** for all error handling (no inline error parsing)
- **`useApiQuery`** for standard data-fetching patterns
- **Types organized by domain** in `src/lib/types/`

## Configuration

| File | Purpose |
|---|---|
| `components.json` | shadcn/ui component configuration |
| `tailwind.config.js` | Tailwind CSS configuration |
| `tsconfig.json` | TypeScript configuration (strict mode) |
| `next.config.js` | Next.js configuration (static export) |
| `.eslintrc.json` | ESLint configuration |

## Adding shadcn/ui Components

```bash
npx shadcn-ui@latest add [component-name]
```
