The GAIO Ecosystem API is a Node.js backend application built with TypeScript that serves multiple client platforms (web and mobile) through REST APIs and potentially WebSockets. The project uses Bun as its JavaScript runtime and follows a modular, domain-driven architecture with a focus on the Dependency Inversion Principle.
src/ ├── apps/ # Application-specific code organized by project │ ├── grip/ # "Grip" application module │ │ ├── controllers/ # Handle HTTP requests and responses │ │ ├── routes/ # Define API endpoints │ │ └── use-cases/ # Business logic implementation │ └── manager/ │ ├── controllers/ │ ├── routes/ │ └── use-cases/ │ ├── db/ # Database related code │ └── postgresql/ # PostgreSQL specific implementations │ └── repositories/ # Data access layer ├── server/ # Server configuration │ ├── middlewares/ # Express middlewares │ └── bootstrap.ts # Server initialization └── utils/ # Shared utility functions ├── env.ts # Environment configuration └── logger.ts # Logging utility
The project follows a Clean Architecture pattern with the following layers: 1. Controllers - Handle HTTP requests/responses and input validation
- Use Cases - Implement business logic 3. Repositories - Handle data access and persistence
This separation ensures:
- Business logic is independent of frameworks and external dependencies
- Code is more testable and maintainable
- Changes in one layer have minimal impact on others
- TypeScript Best Practices
- Use strict type checking
- Avoid any type when possible
Use interfaces and types to define data structures
- Error Handling
- Use proper error handling with try/catch blocks
- Create custom error classes for different error types
- Return appropriate HTTP status codes
- Asynchronous Code
- Use async/await instead of callbacks
- Handle promise rejections properly
- Code Formatting
- Use Biome for consistent code formatting
Follow the configured rules without exceptions
- Write simple, readable code that's easy to understand
- Avoid complex abstractions when simpler solutions exist
- Prioritize clarity over cleverness
- Don't implement features until they're actually needed
- Avoid speculative generality
- Focus on current requirements rather than potential future needs
- Be careful, repeating your self a few times is okay - consider carefully how long would take between refactoring and just simply repeating yourself
- Extract common functionality into reusable components
- Use shared utilities for common operations
- RESTful Principles
- Use appropriate HTTP methods (GET, POST, PUT, DELETE)
- Return proper status codes
- Use consistent URL patterns
- Input Validation
- Validate all input data using Zod schemas
- Return clear error messages for invalid inputs
- Authentication & Authorization
- Use JWT for authentication
- Implement proper middleware for protected routes
- Follow security best practices for token handling
- Runtime: Bun
- Framework: Express.js
- Database ORM: Drizzle
- Validation: Zod
- Authentication: JWT
- Code Formatting: Biome
- Create a new feature branch from main
- Implement the feature following the architecture pattern
- Submit a pull request for review
- Address review comments
- Merge to main after approval
For a new authentication endpoint:
- Define route in
apps/grip/routes/auth.route.ts
- Create controller in
apps/grip/controllers/auth.controller.ts
- Implement business logic in
apps/grip/use-cases/auth.use-case.ts
- Add data access in
db/postgresql/repositories/accounts.repository.ts
- Apply authentication middleware from
server/middlewares/auth.middleware.ts
This ensures a clean separation of concerns and makes the codebase maintainable as it grows.