Caret is an evolving codebase shared across a team of contributors and AI agents. Consistent naming, clear architecture boundaries, disciplined commit messages, and thorough documentation make the project easier to navigate, review, and extend. This page collects the conventions that apply across all layers of the stack — read it before opening your first pull request.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/arrozet/caret/llms.txt
Use this file to discover all available pages before exploring further.
Code Style by Layer
Naming conventions follow each ecosystem’s established best practices. The rules differ between the frontend, Node backend services, and the Python AI service — use the correct convention for the layer you are working in.Frontend (React / TypeScript)
| Element | Convention | Example |
|---|---|---|
| React components | PascalCase | EditorPage.tsx, CollaborationPresenceBar.tsx |
| Functions, variables, properties | camelCase | userData, isVisible, documentTitle |
| React hooks | camelCase starting with use | useAuth, useCollaborationSession, useSaveDocument |
| Event handlers | camelCase prefixed with handle | handleClick, handleSubmit, handleUserInput |
| Constants | UPPER_SNAKE_CASE | MAX_FILE_SIZE, API_BASE_URL |
| Store and hook filenames | camelCase | authStore.ts, useTheme.ts |
Backend — Node Services (TypeScript)
| Element | Convention | Example |
|---|---|---|
| Variables, functions, methods | camelCase | getUserById, documentRepository, userAction |
| Classes and constructors | PascalCase | DocumentService, CollaborationController, UserManager |
| File names | snake_case | user_repository.ts, document_routes.ts |
Backend — Python AI Service (FastAPI)
| Element | Convention | Example |
|---|---|---|
| Variables, functions, methods | snake_case | user_id, create_user, get_all_items |
| Classes, Pydantic models, SQLAlchemy models | PascalCase | UserCreate, ItemResponse, AIAgentService |
| File names / module names | snake_case | ai_router.py, document_repository.py, config.py |
SOLID Principles
Caret applies SOLID principles consistently across all layers. Understanding what each principle means in practice will help you structure new code and review existing contributions.Single Responsibility Principle
Every module, class, and function should have one reason to change. A route handler should only parse the HTTP boundary and call a service — it should not contain business logic or SQL queries. A repository should only contain database access — it should not call external HTTP APIs.
Open/Closed Principle
Code should be open for extension but closed for modification. Prefer adding new service implementations, new Tiptap extensions, or new AI router endpoints over modifying existing ones. Design abstractions (interfaces, base classes, extension hooks) so that new behaviour can be added without touching proven code.
Liskov Substitution Principle
Subtypes must be substitutable for their base types without breaking the program. If a service accepts a repository interface, any concrete repository implementation must honour the full contract — not just the methods it needs. Avoid implementations that silently skip interface methods or throw unexpected errors for valid inputs.
Interface Segregation Principle
Prefer small, focused interfaces over large general-purpose ones. A document read service should not depend on a write interface just because both live in the same repository class. Split interfaces by the consumer’s needs, not by the provider’s convenience.
Dependency Inversion Principle
High-level modules should not depend on low-level modules — both should depend on abstractions. Route handlers should receive their service dependencies through constructor injection rather than importing concrete implementations directly. The
document-service and collab-service already use manual constructor wiring — follow that pattern.Architecture Layer Rule
Every service in Caret follows a strict four-layer hierarchy. Violations — such as importing Drizzle ORM or SQLAlchemy directly into a route handler — will be rejected in code review.| Layer | Responsibility | Must not |
|---|---|---|
| Route / controller / handler | Parse HTTP or WebSocket input, validate, call services, return HTTP responses | Contain business logic or SQL |
| Service | Business rules, orchestration, data mapping | Import ORM models or make raw SQL queries |
| Repository | All SQL and ORM access | Contain business rules or HTTP concepts |
| DTO / schema / model | Typed data shapes only | Contain logic |
Conventional Commits
All commit messages must follow the Conventional Commits standard. This makes the git history scannable, simplifies changelog generation, and helps reviewers understand the scope of a change at a glance.Format
Commit Types
| Type | When to use |
|---|---|
feat | A new feature or capability visible to users or other services |
fix | A bug fix |
docs | Documentation changes only |
style | Formatting, whitespace, missing semicolons — no logic changes |
refactor | Code restructuring that neither adds a feature nor fixes a bug |
test | Adding or fixing tests |
chore | Build tooling, dependency updates, CI configuration |
Examples
Git Workflow
Branch from main
Create a dedicated branch for each significant change. Use a descriptive name that reflects the type and scope:
Make small, focused commits
Commit related changes together and unrelated changes separately. Small commits are easier to review, bisect, and revert if needed. Avoid combining a refactor with a new feature in the same commit.
Open a pull request
Push your branch and open a PR against
main. Describe what the change does and why, link any relevant issues, and confirm that lint, type checks, and tests all pass locally before requesting review.Documentation Standards
All new functions, classes, and non-trivial modules must include documentation written in English.- Docstrings — every function and class needs a docstring that describes its purpose, parameters, and return value. This applies to both TypeScript (JSDoc) and Python (PEP 257 docstrings).
- Inline comments — add comments for technically complex logic, non-obvious implementation choices, algorithm explanations, and design decisions. Avoid restating what the code already clearly says.
- Language — all documentation, comments, and commit messages must be written in English, regardless of the contributor’s primary language.