- Monorepo: Turborepo-managed, with
apps/(main: Next.js web app) andpackages/(shared code:common,shared,ai,ui, etc.). - Core Technologies: Next.js 15 (App Router), React 19.0.0, TypeScript, Tailwind CSS, shadcn/ui, Zustand, Drizzle ORM (Neon PostgreSQL), Better-Auth, Framer Motion, Lucide icons.
- AI/Agents: Agentic Graph System in
packages/ai/(supports OpenAI, Anthropic, Google, Groq, etc.). - Best Practices: Use environment variables, enums for string keys, named exports, shadcn/ui for UI, Bun for all scripts, and document changes in
memory-bank/.
- Use
buninstead ofnpmfor all operations
- Make sure no string in #codebase, use enum pattern.
- Don't hard code values in the codebase.
- Use environment variables for configuration (e.g., API keys, product IDs, ADMIN_USER_IDS for Better-Auth admin access - supports comma-separated user IDs)
- Use centralize enum for custom reusable keys.
- 4-space indentation, single quotes, 100 char line length
- PascalCase components, camelCase hooks/utils, kebab-case files
- Named exports preferred over default exports
- Use oxlint for fast comprehensive linting (run
bun run lint) - Use dprint for code formatting (run
bun run fmt) - Use Prettier for markdown files only (run
bun run format)
- Minimal Design: Follow shadcn/ui principles with clean, minimal aesthetics
- No Colors: Use only black/white/muted colors (avoid gradients, bright colors)
- Minimal Icons: Reduce icon usage to essentials only
- Clean Typography: Rely on typography hierarchy over visual decorations
- Neutral Palette: Use
text-muted-foreground,bg-muted, standard shadcn colors - Simple Interactions: Avoid flashy animations or complex visual effects
- Make sure you DO NOT CREATE ANY debug and test FILES IN ./ ROOT DIRECTORY. Only use files in /temps or apps/web/app/tests/ or /scripts.
- Make sure you run
bun devand check the app console to see if there are any errors before starting to work on anothers task. fix it first. - Plan first, then implement. For substantial changes, request maintainer feedback on the plan before coding.
- REQUIRED: Run
bun run fmtto auto-fix formatting issues with dprint - NEVER commit changes yourself - DO NOT execute
git commitunless you have my approval - Run
bun run lint(oxlint) for comprehensive error checking - Run
bun run buildto verify compilation before major changes - Test core functionality after significant changes
-
NEVER run
./deploy-fly.shwithout user permission -
Always ask for approval before any production deployment
-
This applies to ALL deployment commands and scripts
-
Production Deployment: Use
./deploy-fly.shto deploy to Fly.io (ONLY WITH USER APPROVAL)- Interactive:
./deploy-fly.sh(prompts for version bump type) - Automated:
./deploy-fly.sh --auto --version patch(patch/minor/major) - Features: Auto-commit, semantic versioning, git tagging, Fly.io deployment
- App URL: https://vtchat.io.vn (primary) / https://vtchat.fly.dev (backup)
- Script handles: git status checks, version tagging, pushing to remote, Fly.io deployment
- Interactive:
- Manual fixes: Run
bun run fmtandbun run fmt:checkfor comprehensive formatting fixes with dprint - Philosophy: Encourage good practices without blocking development flow
- Next.js 15 with App Router, React 19.0.0, TypeScript, Tailwind CSS
- Zustand for state, Drizzle ORM for DB, Better Auth for authentication
- Custom bot detection with Better-Auth plugin using isbot library
- Framer Motion for animations, Radix UI components
- Shadcn/ui for UI components, Lucide icons, clsx for classnames
- Payment integration with Creem.io
- Turborepo monorepo:
apps/andpackages/ @repo/common- components/hooks,@repo/shared- types/utils- Use
'use client'for client components
- Chat application with AI models (OpenAI, Anthropic, etc.)
- Subscription tiers:VT offers free tier, and with VT+ focusing only on 3 exclusive research capabilities: Deep Research, Pro Search.
- MCP integration for external tools
- Use promptBoost tools to enhance prompt quality
- You can use playwright MCP tool to test web components integration
- use ChatMode.ChatMode.GEMINI_3_FLASH_LITE to test instead GEMINI_3_PRO because cost.
- Test files should be in
apps/web/app/tests/. Example:./test-vt-plus-only.jsshould be moved toapps/web/app/tests/test-vt-plus-only.js - Every implemented feature should have a test case to maintain quality
- Every unit test should cover critical paths and edge cases
- Use
vitestfor testing, with@testing-library/reactfor React components. - Run tests regularly to ensure code quality
- Use
@testing-library/jest-dom/vitestfor custom matchers - Use
@testing-library/user-eventfor simulating user interactions - Use
@testing-library/reactfor rendering components in tests - Use
@testing-library/jest-domfor custom matchers in tests - Use
@testing-library/react-hooksfor testing custom hooks - Use
@testing-library/domfor DOM-related utilities in tests
- Use
buninstead ofnpmoryarn - Use
bunfor all package management and script execution
- when try to install components, navigatete to ~/Developer/learn-by-doing/vtchat/packages/ui first, then use bunx
- To install shadcn components, check example command:
npx shadcn@latest add label - Use shadcn/ui components for UI elements
- Use
@repo/uifor shared UI components - Use lucide icons from
lucide-react - Use Tailwind CSS for styling
- Use
clsxfor conditional class names - Use
tailwind-mergefor merging Tailwind classes - Use
framer-motionfor animations
- Always use the centralized ky HTTP client:
import { http } from '@repo/shared/lib/http-client' - Never use fetch() directly - bypasses security, error handling, and standardization
- Automatic JSON handling: Methods return parsed JSON automatically
- Built-in error handling: HTTP errors are handled consistently
- API key security: Pass keys via
apiKeysoption, never in headers
// GET requests
const data = await http.get('/api/user/profile');
// POST with data
const result = await http.post('/api/completion', { body: requestData });
// Streaming responses (for AI completions)
const response = await http.postStream('/api/completion', { body, signal });
// Requests with API keys
const result = await http.post('/api/external', {
body: data,
apiKeys: { openai: 'sk-...', anthropic: 'sk-...' },
});- Use
try/catchfor async operations - Use Pino logger from
@repo/shared/loggerfor structured logging with automatic PII redaction - Use
toastfrom@repo/uifor user notifications - Use
ErrorBoundaryfor catching errors in React components
-
DO NOT USE console.log/error/warn** - Always use Pino logger log.info/error/debug/warn (
@repo/shared/lib/logger) -
Import:
import { log } from '@repo/shared/lib/logger'for basic logging (uselognotlogger) -
Usage:
log.info({ key: value }, 'message'),log.error({ error }, 'message') -
Automatic PII redaction for sensitive fields (apiKey, token, password, email, etc.)
-
Structured logging - Always pass metadata as first parameter, message as second
-
API key security - API keys automatically redacted in logs (apiKey, api_key, Authorization headers)
-
PII masking - All string fields automatically masked using
maskPII()function -
Environment-specific configurations (development/production/test)
-
Log levels: debug (dev only), info, warn, error, fatal
- Use Markdown files for documentation, those guides with Guides markdown files should be in
docs/guides/ - You can search for documentation using
context7MCP tool - You can search the internet using MCP tool
tavily-search - Documentation should be in
docs/directory - Help Center = FAQ: When user mentions "help center", they mean the FAQ page for end users
- After every session, you should document what's been done and report status then update
memory-bank/*.mdmd files in that directory. - Periodically update
AGENT.md,AGENTS.mdandCLAUDE.mdwith latest changes from #codebase and #changes.
Continue Session: 'continue_session [session_file' (alias continue) continue')
- Resumes a previous Amp session with enhanced analysis
- If no file provided, lists 5 most recent sessions from ./local_ai_docs/sessions/*
- Usage: Ask Amp to "run continue_session" or "use continue_session with [filename]"
Save Session: save_session [options] (alias save')
- Saves current session with comprehensive analysis
- Options:
- '--deepthink': Enhanced analysis for deeper insights
- '--fast': Quick save without enhanced analysis
- Creates files in • •/local_ai_docs/sessions/ with format: "[datel-[title]-amp.md"
- Usage: Ask Amp to "run save_session" or "save_session --deepthink"
Plan Loop: 'plan_loop [spec_file] [options]' (alias 'plan*)
- Comprehensive feature planning with 7-step process
- Options:
- '--deepthink: Enhanced planning and peer review
- Creates detailed implementation specifications
- Usage: Ask Amp to "run plan_loop with spec.md --deepthink"
Implementation Loop: "implementation_loop [spec_file] [options] (alias "impl')
- Iterative implementation with testing and validation
- Options:
- '--deepthink': Enhanced analysis for complex decisions
- '--fast': Skip enhanced analysis for rapid cycles
- Includes quality gates and automatic testing
- Usage: Ask Amp to "run implementation_loop with spec.md --deepthink"
Default to using Bun instead of Node.js.
- Use
bun <file>instead ofnode <file>orts-node <file> - Use
bun testinstead ofjestorvitest - Use
bun build <file.html|file.ts|file.css>instead ofwebpackoresbuild - Use
bun installinstead ofnpm installoryarn installorpnpm install - Use
bun run <script>instead ofnpm run <script>oryarn run <script>orpnpm run <script> - Bun automatically loads .env, so don't use dotenv.
Bun.serve()supports WebSockets, HTTPS, and routes. Don't useexpress.bun:sqlitefor SQLite. Don't usebetter-sqlite3.Bun.redisfor Redis. Don't useioredis.Bun.sqlfor Postgres. Don't usepgorpostgres.js.WebSocketis built-in. Don't usews.- Prefer
Bun.fileovernode:fs's readFile/writeFile - Bun.$
lsinstead of execa.
Use bun test to run tests.
import { test, expect } from "bun:test";
test("hello world", () => {
expect(1).toBe(1);
});Use HTML imports with Bun.serve(). Don't use vite. HTML imports fully support React, CSS, Tailwind.
Server:
import index from "./index.html"
Bun.serve({
routes: {
"/": index,
"/api/users/:id": {
GET: (req) => {
return new Response(JSON.stringify({ id: req.params.id }));
},
},
},
// optional websocket support
websocket: {
open: (ws) => {
ws.send("Hello, world!");
},
message: (ws, message) => {
ws.send(message);
},
close: (ws) => {
// handle close
}
},
development: {
hmr: true,
console: true,
}
})HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. <link> tags can point to stylesheets and Bun's CSS bundler will bundle.
<html>
<body>
<h1>Hello, world!</h1>
<script type="module" src="./frontend.tsx"></script>
</body>
</html>With the following frontend.tsx:
import React from "react";
// import .css files directly and it works
import './index.css';
import { createRoot } from "react-dom/client";
const root = createRoot(document.body);
export default function Frontend() {
return <h1>Hello, world!</h1>;
}
root.render(<Frontend />);Then, run index.ts
bun --hot ./index.tsFor more information, read the Bun API docs in node_modules/bun-types/docs/**.md.
This section is managed by codemod CLI.
- Core skill:
.opencode/skills/codemod/SKILL.md - Package skills:
.opencode/skills/<package-skill>/SKILL.md - Codemod MCP: use it for JSSG authoring guidance, CLI/workflow guidance, import-helper guidance, and semantic-analysis-aware codemod work.
- Codemod creation command:
/codemod - List installed Codemod skills:
npx codemod ai list --harness opencode --format json