Complete the i18n migration by switching runtime setup and remaining components to i18next-vue, and add shared locale constants/helpers for SSR and client language handling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
13 KiB
AGENTS.md
This file provides guidance for AI coding agents working with the Holistream codebase. hallo
Project Overview
Holistream is a Vue 3 streaming application with Server-Side Rendering (SSR) deployed on Cloudflare Workers. It provides video upload, management, and streaming capabilities for content creators.
Key Characteristics
- Type: Full-stack web application with SSR
- Primary Language: TypeScript
- Package Manager: Bun (evident from
bun.lock) - Deployment Target: Cloudflare Workers
Technology Stack
| Category | Technology | Version |
|---|---|---|
| Framework | Vue | 3.5.27 |
| Router | Vue Router | 5.0.2 |
| Server Framework | Hono | 4.11.7 |
| Build Tool | Vite | 7.3.1 |
| CSS Framework | UnoCSS | 66.6.0 |
| UI Components | PrimeVue | 4.5.4 |
| State Management | Pinia | 3.0.4 |
| Server State | Pinia Colada | 0.21.2 |
| Meta/SEO | @unhead/vue | 2.1.2 |
| Utilities | VueUse | 14.2.0 |
| Validation | Zod | 4.3.6 |
| Deployment | Wrangler | 4.62.0 |
Project Structure
.
├── src/
│ ├── api/ # API client and HTTP adapters
│ │ ├── client.ts # Auto-generated API client from OpenAPI spec
│ │ ├── httpClientAdapter.client.ts # Client-side fetch adapter
│ │ └── httpClientAdapter.server.ts # Server-side fetch adapter
│ ├── client.ts # Client entry point (hydration)
│ ├── components/ # Vue components
│ │ ├── dashboard/ # Dashboard-specific components
│ │ ├── icons/ # Custom icon components
│ │ ├── ui/ # UI primitive components
│ │ ├── ClientOnly.tsx # SSR-safe client-only wrapper
│ │ ├── DashboardLayout.vue # Main dashboard layout
│ │ ├── GlobalUploadIndicator.vue
│ │ ├── NotificationDrawer.vue
│ │ └── RootLayout.vue # Root application layout
│ ├── composables/ # Vue composables
│ │ └── useUploadQueue.ts # Upload queue management
│ ├── index.tsx # Server entry point (Hono app)
│ ├── lib/ # Utility libraries
│ │ ├── constants.ts # Application constants
│ │ ├── directives/ # Custom Vue directives
│ │ ├── hoc/ # Higher-order components
│ │ ├── interface.ts # TypeScript interfaces
│ │ ├── liteMqtt.ts # MQTT client (browser)
│ │ ├── manifest.ts # Vite manifest utilities
│ │ ├── PiniaSharedState.ts # Pinia state hydration plugin
│ │ ├── primePassthrough.ts # PrimeVue theme configuration
│ │ ├── replateStreamText.ts
│ │ └── utils.ts # Utility functions (cn, formatters, etc.)
│ ├── main.ts # App factory function
│ ├── mocks/ # Mock data for development
│ ├── routes/ # Route components (page components)
│ │ ├── auth/ # Authentication pages
│ │ ├── home/ # Public pages (landing, terms, privacy)
│ │ ├── notification/ # Notification page
│ │ ├── overview/ # Dashboard overview
│ │ ├── plans/ # Payments & plans
│ │ ├── profile/ # User profile
│ │ ├── upload/ # Video upload
│ │ ├── video/ # Video management
│ │ ├── index.ts # Router configuration
│ │ └── NotFound.vue # 404 page
│ ├── server/ # Server-side utilities
│ │ └── modules/
│ │ └── merge.ts # Video chunk merge logic
│ ├── stores/ # Pinia stores
│ │ └── auth.ts # Authentication store
│ ├── type.d.ts # TypeScript declarations
│ └── worker/ # Worker utilities
│ ├── html.ts
│ └── ssrLayout.ts
├── bootstrap_btn.ts # Bootstrap button preset for UnoCSS
├── ssrPlugin.ts # Custom Vite SSR plugin
├── uno.config.ts # UnoCSS configuration
├── vite.config.ts # Vite configuration
├── wrangler.jsonc # Cloudflare Workers configuration
├── tsconfig.json # TypeScript configuration
├── package.json # Package dependencies
├── bun.lock # Bun lock file
├── docs.json # OpenAPI/Swagger spec for API
├── auto-imports.d.ts # Auto-generated type declarations
└── components.d.ts # Auto-generated component declarations
Build and Development Commands
# Install dependencies
bun install
# Start development server with hot reload
bun dev
# Build for production (client + worker)
bun run build
# Preview production build locally
bun preview
# Deploy to Cloudflare Workers
bun run deploy
# Generate TypeScript types from Wrangler config
bun run cf-typegen
# View Cloudflare Worker logs
bun run tail
Note
: While npm commands work (
npm run dev, etc.), the project uses Bun as its primary package manager.
Architecture Details
SSR Architecture
The application uses a custom SSR setup defined in ssrPlugin.ts:
- Build Order: Client bundle is built FIRST, then the Worker bundle
- Manifest Injection: Vite manifest is injected into the server build for asset rendering
- Environment-based Resolution:
httpClientAdapterandliteMqttresolve to different implementations based on SSR context
Entry Points:
- Server:
src/index.tsx- Hono app that renders Vue SSR stream - Client:
src/client.ts- Hydrates the SSR-rendered application - App Factory:
src/main.ts- Creates the Vue app instance (used by both)
State Management with SSR
Uses Pinia Colada for server state with SSR hydration:
- Server-side queries are fetched and serialized to
window.__APP_DATA__ - Client hydrates the query cache via
hydrateQueryCache() - Pinia state is serialized and restored via
PiniaSharedStateplugin
Module Aliases
Configured in tsconfig.json and vite.config.ts:
| Alias | Resolution |
|---|---|
@/ |
src/ |
@httpClientAdapter |
src/api/httpClientAdapter.server.ts (SSR) or .client.ts (browser) |
@liteMqtt |
src/lib/liteMqtt.server.ts (SSR) or .ts (browser) |
API Client Architecture
The API client (src/api/client.ts) is auto-generated from the OpenAPI spec (docs.json):
- Uses
customFetchadapter that differs between client/server - Server adapter (
httpClientAdapter.server.ts): Forwards cookies, merges headers, proxies toapi.pipic.fun - Client adapter (
httpClientAdapter.client.ts): Standard fetch with credentials - API proxy route:
/r/*paths proxy tohttps://api.pipic.fun
Routing Structure
Routes are defined in src/routes/index.ts with three main layout groups:
- Public (
/): Landing page, terms, privacy - Auth (
/login,/sign-up,/forgot): Authentication pages (redirects if logged in) - Dashboard: Protected routes requiring authentication
/overview- Main dashboard/upload- Video upload with queue management/video- Video list/video/:id- Video detail/edit/payments-and-plans- Billing management/notification,/profile- User settings
Route meta supports @unhead/vue for SEO:
meta: {
head: {
title: "Page Title",
meta: [{ name: "description", content: "..." }]
}
}
Styling System (UnoCSS)
Configuration in uno.config.ts:
- Presets: Wind4 (Tailwind-like), Typography, Attributify, Bootstrap buttons
- Custom Colors:
primary(#14a74b)secondary(#fd7906)accent,success,info,warning,danger
- Shortcuts:
press-animatedfor button press effects - Transformers:
transformerCompileClass(prefix:_for compiled classes)transformerVariantGroup
Use cn() from src/lib/utils.ts for conditional class merging (combines clsx + tailwind-merge).
Component Auto-Import
Components are auto-imported via unplugin-vue-components:
- PrimeVue components resolved via
PrimeVueResolver - Vue/Pinia/Vue Router APIs auto-imported via
unplugin-auto-import - Type declarations auto-generated to
components.d.tsandauto-imports.d.ts
Development Guidelines
Code Style
- TypeScript: Strict mode enabled
- JSX/TSX: Supported for components (import source:
vue) - CSS: Use UnoCSS utility classes; custom CSS in component
<style>blocks when needed
File Organization
- Page components go in
src/routes/following the route structure - Reusable components go in
src/components/ - Composables go in
src/composables/ - Stores go in
src/stores/ - Server utilities go in
src/server/
HTTP Requests
Always use the generated API client instead of raw fetch:
import { client } from '@/api/client';
// Example
const response = await client.auth.loginCreate({ email, password });
The client handles:
- Base URL resolution
- Cookie forwarding (server-side)
- Type safety
Authentication Flow
useAuthStoremanages auth state with cookie-based sessionsinit()is called on every request to fetch current user via/meendpointbeforeEachrouter guard redirects unauthenticated users from protected routes- MQTT client connects on user login for real-time notifications
File Upload Architecture
Upload queue (src/composables/useUploadQueue.ts):
- Supports both local files and remote URLs
- Presigned POST URLs fetched from API
- Parallel chunk upload (90MB chunks, max 3 parallel)
- Progress tracking with speed calculation
Type Safety
- TypeScript strict mode enabled
CloudflareBindingsinterface for environment variables (generated viacf-typegen)- API types auto-generated from backend OpenAPI spec (
docs.json)
Environment Configuration
Cloudflare Worker Bindings
Configured in wrangler.jsonc:
{
"name": "holistream",
"compatibility_date": "2025-08-03",
"compatibility_flags": ["nodejs_compat"],
"observability": { ... }
}
- No explicit secrets in code - use Wrangler secrets management
- Access environment variables via Hono context:
c.env.VAR_NAME
Local Environment
Create .dev.vars for local development secrets (do not commit):
SECRET_KEY=...
Testing and Quality
Current Status: There are currently no automated test suites (like Vitest) or linting tools (like ESLint/Prettier) configured.
When adding tests or linting:
- Add appropriate dev dependencies
- Update this section with commands and conventions
- Consider the SSR environment when writing tests
Security Considerations
- Cookie Security: Cookies are httpOnly, secure, and sameSite
- CORS: Configured via Hono's CORS middleware
- API Proxy: Backend API is never exposed directly to the browser; all requests go through
/r/*proxy - Input Validation: Use Zod for runtime validation
- XSS Protection: HTML escaping is applied to SSR data via
htmlEscape()function
Common Patterns
Creating a New Page
- Create component in
src/routes/<section>/PageName.vue - Add route to
src/routes/index.tswith appropriate meta - Use
headin route meta for SEO if needed
Using the Upload Queue
import { useUploadQueue } from '@/composables/useUploadQueue';
const { items, addFiles, addRemoteUrls, startQueue } = useUploadQueue();
Accessing Hono Context in Components
import { inject } from 'vue';
const honoContext = inject('honoContext');
Conditional Classes
import { cn } from '@/lib/utils';
const className = cn(
'base-class',
isActive && 'active-class',
variant === 'primary' ? 'text-primary' : 'text-secondary'
);
External Dependencies
- Backend API:
https://api.pipic.fun - MQTT Broker:
wss://mqtt-dashboard.com:8884/mqtt - Fonts: Google Fonts (Google Sans loaded from fonts.googleapis.com)
Important Files Reference
| Purpose | Path |
|---|---|
| Server entry | src/index.tsx |
| Client entry | src/client.ts |
| App factory | src/main.ts |
| Router config | src/routes/index.ts |
| API client | src/api/client.ts |
| Auth store | src/stores/auth.ts |
| SSR plugin | ssrPlugin.ts |
| UnoCSS config | uno.config.ts |
| Wrangler config | wrangler.jsonc |
| Vite config | vite.config.ts |
This document was generated for AI coding agents. For human contributors, see README.md.