42e7bedea4
The honeyDue Go API no longer owns identity — Ory Kratos at
NEXT_PUBLIC_KRATOS_URL does. Rewrite the web app's auth layer to use Kratos
browser self-service flows and the ory_kratos_session cookie.
- Kratos client (src/lib/kratos/): flow init/fetch/submit, whoami, logout,
message helpers, and the useKratosFlow lifecycle hook.
- Generic flow renderer (src/components/auth/): KratosFlowForm renders
ui.nodes (inputs, oidc social buttons, hidden csrf), KratosMessages
surfaces flow-level messages, AuthGate guards /app via whoami.
- Auth pages (login/register/forgot-password/verify-email/reset-password)
rewritten as Kratos login/registration/recovery/verification/settings
flows. Password change in settings now uses the Kratos settings flow.
- Proxy + serverFetch forward the ory_kratos_session cookie to the Go API
instead of "Authorization: Token". Deleted /api/auth/{login,logout,me}.
- Middleware does a cheap ory_kratos_session cookie pre-filter; AuthGate's
whoami call is authoritative.
- auth store rewritten around whoami + GET /auth/me; removed dead auth API
functions, types/auth, validations/auth, code-input.
- Added NEXT_PUBLIC_KRATOS_URL to config (.env.example) and CLAUDE.md.
npm run build passes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
151 lines
7.9 KiB
Markdown
151 lines
7.9 KiB
Markdown
# honeyDue Web (`honeyDueAPI-Web`)
|
|
|
|
Next.js web client for the honeyDue property management platform. Talks to the Go REST API backend.
|
|
|
|
## Build & Run
|
|
|
|
```bash
|
|
npm run dev # Dev server (localhost:3000)
|
|
npm run build # Production build (catches type errors)
|
|
npm run lint # ESLint
|
|
npm run test:e2e # Playwright end-to-end tests
|
|
npm run test:e2e:ui # Playwright with UI
|
|
npm run analyze # Bundle analysis
|
|
```
|
|
|
|
## Stack
|
|
|
|
- **Framework**: Next.js 16 (App Router, React 19)
|
|
- **Styling**: Tailwind CSS v4 + shadcn/ui (Radix primitives)
|
|
- **State**: Zustand (auth, onboarding, theme), TanStack React Query (server state)
|
|
- **Forms**: React Hook Form + Zod validation
|
|
- **Drag & Drop**: @dnd-kit (kanban boards)
|
|
- **Charts**: Recharts
|
|
- **Icons**: Lucide React
|
|
- **Analytics**: PostHog
|
|
- **Testing**: Playwright (E2E), Vitest (unit)
|
|
|
|
## Architecture
|
|
|
|
### Request Flow
|
|
|
|
```
|
|
Browser → Next.js page (client component)
|
|
→ apiFetch("/tasks/") → /api/proxy/tasks (Next.js route handler)
|
|
→ Go API (reads ory_kratos_session cookie, forwards it as a Cookie header)
|
|
```
|
|
|
|
Identity is owned by **Ory Kratos** (`NEXT_PUBLIC_KRATOS_URL`). The browser holds an `ory_kratos_session` cookie set by Kratos. The Next.js `/api/proxy/[...path]` catch-all route forwards that cookie to the Go API, which validates the session against Kratos. The Go API no longer does auth (no `Authorization: Token`).
|
|
|
|
### Auth (Ory Kratos)
|
|
|
|
Login / registration / recovery (forgot-password) / email verification / password changes use **Kratos browser self-service flows**:
|
|
|
|
- Auth pages (`src/app/(auth)/...`) initialize a flow by hard-navigating the browser to `{kratos}/self-service/{type}/browser`; Kratos sets a flow cookie and redirects back with `?flow=<id>`.
|
|
- The page reads `?flow=<id>`, fetches the flow definition (`ui.nodes` / `ui.action` / `ui.method`), and renders it generically via `<KratosFlowForm>`.
|
|
- Social sign-in (Apple/Google) = the `oidc` nodes in the flow.
|
|
- `src/lib/kratos/` holds the client (`getFlow`, `submitFlow`, `whoami`, `logout`, ...) and the `useKratosFlow` hook.
|
|
- Route protection: `<AuthGate>` (in `src/app/app/layout.tsx`) calls `{kratos}/sessions/whoami`; the middleware does a cheap `ory_kratos_session` cookie pre-filter.
|
|
|
|
### Directory Structure
|
|
|
|
```
|
|
src/
|
|
├── app/
|
|
│ ├── (auth)/ # Kratos self-service flow pages (login/register/recovery/verify)
|
|
│ ├── api/proxy/ # Catch-all proxy to Go API
|
|
│ ├── app/ # Authenticated app pages
|
|
│ │ ├── contractors/ # Contractor CRUD
|
|
│ │ ├── documents/ # Document management
|
|
│ │ ├── residences/ # Residence CRUD + detail with kanban
|
|
│ │ ├── settings/ # User settings, theme
|
|
│ │ └── tasks/ # Task CRUD, kanban board
|
|
│ ├── demo/ # Demo mode (fake data, no auth)
|
|
│ └── page.tsx # Landing page
|
|
├── components/
|
|
│ ├── contractors/ # Contractor cards, forms
|
|
│ ├── dashboard/ # Stats, activity, template suggestions
|
|
│ ├── demo/ # Demo banner
|
|
│ ├── documents/ # Document cards, forms
|
|
│ ├── forms/ # Auth form wrapper
|
|
│ ├── layout/ # TopBar, MobileNav, Sidebar
|
|
│ ├── notifications/ # Notification components
|
|
│ ├── onboarding/ # Onboarding flow
|
|
│ ├── residences/ # Residence cards, forms, summary, share
|
|
│ ├── settings/ # Theme picker
|
|
│ ├── shared/ # PageHeader, EmptyState, ErrorBanner, etc.
|
|
│ ├── sharing/ # Share code UI
|
|
│ ├── tasks/ # TaskCard, TaskForm, KanbanBoard, KanbanColumn
|
|
│ └── ui/ # shadcn primitives (button, card, dialog, etc.)
|
|
├── lib/
|
|
│ ├── api/ # API client functions per domain
|
|
│ │ ├── client.ts # apiFetch (client-side) + serverFetch (server-side)
|
|
│ │ ├── tasks.ts # Task API (CRUD, kanban, completions)
|
|
│ │ ├── residences.ts # Residence API (CRUD, sharing, reports)
|
|
│ │ ├── contractors.ts
|
|
│ │ ├── documents.ts
|
|
│ │ └── ...
|
|
│ ├── hooks/ # React Query hooks per domain
|
|
│ │ ├── use-tasks.ts # useTasks, useTask, useCreateTask, etc.
|
|
│ │ ├── use-residences.ts
|
|
│ │ └── ...
|
|
│ ├── demo/ # Demo mode: DataProvider abstraction
|
|
│ │ ├── data-provider-context.tsx # React context
|
|
│ │ ├── real-provider.ts # Real API calls
|
|
│ │ ├── demo-provider.ts # Fake data
|
|
│ │ └── mock-data/ # Static demo data
|
|
│ ├── themes/ # Theme system (Warm Sage palette)
|
|
│ ├── validations/ # Zod schemas
|
|
│ └── utils.ts # cn() helper
|
|
├── stores/
|
|
│ ├── auth.ts # Zustand: user, token, login/logout
|
|
│ ├── onboarding.ts # Zustand: onboarding state
|
|
│ └── theme.ts # Zustand: theme preferences
|
|
└── styles/
|
|
└── themes.css # CSS custom properties for theme
|
|
```
|
|
|
|
### Key Patterns
|
|
|
|
**Data fetching**: All server data uses React Query hooks (`use-*.ts`). Hooks call API functions from `lib/api/`. API functions call `apiFetch()` which proxies through Next.js.
|
|
|
|
**Demo mode**: The app supports a `/demo` route with fake data. Components use `useDataProvider()` to get API functions and `basePath` — this returns either real or demo implementations depending on the route.
|
|
|
|
**Kanban boards**: Tasks display in kanban columns (overdue, due_soon, in_progress, not_started, completed). Uses `@dnd-kit` for drag-and-drop. Column names match Go API: `overdue_tasks`, `due_soon_tasks`, `in_progress_tasks`, `not_started_tasks`, `completed_tasks`.
|
|
|
|
**Middleware** (`src/middleware.ts`): Cheap pre-filter on the `ory_kratos_session` cookie. Redirects users without the cookie to `/login` for protected routes. Skips API routes, static files, and public paths. The authoritative session check is `<AuthGate>` (`whoami`).
|
|
|
|
## Conventions
|
|
|
|
- All pages under `/app/` are `"use client"` components
|
|
- Use `apiFetch()` for client-side API calls, `serverFetch()` for server components/route handlers
|
|
- React Query hooks go in `src/lib/hooks/use-{domain}.ts`
|
|
- API client functions go in `src/lib/api/{domain}.ts`
|
|
- shadcn components in `src/components/ui/` — don't modify these directly
|
|
- Custom components use Tailwind classes, warm shadow CSS variables (`--shadow-warm-sm`, `--shadow-warm-md`)
|
|
- Brand colors: `primary` (sage green), `brand-clay`, `brand-sage` variants defined in CSS custom properties
|
|
- Font: `font-heading` for headings (tracking-tight), system font for body
|
|
- Toast notifications via `sonner` — use `toast.success()`, `toast.error()`
|
|
- Form validation with Zod schemas in `src/lib/validations/`
|
|
- Icons from `lucide-react` — keep consistent sizes (size-4 for inline, size-5 for cards)
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Description | Default |
|
|
|----------|-------------|---------|
|
|
| `NEXT_PUBLIC_API_URL` | Go API URL (client-side) | `https://honeyDue.treytartt.com/api` |
|
|
| `API_URL` | Go API URL (server-side, no proxy) | Falls back to `NEXT_PUBLIC_API_URL` |
|
|
| `NEXT_PUBLIC_KRATOS_URL` | Ory Kratos public API URL (identity) | `https://auth.myhoneydue.com` |
|
|
| `NEXT_PUBLIC_POSTHOG_KEY` | PostHog analytics key | — |
|
|
| `NEXT_PUBLIC_POSTHOG_HOST` | PostHog host | — |
|
|
|
|
See `.env.example` for the full list.
|
|
|
|
## Common Tasks
|
|
|
|
**Add a new page**: Create `src/app/app/{route}/page.tsx` (client component). Add nav item to `src/components/layout/nav-items.ts`.
|
|
|
|
**Add a new API domain**: Create `src/lib/api/{domain}.ts` with typed functions using `apiFetch()`. Create `src/lib/hooks/use-{domain}.ts` with React Query hooks. Add demo provider methods if needed.
|
|
|
|
**Add a shadcn component**: `npx shadcn@latest add {component}` — installs to `src/components/ui/`.
|