Imported from DubbingBase/DubbingBase (
AGENTS.md). Install upstream withnpx skills add DubbingBase/DubbingBase. Copyright stays with the author.
DubbingBase — agent entrypoint
- Read .agents/AGENTS.md first. It takes precedence over everything else.
- For codebase orientation, read .codesight/AGENTS.md, then
.codesight/wiki/index.mdas needed.
AI Agent Instructions and Rules - DubbingBase
This file defines the project architecture, key development commands, and coding rules/best practices that must be strictly followed when making any changes to the codebase.
Scope Boundary: Mobile Excluded
The mobile application is permanently out of scope for agent work. Agents MUST NOT inspect, search, edit, format, test, build, run, or otherwise include apps/mobile. Do not run repository-wide commands that transitively include the mobile workspace; use website-scoped validation instead. If a task would require a mobile change, stop and report the scope conflict.
🏗️ Project Architecture & Hierarchy
The project is structured as a Monorepo managed by pnpm workspaces and turbo. The global system tool configurations (Node.js, Deno, etc.) are managed by Mise via mise.toml.
├── apps/
│ ├── mobile/ # Mobile application (Vue 3, Capacitor)
│ └── website/ # Web application / admin dashboard (Vue 3, Tailwind v4)
├── packages/
│ ├── database/ # Supabase configuration, local migrations, seeds, and generated TypeScript types
│ └── common/ # Shared package (currently empty, intended for common types/utilities)
├── package.json # Global monorepo configuration
├── mise.toml # Environment and task manager (Mise)
└── turbo.json # Turbo Repo configuration to orchestrate builds and tasks
🛠️ Development Commands (via mise)
All development tasks MUST be run via Mise to ensure environment consistency. Always check mise.toml first to see if a command exists before attempting to run raw bash commands or pnpm scripts directly. If a task is defined in mise.toml (e.g. gen-types), you must run it using mise run <task>.
| Command | Description |
|---|---|
mise run dev |
Starts the entire development environment (local Supabase backend + app dev servers). |
mise run backend |
Starts the local Supabase database and environment. |
mise run backend-stop |
Stops the local Supabase backend. |
mise run app |
Starts only the development server for the mobile app in web mode (apps/mobile). |
mise run website |
Starts only the development server for the website (apps/website). |
mise run db-reset |
Resets the local database, applies local migrations, and loads seed data. |
mise run migrate-up |
Applies pending migrations to the local database. |
mise run migrate-down |
Rolls back the last applied migration. |
mise run sync |
Synchronizes mobile app builds with Capacitor platforms (Android, etc.). |
mise run android-dev |
Launches the Android emulator and runs the app in development mode. |
Generating Database TypeScript Types:
After making any database schema changes, run the following command to update TypeScript types in the app:
mise run gen-types
(This command generates types to packages/database/src/database.types.ts).
Remote / Mobile Testing via Tailscale or LAN:
When testing the website from a mobile device or other clients over Tailscale/LAN:
- Ensure the Supabase backend is running (
mise run backend). - Run the website dev server bound to all network interfaces with
mise run website(orHOST=0.0.0.0 pnpm --filter @app/website dev --host 0.0.0.0). - Find your Tailscale IP on the
tailscale0interface usingip a(e.g.100.111.167.123). - Connect from the client browser at
http://<tailscale-ip>:3000(or3001if port 3000 is occupied).
Website Development with Doppler
Doppler is the source of truth for website environment variables. Agents must use the unprefixed secret names consumed by apps/website/nuxt.config.ts (for example, SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY, SUPABASE_SECRET_KEY, TMDB_API_KEY, TVDB_API_KEY, IGDB_CLIENT_ID, and IGDB_CLIENT_SECRET). Do not duplicate values under NUXT_* names; those names exist only as compatibility fallbacks.
Configure the repository once from its root:
doppler setup
Select the dubbingbase project and the appropriate config (dev for local development). Never print secret values. To diagnose configuration, inspect names only with doppler secrets --only-names.
The website requires both the local Supabase backend and the website server. Start them as separate steps from the repository root:
# Start local Supabase first.
mise run backend
# Then start the website with Doppler-injected variables.
doppler run -- mise run website
mise run website does not depend on the backend task, so starting only the website is insufficient. Do not use mise run dev: it invokes the root workspace development task and can include apps/mobile, which is forbidden by the mobile scope boundary. Stop the local backend with mise run backend-stop when finished.
💡 Best Practices by Component
1. Global / Front-end (Common Rules)
- Strict TypeScript: Always type variables, function signatures, and props. Types should strictly follow database types. Never cast using
asand never useany. - Data Fetching Rules:
- Simple single-table DB queries (e.g. a single
supabase.from('table').select(...)) MAY be performed directly without an API route, but must always be encapsulated inside a dedicated API utility composable (e.g.useVoiceActorSubscription). Never inlinesupabase.from(...)calls directly in Vue component<script setup>blocks. - Complex requests (multi-table joins, mutations with side effects, calls to external APIs, or any logic requiring elevated privileges) MUST go through a Nuxt Nitro Server Route (
/api/...). - If a composable is wrapping only simple DB queries, it does not need to route through a server API route. If the composable's logic grows in complexity, migrate it to a Nitro server route at that point.
- Simple single-table DB queries (e.g. a single
- Vue 3: Use the Composition API exclusively with
<script setup lang="ts">syntax. - Formatting: Always run
pnpm formatto format code with Prettier before committing. - Design & Theme: The app follows a premium dark theme. Ensure consistent UI/UX when creating or modifying components. Avoid using default Ionic variables if they result in poor contrast. Instead, explicitly use the established dark theme colors (e.g.,
#1d1d1dfor card backgrounds,#e0e0e0for primary text,#a0a0a0for secondary text,#2a2a2afor borders) or the app's custom CSS variables to maintain a cohesive design. - Presentation Layer Unified Types: Create unified interfaces for display purposes (e.g.,
DisplayMedia,DisplayVoiceActor) instead of passing raw, complex database types (like union types such asMovie | Serie) directly to UI components. This allows the presentation layer to have unified and clean types, and isolates UI templates from underlying database schema complexities.
2. Mobile Application (apps/mobile)
- UI Framework:
- IMPORTANT: The project is migrating away from Ionic, but it is OK to use basic Ionic components (like
ion-content,ion-refresher,ion-router,ion-action-sheet, etc.). Avoid introducing or relying heavily on complex Ionic components. - Use standard HTML/Vue elements styled with Tailwind CSS or Sass where possible for new UI features.
- IMPORTANT: The project is migrating away from Ionic, but it is OK to use basic Ionic components (like
- Capacitor:
- Keep Capacitor for native features/APIs (Camera, Haptics, Keyboard, StatusBar, etc.).
- State Management: Use Pinia for all global stores.
- Styles: Use scoped SCSS (
<style scoped lang="scss">) or Tailwind CSS. - Translations/i18n: All new user-facing strings must be localized using
vue-i18n. Use theuseI18ncomposable and thet()function rather than hardcoding text in templates. Do NOT use fallback strings in thet()function; you must implement actual translations in the locale files. - Feature Flags & Permissions: Use
useFeatureFlagsfor PostHog-driven feature toggles. UseusePermissionsandauthStorefor role-based access control. - Browser APIs over Plugins: Prefer standard HTML5/Browser APIs over Capacitor plugins where applicable (e.g., standard
<input type="file">over the Capacitor Camera plugin) to ensure seamless cross-platform functionality on the web.
3. Web Application (apps/website)
- Styling: The website uses Tailwind CSS v4. Use Tailwind classes for all layouts and UI.
- Data Grids: Use RevoGrid (
@revolist/vue3-datagrid) for complex tables. - Charts: Use Chart.js via
vue-chartjs. - Route Performance & Caching Architecture:
- Dynamic Edge SWR Route Rules: All public media paths (e.g.
/movie/**,/show/**,/game/**, etc.) and all localized prefixes (/fr/**,/es/**,/ja/**) are dynamically generated inapps/website/nuxt.config.tsviaMEDIA_ROUTE_PREFIXES. When adding a new media category or discovery route, always register its prefix inMEDIA_ROUTE_PREFIXESso that all localized variants automatically receive Cloudflare Edge SWR caching. - Global Worker KV Resolver:
apps/website/server/middleware/00-cache.tsautomatically runs on every request to prime the Cloudflare KV cache binding for the isolate. In server routes and composables, useuseCache(event)oruseCache()to access the shared Cloudflare KV cache for external metadata. It is the only persistent server-side data cache; do not add an in-memory value cache. - Edge SWR Caching on Server APIs: Every public GET endpoint MUST set a standardized Edge & Browser SWR
Cache-Controlheader usingsetPublicCacheHeaders(event, profile)(detail,catalog,discovery,search, orstatic). - 0ms Instant Navigation Hydration: When calling
useAsyncDataon public/detail pages, always providegetCachedData: (key, nuxtApp) => nuxtApp.payload.data[key] ?? nuxtApp.static.data[key]to eliminate loading spinners on client-side route transitions and back-navigation. - Progressive DOM Windowing: When rendering dynamic rosters or long lists of cards (cast, episodes, filmography, etc.), never render hundreds of DOM nodes at once. Use the
useProgressiveBatchcomposable oruseIntersectionObserverwith a batch size of 24–36 and a bottom sentinel element. - Client-side Search Filtering: When filtering in-memory arrays via text search inputs, always debounce the query with
refDebounced(query, 150)from@vueuse/coreto prevent frame drops while typing. - Resource Hints & Image Optimization: Media pages must declare
preconnectanddns-prefetchlinks inuseHead.linkfor external CDNs (https://image.tmdb.org,https://thetvdb.com,https://images.igdb.com). Always addloading="lazy"anddecoding="async"to non-heroNuxtImgelements.
- Dynamic Edge SWR Route Rules: All public media paths (e.g.
4. Database & Supabase (packages/database)
- SQL Migrations:
- Never modify the local/remote schema directly. All database schema changes must go through a migration file.
- To create a new migration: Run
pnpm supabase migration new <migration_name>in the appropriate directory. - Migration files are stored in
packages/database/supabase/migrations.
- Querying Local Database:
- The local Supabase database runs on port
55322(you can verify this by runningnpx supabase status). - To query the local DB from the terminal, use:
PGPASSWORD=postgres psql -h 127.0.0.1 -p 55322 -U postgres -d postgres -c "<query>".
- The local Supabase database runs on port
- Seed Data:
- Keep
packages/database/supabase/seed.sqlup to date if you add new tables or reference data.
- Keep
5. External APIs (TMDB, TVDB, IGDB)
Backend routes in apps/website/server/api/ handle integration with TMDB, TVDB, and IGDB with server-side caching.
🤖 AI Agent Behavior Guidelines
- Research First: Before writing code, inspect existing files, imports, and state to understand the setup.
- Preserve Comments: Keep existing comments and docstrings unless explicitly told to remove them.
- Precise Code Changes: Make targeted edits instead of rewriting large files.
- Validation: Test compilation and run formatter tools before completing your turn.
- Local Environment Only: NEVER execute or run production environment commands or actions (e.g., production database pushes, live deployments, remote mutations). Only target local development environments, and do NOT suggest production actions unless strictly and explicitly asked by the user. Specifically, NEVER run
supabase db pushorsupabase functions deploydirectly. All remote deployments must happen strictly through the CI/CD pipeline on themainbranch. - Token Saving: Use
rtk(binary) (https://github.com/rtk-ai/rtk) to save tokens whenever possible. - Scratch & Test Scripts: Do NOT leave one-off test scripts (like
test_*.ts) in the root of the project. If you need a script to test an external API or debug a function, place it inscripts/scratch/or use the.gemini/scratchfolder. - Caching Rules:
- Remember that there is no local Redis cache in the development environment.
- When doing your fetches (e.g. testing APIs via scratch scripts), save the output locally (e.g. in JSON files in the scratch folder) so you don't have to fetch it again repeatedly.
- Changesets: Every code or configuration change must include an appropriate Changesets file in
.changeset/. Keep the entry scoped to the affected package(s), and never include@app/mobileunless mobile work was explicitly authorized.
