Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion PRPs/ai_docs/API_NAMING_CONVENTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ Database values used directly - no mapping layers:
- Operation statuses: `"pending"`, `"processing"`, `"completed"`, `"failed"`

### Time Constants
**Location**: `archon-ui-main/src/features/shared/queryPatterns.ts`
**Location**: `archon-ui-main/src/features/shared/config/queryPatterns.ts`
- `STALE_TIMES.instant` - 0ms
- `STALE_TIMES.realtime` - 3 seconds
- `STALE_TIMES.frequent` - 5 seconds
Expand Down
6 changes: 3 additions & 3 deletions PRPs/ai_docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ Pattern: `{METHOD} /api/{resource}/{id?}/{sub-resource?}`

### Data Fetching
**Core**: TanStack Query v5
**Configuration**: `archon-ui-main/src/features/shared/queryClient.ts`
**Patterns**: `archon-ui-main/src/features/shared/queryPatterns.ts`
**Configuration**: `archon-ui-main/src/features/shared/config/queryClient.ts`
**Patterns**: `archon-ui-main/src/features/shared/config/queryPatterns.ts`

### State Management
- **Server State**: TanStack Query
Expand Down Expand Up @@ -139,7 +139,7 @@ TanStack Query is the single source of truth. No separate state management neede
No translation layers. Database values (e.g., `"todo"`, `"doing"`) used directly in UI.

### Browser-Native Caching
ETags handled by browser, not JavaScript. See `archon-ui-main/src/features/shared/apiWithEtag.ts`.
ETags handled by browser, not JavaScript. See `archon-ui-main/src/features/shared/api/apiClient.ts`.

## Deployment

Expand Down
10 changes: 5 additions & 5 deletions PRPs/ai_docs/DATA_FETCHING_ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Archon uses **TanStack Query v5** for all data fetching, caching, and synchroniz

### 1. Query Client Configuration

**Location**: `archon-ui-main/src/features/shared/queryClient.ts`
**Location**: `archon-ui-main/src/features/shared/config/queryClient.ts`

Centralized QueryClient with:

Expand All @@ -30,7 +30,7 @@ Visibility-aware polling that:

### 3. Query Patterns

**Location**: `archon-ui-main/src/features/shared/queryPatterns.ts`
**Location**: `archon-ui-main/src/features/shared/config/queryPatterns.ts`

Shared constants:

Expand Down Expand Up @@ -64,7 +64,7 @@ Standard pattern across all features:

### ETag Support

**Location**: `archon-ui-main/src/features/shared/apiWithEtag.ts`
**Location**: `archon-ui-main/src/features/shared/api/apiClient.ts`

ETag implementation:

Expand All @@ -83,7 +83,7 @@ Backend endpoints follow RESTful patterns:

## Optimistic Updates

**Utilities**: `archon-ui-main/src/features/shared/optimistic.ts`
**Utilities**: `archon-ui-main/src/features/shared/utils/optimistic.ts`

All mutations use nanoid-based optimistic updates:

Expand All @@ -105,7 +105,7 @@ Polling intervals are defined in each feature's query hooks. See actual implemen
- **Progress**: `archon-ui-main/src/features/progress/hooks/useProgressQueries.ts`
- **MCP**: `archon-ui-main/src/features/mcp/hooks/useMcpQueries.ts`

Standard intervals from `archon-ui-main/src/features/shared/queryPatterns.ts`:
Standard intervals from `archon-ui-main/src/features/shared/config/queryPatterns.ts`:
- `STALE_TIMES.instant`: 0ms (always fresh)
- `STALE_TIMES.frequent`: 5 seconds (frequently changing data)
- `STALE_TIMES.normal`: 30 seconds (standard cache)
Expand Down
10 changes: 5 additions & 5 deletions PRPs/ai_docs/ETAG_IMPLEMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The backend generates ETags for API responses:
- Returns `304 Not Modified` when ETags match

### Frontend Handling
**Location**: `archon-ui-main/src/features/shared/apiWithEtag.ts`
**Location**: `archon-ui-main/src/features/shared/api/apiClient.ts`

The frontend relies on browser-native HTTP caching:
- Browser automatically sends `If-None-Match` headers with cached ETags
Expand All @@ -28,7 +28,7 @@ The frontend relies on browser-native HTTP caching:
#### Browser vs Non-Browser Behavior
- **Standard Browsers**: Per the Fetch spec, a 304 response freshens the HTTP cache and returns the cached body to JavaScript
- **Non-Browser Runtimes** (React Native, custom fetch): May surface 304 with empty body to JavaScript
- **Client Fallback**: The `apiWithEtag.ts` implementation handles both scenarios, ensuring consistent behavior across environments
- **Client Fallback**: The `apiClient.ts` implementation handles both scenarios, ensuring consistent behavior across environments

## Implementation Details

Expand Down Expand Up @@ -81,8 +81,8 @@ Unlike previous implementations, the current approach:

