11 KiB
11 KiB
Handy Server - Development Guidelines
This document contains the development guidelines and instructions for the Happy Server project. This guide OVERRIDES any default behaviors and MUST be followed exactly.
Project Overview
Name: happy-server
Repository: https://github.com/slopus/happy-server.git
License: MIT
Language: TypeScript
Runtime: Node.js 20
Framework: Fastify with opinionated architecture
Core Technology Stack
- Runtime: Node.js 20
- Language: TypeScript (strict mode enabled)
- Web Framework: Fastify 5
- Database: PostgreSQL with Prisma ORM
- Validation: Zod
- HTTP Client: Axios
- Real-time: Socket.io
- Cache/Pub-Sub: Redis (via ioredis)
- Testing: Vitest
- Package Manager: Yarn (not npm)
Development Environment
Commands
yarn build
- TypeScript type checkingyarn start
- Start the serveryarn test
- Run testsyarn migrate
- Run Prisma migrationsyarn generate
- Generate Prisma clientyarn db
- Start local PostgreSQL in Docker
Environment Requirements
- FFmpeg installed (for media processing)
- Python3 installed
- PostgreSQL database
- Redis (for event bus and caching)
Code Style and Structure
General Principles
- Use 4 spaces for tabs (not 2 spaces)
- Write concise, technical TypeScript code with accurate examples
- Use functional and declarative programming patterns; avoid classes
- Prefer iteration and modularization over code duplication
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
- All sources must be imported using "@/" prefix (e.g.,
import "@/utils/log"
) - Always use absolute imports
- Prefer interfaces over types
- Avoid enums; use maps instead
- Use strict mode in TypeScript for better type safety
Folder Structure
/sources # Root of the sources
├── /app # Application entry points
│ ├── api.ts # API server setup
│ └── timeout.ts # Timeout handling
├── /apps # Applications directory
│ └── /api # API server application
│ └── /routes # API routes
├── /modules # Reusable modules (non-application logic)
├── /utils # Low level or abstract utilities
├── /recipes # Scripts to run outside of the server
├── /services # Core services
│ └── pubsub.ts # Pub/sub service
├── /storage # Database and storage utilities
│ ├── db.ts # Database client
│ ├── inTx.ts # Transaction wrapper
│ ├── repeatKey.ts # Key utilities
│ ├── simpleCache.ts # Caching utility
│ └── types.ts # Storage types
└── main.ts # Main entry point
Naming Conventions
- Use lowercase with dashes for directories (e.g., components/auth-wizard)
- When writing utility functions, always name file and function the same way
- Test files should have ".spec.ts" suffix
Tool Usage
Web Search and Fetching
- When in doubt, use web tool to get answers from the web
- Search web when you have some failures
File Operations
- NEVER create files unless they're absolutely necessary
- ALWAYS prefer editing existing files to creating new ones
- NEVER proactively create documentation files (*.md) or README files unless explicitly requested
Utilities
Writing Utility Functions
- Always name file and function the same way for easy discovery
- Utility functions should be modular and not too complex
- Always write tests for utility functions BEFORE writing the code
- Iterate implementation and tests until the function works as expected
- Always write documentation for utility functions
Modules
Module Guidelines
- Modules are bigger than utility functions and abstract away complexity
- Each module should have a dedicated directory
- Modules usually don't have application-specific logic
- Modules can depend on other modules, but not on application-specific logic
- Prefer to write code as modules instead of application-specific code
When to Use Modules
- When integrating with external services
- When abstracting complexity of some library
- When implementing related groups of functions (math, date, etc.)
Known Modules
- ai: AI wrappers to interact with AI services
- eventbus: Event bus to send and receive events between modules and applications
- lock: Simple lock to synchronize access to resources in the whole cluster
- media: Tools to work with media files
Applications
- Applications contain application-specific logic
- Applications have the most complexity; other parts should assist by reducing complexity
- When using prompts, write them to "_prompts.ts" file relative to the application
Database
Prisma Usage
- Prisma is used as ORM
- Use "inTx" to wrap database operations in transactions
- Do not update schema without absolute necessity
- For complex fields, use "Json" type
- NEVER DO MIGRATION YOURSELF. Only run yarn generate when new types needed
Current Schema Status
The project has pending Prisma migrations that need to be applied:
- Migration:
20250715012822_add_metadata_version_agent_state
Events
Event Bus
- eventbus allows sending and receiving events inside the process and between different processes
- eventbus is local or redis based
- Use "afterTx" to send events after transaction is committed successfully instead of directly emitting events
Testing
- Write tests using Vitest
- Test files should be named the same as source files with ".spec.ts" suffix
- For utility functions, write tests BEFORE implementation
API Development
- API server is in
/sources/apps/api
- Routes are in
/sources/apps/api/routes
- Use Fastify with Zod for type-safe route definitions
- Always validate inputs using Zod
Docker Deployment
The project includes a multi-stage Dockerfile:
- Builder stage: Installs dependencies and builds the application
- Runner stage: Minimal runtime with only necessary files
- Exposes port 3000
- Requires FFmpeg and Python3 in the runtime
Important Reminders
- Do what has been asked; nothing more, nothing less
- NEVER create files unless they're absolutely necessary for achieving your goal
- ALWAYS prefer editing an existing file to creating a new one
- NEVER proactively create documentation files (*.md) or README files unless explicitly requested
- Use 4 spaces for tabs (not 2 spaces)
- Use yarn instead of npm for all package management
Debugging Notes
Remote Logging Setup
- Use
DANGEROUSLY_LOG_TO_SERVER_FOR_AI_AUTO_DEBUGGING=true
env var to enable - Server logs to
.logs/
directory with timestamped files (format:MM-DD-HH-MM-SS.log
) - Mobile and CLI send logs to
/logs-combined-from-cli-and-mobile-for-simple-ai-debugging
endpoint
Common Issues & Tells
Socket/Connection Issues
- Tell: "Sending update to user-scoped connection" but mobile not updating
- Tell: Multiple "User disconnected" messages indicate socket instability
- Tell: "Response from the Engine was empty" = Prisma database connection lost
Auth Flow Debugging
- CLI must hit
/v1/auth/request
to create auth request - Mobile scans QR and hits
/v1/auth/response
to approve - Tell: 404 on
/v1/auth/response
= server likely restarted/crashed - Tell: "Auth failed - user not found" = token issue or user doesn't exist
Session Creation Flow
- Sessions created via POST
/v1/sessions
with tag-based deduplication - Server emits "new-session" update to all user connections
- Tell: Sessions created but not showing = mobile app not processing updates
- Tell: "pathname /" in mobile logs = app stuck at root screen
Environment Variables
- CLI: Use
yarn dev:local-server
(NOTyarn dev
) to load.env.dev-local-server
- Server: Use
yarn dev
to start with proper env files - Tell: Wrong server URL = check
HAPPY_SERVER_URL
env var - Tell: Wrong home dir = check
HAPPY_HOME_DIR
(should be~/.happy-dev
for local)
Quick Diagnostic Commands
IMPORTANT: Always Start Debugging With These
# 1. CHECK CURRENT TIME - Logs use local time, know what's current!
date
# 2. CHECK LATEST LOG FILES - Server creates new logs on restart
ls -la .logs/*.log | tail -5
# 3. VERIFY YOU'RE LOOKING AT CURRENT LOGS
# Server logs are named: MM-DD-HH-MM-SS.log (month-day-hour-min-sec)
# If current time is 13:45 and latest log is 08-15-10-57-02.log from 10:57,
# that log started 3 hours ago but may still be active!
tail -1 .logs/[LATEST_LOG_FILE] # Check last entry timestamp
Common Debugging Patterns
# Check server logs for errors
tail -100 .logs/*.log | grep -E "(error|Error|ERROR|failed|Failed)"
# Monitor session creation
tail -f .logs/*.log | grep -E "(new-session|Session created)"
# Check active connections
tail -100 .logs/*.log | grep -E "(Token verified|User connected|User disconnected)"
# See what endpoints are being hit
tail -100 .logs/*.log | grep "incoming request"
# Debug socket real-time updates
tail -500 .logs/*.log | grep -A 2 -B 2 "new-session" | tail -30
tail -200 .logs/*.log | grep -E "(websocket|Socket.*connected|Sending update)" | tail -30
# Track socket events from mobile client
tail -300 .logs/*.log | grep "remote-log.*mobile" | grep -E "(SyncSocket|handleUpdate)" | tail -20
# Monitor session creation flow end-to-end
tail -500 .logs/*.log | grep "session-create" | tail -20
tail -500 .logs/*.log | grep "cmed556s4002bvb2020igg8jf" -A 3 -B 3 # Replace with actual session ID
# Check auth flow for sessions API
tail -300 .logs/*.log | grep "auth-decorator.*sessions" | tail -10
# Debug machine registration and online status
tail -500 .logs/*.log | grep -E "(machine-alive|machine-register|update-machine)" | tail -20
tail -500 .logs/*.log | grep "GET /v1/machines" | tail -10
tail -500 .logs/*.log | grep "POST /v1/machines" | tail -10
# Check what mobile app is seeing
tail -500 .logs/*.log | grep "📊 Storage" | tail -20
tail -500 .logs/*.log | grep "applySessions.*active" | tail -10
Time Format Reference
- CLI logs:
[HH:MM:SS.mmm]
in local time (e.g.,[13:45:23.738]
) - Server logs: Include both
time
(Unix ms) andlocalTime
(HH:MM:ss.mmm) - Mobile logs: Sent with
timestamp
in UTC, converted tolocalTime
on server - All consolidated logs: Have
localTime
field for easy correlation - When writing a some operations on db, like adding friend, sending a notification - always create a dedicated file in relevant subfolder of the @sources/app/ folder. Good example is "friendAdd", always prefix with an entity type, then action that should be performed.
- Never create migrations yourself, it is can be done only by human
- Do not return stuff from action functions "just in case", only essential
- Do not add logging when not asked
- do not run non-transactional things (like uploadign files) in transactions
- After writing an action - add a documentation comment that explains logic, also keep it in sync.
- always use github usernames