TypeScript/Svelte 4 monorepo using Rush.js (pnpm 10.15.1), Node >=20 <25, Webpack 5, Electron, Jest.
Respond to user using Russian language, all comments should be in English.
TypeScript: Strict types, interfaces over types, avoid any, export types separately
Svelte: Script/style/markup order, reactive $:, stores for state, small focused components
Naming: Files kebab-case, Components PascalCase, functions camelCase, constants UPPER_SNAKE_CASE
models/*- Shared types/models- If add resources like component: '' as AnyComponent, ensure is it added into one of api package/resources package or model package. It should be defined only once. It could be IntlString as well or any other '' as Ref declaration.
server-*- Server packagesplugins/*- Client pluginspackages/*- Reusable utilities- Projects 2-3 levels deep, each with
package.json
rush install # Install deps
rush build # Build all
rush build --to PKG # Build specific
rush add -p PKG # Add dependencyIMPORTANT: After making changes to service code (in services/, pods/, etc.), you must rebuild Docker images:
Note: If you're running the UI via rush dev (dev-server), you don't need to restart the front Docker container. Changes will be picked up automatically by the dev server.
# Build Docker images for specific service
rush docker:build --to @hcengineering/pod-ai-bot
rush docker:build --to @hcengineering/love-agent
# Restart Docker containers to use new images
docker compose -f dev/docker-compose.yaml restart aibot
docker compose -f dev/docker-compose.yaml restart love-agentWorkflow for service changes:
- Make code changes to service
- Run
rush build --to <package>(builds TypeScript) - Never Run
rushx formatin the package directory (format & lint) - MAY CAUSE FILE CORRUPTIONS. Lets user do it. - Run
diagnosticsto check for errors - Run
rush docker:build --to <package>(builds Docker image) - Restart the Docker container
Example for ai-bot service:
# After editing services/ai-bot/pod-ai-bot/src/workspace/love.ts
cd services/ai-bot/pod-ai-bot
diagnostics path: "services/ai-bot/pod-ai-bot/src/workspace/love.ts"
cd ../../..
rush docker:build --to @hcengineering/pod-ai-bot
docker compose -f dev/docker-compose.yaml restart aibotIMPORTANT: Use diagnostics tool to check for TypeScript/Svelte errors, NOT rush build:
- ✅
diagnostics()- Check all files for errors/warnings (fast, uses language server) - ✅
diagnostics({ path: "plugins/tracker-resources/src/utils.ts" })- Check specific file - ❌
rush build- Don't use for error checking (runs full transpilation, slower)
rush build performs transpilation which may succeed even with type errors. Always use diagnostics to verify code correctness.
After making changes, always validate the affected packages to ensure diagnostics are accurate:
# Navigate to each modified package and run:
cd <modified-package-directory>
rushx build
rushx _phase:validate
# Examples:
cd plugins/love-resources
rushx build
rushx _phase:validate
cd models/love
rushx build
rushx _phase:validate
cd server-plugins/love-resources
rushx build
rushx _phase:validateThis ensures that the language server has the correct build artifacts and validation passes for the specific packages you modified.
AI AGENTS: DO NOT run formatting commands automatically. Formatting can corrupt or erase files. Let the user handle formatting.
This ensures code style consistency and catches linting errors before commit.
NEVER run formatting commands in parallel or concurrently. The formatter can corrupt or completely erase file contents when run simultaneously on multiple packages.
Rules:
- ❌ DO NOT run
rushx formatcommands - ❌ DO NOT use
--forceflag with formatting - it can cause content loss - ✅ DO run formatting sequentially, one package at a time
- ✅ DO verify file contents after formatting with
git difforgit status - ✅ DO restore files immediately with
git checkout -- <file>if content is lost
If you see files becoming empty or losing content after formatting, immediately restore them:
git checkout -- <affected-files>When generating changelogs (the "All commits" lists), follow these rules:
- Exclude commits whose subject contains
Merge remote-tracking(filter them out). - Strip
Signed-off-by:footers from commit messages (remove the footer content and any lines that are onlySigned-off-by:). - Recommended pipeline (example):
git log --pretty=format:'- %h %s' <range> | grep -v -F 'Merge remote-tracking' | sed -E 's/\s*Signed-off-by:.*$//'- Note:
git log --no-mergesremoves all merge commits; use it only if you intentionally want to omit all merges.
Apply these filters when updating changelog.md or generating release notes so the generated logs exclude noisy merge-tracking commits and signed-off-by lines.
- Always handle errors (proper Error subclasses, catch promises)
- Use async/await, Promise.all() for parallel ops
- Svelte stores for shared state, separate business logic
- JSDoc public APIs, tests alongside code
- Check with
diagnosticsbefore making changes; do not commit locally — use diffs for review and let maintainers handle commits
When debugging issues:
- Add comprehensive logging first - use
console.logwith structured objects showing state, parameters, IDs - Test and analyze logs - let user run the app and provide actual console output
- Propose options before applying fixes or workarounds - when you identify multiple possible approaches (including quick or temporary workarounds), outline each option clearly (pros, cons, risks, and how invasive the change is) and ask the user which variant to proceed with. Do not implement non-trivial temporary workarounds without explicit approval.
- Identify root cause from logs - trace the flow, compare expected vs actual values
- Fix the issue based on findings
- Remove all logging after fix is confirmed - keep production code clean
Logging format:
console.log('[ComponentName.methodName] Description', {
key1: value1,
key2: value2,
objectId: object?._id // Use optional chaining for safety
})❌ any without reason
❌ console.log() in production
❌ Mixed concerns
❌ Circular deps
❌ Ignoring TS errors
❌ Using rush build to check for errors
❌ Running formatting in parallel (causes content loss!)
❌ Using --force flag with formatter
❌ Git policy: do NOT make commits, resets, reverts, or switch branches. Use git only for read-only operations (diff, status, log).
- Infer location from context (models/server/plugins/packages)
- Match existing patterns in codebase
- Include proper imports/types
- When adding a new
IntlStringkey, add corresponding entries to the component language files undercomponent-assets/langfor every supported locale (at minimum include the English entry) and update translations as needed; ensure you rundiagnostics(). Do not commit changes locally — prepare a diff for review and let maintainers perform commits. !!! If diagnostics are not disappearing for fixed items, stop and inform user to reload language servers or wait for build. Wait for continue request from user. - Add error handling
- Use existing utils first
- When fixing bugs:
- Read existing code thoroughly before changing
- Use logging to understand actual runtime behavior
- Trace data flow through components
- Verify assumptions with logs before implementing fixes
- Remove debug code when done
The app uses a provider-based selection/focus system:
focusStore- global focus stateselectionStore- global selection stateListSelectionProvider- manages list navigation, delegates to view-specific handlersSelectDirection-'vertical'(up/down) or'horizontal'(left/right in tables, first/last in lists)
Key principles:
- Navigation uses actual displayed order (from
getLimited()) not projection order - Focus changes propagate through
updateFocus() - Selection follows focus via provider delegation
- Scroll happens automatically via
scrollIntoView()on navigation
For every new files please add a 2026 Intabia Fusion license header like this:
/**
Copyright © 2026 Intabia Fusion.
Licensed under the Eclipse Public License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may
obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/For Svelte files (.svelte) use an HTML comment wrapper and prefix each line with // (to avoid interfering with markup and ensure clear in-file commenting). Example Svelte header:
<!--
// Copyright © 2026 Intabia Fusion.
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->