7a944afdb5
Fixes link color from hardcoded white to currentColor for proper theme support. Adds video and audio modality icons to ModelInfo. Registers anthropic, nvidia, and xiaomi in the provider icon map. Removes unused pagination validation from agents and topics endpoints. Adds convenience start script. Updates AGENTS.md.
190 lines
6.0 KiB
Markdown
190 lines
6.0 KiB
Markdown
# Veridian AGENTS.md
|
|
|
|
**Nuxt 4 AI chat platform with Drizzle + PostgreSQL + better-auth**
|
|
|
|
## Architecture Overview
|
|
|
|
```
|
|
app/ # Nuxt 4 application (SSR)
|
|
├── components/ # Vue components (Sidenav, Message, Settings, etc.)
|
|
├── composables/ # Shared state (useChat, useAuth, useModels, etc.)
|
|
├── layouts/ # Auth and default layouts
|
|
├── middleware/ # Global auth middleware
|
|
├── pages/ # File-based routing (/, /auth/*, /agent/*)
|
|
├── plugins/ # Auth plugins (client/server), remark markdown
|
|
├── types/ # TypeScript interfaces
|
|
└── utils/ # Crypto, model-mapping, search utilities
|
|
|
|
server/ # Server-side API routes
|
|
└── api/
|
|
├── auth/ # Better-auth handler
|
|
├── chat/ # Generation, cancel endpoints
|
|
└── provider/ # Model fetching from providers
|
|
|
|
drizzle/ # Database (migrated from Triplit)
|
|
├── schema.ts # Full schema with auth + app tables
|
|
├── relations.ts # Table relationships
|
|
└── migrations/ # SQL migration files
|
|
|
|
lib/ # Shared utilities
|
|
├── auth.ts # Better-auth server config
|
|
└── auth-client.ts # Better-auth client
|
|
```
|
|
|
|
## Core Commands
|
|
|
|
As an agentic agent, never run the development server yourself.
|
|
Instead, once you have completed your task, end generation and inform me that
|
|
you are done and request a review of your changes. You are allowed to use
|
|
database commands.
|
|
|
|
### Database Commands
|
|
|
|
- `bunx drizzle-kit push` - Push schema changes to database
|
|
- `bunx drizzle-kit generate` - Generate migration from schema changes
|
|
- `bunx drizzle-kit migrate` - Run pending migrations
|
|
|
|
## Code Style
|
|
|
|
- **Indentation**: 4 spaces (no tabs)
|
|
- **Semicolons**: Always required
|
|
- **Equality**: Strict equality only (`===`, `!==`)
|
|
- **Components**: PascalCase, never self-closing tags
|
|
- **Functions**: camelCase for functions, PascalCase for constructors/classes
|
|
- **Constants**: SCREAMING_SNAKE_CASE for constants, camelCase for const values
|
|
- **Files**: kebab-case for files, PascalCase for Vue components
|
|
- **State**: `useState('prefix:name', () => default)` for reactive state
|
|
|
|
## Imports Order
|
|
|
|
Group imports in this order (alphabetical within groups):
|
|
1. Type imports (`types/`)
|
|
2. Dependency imports (npm packages)
|
|
3. Vue/Nuxt imports (`vue`, `#app`, `~~/`, `~/`, `@/`)
|
|
4. Local imports (`lib/`, `server/`)
|
|
|
|
```typescript
|
|
// Example import order
|
|
import type { Result, Ok, Err } from '~~/types/result';
|
|
import type { Foo } from 'vue';
|
|
import { ref, computed } from 'vue';
|
|
import { useFeature } from '~/composables/useFeature';
|
|
import { decrypt } from '~/utils/crypto';
|
|
import { authClient } from '~~/lib/auth-client';
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
Avoid using `throw` statements in your code.
|
|
|
|
Use the `Result<T, E>` type with `Ok()` and `Err()` factory functions:
|
|
|
|
```typescript
|
|
import { type Result, Ok, Err } from '~~/types/result';
|
|
|
|
const myFunction(): Result<ReturnType, ErrorType> {
|
|
if (error) {
|
|
return Err(ErrorType.SpecificError);
|
|
}
|
|
return Ok(data);
|
|
}
|
|
|
|
// Usage
|
|
const result = myFunction();
|
|
if (result.ok === false) {
|
|
console.error(result.error);
|
|
return;
|
|
}
|
|
processData(result.data);
|
|
```
|
|
|
|
## Composables Pattern
|
|
|
|
All composables return reactive state + actions:
|
|
|
|
```typescript
|
|
export const useFeature = () => {
|
|
const state = useState('feature:state', () => defaultValue);
|
|
const computedValue = computed(() => /* logic */);
|
|
const actions = {
|
|
async doSomething() {
|
|
// implementation
|
|
},
|
|
};
|
|
return { state, computedValue, ...actions };
|
|
};
|
|
```
|
|
|
|
## API Route Pattern
|
|
|
|
```typescript
|
|
// File: server/api/endpoint.method.ts
|
|
import { protectRoute } from '~/server/utils/protect';
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
await protectRoute(event);
|
|
// implementation
|
|
return { /* response */ };
|
|
});
|
|
```
|
|
|
|
## Database Query Pattern (Drizzle)
|
|
|
|
```typescript
|
|
// Server-side queries use Drizzle ORM
|
|
import { db } from '~~/server/db';
|
|
import { agents } from '~~/drizzle/schema';
|
|
|
|
// Query with relations
|
|
const result = await db.query.agents.findMany({
|
|
where: eq(agents.userId, userId),
|
|
with: { topics: true, messages: true },
|
|
});
|
|
|
|
// Insert with conflict handling
|
|
await db.insert(agents).values(data).onConflictDoNothing();
|
|
```
|
|
|
|
## Authentication Flow
|
|
|
|
1. **Login**: Client uses `authClient.signIn.email()` → derives encryption key from password
|
|
2. **Session**: Better-auth creates session token → stored in cookie
|
|
3. **API Keys**: Encrypted client-side with AES-GCM (key derived from password + userId)
|
|
|
|
**Key files**: `lib/auth.ts`, `app/plugins/auth.*.ts`, `app/middleware/auth.global.ts`, `app/composables/useAuth.ts`
|
|
|
|
## Styling System
|
|
|
|
**UnoCSS** with semantic color variables in `app/assets/css/base.css`:
|
|
- `--color-accent`, `--color-neutral`, `--color-text`, `--color-muted`
|
|
- `--color-highlight` (for borders/hover states)
|
|
- Theme-aware: `:root.dark` / `:root.light` with `color-mix()`
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Purpose |
|
|
|----------|---------|
|
|
| `DATABASE_URL` | PostgreSQL connection string |
|
|
| `BETTER_AUTH_SECRET` | Auth encryption |
|
|
|
|
## Key Composables
|
|
|
|
| Composable | Purpose |
|
|
|------------|---------|
|
|
| `useAuth()` | Session/user state, signIn/signOut |
|
|
| `useChat(id)` | Send/regenerate messages, create topics |
|
|
| `useModels()` | Providers + models with auto-subscription |
|
|
| `useAgents()` | User's agents with topics |
|
|
| `useSidebar()` | Sidebar state + resize |
|
|
| `useTheme()` | Accent/neutral theme cookies |
|
|
| `useSettings()` | Settings dialog state |
|
|
|
|
## Development Notes
|
|
|
|
- **Never run dev server as agent** - just complete tasks and signal done
|
|
- Always run `bunx drizzle-kit push` after schema changes
|
|
- Use `protectRoute()` in all API routes for auth
|
|
- All UI state that persists → use cookies (`useCookie()`)
|
|
- Real-time data → SSE events via `server/utils/events.ts`
|
|
- API keys → encrypted client-side before DB storage
|