mirror of
https://github.com/SrIzan10/helium.git
synced 2026-06-06 00:56:58 +00:00
224 lines
6.7 KiB
Markdown
224 lines
6.7 KiB
Markdown
# Agent Guidelines for Helium
|
|
|
|
## Project Overview
|
|
|
|
Helium is a Nuxt 3 application for effortless WebRTC screensharing with:
|
|
|
|
- **Framework**: Nuxt 4 (Vue 3 + TypeScript)
|
|
- **Package Manager**: pnpm
|
|
- **Database**: PostgreSQL with Drizzle ORM
|
|
- **Auth**: Clerk
|
|
- **UI**: shadcn-vue + Tailwind CSS v4
|
|
- **State**: Pinia stores
|
|
- **i18n**: @nuxtjs/i18n (English & Spanish)
|
|
|
|
## Build/Dev/Test Commands
|
|
|
|
### Development
|
|
|
|
```bash
|
|
pnpm dev # Start dev server
|
|
pnpm build # Build for production
|
|
pnpm preview # Preview production build
|
|
pnpm generate # Generate static site
|
|
```
|
|
|
|
### Database
|
|
|
|
```bash
|
|
pnpm db:migrate # Generate and run migrations
|
|
```
|
|
|
|
### UI Components
|
|
|
|
```bash
|
|
pnpm ui:add [component] # Add shadcn-vue component
|
|
```
|
|
|
|
### Running Single Tests
|
|
|
|
Currently no test framework is configured. If adding tests, recommend Vitest for unit tests and Playwright for e2e.
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
app/
|
|
├── components/ # Vue components
|
|
│ ├── app/ # Application-specific components
|
|
│ └── ui/ # shadcn-vue UI components
|
|
├── composables/ # Vue composables (e.g., useWebSocketUrl)
|
|
├── layouts/ # Nuxt layouts
|
|
├── lib/ # Utilities, DB schema, types
|
|
│ ├── db/ # Database schema and utils
|
|
│ ├── schema/ # Zod validation schemas
|
|
│ ├── types/ # TypeScript type definitions
|
|
│ └── utils/ # Helper functions
|
|
├── middleware/ # Route middleware (e.g., auth)
|
|
├── pages/ # File-based routing
|
|
├── plugins/ # Nuxt plugins
|
|
└── state/ # Pinia stores
|
|
|
|
server/
|
|
├── api/ # API endpoints
|
|
├── cron/ # Scheduled tasks
|
|
└── routes/ # Server routes (e.g., WebSocket)
|
|
|
|
drizzle/ # Database migrations
|
|
i18n/ # Translation files
|
|
public/ # Static assets
|
|
```
|
|
|
|
## Code Style Guidelines
|
|
|
|
### TypeScript
|
|
|
|
- **Always use TypeScript**: No `.js` files. All code must be typed.
|
|
- **Type imports**: Use `import type` for type-only imports
|
|
|
|
```typescript
|
|
import type { PrimitiveProps } from "reka-ui";
|
|
import type { HTMLAttributes } from "vue";
|
|
```
|
|
|
|
- **Explicit return types**: Prefer explicit return types for functions
|
|
- **No `any`**: Avoid `any` type. Use `unknown` or proper typing
|
|
- **Interface vs Type**: Use `interface` for object shapes, `type` for unions/intersections
|
|
|
|
### Imports
|
|
|
|
- **Path aliases**: Use `@/` for app directory imports and `~/` for root imports
|
|
|
|
```typescript
|
|
import { cn } from "@/lib/utils";
|
|
import { schema } from "~/lib/schema/new-preset";
|
|
```
|
|
|
|
- **Import order**:
|
|
1. External packages
|
|
2. Vue/Nuxt imports
|
|
3. Type imports
|
|
4. Internal utilities
|
|
5. Components
|
|
6. Relative imports
|
|
|
|
### Vue Components
|
|
|
|
- **Script Setup**: Always use `<script setup lang="ts">`
|
|
- **Props**: Define with TypeScript interfaces
|
|
|
|
```typescript
|
|
interface Props extends PrimitiveProps {
|
|
variant?: ButtonVariants["variant"];
|
|
size?: ButtonVariants["size"];
|
|
class?: HTMLAttributes["class"];
|
|
}
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
as: "button",
|
|
});
|
|
```
|
|
|
|
- **Template**: Keep templates clean, extract complex logic to composables
|
|
- **Component naming**: PascalCase for components, kebab-case for files in multi-word components
|
|
|
|
### Naming Conventions
|
|
|
|
- **Files**:
|
|
- Components: PascalCase (e.g., `Button.vue`, `EditPresetDialog.vue`)
|
|
- Composables: camelCase starting with `use` (e.g., `useWebSocketUrl.ts`)
|
|
- API routes: kebab-case with HTTP method (e.g., `[id].get.ts`, `[id].delete.ts`)
|
|
- Database: camelCase for tables (e.g., `schema.ts`, `migrate.ts`)
|
|
- **Variables**: camelCase
|
|
- **Constants**: UPPER_SNAKE_CASE for true constants, camelCase for config objects
|
|
- **Functions**: camelCase, descriptive verbs (e.g., `createPreset`, `getPresetById`)
|
|
- **Components**: PascalCase
|
|
|
|
### Database (Drizzle)
|
|
|
|
- **Schema location**: `app/lib/db/schema.ts`
|
|
- **Relations**: Define relations separately after table definitions
|
|
- **Column naming**: camelCase in TypeScript, snake_case in SQL
|
|
|
|
```typescript
|
|
export const presets = pgTable("presets", {
|
|
createdBy: text("created_by").notNull(),
|
|
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
});
|
|
```
|
|
|
|
- **Migrations**: Always generate migrations with `pnpm db:migrate`
|
|
|
|
### API Routes (Server)
|
|
|
|
- **Event handlers**: Use `defineEventHandler`
|
|
- **Auth**: Check `event.context.auth()` for authentication
|
|
|
|
```typescript
|
|
const { isAuthenticated, userId } = event.context.auth();
|
|
if (!isAuthenticated || !userId) {
|
|
throw createError({ statusCode: 401, statusMessage: "Unauthorized" });
|
|
}
|
|
```
|
|
|
|
- **Error handling**: Use `createError` for HTTP errors
|
|
- **Validation**: Use Zod schemas from `app/lib/schema/`
|
|
- **Response format**: Consistent structure with `success` and `data`/`message` fields
|
|
|
|
```typescript
|
|
return {
|
|
success: true,
|
|
data: preset,
|
|
};
|
|
```
|
|
|
|
### Error Handling
|
|
|
|
- **Server**: Use `createError()` with proper status codes
|
|
- **Client**: Use `toast` from `vue-sonner` for user feedback
|
|
|
|
```typescript
|
|
try {
|
|
await $fetch("/api/presets", { method: "POST" });
|
|
toast.success(t("presetCreatedSuccessfully"));
|
|
} catch (error) {
|
|
toast.error(t("failedToCreatePreset"));
|
|
}
|
|
```
|
|
|
|
- **Validation**: Use Zod with `.safeParse()` and handle errors
|
|
- **Always catch promises**: Never leave promises unhandled
|
|
|
|
### Formatting
|
|
|
|
- **Indentation**: 2 spaces
|
|
- **Quotes**: Double quotes for strings
|
|
- **Semicolons**: Optional but consistent within files
|
|
- **Line length**: Aim for 80-100 characters, break at 120
|
|
- **Trailing commas**: Use in multiline objects/arrays
|
|
- **Comments**: Prevent comments where possible, if the code is not understandable by itself.
|
|
|
|
### State Management
|
|
|
|
- **Pinia stores**: Located in `app/state/`
|
|
- **Store naming**: Descriptive (e.g., `streamer.ts`, `viewer.ts`)
|
|
- **Composables**: Prefer composables over stores for simple state
|
|
|
|
### i18n
|
|
|
|
- **Always use**: Use `useI18n()` composable for all user-facing strings. That is, you must localize any user-facing text.
|
|
|
|
```typescript
|
|
const { t } = useI18n();
|
|
<h1>{{ t('presets') }}</h1>
|
|
```
|
|
|
|
- **Keys**: camelCase (e.g., `createNewPreset`, `deletePresetConfirm`)
|
|
- **Files**: `i18n/locales/en.json` and `i18n/locales/es.json`
|
|
|
|
## Important Notes
|
|
|
|
- **Authentication**: All protected routes must use auth middleware
|
|
- **WebSocket**: Available at `/ws/signaling` for real-time communication
|
|
- **Environment**: Use `.env` file (not committed) for DATABASE_URL and Clerk keys
|
|
- **Clerk**: Auth provider - use `useAuth()` and `useUser()` composables
|
|
- **Styling**: Use Tailwind utility classes, `cn()` helper for conditional classes
|