### Configuration
Cache behavior is controlled through TanStack Query's `staleTime`:
- See `archon-ui-main/src/features/shared/queryPatterns.ts` for standard times
- See `archon-ui-main/src/features/shared/queryClient.ts` for global configuration
- See `archon-ui-main/src/features/shared/config/queryPatterns.ts` for standard times
- See `archon-ui-main/src/features/shared/config/queryClient.ts` for global configuration

## Performance Benefits

Expand All @@ -100,7 +100,7 @@ Cache behavior is controlled through TanStack Query's `staleTime`:

### Core Implementation
- **Backend Utilities**: `python/src/server/utils/etag_utils.py`
- **Frontend Client**: `archon-ui-main/src/features/shared/apiWithEtag.ts`
- **Frontend Client**: `archon-ui-main/src/features/shared/api/apiClient.ts`
- **Tests**: `python/tests/server/utils/test_etag_utils.py`

### Usage Examples
Expand Down
8 changes: 4 additions & 4 deletions PRPs/ai_docs/QUERY_PATTERNS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This guide documents the standardized patterns for using TanStack Query v5 in th
## Core Principles

1. **Feature Ownership**: Each feature owns its query keys in `{feature}/hooks/use{Feature}Queries.ts`
2. **Consistent Patterns**: Always use shared patterns from `shared/queryPatterns.ts`
2. **Consistent Patterns**: Always use shared patterns from `shared/config/queryPatterns.ts`
3. **No Hardcoded Values**: Never hardcode stale times or disabled keys
4. **Mirror Backend API**: Query keys should exactly match backend API structure

Expand Down Expand Up @@ -49,7 +49,7 @@ export const taskKeys = {
### Import Required Patterns

```typescript
import { DISABLED_QUERY_KEY, STALE_TIMES } from "@/features/shared/queryPatterns";
import { DISABLED_QUERY_KEY, STALE_TIMES } from "@/features/shared/config/queryPatterns";
```

### Disabled Queries
Expand Down Expand Up @@ -106,7 +106,7 @@ export function useFeatureDetail(id: string | undefined) {
## Mutations with Optimistic Updates

```typescript
import { createOptimisticEntity, replaceOptimisticEntity } from "@/features/shared/optimistic";
import { createOptimisticEntity, replaceOptimisticEntity } from "@/features/shared/utils/optimistic";

export function useCreateFeature() {
const queryClient = useQueryClient();
Expand Down Expand Up @@ -161,7 +161,7 @@ vi.mock("../../services", () => ({
}));

// Mock shared patterns with ALL values
vi.mock("../../../shared/queryPatterns", () => ({
vi.mock("../../../shared/config/queryPatterns", () => ({
DISABLED_QUERY_KEY: ["disabled"] as const,
STALE_TIMES: {
instant: 0,
Expand Down
6 changes: 3 additions & 3 deletions PRPs/ai_docs/optimistic_updates.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Core Architecture

### Shared Utilities Module
**Location**: `src/features/shared/optimistic.ts`
**Location**: `src/features/shared/utils/optimistic.ts`

Provides type-safe utilities for managing optimistic state across all features:
- `createOptimisticId()` - Generates stable UUIDs using nanoid
Expand Down Expand Up @@ -73,13 +73,13 @@ Reusable component showing:
- Uses `createOptimisticId()` directly for progress tracking

### Toasts
- **Location**: `src/features/ui/hooks/useToast.ts:43`
- **Location**: `src/features/shared/hooks/useToast.ts:43`
- Uses `createOptimisticId()` for unique toast IDs

## Testing

### Unit Tests
**Location**: `src/features/shared/optimistic.test.ts`
**Location**: `src/features/shared/utils/tests/optimistic.test.ts`

Covers all utility functions with 8 test cases:
- ID uniqueness and format validation
Expand Down
2 changes: 1 addition & 1 deletion archon-ui-main/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { queryClient } from './features/shared/queryClient';
import { queryClient } from './features/shared/config/queryClient';
import { KnowledgeBasePage } from './pages/KnowledgeBasePage';
import { SettingsPage } from './pages/SettingsPage';
import { MCPPage } from './pages/MCPPage';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useQuery } from "@tanstack/react-query";
import { callAPIWithETag } from "../../../features/shared/apiWithEtag";
import { createRetryLogic, STALE_TIMES } from "../../../features/shared/queryPatterns";
import { callAPIWithETag } from "../../../features/shared/api/apiClient";
import { createRetryLogic, STALE_TIMES } from "../../../features/shared/config/queryPatterns";
import type { HealthResponse } from "../types";

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Enhanced Knowledge Card Component
* Individual knowledge item card with excellent UX and inline progress
* Knowledge Card component
* Displays a knowledge item with inline progress and status UI
* Following the pattern from ProjectCard
*/

Expand All @@ -10,7 +10,7 @@ import { Clock, Code, ExternalLink, File, FileText, Globe } from "lucide-react";
import { useState } from "react";
import { KnowledgeCardProgress } from "../../progress/components/KnowledgeCardProgress";
import type { ActiveOperation } from "../../progress/types";
import { isOptimistic } from "../../shared/optimistic";
import { isOptimistic } from "@/features/shared/utils/optimistic";
import { StatPill } from "../../ui/primitives";
import { OptimisticIndicator } from "../../ui/primitives/OptimisticIndicator";
import { cn } from "../../ui/primitives/styles";
Expand Down Expand Up @@ -144,6 +144,7 @@ export const KnowledgeCard: React.FC<KnowledgeCardProps> = ({
};

return (
// biome-ignore lint/a11y/useSemanticElements: Card contains nested interactive elements (buttons, links) - using div to avoid invalid HTML nesting
<motion.div
className="relative group cursor-pointer"
role="button"
Expand Down
17 changes: 7 additions & 10 deletions archon-ui-main/src/features/knowledge/hooks/useKnowledgeQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useMemo, useState } from "react";
import { createOptimisticEntity, createOptimisticId } from "@/features/shared/optimistic";
import { useSmartPolling } from "@/features/shared/hooks";
import { useToast } from "@/features/shared/hooks/useToast";
import { createOptimisticEntity, createOptimisticId } from "@/features/shared/utils/optimistic";
import { useActiveOperations } from "../../progress/hooks";
import { progressKeys } from "../../progress/hooks/useProgressQueries";
import type { ActiveOperation, ActiveOperationsResponse } from "../../progress/types";
import { DISABLED_QUERY_KEY, STALE_TIMES } from "../../shared/queryPatterns";
import { useSmartPolling } from "@/features/shared/hooks";
import { useToast } from "@/features/shared/hooks/useToast";
import { DISABLED_QUERY_KEY, STALE_TIMES } from "../../shared/config/queryPatterns";
import { knowledgeService } from "../services";
import type {
CrawlRequest,
Expand Down Expand Up @@ -170,7 +170,6 @@ export function useCrawlUrl() {
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
} as Omit<KnowledgeItem, "id">);
const tempItemId = optimisticItem.id;

// Update all summaries caches with optimistic data, respecting each cache's filter
const entries = queryClient.getQueriesData<KnowledgeItemsResponse>({
Expand Down Expand Up @@ -229,7 +228,7 @@ export function useCrawlUrl() {
});

// Return context for rollback and replacement
return { previousSummaries, previousOperations, tempProgressId, tempItemId };
return { previousSummaries, previousOperations, tempProgressId };
},
onSuccess: (response, _variables, context) => {
// Replace temporary IDs with real ones from the server
Expand Down Expand Up @@ -313,7 +312,6 @@ export function useUploadDocument() {
previousSummaries?: Array<[readonly unknown[], KnowledgeItemsResponse | undefined]>;
previousOperations?: ActiveOperationsResponse;
tempProgressId: string;
tempItemId: string;
}
>({
mutationFn: ({ file, metadata }: { file: File; metadata: UploadMetadata }) =>
Expand Down Expand Up @@ -352,7 +350,6 @@ export function useUploadDocument() {
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
} as Omit<KnowledgeItem, "id">);
const tempItemId = optimisticItem.id;

// Respect each cache's filter (knowledge_type, tags, etc.)
const entries = queryClient.getQueriesData<KnowledgeItemsResponse>({
Expand Down Expand Up @@ -410,7 +407,7 @@ export function useUploadDocument() {
};
});

return { previousSummaries, previousOperations, tempProgressId, tempItemId };
return { previousSummaries, previousOperations, tempProgressId };
},
onSuccess: (response, _variables, context) => {
// Replace temporary IDs with real ones from the server
Expand All @@ -421,7 +418,7 @@ export function useUploadDocument() {
return {
...old,
items: old.items.map((item) => {
if (item.id === context.tempItemId) {
if (item.source_id === context.tempProgressId) {
return {
...item,
source_id: response.progressId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
*/

import { useCallback, useEffect, useState } from "react";
import { copyToClipboard } from "../../../shared/utils/clipboard";
import { InspectorDialog, InspectorDialogContent, InspectorDialogTitle } from "../../../ui/primitives";
import type { CodeExample, DocumentChunk, InspectorSelectedItem, KnowledgeItem } from "../../types";
import { useInspectorPagination } from "../hooks/useInspectorPagination";
import { ContentViewer } from "./ContentViewer";
import { InspectorHeader } from "./InspectorHeader";
import { InspectorSidebar } from "./InspectorSidebar";
import { copyToClipboard } from "../../../shared/utils/clipboard";

interface KnowledgeInspectorProps {
item: KnowledgeItem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { useInfiniteQuery } from "@tanstack/react-query";
import { useMemo } from "react";
import { STALE_TIMES } from "@/features/shared/queryPatterns";
import { STALE_TIMES } from "@/features/shared/config/queryPatterns";
import { knowledgeKeys } from "../../hooks/useKnowledgeQueries";
import { knowledgeService } from "../../services";
import type { ChunksResponse, CodeExample, CodeExamplesResponse, DocumentChunk } from "../../types";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Handles all knowledge-related API operations using TanStack Query patterns
*/

import { callAPIWithETag } from "../../shared/apiWithEtag";
import { APIServiceError } from "../../shared/errors";
import { callAPIWithETag } from "../../shared/api/apiClient";
import { APIServiceError } from "../../shared/types/errors";
import type {
ChunksResponse,
CodeExamplesResponse,
Expand Down
Loading