├── .python-version ├── CLAUDE.md ├── helpers ├── justdo-web-app-ce ├── justdo-landing-app-ce ├── .gitignore ├── LICENSE ├── utils ├── build-docker-image │ ├── Dockerfile │ └── build-docker-image.bash ├── eula.txt ├── eula.bash ├── test-justdo └── run-justdo ├── .gitmodules ├── .cursor └── rules │ ├── 050-testing.mdc │ ├── 033-client-style.mdc │ ├── 070-terminology.mdc │ ├── 030-coding-style.mdc │ ├── 040-architecture.mdc │ ├── 020-structure.mdc │ ├── 032-coffeescript-style.mdc │ ├── tasks │ ├── 040-meteor-3-migration.mdc │ ├── 030-i18n-files.mdc │ ├── 050-version-updates.mdc │ ├── 150-instruction-for-gantt-custom-coloring.mdc │ ├── 010-test-generation.mdc │ └── 060-i18n-language-specific-routes.mdc │ ├── 031-bash-development.mdc │ ├── 060-package-integration.mdc │ ├── 010-workflow.mdc │ └── 999-mdc-format.mdc ├── Changelog.md ├── .cursorrules ├── justdo ├── .cursorignore ├── docker-compose.yml ├── README.md └── default-config.bash /.python-version: -------------------------------------------------------------------------------- 1 | 2.7 2 | -------------------------------------------------------------------------------- /CLAUDE.md: -------------------------------------------------------------------------------- 1 | .cursorrules -------------------------------------------------------------------------------- /helpers: -------------------------------------------------------------------------------- 1 | modules/bash-helpers/functions -------------------------------------------------------------------------------- /justdo-web-app-ce: -------------------------------------------------------------------------------- 1 | modules/justdo-web-app-ce -------------------------------------------------------------------------------- /justdo-landing-app-ce: -------------------------------------------------------------------------------- 1 | modules/justdo-landing-app-ce -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ssl 2 | mongo-key 3 | dev-logs 4 | .*-env-conf* 5 | config.bash 6 | npm-debug.log 7 | mongo-dumps 8 | .DS_Store 9 | node_modules 10 | .agreement-signed 11 | .mailing-list-initialized -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | JustDo 2 | ====== 3 | 4 | JustDo is proprietary software owned by JustDo, Inc. To use JustDo, you must purchase a license from: https://justdo.com/pricing . 5 | For more information regarding the license, please read https://justdo.com/source-available-license . 6 | -------------------------------------------------------------------------------- /utils/build-docker-image/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM meteor/node:14.21.4 2 | 3 | # Use /bin/bash as a shell 4 | RUN rm /bin/sh && ln -s /bin/bash /bin/sh 5 | 6 | # Install meteor 7 | RUN curl https://install.meteor.com/\?release\=2.16 | sh 8 | 9 | WORKDIR /app 10 | COPY ./output /app 11 | 12 | EXPOSE 3000 3001 4000 13 | 14 | CMD cd /app && METEOR_ALLOW_SUPERUSER="true" ./justdo run -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "modules/justdo-web-app-ce"] 2 | path = modules/justdo-web-app-ce 3 | url = git@github.com:justdoinc/justdo-web-app-ce.git 4 | [submodule "modules/justdo-landing-app-ce"] 5 | path = modules/justdo-landing-app-ce 6 | url = git@github.com:justdoinc/justdo-landing-app-ce.git 7 | [submodule "modules/bash-helpers"] 8 | path = modules/bash-helpers 9 | url = git@github.com:theosp/bash-helpers.git 10 | -------------------------------------------------------------------------------- /utils/eula.txt: -------------------------------------------------------------------------------- 1 | By running JustDo you are agreeing to comply with our Terms and Conditions, Source-Available Terms and Conditions and Trademark Policy. 2 | Please read the following documents before proceeding: 3 | 4 | Terms and Conditions: https://justdo.com/terms-and-conditions 5 | Source-Available Terms and Conditions: https://justdo.com/source-available-license 6 | Trademark Policy: https://justdo.com/trademark-policy 7 | 8 | Once you have read and agreed to the above documents, please type "agree" and press Enter to continue. 9 | -------------------------------------------------------------------------------- /.cursor/rules/050-testing.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Use when the user prompt includes "test" 3 | globs: 4 | alwaysApply: false 5 | --- 6 | # Testing Guidelines 7 | 8 | ## Testing Principles 9 | - Valid test cases will always contain the `.app-test.coffee` extension 10 | - When implementing tests, review the specific pattern used in similar files 11 | - For comprehensive test creation guidance, see the full test generation guidelines in the tasks folder 12 | [010-test-generation.mdc](mdc:.cursor/rules/tasks/010-test-generation.mdc) 13 | 14 | ## Test Coverage Requirements 15 | - All new features should have appropriate test coverage 16 | - Bug fixes should include regression tests to prevent recurrence 17 | - API changes require test updates to ensure continued functionality 18 | - UI components should have basic rendering and interaction tests 19 | - Complex business logic requires unit tests with multiple scenarios 20 | -------------------------------------------------------------------------------- /utils/eula.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export SKIP_EULA_PROMPT="${SKIP_EULA_PROMPT:-"false"}" 4 | 5 | showEula() { 6 | if [[ "$SKIP_EULA_PROMPT" == "true" ]]; then 7 | return 0 8 | fi 9 | 10 | if [[ -f "$MAIN_DIR/.agreement-signed" ]]; then 11 | return 0 12 | fi 13 | 14 | cat "$MAIN_DIR/utils/eula.txt" 15 | 16 | read -r response 17 | 18 | # Convert response to lowercase and trim leading/trailing whitespace 19 | lower_response=$(echo "$response" | tr '[:upper:]' '[:lower:]' | sed 's/^[[:space:]]*//; s/[[:space:]]*$//') 20 | 21 | if [ "$lower_response" = "agree" ]; then 22 | local date=$(date +%Y-%m-%d) 23 | echo "$date" > "$MAIN_DIR/.agreement-signed" 24 | 25 | "$self" join-mailing-list 26 | 27 | return 0 28 | else 29 | announceErrorAndExit "You must agree to the terms and conditions to proceed." 30 | 31 | return 1 32 | fi 33 | 34 | return 0 35 | } 36 | 37 | showEula 38 | -------------------------------------------------------------------------------- /.cursor/rules/033-client-style.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: **/*.html,**/*.sass,**/*.css,**/*.coffee 4 | alwaysApply: false 5 | --- 6 | # Client-Side Coding Style Guidelines 7 | 8 | ## Frontend Guidelines 9 | 10 | - **Libraries**: Use Underscore.js for operations on JS data structures 11 | - **Frontend**: Blaze framework for templates and UI components 12 | 13 | ## HTML/Blaze Guidelines 14 | 15 | - Only use tags for real links to other pages/external sources 16 | - Never use `href="#"` without `e.preventDefault()` in event handler 17 | - Templates naming: under_scored 18 | - Boolean helpers should return true/false (not string classes) 19 | - Use dash-separated attributes and class/id names in HTML 20 | 21 | ## CSS/SASS Guidelines 22 | 23 | - Use 2-space indentation 24 | - Prefer classes over IDs (except for form inputs with labels) 25 | - Use hyphen-separated names for classes/IDs 26 | - Avoid global rules (scope styles to specific containers) 27 | - Avoid inline styling and `!important` unless absolutely necessary 28 | 29 | ## Security Guidelines 30 | 31 | - Always use `xssGuard` helper with triple braces: `{{{xssGuard content}}}` instead of `{{{content}}}` -------------------------------------------------------------------------------- /.cursor/rules/070-terminology.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: **/justdo-web-app*/**, **/justdo-landing-app*/** 4 | alwaysApply: false 5 | --- 6 | # Terminology Clarification 7 | 8 | ## The Ambiguity of "Project" in JustDo 9 | 10 | - The term "project" is ambiguous in the JustDo codebase due to historical terminology changes 11 | - When JustDo started, **Boards** used to be called **Projects** 12 | - Later, we started calling these **Projects** as **JustDos** 13 | - Then we introduced a new concept also called **Project**, which refers to a task that is designated as a Project 14 | 15 | ## Current Terminology 16 | 17 | - **Board**: A container for tasks and the current term for what was once called a Project 18 | - **JustDo**: The renamed term for what was originally called a Project (now a Board) 19 | - **Project Task**: A task that has been designated as a Project (the current meaning of "Project") 20 | 21 | ## Usage Guidelines 22 | 23 | - When referring to the container for tasks, use "JustDo" 24 | - When referring to a task designated as a Project, use "Project" for user-facing terminology 25 | - Be aware that old code and documentation may use these terms inconsistently 26 | - Add comments when necessary to clarify ambiguous usages 27 | -------------------------------------------------------------------------------- /.cursor/rules/030-coding-style.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: **/*.bash,**/*.sh,**/*.coffee,**/*.html,**/*.sass,**/*.css 4 | alwaysApply: false 5 | --- 6 | # Coding Style Guidelines 7 | 8 | This file provides an overview of the coding style guidelines for different technologies used in the JustDo codebase. For detailed guidelines, please refer to the specific files: 9 | 10 | ## Technology-Specific Guidelines 11 | 12 | - **Bash Scripting**: [031-bash-style.mdc](mdc:.cursor/rules/031-bash-style.mdc) 13 | - **CoffeeScript**: [032-coffeescript-style.mdc](mdc:.cursor/rules/032-coffeescript-style.mdc) 14 | - **Client-Side (HTML/CSS)**: [033-client-style.mdc](mdc:.cursor/rules/033-client-style.mdc) 15 | 16 | ## Common Naming Conventions 17 | 18 | - under_scored for non-functions and Blaze templates 19 | - lowerCamel *only* for functions and methods 20 | - PascalCase for classes/constructors 21 | - ALL_UPPER for global variables 22 | 23 | ## Core Philosophy 24 | 25 | - Code is primarily written for humans to read and understand, not just for computers to execute 26 | - "Explicit is better than implicit. Simple is better than complex. Readability counts." 27 | - Maintain consistency with existing code style when modifying files 28 | - Keep code DRY (Don't Repeat Yourself) 29 | - Prefer verbose variable names and maintainability over concise code -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | 2025.03.22, Version 5.8.4 2 | 3 | * Update web-app to v5.8.4 4 | * Update landing-app to v5.8.4 5 | * Update bash-helpers submodule with improved cross-platform compatibility: 6 | - Add requireMinimumBashVersion and requireBashVersion functions 7 | - Update shebangs in script files 8 | - Refactor recursiveEnvsubst to avoid xargs and process files individually 9 | - Add strReplace function 10 | 11 | 2025.03.05, Version 5.8.3 12 | 13 | * Update web-app to v5.8.3 14 | * Update landing-app to v5.8.3 15 | 16 | 2025.02.19, Version 5.8.2 17 | 18 | * Update shipped license to 15 free users on localhost 19 | * Support --prefer-existing-env-vars flag in run-justdo 20 | * Update default-config.bash with more documentation for FIREBASE_SERVER_KEY setup 21 | 22 | * Update web-app to v5.8.2 23 | * Update landing-app to v5.8.2 24 | 25 | 2025.02.14, Version 5.8.1 26 | 27 | * Update web-app to v5.8.1 28 | * Update landing-app to v5.8.1 29 | 30 | 2025.02.07, Version 5.8.0 31 | 32 | * Update web-app to v5.8.0 33 | * Update landing-app to v5.8.0 34 | 35 | 2025.02.19, Version 5.8.2 36 | 37 | * Update web-app to v5.8.2 38 | * Update landing-app to v5.8.2 39 | 40 | 2025.02.14, Version 5.8.1 41 | 42 | * Update web-app to v5.8.1 43 | * Update landing-app to v5.8.1 44 | 45 | 2025.02.07, Version 5.8.0 46 | 47 | * Update web-app to v5.8.0 48 | * Update landing-app to v5.8.0 49 | 50 | 2025.01.31, Version 5.7.2 51 | 52 | * Update web-app to v5.7.2 53 | 54 | 2025.01.30, Version 5.7.1 55 | 56 | * First source-available release of JustDo 🎉 57 | -------------------------------------------------------------------------------- /.cursor/rules/040-architecture.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Package structure and component design principles 3 | globs: **/justdo-web-app*/**,**/justdo-landing-app*/**,**/justdo*packages/** 4 | alwaysApply: false 5 | --- 6 | # Architecture Guidelines 7 | 8 | ## Architecture Principles 9 | - **Package-first**: Implement functionality as packages whenever possible 10 | - **Package Organization**: 11 | - Source-available packages: modules/justdo-packages (symlinked to application/packages) 12 | - Proprietary packages: modules/justdo-ee-packages (symlinked to application/packages) 13 | - **New Packages**: Always create new packages in modules/justdo-packages (source-available) 14 | - **Application Code**: Only use /application folder level code when necessary - always prefer packages 15 | - Place client-only code in /client, server-only in /server 16 | - Use /lib only when strict load order control is needed 17 | 18 | ## Package Exposures 19 | 20 | Instances of a package may be exposed to different namespaces. Examples: 21 | - JustdoAccounts is exposed as APP.accounts 22 | - JustdoSeo is exposed as APP.justdo_seo 23 | - JustdoHelpers is not a constructor; it is exposed globally and used as JustdoHelpers.getURL() 24 | - GridDataCom is constructed as part of a Project instance 25 | 26 | If a package has an app-integration.coffee file, it will typically show how the package is exposed. 27 | Otherwise, perform a full code search (e.g., searching for "new " or one of the package methods) to determine how to correctly access the package. 28 | -------------------------------------------------------------------------------- /.cursor/rules/020-structure.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | alwaysApply: true 5 | --- 6 | 7 | ## Codebase Structure 8 | - `justdo`: Project root repository (the Community Edition) 9 | - `modules/justdo-web-app-ce`: Web app CE repository 10 | - `modules/justdo-landing-app-ce`: Landing app CE repository 11 | - Both app repositories have git submodules under their respective `modules` directories: 12 | - `modules/justdo-packages`: Source-available packages 13 | - `modules/bash-helpers`: Git submodule containing bash helper functions 14 | - Contains reusable bash functions used by both CE and closed-source versions 15 | - A symlink exists at the repository root: `helpers -> modules/bash-helpers/functions` 16 | - This symlink structure is identical in both CE and closed-source repositories 17 | - Note that both app repositories reference the same git submodules, but may point to different commits 18 | - When working on web app features, modify the submodules in `justdo-web-app-ce` 19 | - When working on landing page features, modify the submodules in `justdo-landing-app-ce` 20 | 21 | ## Commands 22 | - (The following bash scripts exists in the project root. If the current pwd is different, ensure to `cd` back to the root directory) 23 | - Start dev environment: `./run-dev-environment.bash` 24 | - Run full app tests: `./test-dev-environment.bash` 25 | - Run tests and exit after completion: `./test-dev-environment.bash --once` 26 | - Run a subset of tests: `MOCHA_GREP="" ./test-dev-environment.bash --once` 27 | - For example, to run tests with `describe "*+grid*+"` (name of suite containing grid), use `MOCHA_GREP="/grid/i"` 28 | - Build for production: Handled by CI/CD pipeline -------------------------------------------------------------------------------- /.cursorrules: -------------------------------------------------------------------------------- 1 | # Cursor Rules Documentation 2 | 3 | This file serves as both documentation for the `.cursor/rules` directory structure and for backward compatibility with the legacy `.cursorrules` approach. It also serves as an entrypoint for CLAUDE.md or other AI tools to understand the .cursor/rules folder that is the main agents knowledge base. 4 | 5 | ## Structure of `.cursor/rules` 6 | 7 | Rules in the `.cursor/rules` directory follow this structure: 8 | 9 | - File extension: `.mdc` 10 | - File format: Markdown with YAML frontmatter 11 | 12 | ### Frontmatter Structure 13 | 14 | Each rule file has a YAML frontmatter section at the top with these properties: 15 | 16 | ``` 17 | --- 18 | description: Brief description of what the rule does 19 | globs: **/*.js, **/*.ts # File patterns this rule applies to 20 | alwaysApply: true # Whether this rule should always be applied regardless of file context 21 | --- 22 | ``` 23 | 24 | ### Rule Content 25 | 26 | After the frontmatter, the main content is markdown: 27 | 28 | ```markdown 29 | # Your rule title 30 | 31 | - You can reference other files using @file syntax 32 | - You can organize rules by purpose (e.g., standards, workflows) 33 | - Rules can contain code examples, guidelines, or architectural decisions 34 | ``` 35 | 36 | ## Organization 37 | 38 | Rules are organized in the `.cursor/rules` directory: 39 | - Task-specific rules should be placed in `.cursor/rules/tasks/` 40 | - General rules can be placed directly in `.cursor/rules/` 41 | 42 | ## How Rules Are Applied 43 | 44 | 1. Rules matching the current file(s) via glob patterns are automatically included 45 | 2. Rules with `alwaysApply: true` are included in all contexts 46 | 3. When referencing a file that matches a rule, that rule is included as context 47 | 48 | ## Creating New Rules 49 | 50 | Use the command palette (Cmd + Shift + P) > New Cursor Rule to create a new rule file with the proper structure. -------------------------------------------------------------------------------- /utils/build-docker-image/build-docker-image.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | shopt -s extglob 4 | 5 | SCRIPT_DIR="$(dirname ${BASH_SOURCE[0]})" 6 | OUTPUT_DIR="$SCRIPT_DIR/output" 7 | LANDING_APP_REL_DIR="justdo-landing-app-ce" 8 | WEB_APP_REL_DIR="justdo-web-app-ce" 9 | 10 | # Ensure that all git repositories are clean 11 | REPO_PATHS_TO_CHECK_FOR_CLEAN_GIT_REP=( 12 | "$MAIN_DIR" 13 | "$MAIN_DIR/$LANDING_APP_DIR" 14 | "$MAIN_DIR/$WEB_APP_DIR" 15 | ) 16 | # for repo_path in "${REPO_PATHS_TO_CHECK_FOR_CLEAN_GIT_REP[@]}"; do 17 | # pushd "$repo_path" 18 | # if ! isCleanGitRep; then 19 | # announceErrorAndExit "Git repository at $repo_path isn't clean. Please commit all changes and try $self again" 20 | # fi 21 | # popd 22 | # done 23 | 24 | # rm -rf "$OUTPUT_DIR" 25 | mkdir -p $OUTPUT_DIR 26 | 27 | rsync -av --exclude 'output' --exclude 'node_modules' --exclude '.DS_Store' --exclude '.meteor' --exclude '.npm' "$MAIN_DIR/" "$OUTPUT_DIR" 28 | 29 | APP_REPO_DIRS=( 30 | "$LANDING_APP_REL_DIR" 31 | "$WEB_APP_REL_DIR" 32 | ) 33 | for repo_path in "${APP_REPO_DIRS[@]}"; do 34 | # Copy .meteor folder 35 | source_app_application_path="$MAIN_DIR/$repo_path/application" 36 | dest_app_application_path="$OUTPUT_DIR/$repo_path/application" 37 | 38 | mkdir -p "$dest_app_application_path/.meteor" 39 | cp -r $source_app_application_path/.meteor/!(\.|\.\.|local|\.id) "$dest_app_application_path/.meteor" 40 | 41 | # Create the .meteor/.id file 42 | cat > "$dest_app_application_path/.meteor/.id" < true` instead of `a = () -> true` 22 | - Use dot notation for object properties: `obj.prop` instead of `obj["prop"]` 23 | - Always include explicit `return` except in one-liners 24 | - Don't wrap if conditions in parentheses: `if x` instead of `if (x)` 25 | - Use double quotes `"` instead of single quotes 26 | - Use triple double quotes `"""` for multiline strings and HTML content 27 | 28 | ## Security Guidelines 29 | 30 | - Always use `xssGuard` helper with triple braces: `{{{xssGuard content}}}` instead of `{{{content}}}` 31 | 32 | ## Database Guidelines 33 | 34 | - Collection names: under_scored (plugins add short prefix, e.g., `meetings_`) 35 | - Field names: under_scored 36 | - Always specify `fields` option in all queries (find/findOne/etc.) 37 | - Request only the minimum fields needed 38 | - Use `{fields: undefined}` explicitly when all fields are required 39 | - Ensure proper indexes are in place for all queries 40 | 41 | ## Naming Conventions 42 | 43 | - under_scored for non-functions and Blaze templates 44 | - lowerCamel *only* for functions and methods 45 | - PascalCase for classes/constructors 46 | - ALL_UPPER for global variables -------------------------------------------------------------------------------- /.cursor/rules/tasks/040-meteor-3-migration.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Use when user prompt includes request to migrate to Meteor 3 3 | globs: **/*.coffee,**/*.js,**/package.js,**/methods* 4 | alwaysApply: false 5 | --- 6 | # Meteor 3 Migration Guidelines 7 | 8 | ## MongoDB Method Conversion 9 | 10 | 1. Replace collection methods with their async counterparts: 11 | - find().fetch() → await find().fetchAsync() 12 | - findOne() → await findOneAsync() 13 | - insert() → await insertAsync() 14 | - update() → await updateAsync() 15 | - remove() → await removeAsync() 16 | - upsert() → await upsertAsync() 17 | - find().count() → await find().countAsync() 18 | 19 | 2. Add 'await' before each async call. Do not use Promise.await. 20 | 21 | 3. For CoffeeScript in Meteor: 22 | - DO NOT add the 'async' keyword to functions - CoffeeScript automatically adds it when compiling 23 | - Add console.log statements to debug execution flow if needed 24 | - When functions throw errors, ensure tests are updated to handle async rejections 25 | - For testing async error cases, use try/catch with await: 26 | ``` 27 | try 28 | await functionCall() 29 | assert.fail("Expected to throw") 30 | catch error 31 | expect(error).to.exist 32 | ``` 33 | 34 | ## Naming Conventions 35 | 36 | 4. Naming conventions for async methods: 37 | - Add "Async" suffix to method names that use async MongoDB operations 38 | - Example: `getQuickNoteDoc` → `getQuickNoteDocAsync` 39 | - Update all internal method calls to use the new async method names 40 | - Keep Meteor method names in `Meteor.methods` unchanged for backward compatibility 41 | - Update the implementation of Meteor methods to call the new async methods 42 | 43 | ## Meteor Methods 44 | 45 | 5. Check methods that use these operations: 46 | - Methods that now use await should be made async-aware 47 | - Update method calls to use Meteor.callAsync instead of Meteor.call 48 | 49 | 6. Make sure functions that return collection operation results return the awaited result 50 | 51 | ## Transition Period 52 | 53 | 7. During the transition period (Meteor 2.16 to Meteor 3): 54 | - Both sync and async MongoDB methods are supported 55 | - In test files, you can keep using the original MongoDB methods for verification 56 | - Only add `await` when calling the API methods that were converted to async 57 | 58 | ## Testing 59 | 60 | 8. Testing the implementation: 61 | - Start dev environment: `./run-dev-environment.bash` 62 | - Run tests: `./test-dev-environment.bash` 63 | - Run tests and exit after completion: `./test-dev-environment.bash --once` 64 | - Run a specific test: `MOCHA_GREP="/test pattern/i" ./test-dev-environment.bash` 65 | - Run a specific test and exit after completion: `MOCHA_GREP="/test pattern/i" ./test-dev-environment.bash --once` 66 | - For testing async/await changes specifically, watch for: 67 | - Promise rejection warnings in the console 68 | - Tests that pass but should fail (error handling issues) 69 | - Missing await keywords causing unexpected behavior 70 | - Unexpected unhandled promise rejections 71 | - Debug using browser console and server logs for async execution flow 72 | 73 | -------------------------------------------------------------------------------- /.cursor/rules/031-bash-development.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: **/*.bash,**/*.sh 4 | alwaysApply: false 5 | --- 6 | # Bash Development Guidelines 7 | 8 | ## Bash Scripting Conventions 9 | 10 | - **Preferred Shell Language**: 11 | - Bash is the preferred shell scripting language for all scripts in this repository 12 | - Always use Bash instead of other shells (sh, zsh, fish, etc.) for new scripts 13 | - Existing scripts in other shells should be migrated to Bash when possible 14 | 15 | - **Shebang Line**: 16 | - All Bash scripts must use `#!/usr/bin/env bash` as the shebang line 17 | - Never use `#!/bin/bash` as it is not portable across systems 18 | - The env-based shebang allows the script to use the bash version found in PATH 19 | - This is especially important for cross-platform compatibility (macOS/Linux) 20 | 21 | - **Variable Naming**: 22 | - Use lowercase for regular variables: `package_name`, `file_path`, `current_dir` 23 | - Use UPPERCASE only for constants and environment variables: `APP_VERSION`, `NODE_ENV` 24 | - Example: `package_name="$(echo "$rel_path" | cut -d'/' -f1)"` (not `PACKAGE_NAME=...`) 25 | 26 | - **Parameter Quoting**: 27 | - Always double-quote variable references: `"$variable"` (not `$variable`) 28 | - Double-quote command substitutions: `"$(command)"` (not `$(command)`) 29 | - This prevents word splitting and unexpected behavior with spaces/special characters 30 | - Example: `if [[ -n "$package_name" ]]; then` (not `if [[ -n $package_name ]]; then`) 31 | 32 | ## Using Bash Helpers 33 | 34 | - **Always** leverage the `helpers` directory (symlink to `modules/bash-helpers/functions`) for common operations 35 | - This promotes code reuse and consistency across all bash scripts in the project 36 | - Most main bash utilities implemented in this project load all helpers by default 37 | - Rather than copy-pasting code between scripts, use or extend these helpers 38 | 39 | ## Adding New Helper Functions 40 | 41 | - If you find yourself writing the same bash function multiple times across different scripts, it should be added to the bash-helpers repository 42 | - Follow these steps to add a new helper: 43 | 1. Implement and test the function in your current script first 44 | 2. Once working correctly, move it to an appropriate file in `modules/bash-helpers/functions` 45 | 3. Group related functions together in topic-specific files 46 | 4. Add documentation comments above the function 47 | 5. Update your original script to use the new helper 48 | 49 | ## Helpers Organization 50 | 51 | - Related helper functions are grouped in specific files by domain/purpose 52 | - All helpers follow consistent naming and parameter passing conventions 53 | - Helper functions include inline documentation explaining: 54 | - Purpose and usage 55 | - Parameters (with types and default values if applicable) 56 | - Return values or side effects 57 | - Examples of typical usage 58 | 59 | ## DRY Principles 60 | 61 | - Never duplicate bash code across multiple scripts 62 | - When you identify repeated code patterns, extract them to helper functions 63 | - Functions in the bash-helpers repository should be: 64 | - Well-named and focused on a single responsibility 65 | - Properly documented with usage examples 66 | - Tested for edge cases 67 | - Designed to be reusable across multiple contexts -------------------------------------------------------------------------------- /.cursor/rules/060-package-integration.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: **/justdo-web-app*/**, **/justdo-landing-app*/** 4 | alwaysApply: false 5 | --- 6 | # Meteor Package Integration Verification 7 | 8 | ## Package Existence vs. Integration 9 | 10 | When discussing Meteor packages in the JustDo codebase, it's important to distinguish between: 11 | 12 | 1. **Package Existence**: Whether a package exists in the codebase (in repositories or submodules) 13 | 2. **Package Integration**: Whether a package is properly integrated into a Meteor application 14 | 15 | A package can exist in the codebase but not be integrated into an application, making it effectively unavailable at runtime. 16 | 17 | ## Verifying Package Integration 18 | 19 | To fully verify if a package is integrated and available in a Meteor application, you must check all of the following: 20 | 21 | ### 1. Package Existence 22 | 23 | First, confirm the package exists in one of these locations: 24 | - In `modules/justdo-packages/` (source-available packages) 25 | - In `modules/justdo-ee-packages/` (enterprise edition packages) 26 | - In `modules/justdo-bespoke-packages/` (client-specific packages) 27 | - In the Meteor package ecosystem (published packages via Atmosphere) 28 | - In the npm ecosystem (for npm packages used through Meteor) 29 | 30 | ### 2. Symlink Verification 31 | 32 | Check if the package is properly symlinked in the application: 33 | - For local packages, verify there's a symlink in `application/packages/` pointing to the package directory 34 | - For example: `application/packages/justdo-accounts` -> `../../modules/justdo-packages/justdo-accounts` 35 | 36 | ### 3. Meteor Package Inclusion 37 | 38 | Check if the package is included in the Meteor application's packages list: 39 | - Open `.meteor/packages` in the application directory 40 | - Look for the package name as it appears in its `package.js` file under the `name` field 41 | - Example: If `package.js` contains `name: "justdoinc:justdo-accounts"`, then `.meteor/packages` should include `justdoinc:justdo-accounts` 42 | 43 | ## Example Verification Process 44 | 45 | For a comprehensive integration check, follow these steps: 46 | 47 | ```bash 48 | # 1. Find the package in the codebase 49 | find . -type d -name "justdo-accounts" 50 | 51 | # 2. Check the package definition to find its official name 52 | cat modules/justdo-packages/justdo-accounts/package.js | grep "name:" 53 | 54 | # 3. Verify symlink in application/packages 55 | ls -la application/packages/justdo-accounts 56 | 57 | # 4. Confirm presence in .meteor/packages 58 | grep "justdoinc:justdo-accounts" application/.meteor/packages 59 | ``` 60 | 61 | ## Package.js Extension: i18n Support 62 | 63 | JustDo has extended the standard Meteor package.js API with custom i18n functionality: 64 | 65 | 1. The extension is implemented in the `000-package-js-i18n` package 66 | 2. It adds the global `addI18nFiles` function that can be used in package.js files 67 | 3. This function helps manage language file loading across the application 68 | 69 | For detailed i18n implementation, see: 70 | [030-i18n-files.mdc](mdc:.cursor/rules/tasks/030-i18n-files.mdc) 71 | 72 | ## Common Integration Issues 73 | 74 | 1. **Missing Symlink**: Package exists but isn't symlinked in application/packages 75 | 2. **Incorrect Package Name**: Mismatch between package.js name and .meteor/packages entry 76 | 3. **Version Conflicts**: Two packages depend on different versions of the same package 77 | 4. **Missing Dependencies**: Package is added but its dependencies aren't included 78 | 79 | ## Checking for Active Plugins 80 | 81 | Some packages act as plugins and require additional verification: 82 | 1. Check the package's documentation for activation requirements 83 | 2. Look for initialization code in the application startup sequence 84 | 3. Verify any required configuration settings are present 85 | -------------------------------------------------------------------------------- /.cursor/rules/010-workflow.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: 3 | globs: 4 | alwaysApply: true 5 | --- 6 | # Workflow Guidelines 7 | 8 | ## First Step for Any Task 9 | - Before starting work on any task, always check the `.cursor/rules/tasks` directory for relevant guidance 10 | - Look for files matching your task type (e.g., `[020-blog-posts.md](mdc:.cursor/rules/tasks/020-blog-posts.md)` for blog creation) 11 | - These documents contain established workflows, conventions, and requirements specific to each task type 12 | - Following these task-specific rules will ensure consistency and reduce rework 13 | - If multiple rule files seem relevant, review all of them before proceeding 14 | 15 | ## Development Environment Requirements 16 | - All bash scripts in this repository require Bash 5+ to run correctly 17 | - Different platforms have different default bash versions and installation methods 18 | - **All new scripts must use `#!/usr/bin/env bash` as their shebang line** for cross-platform compatibility 19 | 20 | ### macOS 21 | - The default `/bin/bash` is version 3.2, which won't work with our scripts 22 | - Install a newer version of bash using Homebrew: `brew install bash` 23 | - When running scripts manually, use: `/opt/homebrew/bin/bash ./script.bash` 24 | - Or set PATH to prefer the Homebrew version: `PATH="/opt/homebrew/bin:$PATH" ./script.bash` 25 | 26 | ### Linux 27 | - Modern Linux distributions often ship with Bash 5+ by default 28 | - Check your bash version with: `bash --version` 29 | - If needed, update bash using your distribution's package manager: 30 | - Debian/Ubuntu: `sudo apt-get install -y bash` 31 | - RHEL/Fedora: `sudo dnf install -y bash` 32 | - Run scripts using the system bash: `bash ./script.bash` 33 | 34 | ### Key Bash 5+ Features Used 35 | - Associative arrays (`declare -A`) 36 | - Name references (`local -n`) 37 | - Parameter transformation (`${var^}` for uppercase first character) 38 | - Other modern bash syntax features 39 | 40 | ### Enforcing Bash 5+ Usage 41 | 42 | To ensure scripts consistently use Bash 5+, you can take these steps: 43 | 44 | 1. **Update shebang lines** to use the env approach, which is cross-platform compatible: 45 | ```bash 46 | # Use find and sed to update shebangs 47 | find . -name "*.bash" -type f -exec sed -i 's|^#!/bin/bash|#!/usr/bin/env bash|g' {} \; 48 | ``` 49 | 50 | 2. **Use env to respect PATH** when calling bash scripts: 51 | ```bash 52 | # macOS with Homebrew 53 | PATH="/opt/homebrew/bin:$PATH" ./development-helpers.bash update-open-source 54 | 55 | # Linux (if bash 5+ is not the default) 56 | PATH="/path/to/bash5/bin:$PATH" ./development-helpers.bash update-open-source 57 | ``` 58 | 59 | 3. **Use the requireMinimumBashVersion helper** at the start of important scripts: 60 | ```bash 61 | requireMinimumBashVersion 5 62 | ``` 63 | 64 | This helper will automatically check the Bash version and provide a helpful error message if the minimum version requirement is not met. 65 | 66 | ## Last Step for Any Task 67 | - If you've learned new concepts, workflows, or best practices during task completion, suggest updates to the relevant rules 68 | - For new workflows that aren't covered by existing rules, suggest creating a new rule file 69 | - Evaluate whether tests should be added for your changes: 70 | - For functional code, new features, API changes, or bug fixes, tests are essential 71 | - For content-only changes (like blog posts) or documentation updates, tests are typically not required 72 | - When in doubt, err on the side of adding tests - they provide long-term stability and prevent regressions 73 | - Always run appropriate tests before considering a task complete: 74 | - For localized changes, run related tests with `MOCHA_GREP="/relevant_pattern/i" ./test-dev-environment.bash --once` 75 | - For significant changes, run the full test suite with `./test-dev-environment.bash --once` 76 | - Verify that no regressions are introduced by your changes 77 | -------------------------------------------------------------------------------- /.cursor/rules/tasks/030-i18n-files.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Guidelines for working with internationalization (i18n) files 3 | globs: **/*.i18n.json,**/_i18n-conf.json,**/project-tap.i18n 4 | alwaysApply: false 5 | --- 6 | # i18n Files Guidelines 7 | 8 | ## Understanding the i18n System 9 | 10 | JustDo uses a customized internationalization (i18n) system based on Meteor's tap:i18n package, with additional tooling to manage language files across the application. 11 | 12 | ## Important: File Size Limitations 13 | 14 | The JustDo i18n system uses language models (LLMs) to perform translations. Due to token limitations in these models: 15 | 16 | 1. **Each i18n file should be kept under 2000 characters** 17 | 2. **Large content must be split into multiple files** (part1, part2, etc.) 18 | 3. **Exceeding size limits may result in incomplete or failed translations** 19 | 20 | This is why you'll see most content divided into multiple part files, especially for blog posts and feature-rich pages. 21 | 22 | ## How `addI18nFiles` Works 23 | 24 | The `addI18nFiles` function is a core utility that manages language file loading in the package system. Understanding its syntax is crucial for proper i18n implementation. 25 | 26 | ### Syntax 27 | 28 | ```javascript 29 | this.addI18nFiles(api, i18n_pattern, langs); 30 | ``` 31 | 32 | - **api**: The Meteor package API object 33 | - **i18n_pattern**: A file path pattern with `{}` as a placeholder for the language code 34 | - **langs**: (Optional) Language group or array of language codes to include (defaults to "all") 35 | 36 | ### Language Restriction Options 37 | 38 | When specifying which languages to include, you have several options: 39 | 40 | 1. **Omit the parameter** to include all supported languages 41 | 2. **"all"**: Include all supported languages (same as omitting) 42 | 3. **"core"**: Include only core languages (English, Hebrew, Portuguese, Spanish, etc.) 43 | 4. **"default_lang_only"**: Include only the default language (English) 44 | 5. **Array of specific language codes**: e.g., `["en", "he", "pt"]` 45 | 46 | Example usage in package.js: 47 | 48 | ```javascript 49 | // Include all supported languages 50 | this.addI18nFiles(api, "lib/both/i18n/part1.{}.i18n.json"); 51 | 52 | // Include only the English version 53 | this.addI18nFiles(api, "lib/both/i18n/part1.{}.i18n.json", "default_lang_only"); 54 | 55 | // Include only specific languages 56 | this.addI18nFiles(api, "lib/both/i18n/part1.{}.i18n.json", ["en", "he", "pt"]); 57 | ``` 58 | 59 | ## i18n Configuration File 60 | 61 | Each i18n directory can include a `_i18n-conf.json` file to control language support and translation instructions. 62 | 63 | ### Structure 64 | 65 | ```json 66 | { 67 | "custom_supported_langs": "core", 68 | "extra_i18n_instructions": "Instructions for the translation system..." 69 | } 70 | ``` 71 | 72 | - **custom_supported_langs**: Controls which languages to support (overrides package.js setting) 73 | - **extra_i18n_instructions**: Provides specific instructions to the translation system 74 | 75 | ### Example 76 | 77 | ```json 78 | { 79 | "custom_supported_langs": "core", 80 | "extra_i18n_instructions": "This is a technical document. Please keep technical terms like 'API', 'Docker', etc. in their original English form." 81 | } 82 | ``` 83 | 84 | ## Best Practices 85 | 86 | 1. **Group related content** in the same file to maintain context for translators 87 | 2. **Split large files** into logical sections (part1, part2, etc.) 88 | 3. **Use clear key names** that describe the content they contain 89 | 4. **Keep specialized terminology** in separate files with specific translation instructions 90 | 5. **Regularly check the character count** of each file to ensure it stays under 2000 characters 91 | 92 | ## Common Problems and Solutions 93 | 94 | 1. **Missing translations**: Check if the language is included in the `addI18nFiles` call or `_i18n-conf.json` 95 | 2. **Translation errors**: Ensure the file is under 2000 characters 96 | 3. **Context loss**: Keep related content in the same file even if splitting into parts 97 | 4. **Inconsistent terminology**: Use `extra_i18n_instructions` to guide translators on specialized terms 98 | -------------------------------------------------------------------------------- /.cursor/rules/999-mdc-format.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Use when user asks to create or update *.mdc files 3 | globs: **/*.mdc 4 | alwaysApply: false 5 | --- 6 | # MDC File Format Guide 7 | 8 | MDC (Markdown Configuration) files are used by Cursor to provide context-specific instructions to AI assistants. This guide explains how to create and maintain these files properly. 9 | 10 | ## File Structure 11 | 12 | Each MDC file consists of two main parts: 13 | 14 | 1. **Frontmatter** - Configuration metadata at the top of the file 15 | 2. **Markdown Content** - The actual instructions in Markdown format 16 | 17 | ### Frontmatter 18 | 19 | The frontmatter must be the first thing in the file and must be enclosed between triple-dash lines (`---`). Configuration should be based on the intended behavior: 20 | 21 | ``` 22 | --- 23 | # Configure your rule based on desired behavior: 24 | 25 | description: Brief description of what the rule does 26 | globs: **/*.js, **/*.ts # Optional: Comma-separated list, not an array 27 | alwaysApply: false # Set to true for global rules 28 | --- 29 | ``` 30 | 31 | > **Important**: Despite the appearance, the frontmatter is not strictly YAML formatted. The `globs` field is a comma-separated list and should NOT include brackets `[]` or quotes `"`. 32 | 33 | #### Guidelines for Setting Fields 34 | 35 | - **description**: Should be agent-friendly and clearly describe when the rule is relevant. Format as `:
` for best results. 36 | - **globs**: 37 | - If a rule is only relevant in very specific situations, leave globs empty so it's loaded only when applicable to the user request. 38 | - If the only glob would match all files (like `**/*`), leave it empty and set `alwaysApply: true` instead. 39 | - Otherwise, be as specific as possible with glob patterns to ensure rules are only applied with relevant files. 40 | - **alwaysApply**: Use sparingly for truly global guidelines. 41 | 42 | #### Glob Pattern Examples 43 | 44 | - **/*.js - All JavaScript files 45 | - src/**/*.jsx - All JSX files in the src directory 46 | - **/components/**/*.vue - All Vue files in any components directory 47 | 48 | ### Markdown Content 49 | 50 | After the frontmatter, the rest of the file should be valid Markdown: 51 | 52 | ```markdown 53 | # Title of Your Rule 54 | 55 | ## Section 1 56 | - Guidelines and information 57 | - Code examples 58 | 59 | ## Section 2 60 | More detailed information... 61 | ``` 62 | 63 | ## Special Features 64 | 65 | ### File References 66 | 67 | You can reference other files from within an MDC file using the markdown link syntax: 68 | 69 | ``` 70 | [rule-name.mdc](mdc:location/of/the/rule.mdc) 71 | ``` 72 | 73 | When this rule is activated, the referenced file will also be included in the context. 74 | 75 | ### Code Blocks 76 | 77 | Use fenced code blocks for examples: 78 | 79 | ````markdown 80 | ```javascript 81 | // Example code 82 | function example() { 83 | return "This is an example"; 84 | } 85 | ``` 86 | ```` 87 | 88 | ## Best Practices 89 | 90 | 1. **Clear Organization** 91 | - Use numbered prefixes (e.g., `01-workflow.mdc`) for sorting rules logically 92 | - Place task-specific rules in the `tasks/` subdirectory 93 | - Use descriptive filenames that indicate the rule's purpose 94 | 95 | 2. **Frontmatter Specificity** 96 | - Be specific with glob patterns to ensure rules are only applied in relevant contexts 97 | - Use `alwaysApply: true` for truly global guidelines 98 | - Make descriptions clear and concise so AI knows when to apply the rule 99 | 100 | 3. **Content Structure** 101 | - Start with a clear title (H1) 102 | - Use hierarchical headings (H2, H3, etc.) to organize content 103 | - Include examples where appropriate 104 | - Keep instructions clear and actionable 105 | 106 | 4. **File Size Considerations** 107 | - Keep files focused on a single topic or closely related topics 108 | - Split very large rule sets into multiple files and link them with references 109 | - Aim for under 300 lines per file when possible 110 | 111 | ## Usage in Cursor 112 | 113 | When working with files in Cursor, rules are automatically applied when: 114 | 115 | 1. The file you're working on matches a rule's glob pattern 116 | 2. A rule has `alwaysApply: true` set in its frontmatter 117 | 3. The agent thinks the rule's description matches the user request 118 | 4. You explicitly reference a rule in a conversation with Cursor's AI 119 | 120 | ## Creating/Renaming/Removing Rules 121 | 122 | - When a rule file is added/renamed/removed, update also the list under 010-workflow.mdc. 123 | - When changs are made to multiple `mdc` files from a single request, review also [999-mdc-format]((mdc:.cursor/rules/999-mdc-format.mdc)) to consider whether to update it too. 124 | 125 | ## Updating Rules 126 | 127 | When updating existing rules: 128 | 129 | 1. Maintain the frontmatter format 130 | 2. Keep the same glob patterns unless intentionally changing the rule's scope 131 | 3. Update the description if the purpose of the rule changes 132 | 4. Consider whether changes should propagate to related rules (e.g., CE versions) 133 | -------------------------------------------------------------------------------- /utils/test-justdo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # IMPORTANT!!! INTENDED TO BE USED BY justdo only! 5 | # 6 | 7 | # Parse command line arguments 8 | run_once="false" 9 | 10 | for arg in "$@"; do 11 | if [[ "$arg" == "--once" ]]; then 12 | run_once="true" 13 | fi 14 | done 15 | 16 | APP_PATHS=( 17 | "justdo-web-app-ce/application" 18 | "justdo-landing-app-ce/application" 19 | ) 20 | PACKAGES_SUBDIR="packages" # Relative to the app's dir 21 | TEST_CASES_SUBDIR="app-tests" # Relative to the app's dir 22 | 23 | # Define the cleanup function to remove symlinks when script exits 24 | # We are considering symlinks as auto-generated files, hence we clean them up on exit 25 | # and upon rebuilding the test environment. 26 | # Note that non-symlinks, are considered as permanent files, and are not removed (they are basically 27 | # actual app level tests and not packages tests). 28 | cleanup() { 29 | local app_path 30 | 31 | for app_path in "${APP_PATHS[@]}"; do 32 | if [ -d "$app_path/$TEST_CASES_SUBDIR" ]; then 33 | (cd "$app_path" && platformFind "$TEST_CASES_SUBDIR" -type l -exec rm -f {} \; 2>/dev/null) 34 | fi 35 | done 36 | } 37 | 38 | initial_node_pids=$(pgrep -x node) 39 | cleanPids(){ 40 | sleep 3 # Wait for the processes to start, for case break was triggered very early on 41 | 42 | local current_node_pids=$(pgrep -x node) 43 | local pid 44 | 45 | for pid in "$current_node_pids"; do 46 | if [[ ! " $initial_node_pids " =~ " $pid " ]]; then 47 | kill -9 $pid 48 | fi 49 | done 50 | } 51 | 52 | exitProcedures(){ 53 | announceStep "Cleaning up..." 54 | cleanup 55 | cleanPids 56 | } 57 | 58 | # Set up the trap to call cleanup function on script exit (for any reason) 59 | trap exitProcedures EXIT 60 | 61 | # Ensure the test directories exist and symlink test files from packages 62 | for app_path in "${APP_PATHS[@]}"; do 63 | pushd "$app_path" 64 | announceMainStep "Processing app: $app_path" 65 | 66 | # Ensure TEST_CASES_SUBDIR exists 67 | mkdir -p "$TEST_CASES_SUBDIR" 68 | 69 | # Clean up existing symlinks, but preserve regular files 70 | cleanup 71 | 72 | # Find test files in packages and create symlinks in TEST_CASES_SUBDIR 73 | announceStep "Searching for test files in $PACKAGES_SUBDIR" 74 | 75 | # Check if PACKAGES_SUBDIR exists 76 | if [ ! -d "$PACKAGES_SUBDIR" ]; then 77 | announceError "Packages directory not found: $PACKAGES_SUBDIR" 78 | popd 79 | continue 80 | fi 81 | 82 | announceStep "Searching for test files in $PACKAGES_SUBDIR" 83 | # Find test files in packages and create symlinks in TEST_CASES_SUBDIR 84 | # Using find with the -L flag to follow symlinks 85 | platformFind -L "$PACKAGES_SUBDIR" -type f \( -name "*.app-test.*" -o -name "*.app-tests.*" \) | while read -r test_file; do 86 | # Skip if test_file is empty 87 | if [ -z "$test_file" ]; then 88 | announceError "Warning: Empty test file path detected, skipping" 89 | continue 90 | fi 91 | 92 | # Extract the package name (first directory after PACKAGES_SUBDIR) 93 | rel_path=${test_file#"$PACKAGES_SUBDIR/"} 94 | package_name="$(echo "$rel_path" | cut -d'/' -f1)" 95 | 96 | # Check if package name was successfully extracted 97 | if [ -z "$package_name" ]; then 98 | announceError "Warning: Could not determine package name for $test_file, skipping" 99 | continue 100 | fi 101 | 102 | # If the package is a symlink, resolve its actual name 103 | package_path="$PACKAGES_SUBDIR/$package_name" 104 | if [ -L "$package_path" ]; then 105 | # Get the name of the directory the symlink points to 106 | # Use platformReadlink for cross-platform compatibility 107 | linked_dir="$(platformReadlink -f "$package_path" 2>/dev/null || readlink "$package_path")" 108 | if [ -n "$linked_dir" ]; then 109 | package_name="$(basename "$linked_dir")" 110 | fi 111 | fi 112 | 113 | # Determine if the file is for client, server, or both 114 | if [[ "$test_file" == *"server"* ]]; then 115 | target_dir="server" 116 | elif [[ "$test_file" == *"client"* ]]; then 117 | target_dir="client" 118 | else 119 | target_dir="both" 120 | fi 121 | 122 | # Create the package-specific directory structure 123 | package_target_dir="$TEST_CASES_SUBDIR/$package_name/$target_dir" 124 | mkdir -p "$package_target_dir" 125 | 126 | # Get the test file name without the path 127 | test_file_name="$(basename "$test_file")" 128 | 129 | # Create symlink (overwrite if exists) 130 | echo "Creating symlink for: $test_file in $package_name/$target_dir" 131 | ln -sf "$(pwd)/$test_file" "$package_target_dir/$test_file_name" 132 | done 133 | 134 | popd 135 | done 136 | 137 | announceMainStep "Test directories prepared and test files symlinked" 138 | 139 | # Set TEST_MODE to true and pass the --once flag if specified 140 | if [[ "$run_once" == "true" ]]; then 141 | announceStep "Running tests in --once mode (tests will exit after completion)" 142 | fi 143 | TEST_MODE="true" TEST_RUN_ONCE="$run_once" . "utils/run-justdo" -------------------------------------------------------------------------------- /.cursor/rules/tasks/050-version-updates.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Guidelines for preparing the codebase for a new version release and updating changelogs 3 | globs: "**/Changelog" 4 | alwaysApply: false 5 | --- 6 | 7 | # Version Update Guidelines 8 | 9 | This document outlines the process for preparing the codebase for a new version release, with specific focus on updating changelogs across different repositories in the JustDo ecosystem. 10 | 11 | ## Overview 12 | 13 | When preparing for a new version release, we need to: 14 | 1. Identify changes made since the last version 15 | 2. Document these changes in appropriate changelog files 16 | 3. Ensure consistency across repositories 17 | 18 | ## Affected Repositories and Files 19 | 20 | The primary changelog files that need to be updated are: 21 | - Main DevOps Changelog: `/ChangeLog` 22 | - Web App Changelog: `/nodes/justdo-web-app/justdo-web-app/Changelog` 23 | - Landing App Changelog: `/nodes/justdo-web-landing-app/justdo-landing-app/Changelog` 24 | 25 | ## Important Guidelines 26 | 27 | ### NEVER Modify Previously Published Entries 28 | 29 | ⚠️ **CRITICAL**: Never modify any content in previously published changelog entries, even for seemingly harmless formatting changes. When adding new entries, be extremely careful to: 30 | 31 | 1. Only add new content at the top of the file 32 | 2. Never change spacing, formatting, or content of existing entries 33 | 3. Use a consistent format for the new entry that matches the existing pattern 34 | 4. When using code editors or automated tools, verify that they haven't accidentally modified existing content 35 | 36 | This ensures the historical record remains intact and consistent. 37 | 38 | ## Process 39 | 40 | ### 1. Identifying the Previous Version 41 | 42 | First, identify the most recent version tag: 43 | 44 | ```bash 45 | cd /Users/theosp/justdo 46 | git tag -l "v*" --sort=-v:refname | head -1 47 | ``` 48 | 49 | ### 2. Comparing Changes Since Last Version 50 | 51 | To properly document all changes, you need to: 52 | 53 | #### a. Identify Submodule Commits at Previous Version Tag 54 | 55 | Check out the previous version tag and note the commit hashes for submodules: 56 | 57 | ```bash 58 | cd /Users/theosp/justdo 59 | git checkout v5.x.y # Replace with actual previous version tag 60 | ``` 61 | 62 | Note the commit hashes for: 63 | - Web app: `nodes/justdo-web-app/justdo-web-app` 64 | - Landing app: `nodes/justdo-web-landing-app/justdo-landing-app` 65 | - Bash helpers: `modules/bash-helpers` 66 | - Their respective submodules (packages, ee-packages, etc.) 67 | 68 | #### b. Compare Direct Changes in Main Repositories 69 | 70 | For both web app and landing app repositories, compare changes between the previously tagged commit and current HEAD: 71 | 72 | ```bash 73 | cd /Users/theosp/justdo/nodes/justdo-web-app/justdo-web-app 74 | git log --pretty=format:"%h %s" ..HEAD 75 | ``` 76 | 77 | Replace `` with the actual commit hash from the previous version tag. 78 | 79 | #### c. Check Submodule Changes 80 | 81 | For each important submodule, compare changes between its state in the previous version and current state: 82 | 83 | ```bash 84 | cd /Users/theosp/justdo/nodes/justdo-web-app/justdo-web-app 85 | git diff HEAD -- modules/justdo-packages 86 | git diff HEAD -- modules/justdo-ee-packages 87 | ``` 88 | 89 | Then examine changes within each submodule: 90 | 91 | ```bash 92 | cd modules/justdo-packages 93 | git log --pretty=format:"%h %s" .. 94 | ``` 95 | 96 | #### d. Check Other Important Repository Submodules 97 | 98 | Always check the following critical submodules: 99 | 100 | ```bash 101 | # Check bash-helpers changes 102 | cd /Users/theosp/justdo 103 | git submodule update --init modules/bash-helpers 104 | cd modules/bash-helpers 105 | git log --pretty=format:"%h %s" .. 106 | 107 | # Check justdo-ce changes if relevant 108 | cd /Users/theosp/justdo 109 | git submodule update --init modules/justdo-ce 110 | cd modules/justdo-ce 111 | git log --pretty=format:"%h %s" .. 112 | ``` 113 | 114 | ### 3. Organizing Changelog Entries 115 | 116 | Changelog entries should be organized as follows: 117 | 118 | #### Format 119 | 120 | ``` 121 | YYYY.MM.DD, Version X.Y.Z 122 | 123 | * User-facing change 1 124 | * User-facing change 2 125 | 126 | LOW LEVEL CHANGES 127 | 128 | * Technical/internal change 1 129 | * Technical/internal change 2 130 | ``` 131 | 132 | #### Priority Order 133 | 134 | 1. User-visible improvements and features 135 | 2. Bug fixes 136 | 3. Content updates (blog posts, documentation) 137 | 4. Technical/infrastructure changes (under "LOW LEVEL CHANGES") 138 | 139 | ### 4. Content Guidelines 140 | 141 | - **Be specific**: Include issue/PR numbers when available 142 | - **Be comprehensive**: Document significant changes in all repositories and submodules 143 | - **Be contextual**: Explain why changes matter, not just what changed 144 | - **Note dependencies**: If a change in one repo affects another, note this relationship 145 | - **Special attention**: Always highlight changes to: 146 | - Blog posts and content 147 | - Database schema 148 | - API changes 149 | - Performance improvements 150 | - Security fixes 151 | 152 | ### 5. Post-Update Verification 153 | 154 | After updating the changelogs: 155 | 156 | 1. Verify version numbers are consistent across all files 157 | 2. Ensure the date format is consistent (YYYY.MM.DD) 158 | 3. Check for typos and formatting issues 159 | 160 | ## Note on Selective Updates 161 | 162 | It's possible that there will be no updates for the landing app or vice versa - in such cases, only update the changelogs that contain actual changes. The main DevOps changelog should always reflect which components were updated in each version. -------------------------------------------------------------------------------- /.cursor/rules/tasks/150-instruction-for-gantt-custom-coloring.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Use when information about custom Gantt coloring would be helpful 3 | globs: 4 | alwaysApply: false 5 | --- 6 | # Gantt Chart Custom Coloring 7 | 8 | This document explains how to use the custom coloring API for gantt charts in the Planning Utilities module. 9 | 10 | ## Overview 11 | 12 | The custom coloring API allows developers to specify condition-based colors for Gantt chart task bars. This is useful for visually encoding additional information beyond the default coloring scheme (which only differentiates critical path tasks). 13 | 14 | ## API 15 | 16 | The Planning Utilities module provides the following methods for custom coloring: 17 | 18 | ### `registerGanttColorCondition(condition_id, condition_func)` 19 | 20 | Register a condition function that determines task bar colors. 21 | 22 | **Parameters:** 23 | - `condition_id`: String identifier for the condition (used for unregistering and debugging) 24 | - `condition_func`: Function that takes a task document and returns a color object or undefined 25 | 26 | **Color Object Format:** 27 | ```coffeescript 28 | { 29 | background: "#hex_color" # Background color (hex format) 30 | border: "#hex_color" # Border color (hex format) 31 | alpha: 0.5 # Optional transparency (0-1) 32 | } 33 | ``` 34 | 35 | If the condition function returns `undefined`, default coloring will be used. 36 | 37 | ### `unregisterGanttColorCondition(condition_id)` 38 | 39 | Remove a previously registered condition function. 40 | 41 | **Parameters:** 42 | - `condition_id`: The string identifier of the condition to remove 43 | 44 | ## Usage Examples 45 | 46 | ### Basic Example 47 | 48 | This example colors all task bars for tasks in the "Design" category blue: 49 | 50 | ```coffeescript 51 | APP.justdo_planning_utilities.registerGanttColorCondition "design_category_color", (task) -> 52 | if task.categories? and "Design" in task.categories 53 | return { 54 | background: "#3498db" 55 | border: "#2980b9" 56 | } 57 | return 58 | ``` 59 | 60 | ### Project-Specific Coloring 61 | 62 | This example applies a color scheme only to specific projects by checking the project ID inside the condition function: 63 | 64 | ```coffeescript 65 | APP.justdo_planning_utilities.registerGanttColorCondition "blocked_tasks_color", (task) -> 66 | # Only apply to specific projects 67 | project_ids = ["project_id_1", "project_id_2"] 68 | 69 | if task.project_id in project_ids and task.state is "blocked" 70 | return { 71 | background: "#e74c3c" 72 | border: "#c0392b" 73 | alpha: 0.8 74 | } 75 | return 76 | ``` 77 | 78 | ### Priority-Based Coloring 79 | 80 | This example colors tasks based on their priority: 81 | 82 | ```coffeescript 83 | APP.justdo_planning_utilities.registerGanttColorCondition "priority_colors", (task) -> 84 | switch task.priority 85 | when "high" 86 | return { 87 | background: "#e74c3c" 88 | border: "#c0392b" 89 | } 90 | when "medium" 91 | return { 92 | background: "#f39c12" 93 | border: "#d35400" 94 | } 95 | when "low" 96 | return { 97 | background: "#2ecc71" 98 | border: "#27ae60" 99 | } 100 | else 101 | return 102 | ``` 103 | 104 | ### Progress-Based Color Intensity 105 | 106 | This example changes the alpha (transparency) based on task progress: 107 | 108 | ```coffeescript 109 | APP.justdo_planning_utilities.registerGanttColorCondition "progress_intensity", (task) -> 110 | # Get progress percentage 111 | progress = task[JustdoPlanningUtilities.progress_percentage_pseudo_field_id] or 0 112 | 113 | # Skip if task has no progress 114 | if progress is 0 115 | return 116 | 117 | # Calculate alpha - ranges from 0.3 (0% complete) to 1.0 (100% complete) 118 | alpha = 0.3 + (progress / 100) * 0.7 119 | 120 | return { 121 | background: "#3498db" 122 | border: "#2980b9" 123 | alpha: alpha 124 | } 125 | ``` 126 | 127 | ## Multiple Conditions 128 | 129 | When multiple condition functions are registered, they are evaluated in no specific order. The first function that returns a color object will be used, and subsequent functions will be skipped. 130 | 131 | If you need a specific evaluation order, consider creating a single condition function that applies multiple conditions in the desired order. 132 | 133 | ## Browser Support 134 | 135 | The alpha transparency feature uses RGBA colors, which are supported in all modern browsers. 136 | 137 | ## Performance Considerations 138 | 139 | Condition functions are called frequently during rendering, so they should be kept simple and efficient. Avoid expensive operations like database queries inside condition functions. 140 | 141 | ## Color Helper Functions 142 | - Use camelCase for function and variable names (e.g., `hexToRgb`, `applyCustomColors`) 143 | - Centralize color conversion and manipulation in helper functions 144 | - Include functions for: 145 | - Converting hex colors to RGB for RGBA use 146 | - Darkening and lightening colors by percentage 147 | - Applying custom colors with flexible options 148 | 149 | ## Custom Color Application 150 | - Use the `applyCustomColors` helper for consistent styling 151 | - Always check if custom colors exist before applying them 152 | - Pass options object for styling variations: 153 | - `bg_alpha_modifier`: Adjusts transparency of background 154 | - `border_alpha_modifier`: Adjusts transparency of border 155 | - `lighten_bg_percent`: Percentage to lighten background 156 | - `darken_bg_percent`: Percentage to darken background 157 | 158 | ## Condition Examples 159 | - Priority-based coloring 160 | - Progress-based transparency 161 | - Past due date highlighting (for in-progress/pending tasks) 162 | - Alternating colors based on sequence IDs 163 | - Buffer task styling 164 | 165 | ## Best Practices 166 | - Ensure colors have sufficient contrast for accessibility 167 | - Use alpha channels for subtle visual hierarchy 168 | - Test color schemes with different task states and progress values -------------------------------------------------------------------------------- /justdo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ORIGINAL_PWD="${ORIGINAL_PWD:-"$PWD"}" 4 | cd "$(dirname $0)" # cd to script dir 5 | 6 | export NO_COLOR="${NO_COLOR:-"false"}" 7 | export SUPPRESS_MISSING_FEATURES_ERRORS="true" 8 | for helper in helpers/*.bash; do 9 | . $helper 10 | done 11 | 12 | export MAIN_DIR="$(expandPath .)" 13 | export LOGS_FOLDER="$MAIN_DIR/dev-logs" 14 | 15 | if [[ ! -d "$LOGS_FOLDER" ]]; then 16 | mkdir "$LOGS_FOLDER" 17 | fi 18 | 19 | self="./justdo" 20 | 21 | helper_name="$1" 22 | shift 23 | 24 | announceMainStep "Running helper: $helper_name" 25 | 26 | # JUSTDO_PACKAGES_DIR is used by utils/packages-publisher.bash 27 | export JUSTDO_PACKAGES_DIR="$(expandPath output)" 28 | 29 | . "utils/eula.bash" 30 | 31 | case "$helper_name" in 32 | "run") 33 | . "utils/run-justdo" "$@" 34 | ;; 35 | 36 | "test") 37 | . "utils/test-justdo" "$@" 38 | ;; 39 | 40 | "join-mailing-list") 41 | if [[ -f ".mailing-list-initialized" ]]; then 42 | return 43 | fi 44 | 45 | curl_exist="$(command -v curl)" 46 | wget_exist="$(command -v wget)" 47 | 48 | if [[ -z "$curl_exist" ]] && [[ -z "$wget_exist" ]]; then 49 | return 50 | fi 51 | 52 | echo 53 | echo "📧 Join our mailing list and stay updated with latest news, promotions and terms updates." 54 | echo "📩 Enter your email address (or press Enter to skip):" 55 | read -r response 56 | 57 | if [[ -n "$response" ]]; then 58 | url="https://justdo.com/join-mailing-list" 59 | 60 | if [[ -n "$curl_exist" ]]; then 61 | response_code="$(curl -s -o /dev/null -w "%{http_code}" -X POST -d "email=$response" "$url")" 62 | elif [[ -n "$wget_exist" ]]; then 63 | response="$(wget --server-response --post-data="email=$response" "$url" -O /dev/null 2>&1)" 64 | response_code="$(echo "$response" | awk '/^ HTTP/{print $2}')" 65 | fi 66 | 67 | echo "$response" > ".mailing-list-initialized" 68 | 69 | echo 70 | if [[ $response_code -eq "200" ]]; then 71 | echo "Thank you for joining our mailing list! 🎉" 72 | else 73 | echo "Oops, failed to join the mailing list. Please send us a request at https://justdo.com/contact" 74 | fi 75 | echo 76 | else 77 | echo "You can join our mailing list at any time by calling: $self join-mailing-list" 78 | fi 79 | ;; 80 | 81 | # 82 | # Dev helpers 83 | # 84 | "debug-development-environment") 85 | meteor_pid="$(ps aux | grep meteor | grep web-app | grep -v mongo | awk '{print $2}')" 86 | 87 | if [[ -n "$meteor_pid" ]]; then 88 | kill -usr1 "$meteor_pid" 89 | 90 | announceStep "Done. Visit: chrome://inspect/#devices" 91 | else 92 | announceErrorAndExit "Failed to find the development environment Meteor process" 93 | fi 94 | ;; 95 | 96 | "mongo-backup") 97 | mongodump="mongodump" 98 | 99 | if ! commandExists "$mongodump"; then 100 | announceErrorAndExit "This helper requires '$mongodump' to be installed. Please install MongoDB tools and ensure '$mongodump' is available in your PATH." 101 | fi 102 | 103 | backup_dir="mongo-dumps" 104 | mkdir -p "$backup_dir" 105 | cd "$backup_dir" 106 | 107 | time_stamp="$(date "+%F-%H:%M")" 108 | backup_file="mongo-backup--localhost--$time_stamp.archive.gz" 109 | 110 | mongodump="$(which $mongodump)" 111 | 112 | "$mongodump" \ 113 | --host "localhost" \ 114 | --port "3001" \ 115 | --archive="$backup_file" \ 116 | --gzip 117 | ;; 118 | "mongo-reset") 119 | mongosh="mongosh" 120 | 121 | if ! commandExists "$mongosh"; then 122 | announceErrorAndExit "This helper requires '$mongosh' to be installed. Please install MongoDB tools and ensure '$mongosh' is available in your PATH." 123 | fi 124 | 125 | announceStep "ARE YOU SURE?! - type 'yes'" 126 | 127 | read ans 128 | if [[ "$ans" != "yes" ]]; then 129 | announceStep "Exit without reset" 130 | 131 | exit 132 | fi 133 | 134 | "$mongosh" \ 135 | --host "localhost" \ 136 | --port "3001" \ 137 | "meteor" --eval "db.dropDatabase()" 138 | ;; 139 | "mongo-restore") 140 | mongorestore="mongorestore" 141 | backup_file="$1" 142 | 143 | if ! commandExists "$mongorestore"; then 144 | announceErrorAndExit "This helper requires '$mongorestore' to be installed. Please install MongoDB tools and ensure '$mongorestore' is available in your PATH." 145 | fi 146 | 147 | if [[ -z "$backup_file" ]]; then 148 | announceMainStep "Usage:" 149 | 150 | echo "$self $helper_name .gz" 151 | 152 | exit 153 | fi 154 | 155 | /usr/bin/env "$mongorestore" \ 156 | --host "localhost" \ 157 | --port "3001" \ 158 | --archive="$backup_file" \ 159 | --nsFrom="justdo.*" --nsTo="meteor.*" \ 160 | --gzip 161 | ;; 162 | 163 | "web-app-shell") 164 | cd "justdo-web-app-ce/application" 165 | 166 | meteor shell 167 | ;; 168 | "landing-app-shell") 169 | cd "justdo-landing-app-ce/application" 170 | 171 | meteor shell 172 | ;; 173 | "configure-dev-environment") 174 | configuration_file="config.bash" 175 | 176 | if [[ -f "$configuration_file" ]]; then 177 | announceErrorAndExit "configuration file already exists under $configuration_file" 178 | fi 179 | 180 | platformCp $MAIN_DIR/default-config.bash $configuration_file 181 | 182 | announceMainStep "Configuration file created under: $configuration_file" 183 | ;; 184 | *) 185 | announceStep "Use one of the following helpers:" 186 | 187 | commands=( $(cat "$(basename $0)" | grep -e '^\s\+".\+")' | platformSed -e 's/\s\+"\(.\+\)")/\1/g' | platformSed -e 's/"\s\+|\s\+"/ /g') ) 188 | 189 | n=${#commands[*]} 190 | for (( i=0; i < n; i += 1 )); do 191 | item="${commands[i]}" 192 | 193 | echo "$0 $item" 194 | done 195 | unset i n item 196 | ;; 197 | esac 198 | -------------------------------------------------------------------------------- /.cursor/rules/tasks/010-test-generation.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Use when the user prompt asks to generate or update test files 3 | globs: **/*.app-test* 4 | alwaysApply: false 5 | --- 6 | # Test Generation Guidelines 7 | 8 | ## Test File Creation Instructions 9 | 10 | 1. **Naming and Location:** 11 | - All test files is named with `.app-test.coffee` extension 12 | - Place test files in the same directory as the code being tested 13 | - Use package condition check: `if Package["package-name"]?`, package-name should be exactly the same as the one in package.js, including the portion before the colon ":". 14 | 15 | 2. **Basic Structure:** 16 | ```coffeescript 17 | if Package["package-name"]? 18 | {expect, assert} = require "chai" 19 | 20 | describe "Package API", -> 21 | # Setup variables 22 | # before/beforeEach/after/afterEach hooks 23 | # Test groups and cases 24 | ``` 25 | - Refer to existing tests that has the `.app-test.coffee` extension. The codebase may contain legacy unittests that does not have this extention, those files should be ignored. 26 | 27 | 3. **Setup and Cleanup:** 28 | - Use `before/beforeEach` for setup and `after/afterEach` for cleanup 29 | - Create helper functions for test data creation and cleanup 30 | - For async environment setup: `before (done) -> APP.getEnv -> done()` 31 | - Reset all affected collections between tests 32 | - Create required test objects with all mandatory fields 33 | 34 | 4. **Required Fields for Common Objects:** 35 | - Use APIs from the `grid-data` package to CRUD Tasks 36 | - Use APIs from the `justdo-projects` package to CRUD Projects 37 | - `justdo-tasks-collections-manager/lib/both/tasks-schema.coffee` contains the schema definition of a Task 38 | - `justdo-projects/lib/both/schema.coffee` contains the schema definition of a Project 39 | 40 | 5. **Path Format in Grid API:** 41 | - Use trailing slashes: `/#{parent_id}/#{task_id}/` 42 | - Root path should be `/#{root_task_id}/` 43 | 44 | 6. **Testing Asynchronous Code:** 45 | - Use `async/await` pattern for Promise-based APIs 46 | - For callback APIs, use the `done` parameter 47 | - Handle errors with try/catch in async tests: 48 | ```coffeescript 49 | it "should handle errors", -> 50 | try 51 | await APP.package_name.asyncMethod(invalid_params) 52 | assert.fail("Expected to throw error") 53 | catch error 54 | expect(error).to.exist 55 | return 56 | ``` 57 | - DO NOT add the 'async' keyword to test functions - CoffeeScript automatically adds it when compiling 58 | - When testing methods with "Async" suffix, make sure to use await: 59 | ```coffeescript 60 | it "should perform expected behavior", -> 61 | # Execute 62 | result = await APP.package_name.someMethodAsync(params) 63 | 64 | # Verify 65 | expect(result).to.exist 66 | return 67 | ``` 68 | 69 | 7. **Collection operation vs Existing APIs:** 70 | - Some collections are exposed to APP.collections, some are exposed under a package's namespace only, and some are available in both places. 71 | - When a collection operation is required, try to search for APIs that uses that collection to find existing APIs that does the job, instead of updating the collection directly. 72 | e.g. Instead of calling `APP.collections.Tasks.insert()`, Use `APP.projects._grid_data_com.addChild/addRootChild` 73 | - This would ensure proper validation and the execution of hooks, to deliver accurate test results. 74 | - If the operation involves CRUD of Tasks, ensure to look into `grid-data-com-server-api.coffee` for relevant APIs 75 | - If the operation involves CRUD of Projects, ensure to look into the `justdo-projects` package for relevant APIs 76 | 77 | 8. **Using Existing APIs vs Mocking:** 78 | - Prefer using existing APIs directly instead of mocking when possible 79 | - The test environment creates a separate database for testing 80 | - Only mock external services or APIs that cannot be tested directly 81 | - If you need to mock, follow these guidelines: 82 | ```coffeescript 83 | before -> 84 | original_method = APP.package_name.methodToMock 85 | APP.package_name.methodToMock = (args) -> return mock_result 86 | 87 | after -> 88 | APP.package_name.methodToMock = original_method 89 | ``` 90 | 91 | 9. **Testing Behavioral Patterns:** 92 | - Task deletion is logical, check for `_raw_removed_date`, not non-existence 93 | - Verify field existence rather than assuming records are deleted 94 | - Test both success cases and expected error cases 95 | - Include at least one assertion for each expected behavior 96 | - Structure tests with clear Setup, Execute, and Verify sections: 97 | ```coffeescript 98 | it "should perform expected behavior", -> 99 | # Setup 100 | # ...setup code... 101 | 102 | # Execute 103 | result = APP.package_name.someMethod(params) 104 | 105 | # Verify 106 | expect(result).to.exist 107 | # ...more assertions... 108 | 109 | return 110 | ``` 111 | 112 | ## Running Tests 113 | - After making changes to a test file, always run the tests to verify your changes 114 | - Fix any failing tests before proceeding with further changes 115 | - If you encounter MongoDB connection issues, try restarting the test environment 116 | 117 | ## Common Issues and Solutions 118 | 119 | 1. **MongoDB Connection Issues:** 120 | - If you encounter MongoDB connection timeouts, try restarting the test environment 121 | - Make sure no other instances of the test environment are running 122 | 123 | 2. **Missing Required Fields:** 124 | - Tasks require specific fields like `parents2` with the correct structure 125 | - Check the schema definitions if you're unsure about required fields 126 | 127 | 3. **Test Environment Setup:** 128 | - Always use `APP.getEnv` in the `before` hook to ensure the environment is ready 129 | - Clean up all test data in the `after` hook to prevent test pollution 130 | 131 | 4. **Assertion Failures:** 132 | - Be specific in your assertions to make debugging easier 133 | - Use descriptive error messages in `assert.fail()` calls 134 | 135 | 5. **Async/Await Issues:** 136 | - Missing `await` before async method calls is a common source of errors 137 | - Make sure to use `await` with all methods that have "Async" suffix 138 | - Use try/catch blocks to properly handle async errors 139 | - Remember that CoffeeScript automatically adds the 'async' keyword to functions that use await 140 | -------------------------------------------------------------------------------- /.cursorignore: -------------------------------------------------------------------------------- 1 | # Package management directories 2 | **/packages 3 | **/.meteor 4 | **/node_modules 5 | **/.npm 6 | 7 | # Translation files (keep only English) 8 | *.i18n.json 9 | !*en.i18n.json 10 | 11 | mongo-dumps 12 | 13 | 14 | # Package management directories 15 | **/packages 16 | **/.meteor 17 | **/node_modules 18 | **/.npm 19 | 20 | # Translation files (keep only English) 21 | *.i18n.json 22 | !*en.i18n.json 23 | 24 | mongo-dumps 25 | 26 | 27 | # Package management directories 28 | **/packages 29 | **/.meteor 30 | **/node_modules 31 | **/.npm 32 | 33 | # Translation files (keep only English) 34 | *.i18n.json 35 | !*en.i18n.json 36 | 37 | mongo-dumps 38 | 39 | 40 | # Package management directories 41 | **/packages 42 | **/.meteor 43 | **/node_modules 44 | **/.npm 45 | 46 | # Translation files (keep only English) 47 | *.i18n.json 48 | !*en.i18n.json 49 | 50 | mongo-dumps 51 | 52 | 53 | # Package management directories 54 | **/packages 55 | **/.meteor 56 | **/node_modules 57 | **/.npm 58 | 59 | # Translation files (keep only English) 60 | *.i18n.json 61 | !*en.i18n.json 62 | 63 | mongo-dumps 64 | 65 | 66 | # Package management directories 67 | **/packages 68 | **/.meteor 69 | **/node_modules 70 | **/.npm 71 | 72 | # Translation files (keep only English) 73 | *.i18n.json 74 | !*en.i18n.json 75 | 76 | mongo-dumps 77 | 78 | 79 | # Package management directories 80 | **/packages 81 | **/.meteor 82 | **/node_modules 83 | **/.npm 84 | 85 | # Translation files (keep only English) 86 | *.i18n.json 87 | !*en.i18n.json 88 | 89 | mongo-dumps 90 | 91 | 92 | # Package management directories 93 | **/packages 94 | **/.meteor 95 | **/node_modules 96 | **/.npm 97 | 98 | # Translation files (keep only English) 99 | *.i18n.json 100 | !*en.i18n.json 101 | 102 | mongo-dumps 103 | 104 | 105 | # Package management directories 106 | **/packages 107 | **/.meteor 108 | **/node_modules 109 | **/.npm 110 | 111 | # Translation files (keep only English) 112 | *.i18n.json 113 | !*en.i18n.json 114 | 115 | mongo-dumps 116 | 117 | 118 | # Package management directories 119 | **/packages 120 | **/.meteor 121 | **/node_modules 122 | **/.npm 123 | 124 | # Translation files (keep only English) 125 | *.i18n.json 126 | !*en.i18n.json 127 | 128 | mongo-dumps 129 | 130 | 131 | # Package management directories 132 | **/packages 133 | **/.meteor 134 | **/node_modules 135 | **/.npm 136 | 137 | # Translation files (keep only English) 138 | *.i18n.json 139 | !*en.i18n.json 140 | 141 | mongo-dumps 142 | 143 | 144 | # Package management directories 145 | **/packages 146 | **/.meteor 147 | **/node_modules 148 | **/.npm 149 | 150 | # Translation files (keep only English) 151 | *.i18n.json 152 | !*en.i18n.json 153 | 154 | mongo-dumps 155 | 156 | 157 | # Package management directories 158 | **/packages 159 | **/.meteor 160 | **/node_modules 161 | **/.npm 162 | 163 | # Translation files (keep only English) 164 | *.i18n.json 165 | !*en.i18n.json 166 | 167 | mongo-dumps 168 | 169 | 170 | # Package management directories 171 | **/packages 172 | **/.meteor 173 | **/node_modules 174 | **/.npm 175 | 176 | # Translation files (keep only English) 177 | *.i18n.json 178 | !*en.i18n.json 179 | 180 | mongo-dumps 181 | 182 | 183 | # Package management directories 184 | **/packages 185 | **/.meteor 186 | **/node_modules 187 | **/.npm 188 | 189 | # Translation files (keep only English) 190 | *.i18n.json 191 | !*en.i18n.json 192 | 193 | mongo-dumps 194 | 195 | 196 | # Package management directories 197 | **/packages 198 | **/.meteor 199 | **/node_modules 200 | **/.npm 201 | 202 | # Translation files (keep only English) 203 | *.i18n.json 204 | !*en.i18n.json 205 | 206 | mongo-dumps 207 | 208 | 209 | # Package management directories 210 | **/packages 211 | **/.meteor 212 | **/node_modules 213 | **/.npm 214 | 215 | # Translation files (keep only English) 216 | *.i18n.json 217 | !*en.i18n.json 218 | 219 | mongo-dumps 220 | 221 | 222 | # Package management directories 223 | **/packages 224 | **/.meteor 225 | **/node_modules 226 | **/.npm 227 | 228 | # Translation files (keep only English) 229 | *.i18n.json 230 | !*en.i18n.json 231 | 232 | mongo-dumps 233 | 234 | 235 | # Package management directories 236 | **/packages 237 | **/.meteor 238 | **/node_modules 239 | **/.npm 240 | 241 | # Translation files (keep only English) 242 | *.i18n.json 243 | !*en.i18n.json 244 | 245 | mongo-dumps 246 | 247 | 248 | # Package management directories 249 | **/packages 250 | **/.meteor 251 | **/node_modules 252 | **/.npm 253 | 254 | # Translation files (keep only English) 255 | *.i18n.json 256 | !*en.i18n.json 257 | 258 | mongo-dumps 259 | 260 | 261 | # Package management directories 262 | **/packages 263 | **/.meteor 264 | **/node_modules 265 | **/.npm 266 | 267 | # Translation files (keep only English) 268 | *.i18n.json 269 | !*en.i18n.json 270 | 271 | mongo-dumps 272 | 273 | 274 | # Package management directories 275 | **/packages 276 | **/.meteor 277 | **/node_modules 278 | **/.npm 279 | 280 | # Translation files (keep only English) 281 | *.i18n.json 282 | !*en.i18n.json 283 | 284 | mongo-dumps 285 | 286 | 287 | # Package management directories 288 | **/packages 289 | **/.meteor 290 | **/node_modules 291 | **/.npm 292 | 293 | # Translation files (keep only English) 294 | *.i18n.json 295 | !*en.i18n.json 296 | 297 | mongo-dumps 298 | 299 | 300 | # Package management directories 301 | **/packages 302 | **/.meteor 303 | **/node_modules 304 | **/.npm 305 | 306 | # Translation files (keep only English) 307 | *.i18n.json 308 | !*en.i18n.json 309 | 310 | mongo-dumps 311 | 312 | 313 | # Package management directories 314 | **/packages 315 | **/.meteor 316 | **/node_modules 317 | **/.npm 318 | 319 | # Translation files (keep only English) 320 | *.i18n.json 321 | !*en.i18n.json 322 | 323 | mongo-dumps 324 | 325 | 326 | # Package management directories 327 | **/packages 328 | **/.meteor 329 | **/node_modules 330 | **/.npm 331 | 332 | # Translation files (keep only English) 333 | *.i18n.json 334 | !*en.i18n.json 335 | 336 | mongo-dumps 337 | 338 | 339 | # Package management directories 340 | **/packages 341 | **/.meteor 342 | **/node_modules 343 | **/.npm 344 | 345 | # Translation files (keep only English) 346 | *.i18n.json 347 | !*en.i18n.json 348 | 349 | mongo-dumps 350 | 351 | 352 | # Package management directories 353 | **/packages 354 | **/.meteor 355 | **/node_modules 356 | **/.npm 357 | 358 | # Translation files (keep only English) 359 | *.i18n.json 360 | !*en.i18n.json 361 | 362 | mongo-dumps 363 | 364 | 365 | # Package management directories 366 | **/packages 367 | **/.meteor 368 | **/node_modules 369 | **/.npm 370 | 371 | # Translation files (keep only English) 372 | *.i18n.json 373 | !*en.i18n.json 374 | 375 | mongo-dumps 376 | 377 | 378 | # Package management directories 379 | **/packages 380 | **/.meteor 381 | **/node_modules 382 | **/.npm 383 | 384 | # Translation files (keep only English) 385 | *.i18n.json 386 | !*en.i18n.json 387 | 388 | mongo-dumps 389 | 390 | 391 | -------------------------------------------------------------------------------- /.cursor/rules/tasks/060-i18n-language-specific-routes.mdc: -------------------------------------------------------------------------------- 1 | --- 2 | description: Use when information about language specific i18n routes would be helpful 3 | globs: 4 | alwaysApply: false 5 | --- 6 | 7 | # Language-Specific Routes Implementation Guidelines 8 | 9 | ## Key Packages 10 | 11 | The i18n and routing functionality is spread across several packages: 12 | - `justdo-i18n`: Core internationalization features 13 | - `justdo-i18n-routes`: Handles route translation and language prefixing 14 | - `justdo-site-mapper`: Manages sitemap generation 15 | - `justdo-seo`: Handles SEO aspects including alternate language links 16 | - `justdo-news`: Example of content with language-specific limitations 17 | 18 | ## Route Registration and Translatable Flag 19 | 20 | There are two key concepts to understand for i18n routing: 21 | 22 | 1. **Route Registration**: Routes must be known to the i18n system to be handled properly 23 | 2. **Translatable Flag**: Routes must be marked as translatable to receive language prefixes 24 | 25 | ### Using `registerRoutes` 26 | 27 | The `justdo-i18n-routes` package provides a `registerRoutes` method that registers routes with both Iron Router and the i18n system: 28 | 29 | ```coffeescript 30 | APP.justdo_i18n_routes.registerRoutes [{ 31 | path: "/example", 32 | routingFunction: -> 33 | # Route handler function 34 | @render "example_template" 35 | route_options: { 36 | name: "example" 37 | translatable: true 38 | } 39 | }] 40 | ``` 41 | 42 | When you call `registerRoutes`: 43 | - The route is registered with Iron Router in the standard way 44 | - The route is also marked in the `i18n_routes` object maintained by the package 45 | - This marking makes the route **eligible** for i18n processing 46 | 47 | ### The `translatable: true` Flag 48 | 49 | Setting `translatable: true` in the route options is required for a route to actually receive language-specific handling: 50 | 51 | ```coffeescript 52 | # Standard Iron Router definition 53 | Router.route "/example", 54 | name: "example" 55 | translatable: true 56 | # other options... 57 | ``` 58 | 59 | Important notes: 60 | - **Both mechanisms are needed**: A route registered with `registerRoutes` still needs `translatable: true` to receive language prefixes 61 | - **Flexibility**: You can register routes that are known to the i18n system but don't need translations yet 62 | - **Dynamic control**: You can easily enable/disable translations for routes by toggling the `translatable` flag 63 | 64 | ### How They Work Together 65 | 66 | 1. **Route Registration** (via `registerRoutes` or standard `Router.route`) makes the route known to the system 67 | 2. **`translatable: true` Flag** enables the generation of language-specific URLs and alternate links 68 | 3. **`getI18nKeyToDetermineSupportedLangs` Function** (optional) restricts which languages are supported 69 | 70 | ## Language Support Determination 71 | 72 | The system uses a hierarchical approach to determine which languages are supported for a given route: 73 | 74 | 1. Check if the route is marked as `translatable: true` (required for any i18n support) 75 | 2. If the route provides a `getI18nKeyToDetermineSupportedLangs` function, use it to: 76 | - Determine an i18n key that represents the content 77 | - Check which languages have translations for that key 78 | 3. If no key or function is provided, all supported languages are considered available 79 | 80 | ## Key Functions 81 | 82 | ### Client and Server Functions 83 | 84 | - **`getI18nKeyToDetermineSupportedLangFromPath(path)`**: Extracts the i18n key for a given path 85 | - Removes HRP (Human Readable Parts) from the path 86 | - Retrieves the route and checks if it's translatable 87 | - Returns the i18n key if available 88 | 89 | ### Server-Only Functions 90 | 91 | - **`getSupportedLangsForPath(path)`**: Determines which languages are supported for a path 92 | - For non-translatable routes, returns only the default language 93 | - For translatable routes without restrictions, returns all supported languages 94 | - For routes with i18n key restrictions, returns only languages with translations 95 | 96 | ### URL Generation 97 | 98 | - **`i18nPath(path, lang, options)`**: Converts a path to include language prefix when appropriate 99 | - Only adds language prefix for non-default languages 100 | - Only adds prefix for translatable routes 101 | - Only adds prefix if the language is supported for the specific content 102 | - Accepts `skip_lang_check: true` option to bypass content-specific language checks 103 | 104 | - **`i18nPathAndHrp(path, lang, options)`**: Combines i18nPath with Human Readable Parts 105 | 106 | ## Implementation Example 107 | 108 | To implement language-specific routes for new content: 109 | 110 | 1. Mark your route as translatable: 111 | 112 | ```coffeescript 113 | Router.route "/example-page", 114 | name: "example_page" 115 | translatable: true 116 | # ...other options 117 | ``` 118 | 119 | 2. Add a function to determine supported languages (optional): 120 | 121 | ```coffeescript 122 | Router.route "/example-content/:id", 123 | name: "example_content" 124 | translatable: true 125 | getI18nKeyToDetermineSupportedLangs: (path) -> 126 | # Extract content ID from path 127 | matches = path.match /\/example-content\/([^\/\?]+)/ 128 | return null unless matches? 129 | 130 | content_id = matches[1] 131 | # Find the content 132 | content = ExampleContents.findOne {_id: content_id}, {fields: {title_i18n_key: 1}} 133 | 134 | # Return the i18n key that determines which languages are supported 135 | return content?.title_i18n_key 136 | # ...other options 137 | ``` 138 | 139 | 3. Apply i18n to links: 140 | 141 | ```coffeescript 142 | url = "/example-content/123" 143 | i18n_url = APP.justdo_i18n_routes.i18nPathAndHrp(url) 144 | ``` 145 | 146 | ## Runtime Behavior 147 | 148 | 1. When a user navigates to `/lang/zh-TW/pricing` (a fully translated page): 149 | - Content is displayed in Chinese 150 | - UI components (header, menu) are in Chinese 151 | - Links to other translated pages maintain the `/lang/zh-TW/` prefix 152 | 153 | 2. When a user with active language "zh-TW" navigates to `/terms-and-conditions` (English-only page): 154 | - Content is displayed in English (default language) 155 | - UI components remain in Chinese 156 | - Language-specific prefix is omitted from the URL 157 | - Links back to translated pages will restore the language prefix 158 | 159 | ## SEO Considerations 160 | 161 | The system automatically: 162 | 163 | - Updates `` tags to only include supported languages 164 | - Ensures sitemap.xml only includes language variants that actually exist 165 | - Handles canonical URLs correctly for each language version 166 | 167 | ## Troubleshooting 168 | 169 | - If language prefixes aren't being added correctly, check if the route is marked as `translatable: true` 170 | - If alternate links are incorrect, verify the i18n key is being returned properly 171 | - Server logs may show "Note: Language support for /path can't be fully determined on client side" which is expected for client-side rendering 172 | 173 | ## Testing Language Support 174 | 175 | To verify language support for a specific path: 176 | 177 | ```coffeescript 178 | # Server-side 179 | supported_langs = APP.justdo_i18n_routes.getSupportedLangsForPath("/example-path") 180 | console.log(supported_langs) 181 | 182 | # Server or client 183 | i18n_key = APP.justdo_i18n_routes.getI18nKeyToDetermineSupportedLangFromPath("/example-path") 184 | console.log(i18n_key) 185 | ``` -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | volumes: 2 | mongodb-data: 3 | # This named volume defaults to Docker's internal storage. If you prefer a 4 | # specific host path (e.g., to browse files on your Mac or manage backups), 5 | # you can use a bind mount instead: 6 | # 7 | # driver: local 8 | # driver_opts: 9 | # type: none 10 | # o: bind 11 | # device: /absolute/path/on/host/mongodb-data 12 | # 13 | # For details: https://docs.docker.com/storage/bind-mounts/ 14 | 15 | mongodb-config: 16 | # Used to persist the replica set configuration. 17 | 18 | services: 19 | mongodb: 20 | # Despite the fact we are using a single MongoDB instance, we are using a 21 | # replica set to support Meteor's oplog-tailing based reactivity - this is 22 | # a requirement for JustDo. 23 | # 24 | # For the parts related to the configuration of the MongoDB replica set, we 25 | # owe our thanks to the following guide from which we borrowed quite a bit: 26 | # https://medium.com/workleap/the-only-local-mongodb-replica-set-with-docker-compose-guide-youll-ever-need-2f0b74dd8384 27 | # https://archive.is/wip/aVFku 28 | image: mongo:7.0.5 29 | 30 | # We override the entrypoint with a small bash snippet that generates a 31 | # mongo-keyfile if it’s missing 32 | entrypoint: > 33 | bash -c ' 34 | set -e 35 | # If no keyFile in /data/configdb, generate one 36 | if [ ! -f /data/configdb/mongo-keyfile ]; then 37 | echo "No keyFile found in /data/configdb; generating one..." 38 | openssl rand -base64 756 > /data/configdb/mongo-keyfile 39 | chmod 400 /data/configdb/mongo-keyfile 40 | fi 41 | # Then hand off control to the official docker-entrypoint.sh with our mongod args 42 | exec /usr/local/bin/docker-entrypoint.sh "$@" 43 | ' 44 | 45 | command: 46 | - "mongod" 47 | - "--replSet" 48 | - "rs0" 49 | - "--bind_ip_all" 50 | - "--port" 51 | - "27017" 52 | - "--keyFile" 53 | - "/data/configdb/mongo-keyfile" 54 | - "--auth" 55 | 56 | # We bind MongoDB’s default port (27017) to localhost (127.0.0.1) so you 57 | # can use tools like MongoDB Compass or the mongo CLI for backups/debugging 58 | # without publicly exposing the database. If you need remote access, 59 | # switch to "0.0.0.0:27017:27017" - *and use a secure username/password*. 60 | # 61 | # You can also change the host-bound port (e.g., "127.0.0.1:32000:27017") 62 | # without affecting JustDo’s internal configuration, since it connects to 63 | # MongoDB via Docker’s internal network on port 27017. 64 | ports: 65 | - "127.0.0.1:27017:27017" 66 | 67 | # "This healthcheck is used to ensure the MongoDB replica set is properly 68 | # configured. It will fail if the replica set is not properly configured." 69 | # https://archive.is/wip/aVFku 70 | healthcheck: 71 | test: > 72 | bash -c "echo \" 73 | try { 74 | rs.status() 75 | } catch (err) { 76 | rs.initiate({ 77 | _id:'rs0', 78 | members:[{_id:0, host:'mongodb:27017'}] 79 | }) 80 | } 81 | \" | mongosh --port 27017 -u ${MONGO_USERNAME:-admin} -p ${MONGO_PASSWORD:-password} --authenticationDatabase admin" 82 | interval: 5s 83 | timeout: 30s 84 | retries: 30 85 | volumes: 86 | - mongodb-data:/data/db 87 | - mongodb-config:/data/configdb # Used to persist the replica set configuration. 88 | environment: 89 | - MONGO_INITDB_ROOT_USERNAME=${MONGO_USERNAME:-admin} 90 | - MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD:-password} 91 | # IMPORTANT! ↑ You *must* change this to a secure password if you open it 92 | # beyond localhost. 93 | 94 | justdo: 95 | image: justdoinc/justdo:latest 96 | platform: linux/amd64 97 | ports: 98 | # JustDo consists of two apps that need to know their respective ports 99 | # (for redirects between the landing page and the main web app). For 100 | # simple setups without a reverse proxy, the internal and external ports 101 | # should match. 102 | - "${LANDING_APP_PORT:-3150}:${LANDING_APP_PORT:-3150}" 103 | - "${APP_PORT:-3151}:${APP_PORT:-3151}" 104 | depends_on: 105 | - mongodb 106 | environment: 107 | - MONGO_URL=mongodb://${MONGO_USERNAME:-admin}:${MONGO_PASSWORD:-password}@mongodb:27017/justdo?authSource=admin&replicaSet=rs0 108 | - MONGO_OPLOG_URL=mongodb://${MONGO_USERNAME:-admin}:${MONGO_PASSWORD:-password}@mongodb:27017/local?authSource=admin&replicaSet=rs0 109 | 110 | # For most setups, these must match the values used in 'ports:' above. 111 | - LANDING_APP_PORT=${LANDING_APP_PORT:-3150} 112 | - APP_PORT=${APP_PORT:-3151} 113 | 114 | # For a full list of supported environment variables, see: 115 | # https://github.com/justdoinc/justdo/blob/master/default-config.bash You 116 | # can override any default configurations by setting values here. 117 | 118 | # Common environment variable modifications (uncomment as needed): 119 | # 120 | # 1. Connecting to a custom MongoDB server: 121 | # 122 | # - MONGO_URL=mongodb://user:password@myhost:27017/justdo 123 | # - MONGO_OPLOG_URL=mongodb://user:password@myhost:27017/local 124 | # 125 | # Notes: 126 | # 127 | # a. Meteor relies on the MongoDB's oplog to provide reactivity. 128 | # If you're using a custom MongoDB server, you must ensure it is 129 | # using replica set configuration and that the 'local' database is 130 | # enabled. Otherwise the app will malfunction, and behave in an 131 | # unexpected manner. 132 | # 133 | # b. This replaces MONGO_URL/MONGO_OPLOG_URL earlier defined entirely, so remove them to avoid duplication. 134 | # 135 | # c. If you're using a custom MongoDB server: 136 | # i. Remove the entire 'mongodb:' service definition above. 137 | # ii. Under 'justdo' service, remove '- mongodb' from 'depends_on'. 138 | # If that leaves 'depends_on' empty, remove it entirely. 139 | # iii. Remove '- mongodb-data:' and '- mongodb-config:' from 140 | # 'volumes'. If 'volumes' is empty, remove it entirely. 141 | # 142 | # d. Example for connecting to MongoDB Atlas: 143 | # 144 | # Atlas requires a separate user for the oplog reading with read 145 | # access to the 'local' db. See step 6.2 here: 146 | # http://archive.is/B8XRf 147 | # 148 | # The following was tested with the free tier of MongoDB Atlas (on 149 | # March 2025, using MongoDB 8, which was the current free tier 150 | # version): 151 | # 152 | # 1. Create the cluster. 153 | # 2. Under the Database Access section create two users: 154 | # - one named 'admin' with read and write access to the 'justdo' 155 | # database. Under 'Database User Privileges', Under 'Built-In 156 | # Roles', select 'Read and Write to Any Database' (it translates 157 | # to 'readWriteAnyDatabase@admin') 158 | # - one named 'oplog-reader' with read access to the 'local' 159 | # database. Under 'Database User Privileges', Under 'Specific 160 | # Privileges', set 'read@local' 161 | # 3. Under the Network Access section, add your IP address to the 162 | # allowed IP addresses. 163 | # 4. Under the Clusters section, click on 'Connect', Select 164 | # 'Driver', 'Node.js', '4.1 or later', 'Use a connection string' 165 | # 5. Replace the , , , and 166 | # in the URLs below. 167 | # 6. NOTE by default the connection string doesn't have the database 168 | # name, the authSource, and the readPreference parameters - you need 169 | # to add them. 170 | # It is best that you'll update the connection string below, 171 | # instead of copy-pasting the connection string from the MongoDB 172 | # Atlas UI. 173 | # 174 | # When connecting use the following URLs: 175 | # 176 | # - MONGO_URL=mongodb+srv://:@/justdo?appName=&retryWrites=true&w=majority&authSource=admin&readPreference=primary 177 | # - MONGO_OPLOG_URL=mongodb+srv://:@/local?appName=&retryWrites=true&w=majority&authSource=admin&readPreference=primary 178 | # 179 | # 2. Use a Custom Domain + Reverse Proxy: 180 | # 181 | # - LANDING_APP_HOSTNAME=yourapp.example.com 182 | # - WEB_APP_HOSTNAME=yourapp.example.com 183 | # 184 | # Notes: 185 | # a. The default JustDo license is valid only for localhost. If you plan to use a 186 | # custom domain, you’ll need a new license. Check https://justdo.com/pricing— 187 | # trial periods are available. 188 | # 189 | # When requesting a license, keep in mind that it’s tied to the 190 | # domain name of your landing app (excluding any port numbers). For 191 | # instance, if your landing page is at 192 | # https://justdo.example.com:8080, the license will apply to 193 | # justdo.example.com. 194 | # 195 | # b. For the *JustDo Mobile App* to work properly, you should follow 196 | # the following domain structure: 197 | # 198 | # - justdo.example.com (Landing Page) 199 | # - app-justdo.example.com (Web App) 200 | # 201 | # The key point is that the web app domain shares the same base domain as the 202 | # landing page, prefixed with 'app-'. 203 | # 204 | # The following is also a valid domain structure: 205 | # 206 | # - x.example.com (Landing Page) 207 | # - app-x.example.com (Web App) 208 | # 209 | # To expose both apps on port 80 (or 443) for these separate domains, you’ll 210 | # likely need a reverse proxy (e.g., Nginx or AWS ALB) that routes requests 211 | # to the correct internal ports. 212 | # 213 | # For instance: 214 | # 215 | # - The reverse proxy routes justdo.example.com → port 3150 (landing page) 216 | # - The reverse proxy routes app-justdo.example.com → port 3151 (web app) 217 | # 218 | # *You must* tell the apps their public-facing domains differ from the internal 219 | # bindings. For that, set the following environment variables: 220 | # 221 | # - LANDING_APP_EXTERNAL_PORT=80 222 | # - APP_EXTERNAL_PORT=80 223 | # 224 | # So, a full reverse proxy example for the JustDo Mobile app (on justdo.example.com) 225 | # and the JustDo Web App (on app-justdo.example.com) might be: 226 | # 227 | # - LANDING_APP_HOSTNAME=justdo.example.com 228 | # - APP_HOSTNAME=app-justdo.example.com 229 | # - LANDING_APP_EXTERNAL_PORT=80 230 | # - APP_EXTERNAL_PORT=80 231 | # 232 | # Typically, the reverse proxy handles SSL. If you enable SSL, you’ll likely use 233 | # port 443 externally for both apps. In that scenario: 234 | # - LANDING_APP_EXTERNAL_PORT=443 235 | # - APP_EXTERNAL_PORT=443 236 | # 237 | # Don’t forget to set up a redirect from port 80 to 443 if you’re using SSL. 238 | # 239 | # 3. Setting an acquired JustDo license: 240 | # 241 | # - JUSTDO_LICENSING_LICENSE=YOUR_LICENSE_KEY 242 | # 243 | # Note: When requesting a license, keep in mind that it’s tied to the 244 | # domain name of your landing app (excluding any port numbers). For 245 | # instance, if your landing page is at https://justdo.example.com:8080, 246 | # the license will apply to justdo.example.com. 247 | # 248 | # 4. Set up an SMTP server (for email notifications): 249 | # 250 | # - MAIL_SENDER_EMAIL=you@example.com # The email address used to send emails 251 | # - MAIL_URL=smtps://:@:465/?secure=true # The SMTP server address 252 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JustDo 2 | 3 | [JustDo](https://justdo.com) is an all-purpose, enterprise-grade project management platform designed for maximum flexibility and customization. 4 | 5 | This repository contains the community edition, source-available version of JustDo, which allows for deep customization and integration possibilities. 6 | 7 | ![JustDo](https://justdo-media-files.s3.us-west-2.amazonaws.com/github-media/Github_min.png) 8 | 9 | ## 🌟 **Why Choose JustDo?** 10 | 11 | - **🎯 Perfect for Distributors**: We feature a simple *Flat Monthly Fee* pricing model with No Revenue Sharing! Unlock multiple revenue streams by offering licenses and various services to your customers, including: hosting, customization, training, business consulting, and more. 12 | - **🚀 Enterprise-Grade Performance**: Handle massive projects with over **200,000 tasks** and thousands of users without breaking a sweat. 13 | - **🧩 Fully Customizable**: Modify and extend JustDo to fit any client's unique requirements. 14 | - **🤖 AI-Powered Features**: Leverage cutting-edge AI to automate tasks, generate project structures from prompts, and enhance productivity. 15 | - **🔒 Top-Notch Security**: We offer on-premises and intranet deployment options for clients with strict security needs. The source code is available and fully auditable by you. We provide end-to-end encryption and SSO integration. 16 | - **🌐 Global Reach**: Support for **60+ languages**, including full **Right-to-Left (RTL)** support for languages such as Arabic and Hebrew - the best of its kind in the Project Management world. 17 | - **🎨 White-Label Ready**: Customize the platform with your own branding to offer a seamless experience for your clients. Load any Bootstrap theme or create your own. 18 | - **🔌 Extensive Plugin Ecosystem**: Choose from **150+ plugins** or create your own to extend functionality. 19 | 20 | [Check our full features list](https://justdo.com/pricing) 21 | 22 | 23 | ## 🚀 Installation & Usage 24 | 25 | The installation options are as follows: 26 | 27 | * [Option 1: Quick Start With a Convenient One-Liner](#option-1-quick-start-with-a-convenient-one-liner) 28 | * [Maintanance Operations for Option 1](#maintanance-operations) 29 | * [Option 2: Customized Docker Compose Setup](#option-2-customized-docker-compose-setup) 30 | * [Maintanance Operations for Option 2](#maintanance-operations) 31 | * [Option 3: Running Development Environment from Source Code](#option-3-running-development-environment-from-source-code) 32 | 33 | ### Option 1: Quick Start With a Convenient One-Liner 34 | 35 | This is the **recommended option** for quickly evaluating JustDo under `localhost`. You can also explore a demo instance at [justdo.com](https://justdo.com). This setup works well for local testing. For a production-ready configuration see [Option 2](#option-2-customized-docker-compose-setup). 36 | 37 | You can copy and paste the following line into your shell for a quick setup: 38 | ```bash 39 | curl -Ls https://justdo.com/docker-compose.yml | docker compose -p "justdo" -f - up -d 40 | ``` 41 | This will start a *JustDo* container and a *MongoDB* container. 42 | 43 | **Please allow *2–3 minutes* for everything to fully initialize.** 44 | 45 | #### Accessing JustDo: 46 | 47 | JustDo consists of two apps: 48 | 49 | 50 | * Landing Page (Registration/Login) at http://localhost:3150 51 | * Main Web App at http://localhost:3151 52 | 53 | Check the [Maintanance Operations](#maintanance-operations) section for details about stopping/starting/removing the JustDo stack & information about the MongoDB container backup/restore. 54 | 55 | ### Option 2: Customized Docker Compose Setup 56 | 57 | **Purpose:** This option offers a **production-ready** or **fully customizable** JustDo environment. Rather than using a quick one-liner, you'll **download** our [docker-compose.yml](https://justdo.com/docker-compose.yml) file. We've included **extensive comments** and example configurations for the most common customizations, so you can adapt the setup to your specific needs. 58 | 59 | #### Step 1: Download and Modify `docker-compose.yml` 60 | 61 | 1. [Download the docker-compose.yml file](https://justdo.com/docker-compose.yml). 62 | 2. Open it in a text editor and adjust ports, credentials, or environment variables to match your requirements. 63 | 64 | **Notes:** 65 | 66 | 1. **Use a Secure MongoDB Password** 67 | Even though the MongoDB container is bound to `127.0.0.1` and not exposed externally, it's still best practice to set a strong password for the admin user. 68 | 69 | 2. **Override Any Environment Variable** 70 | All environment variables referenced in our [default-config.bash](https://raw.githubusercontent.com/justdoinc/justdo/refs/heads/master/default-config.bash) are supported; simply define or override them under the `environment:` section of the justdo service. 71 | 72 | 3. **Switching from Option 1** 73 | If you already installed the JustDo stack with Option 1 and now want to configure the MongoDB password, you'll need to remove the existing stack first (see [Maintenance Operations](#maintanance-operations)). Doing so clears the data stored in the volumes—assuming it was for evaluation only. If you need to keep that data, **back it up** before switching to Option 2. 74 | 75 | #### Step 2: Installing the Docker Compose stack 76 | 77 | Run the following command to start the containers in the folder in which you located the `docker-compose.yml` file: 78 | 79 | ```bash 80 | docker compose -p "justdo" up -d 81 | ``` 82 | 83 | Note that we use `-p "justdo"` to specify the project name for this Docker Compose stack. This ensures container names stay consistent and predictable—so the [maintenance commands](#maintenance-operations) below (e.g., stopping or removing containers) will function as expected. 84 | 85 | **Please allow *2–3 minutes* for everything to fully initialize.** 86 | 87 | #### Step 3: Access JustDo 88 | 89 | If you didn't change the default ports in the `docker-compose.yml` file, you can access JustDo at: 90 | 91 | 92 | * Landing Page (Registration/Login) at http://localhost:3150 93 | * Main Web App at http://localhost:3151 94 | 95 | Check the [Maintanance Operations](#maintanance-operations) section for details about stopping/starting/removing the JustDo stack & information about the MongoDB container backup/restore. 96 | 97 | ### Option 3: Running Development Environment from Source Code 98 | 99 | [The source code of JustDo is available on GitHub](https://github.com/justdoinc/justdo). If you prefer to run JustDo natively or want to customize the codebase, follow these steps: 100 | 101 | #### Step 1: Install Prerequisites 102 | 103 | ##### Install Meteor 104 | 105 | JustDo is built on [Meteor.js](https://www.meteor.com/), a powerful full-stack JavaScript framework for building real-time applications. 106 | 107 | Install Meteor.js by running the following command in your terminal: 108 | ```bash 109 | curl https://install.meteor.com/\?release\=2.16 | sh 110 | ``` 111 | 112 | ##### macOS Additional Steps 113 | 114 | We have minimized external dependencies as much as possible. However, on macOS, you'll need to ensure that **Python 2.7** is installed, as it is required for the compilation processes of some of our packages. Additionally, you'll need to install the **Xcode Command Line Tools**. 115 | 116 | 1. **Install Python 2.7 using Homebrew & pyenv:** 117 | 118 | Note: The following steps are optional and only required if you don't have Python 2.7 installed on your system. Further they are one of many ways to install Python 2.7 on macOS. 119 | 120 | ```bash 121 | brew install pyenv 122 | pyenv init # Follow the steps presented in the output 123 | ``` 124 | 125 | *Close your shell and start a new one* to ensure that pyenv is initialized. 126 | 127 | ```bash 128 | pyenv install 2.7 129 | ``` 130 | 131 | 2. **Install Xcode Command Line Tools:** 132 | 133 | Run the following command to install the Xcode Command Line Tools: 134 | 135 | ```bash 136 | xcode-select --install 137 | ``` 138 | 139 | ##### Linux Additional Steps 140 | 141 | JustDo is fully supported on Linux. No further steps are required. 142 | 143 | ##### Windows Users 144 | 145 | As of now, JustDo is not officially supported on Windows. However, you can run JustDo on Windows using the Windows Subsystem for Linux (WSL) or a virtual machine. 146 | 147 | #### Step 2: Clone the Repository 148 | 149 | Clone the JustDo repository and its submodules: 150 | 151 | ```bash 152 | git clone --recursive git@github.com:justdoinc/justdo.git 153 | cd justdo 154 | ``` 155 | 156 | #### Step 3: Run JustDo 157 | 158 | Start the JustDo application: 159 | 160 | ```bash 161 | ./justdo run 162 | ``` 163 | 164 | **The initial setup will take 10-15 minutes to complete - please be patient.** Consequitive runs will run much faster. 165 | 166 | Once the application is running, you can access it: 167 | 168 | * Landing Page (Registration/Login) - [http://localhost:4000/](http://localhost:4000/) 169 | * Main Web App - [http://localhost:3000/app](http://localhost:3000/app) 170 | 171 | (Note that the default ports for the development environment are different from the Docker environment.) 172 | 173 | ## Maintanance Operations 174 | 175 | This section is relevant only if you started the JustDo stack using the `docker-compose.yml` file from Option 1 or Option 2 above. 176 | 177 | ### Stopping JustDo 178 | 179 | If you just want to stop running containers (but keep volumes/data intact): 180 | 181 | ```bash 182 | docker compose -p "justdo" stop 183 | ``` 184 | 185 | This stops the containers without removing volumes or networks. 186 | 187 | ### Starting JustDo after stopping it 188 | 189 | To start the stack: 190 | 191 | ```bash 192 | docker compose -p "justdo" start 193 | ``` 194 | 195 | ### Removing JustDo completely 196 | 197 | To remove all containers, networks, and volumes associated with the JustDo stack: 198 | 199 | ```bash 200 | docker compose -p "justdo" down 201 | ``` 202 | 203 | This cleans up everything created by the Compose file except the data stored in volumes. 204 | 205 | If you also want to remove the data stored in volumes, run the following command: 206 | 207 | **Be careful with this command, as it will remove all your data!** (you can backup the data before running this command, details under [Backup/Restore](#mongodb-container-backuprestore)) 208 | 209 | ```bash 210 | docker compose -p "justdo" down -v 211 | ``` 212 | 213 | This cleans up everything created by the Compose file, **including any data stored in volumes**. If you plan to reinstall later, note that you'll be starting from a blank slate - *all your data will be removed*. 214 | 215 | To also remove the JustDo image: 216 | 217 | ```bash 218 | docker rmi justdoinc/justdo 219 | ``` 220 | 221 | Note we don't remove the mongo image, as it might be used by other stacks. 222 | 223 | ### MongoDB Container Backup/Restore 224 | 225 | By default, the setup above doesn't include an automated backup process for MongoDB - **backups are your sole responsibility!** 226 | 227 | The following is a basic example of how to manually back up or restore your data, see it only as a reference to start building your own backup/restore process, with your particular needs in mind. 228 | 229 | **Backup**: 230 | 231 | ```bash 232 | docker exec justdo-mongodb-1 sh -c 'mongodump --username admin --password password --authenticationDatabase admin --archive' > db.dump 233 | ``` 234 | 235 | This creates a db.dump file in your current directory, containing a snapshot of your MongoDB data. 236 | 237 | **Restore**: 238 | 239 | ```bash 240 | cat db.dump | docker exec -i justdo-mongodb-1 mongorestore --username admin --password password --authenticationDatabase admin --archive 241 | ``` 242 | 243 | **Note** 244 | You must replace `password` in both of the commands above with the actual password. 245 | 246 | - **If you used Option 1** 247 | The default password is literally `password`. Running the command *as-is* should work. This option is **not** intended for production and is only used when MongoDB is not exposed to external networks. 248 | 249 | - **If you used Option 2** 250 | Use the password you specified in your `docker-compose.yml` file. 251 | 252 | ## 🔗 Related Repositories 253 | 254 | - [JustDo Main Repository](https://github.com/justdoinc/justdo) 255 | - [JustDo Web App](https://github.com/justdoinc/justdo-web-app-ce) 256 | - [JustDo Landing App](https://github.com/justdoinc/justdo-landing-app-ce) 257 | - [JustDo Packages](https://github.com/justdoinc/justdo-packages) 258 | 259 | ## 🛠️ **Developer-Friendly** 260 | 261 | ### **For Developers and Consultants** 262 | 263 | JustDo is designed with developers and consultants in mind: 264 | 265 | - **Easy Customization**: Modify the platform to suit any industry or client need. 266 | - **Plugin Development**: Create custom plugins with our robust SDK. 267 | - **Scalable Architecture**: Build solutions that grow with your clients - JustDo was designed to be horizontally scalable. 268 | 269 | ### **Multiple Revenue Streams** 270 | 271 | As a JustDo distributor or consultant, you can unlock various revenue opportunities: 272 | 273 | - **Software Licensing**: Earn recurring revenue from user subscriptions. 274 | - **Hosting Services**: Offer cloud or on-premise solutions. 275 | - **Customization**: Provide tailored solutions for specific client needs. 276 | - **Training & Support**: Offer ongoing services to enhance client engagement. 277 | - **Business Consulting**: Leverage JustDo to expand your service offerings. 278 | 279 | ## 🌍 **Join Our Community** 280 | 281 | - **Website**: [https://justdo.com](https://justdo.com) 282 | - **Twitter**: [@justdo_com](https://twitter.com/justdo_com) 283 | - **Contact**: [info@justdo.com](mailto:info@justdo.com) 284 | 285 | ## 🤝 **Contributing** 286 | 287 | We welcome contributions to enhance JustDo. Whether it's reporting bugs, suggesting new features, or improving documentation, your input is valuable. 288 | 289 | - **Issue Tracker**: Report issues or request features on our [GitHub Issues](https://github.com/justdoinc/justdo/issues). 290 | - **Pull Requests**: Submit improvements or fixes via [pull requests](https://github.com/justdoinc/justdo/pulls). 291 | 292 | --- 293 | 294 | *Note: For licensing information, please refer to the [LICENSE](LICENSE) file.* 295 | -------------------------------------------------------------------------------- /utils/run-justdo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # IMPORTANT!!! INTENDED TO BE USED BY justdo only! 5 | # 6 | 7 | # Synopsis 8 | # ======== 9 | # 10 | # ./run-justdo [environment_name] [--prefer-existing-env-vars] 11 | # 12 | # environment_name: 13 | # 14 | # Will be used to load environment variables configuration file, the 15 | # name of the file loaded will be: .[environment_name]-env-conf 16 | # 17 | # If environment_name isn't set it will default to: config.bash 18 | # 19 | # --prefer-existing-env-vars: 20 | # 21 | # If this flag is provided, existing environment variables will take precedence 22 | # over those defined in the configuration file. 23 | # 24 | # If conf-file isn't provided, we use by default config.bash 25 | 26 | # echo 'NODE_TLS_REJECT_UNAUTHORIZED="0" applied, after upgrading Meteor, remove this line' 27 | # export NODE_TLS_REJECT_UNAUTHORIZED="0" 28 | 29 | # Environmental variables: 30 | # ======================== 31 | # 32 | # * WEB_APP_HOSTNAME - self explanatory - can also be configured by using ./configure-dev-environment.bash 33 | # * LANDING_APP_HOSTNAME - self explanatory - can also be configured by using ./configure-dev-environment.bash 34 | # * APP_PORT - (default: 3000) self explanatory - can also be configured by using ./configure-dev-environment.bash 35 | # * LANDING_APP_PORT - (default: 4000) self explanatory - can also be configured by using ./configure-dev-environment.bash 36 | # * APP_EXTERNAL_PORT - (default: $APP_PORT) If the port used to access the app is different from the port we bind 37 | # (example, in case of port forwarding) you can set the external app 38 | # port here. 39 | # * LANDING_APP_EXTERNAL_PORT - (default: $LANDING_APP_PORT) See explanation for APP_EXTERNAL_PORT 40 | # * MAIL_URL - self explanatory - can also be configured by using ./configure-dev-environment.bash 41 | # * MONGO_TUNNEL_HOST - Set $MONGO_TUNNEL_HOST to a ssh host (including username, 42 | # e.g. a@x.com) to automatically set tunneling to that host 43 | # * MONGO_TUNNEL_HOST_PORT - Relevant only if $MONGO_TUNNEL_HOST is set. 44 | # The Mongo port in the remote host. 45 | # Default to: 27017. 46 | # * MONGO_TUNNEL_MONGO_CREDENTIALS - Relevant only if $MONGO_TUNNEL_HOST is set. 47 | # Should be of the form: "user:pass". 48 | # Default to: "" 49 | # * SMTP_TUNNEL_HOST - Set $SMTP_TUNNEL_HOST to a ssh host (including username, 50 | # e.g. a@x.com) to automatically set tunneling to that host 51 | # * BIND_TO_NET - DEPRECATED If set to one of the network interfaces listed on ifconfig 52 | # we will set HOST_DOMAIN to that interface ip automatically 53 | # in the process we will override HOST_DOMAIN configured as 54 | # environmental variable or by using ./configure-dev-environment.bash 55 | # * DEBUG_ENVIRONMENT - Set to "landing-app"/"web-app" if you want us to run the meteor 56 | # command for the landing app/web-app with the debug command. 57 | # At the moment, only one environment can run with the 58 | # debug command. Leave unset/empty/with any other value 59 | # will have no effect. 60 | # * TEST_MODE - Set to "true" if you want us to run the meteor command for the 61 | # web-app and landing-app with the test command. 62 | # * MOCHA_GREP - When TEST_MODE is "true", you can set MOCHA_GREP to a pattern to filter 63 | # the tests to run by their name. For example: MOCHA_GREP="/my test/i" will 64 | # only run tests with "my test" in their name. 65 | # * TEST_RUN_ONCE - When TEST_MODE is "true", setting this to "true" will run tests with 66 | # the --once flag, causing the test process to exit after completion. 67 | # 68 | 69 | # Examples: 70 | # 71 | # Connecting to an already tunneled Atlas server: 72 | # 73 | # IMPORTANT! turn off jobs processors first!!! 74 | # 75 | # Replace XXX with passwords 76 | # 77 | # $ ssh -L 27017:main-shard-00-00-gzrj5.mongodb.net:27017 daniel@52.35.250.242 -N 78 | # $ MONGO_URL="mongodb://admin:XXX@localhost:27017/justdo?ssl=true&authSource=admin" OPLOG_URL="mongodb://oplog-reader:XXX@localhost:27017/local?ssl=true&authSource=admin" ./run-justdo 79 | # 80 | # Tunneling example: 81 | # 82 | # $ MONGO_TUNNEL_HOST="JustdoMain" MONGO_TUNNEL_HOST_PORT="32000" MONGO_TUNNEL_MONGO_CREDENTIALS="user:pass" MONGO_TUNNEL_AUTH_SOURCE="admin" ./run-justdo 83 | # 84 | 85 | cd "$(dirname $0)" # cd to script dir 86 | 87 | export LOGS_FOLDER="dev-logs" 88 | 89 | appendPortToURL () { 90 | # appendPortToURL $url $port 91 | # 92 | # Appends the port to the url, if the port isn't port 80 93 | 94 | local url="$1" 95 | local port="$2" 96 | 97 | if [[ "$port" != 80 ]]; then 98 | echo "$url:$port" 99 | else 100 | echo "$url" 101 | fi 102 | } 103 | 104 | meteor_command=( "meteor" ) 105 | # meteor_command=~/meteor/meteor # uncomment to run meteor from local git checkout. 106 | 107 | if [[ "${meteor_command[@]}" != "meteor" ]]; then 108 | # XXX I am not sure whether this is really necessary 109 | alias meteor="${meteor_command[@]}" 110 | fi 111 | 112 | # Parse arguments 113 | 114 | prefer_existing_env_vars=false 115 | 116 | for arg in "$@"; do 117 | if [[ "$arg" == "--prefer-existing-env-vars" ]]; then 118 | prefer_existing_env_vars=true 119 | elif [[ "$arg" != --* ]]; then 120 | configuration_file_env="$arg" 121 | fi 122 | done 123 | 124 | configuration_file="config.bash" 125 | 126 | if [[ ! -e "$configuration_file" ]]; then 127 | announceStep "Calling $ ./justdo configure-dev-environment to create the default configuration file." 128 | 129 | ./justdo configure-dev-environment 130 | 131 | if [[ ! -d "$LOGS_FOLDER" ]]; then 132 | mkdir "$LOGS_FOLDER" 133 | fi 134 | 135 | announceStep "You can configure ./run-justdo settings on: '$configuration_file'" 136 | 137 | echo "" 138 | echo "🚀 First Run Notice 🚀" 139 | echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 140 | echo "⚠️ This is the first run, so it might take a few minutes to install and compile all dependencies." 141 | echo "⏱️ Future runs will be much quicker." 142 | echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 143 | echo "" 144 | wait_time_sec=3 145 | echo "➡️ Press to continue... or wait $wait_time_sec seconds" 146 | 147 | read -t "$wait_time_sec" 148 | fi 149 | 150 | if [[ "$prefer_existing_env_vars" == true ]]; then 151 | # Create a temporary file to store modified configuration 152 | temp_config_file=$(mktemp) 153 | 154 | # Copy the original configuration file 155 | cp "$configuration_file" "$temp_config_file" 156 | 157 | # Get all currently defined environment variables 158 | existing_vars="$(env | platformGrep -E '^[[:alnum:]_]+=.*$' | cut -d= -f1)" 159 | 160 | # For each existing variable, remove its export line from the temp config 161 | while IFS= read -r var; do 162 | # Define the pattern to match export statements for this variable 163 | export_pattern="^\s*export\s+$var=" 164 | 165 | # Check if the variable exists in the config file before attempting to remove it 166 | if platformGrep -qE "$export_pattern" "$temp_config_file"; then 167 | announceStep "Removing export line for $var" 168 | # Remove export lines for this variable 169 | platformSed -i -E "/$export_pattern/d" "$temp_config_file" 170 | fi 171 | done <<< "$existing_vars" 172 | 173 | # Source the modified configuration file 174 | . "$temp_config_file" 175 | 176 | # Clean up 177 | rm -f "$temp_config_file" 178 | 179 | announceStep "Using existing environment variables where available" 180 | else 181 | # Source the configuration file normally 182 | . "$configuration_file" 183 | fi 184 | 185 | if [[ -n "$MONGO_TUNNEL_HOST" ]]; then 186 | 187 | MONGO_TUNNEL_HOST_PORT="${MONGO_TUNNEL_HOST_PORT:-"27017"}" 188 | announceStep "Setting up Mongo tunnel to $MONGO_TUNNEL_HOST:$MONGO_TUNNEL_HOST_PORT under port 30000 (127.0.0.1)" 189 | 190 | (ssh -L 30000:127.0.0.1:$MONGO_TUNNEL_HOST_PORT "$MONGO_TUNNEL_HOST" -N) & 191 | 192 | if [[ -n "$MONGO_TUNNEL_MONGO_CREDENTIALS" ]]; then 193 | MONGO_TUNNEL_MONGO_CREDENTIALS+="@" 194 | else 195 | MONGO_TUNNEL_MONGO_CREDENTIALS="" 196 | fi 197 | 198 | MONGO_URL="mongodb://${MONGO_TUNNEL_MONGO_CREDENTIALS}127.0.0.1:30000/justdo" 199 | OPLOG_URL="mongodb://${MONGO_TUNNEL_MONGO_CREDENTIALS}127.0.0.1:30000/local" 200 | 201 | if [[ -n "$MONGO_TUNNEL_AUTH_SOURCE" ]]; then 202 | # The db used to authenticate the connecting user 203 | MONGO_URL+="?authSource=$MONGO_TUNNEL_AUTH_SOURCE" 204 | OPLOG_URL+="?authSource=$MONGO_TUNNEL_AUTH_SOURCE" 205 | fi 206 | 207 | export MONGO_URL 208 | export OPLOG_URL 209 | fi 210 | 211 | if [[ -n "$SMTP_TUNNEL_HOST" ]]; then 212 | announceStep "Setting up SMTP tunnel to $SMTP_TUNNEL_HOST:25 under port 30025 (127.0.0.1)" 213 | 214 | (ssh -L 30025:127.0.0.1:25 "$SMTP_TUNNEL_HOST" -N) & 215 | 216 | export MAIL_URL="smtp://localhost:30025" 217 | fi 218 | 219 | # if [[ -n "$BIND_TO_NET" ]]; then 220 | # net_addr=$(ifconfig "$BIND_TO_NET" | platformGrep 'inet addr' | awk "{print \$2}") 221 | # net_addr="${net_addr##addr:}" 222 | # 223 | # announceStep "Binding to $BIND_TO_NET ($net_addr)" 224 | # 225 | # export HOST_DOMAIN="$net_addr" 226 | # fi 227 | 228 | export justdo_web_app_path="justdo-web-app-ce/application" 229 | # export justdo_web_app_path="output/justdo/justdo-web-app-ce/application" 230 | export justdo_landing_app_path="justdo-landing-app-ce/application" 231 | # export justdo_landing_app_path="output/justdo/justdo-landing-app/application" 232 | 233 | announceStep "Starting web app" 234 | 235 | startMeteor () { 236 | # Touch is necessary as `readlink -f` behaves differently in Linux and Mac for non-existing 237 | # files (Mac returns empty string). 238 | touch "$LOG_FILE" 239 | 240 | # expandPath is intentionally not used here as we don't want to rely on users to install on mac 241 | # greadlink or coreutils (to reduce dependencies). Without greadlink, in mac 242 | # readlink -f behaves differently for non-existing files (returns empty string). 243 | local log_file="$(readlink -f "$LOG_FILE")" 244 | 245 | rm "$log_file" 2>/dev/null 246 | 247 | cd "$APP_PATH" 248 | 249 | "${meteor_command[@]}" npm install 250 | 251 | local -a extra_args=() 252 | if [[ "$DEBUG_MODE" == "true" ]]; then 253 | extra_args+=(debug) 254 | fi 255 | 256 | if [[ "$TEST_MODE" == "true" ]]; then 257 | extra_args+=(test --full-app --driver-package meteortesting:mocha) 258 | 259 | # Add --once flag if TEST_RUN_ONCE is set to true 260 | if [[ "$TEST_RUN_ONCE" == "true" ]]; then 261 | extra_args+=(--once) 262 | fi 263 | fi 264 | 265 | if [[ "$BUNDLE_VISUALIZER" == "true" ]]; then 266 | extra_args+=(--extra-packages bundle-visualizer --production) 267 | fi 268 | 269 | if [[ "$RUN_PRODUCTION_MODE" == "true" ]]; then 270 | extra_args+=(--production) 271 | fi 272 | 273 | if [[ -n "$MAX_OLD_SPACE_SIZE" ]]; then 274 | export NODE_OPTIONS="--max-old-space-size=$MAX_OLD_SPACE_SIZE" 275 | fi 276 | 277 | export METEOR_DISABLE_OPTIMISTIC_CACHING=1 278 | 279 | echo "${extra_args[@]}" 280 | 281 | ROOT_URL="$(appendPortToURL "http://$HOST_DOMAIN" "$EXTERNAL_PORT")" "${meteor_command[@]}" "${extra_args[@]}" -p $PORT 2>&1 | tee "$log_file" 282 | } 283 | 284 | web_app_log="$LOGS_FOLDER/web-app.log" 285 | web_app_meteor_port="${APP_PORT:-"3000"}" 286 | landing_app_meteor_port="${LANDING_APP_PORT:-"4000"}" 287 | 288 | web_app_external_meteor_port="${APP_EXTERNAL_PORT:-"$web_app_meteor_port"}" 289 | landing_app_external_meteor_port="${LANDING_APP_EXTERNAL_PORT:-"$landing_app_meteor_port"}" 290 | 291 | ( 292 | export LOG_FILE="$web_app_log" 293 | export PORT="$web_app_meteor_port" 294 | export EXTERNAL_PORT="$web_app_external_meteor_port" 295 | export APP_PATH="$justdo_web_app_path" 296 | 297 | export APP_VERSION="$(cd $APP_PATH; git describe)" 298 | export EXPOSE_APP_VERSION="true" 299 | 300 | export WEB_APP_ROOT_URL="$(appendPortToURL "http://$WEB_APP_HOSTNAME" "$web_app_external_meteor_port")" 301 | export LANDING_APP_ROOT_URL="$(appendPortToURL "http://$LANDING_APP_HOSTNAME" "$landing_app_external_meteor_port")" 302 | 303 | export HOST_DOMAIN="$WEB_APP_HOSTNAME" 304 | export MAX_OLD_SPACE_SIZE="$WEB_APP_NODE_MAX_OLD_SPACE_SIZE" 305 | 306 | if [[ "$DEBUG_ENVIRONMENT" == "web-app" ]]; then 307 | export DEBUG_MODE="true" 308 | fi 309 | 310 | startMeteor 311 | ) & 312 | 313 | if [[ -z "$MONGO_URL" ]]; then 314 | # If $MONGO_URL is not set, we set it to the local web app's url 315 | # for that, we need to wait for the wap app's mongo to become ready. 316 | announceStep "Waiting for Web App MongoDB to become ready" 317 | while true; do 318 | cat "$web_app_log" 2>/dev/null | platformGrep "Started MongoDB." 319 | 320 | if [[ $? -eq 0 ]]; then 321 | announceStep "Web App MongoDB ready" 322 | 323 | break 324 | fi 325 | 326 | sleep 0.5 327 | done 328 | fi 329 | 330 | announceStep "Web app ready, initiating landing app" 331 | ( 332 | export LOG_FILE="$LOGS_FOLDER/landing-app.log" 333 | export PORT="$landing_app_meteor_port" 334 | export EXTERNAL_PORT="$landing_app_external_meteor_port" 335 | export APP_PATH="$justdo_landing_app_path" 336 | 337 | export APP_VERSION="$(cd $APP_PATH; git describe)" 338 | export EXPOSE_APP_VERSION="true" 339 | 340 | if [[ -z "$MONGO_URL" ]]; then 341 | export MONGO_URL="mongodb://localhost:$(($web_app_meteor_port + 1))/meteor" 342 | fi 343 | 344 | if [[ -z "$OPLOG_URL" ]]; then 345 | export OPLOG_URL="mongodb://localhost:$(($web_app_meteor_port + 1))/local" 346 | fi 347 | 348 | export WEB_APP_ROOT_URL="$(appendPortToURL "http://$WEB_APP_HOSTNAME" "$web_app_external_meteor_port")" 349 | export LANDING_APP_ROOT_URL="$(appendPortToURL "http://$LANDING_APP_HOSTNAME" "$landing_app_external_meteor_port")" 350 | 351 | export HOST_DOMAIN="$LANDING_APP_HOSTNAME" 352 | export MAX_OLD_SPACE_SIZE="$LANDING_APP_NODE_MAX_OLD_SPACE_SIZE" 353 | 354 | if [[ "$DEBUG_ENVIRONMENT" == "landing-app" ]]; then 355 | export DEBUG_MODE="true" 356 | fi 357 | 358 | startMeteor 359 | ) & 360 | 361 | wait 362 | -------------------------------------------------------------------------------- /default-config.bash: -------------------------------------------------------------------------------- 1 | # Auto generated by configure-dev-environment.bash during installation 2 | # Run ./configure-dev-environment.bash to reset 3 | export MAIL_SENDER_EMAIL="" 4 | export MAIL_URL="" 5 | 6 | # JustDo AI 7 | export JUSTDO_AI_ENABLED="false" # Enabled when it is set to "true" 8 | export JUSTDO_AI_CONF='{}' 9 | # Holds the secret configuration that are not exposed to client. E.g. api keys. 10 | # Example: export JUSTDO_AI_SECRET_CONF={'vendors': {'openai': {'api_key':''}}} 11 | export JUSTDO_AI_SECRET_CONF='{}' 12 | 13 | ### Ngrok configuration 14 | 15 | # Setup: 16 | # 17 | # * Install Ngrok 18 | # * Append the following to ~/.ngrok2/ngrok.yml 19 | # 20 | # tunnels: 21 | # web: 22 | # proto: http 23 | # addr: 3000 24 | # landing: 25 | # proto: http 26 | # addr: 4000 27 | # * Call: $ ngrok start --all 28 | # * Set WEB_APP_HOSTNAME & LANDING_APP_HOSTNAME to the domains provided by 29 | # ngrok 30 | # * Start the development environment: $ ./run-dev-environment.bash 31 | # 32 | # export WEB_APP_HOSTNAME="81f20f92.ngrok.io" 33 | # export APP_PORT="${APP_PORT:-"3000"}" 34 | # export APP_EXTERNAL_PORT="80" # If not set, will default to $APP_PORT 35 | # export LANDING_APP_HOSTNAME="8d75a58c.ngrok.io" 36 | # export LANDING_APP_PORT="${LANDING_APP_PORT:-"4000"}" 37 | # export LANDING_APP_EXTERNAL_PORT="80" # If not set, will default to $LANDING_APP_PORT 38 | 39 | ### CDNs 40 | export CDN="" 41 | 42 | # Log level 43 | export LOG_LEVEL="DEBUG" # The following log levels are supported "DEBUG", "INFO", "WARN" (default), "ERROR", "OFF" 44 | 45 | # Landing page type 46 | export LANDING_PAGE_TYPE="login-only" # The following types are supported: "login-only" (default), "marketing" 47 | 48 | # Organizations 49 | export ORGANIZATIONS="false" # The Organizations feature adds another logical layer that contains JustDos. 50 | # When enabled, each JustDo belongs to an organization. 51 | # Set to "true" to enable. 52 | 53 | # Experimentation features 54 | export SUPPORT_ANON_LOGIN="false" # If set to true we allow using, and experimenting, with JustDo without registration. 55 | export JUSTDO_SANDBOX_MODE="0" # 0 means JustDo Sandbox Mode isn't enabled. 56 | # 57 | # Can be set to a positive integer to enable Sandbox Mode only with the ORGANIZATIONS env var set to 58 | # true also. 59 | # 60 | # In Sandbox Mode JustDo is geared for demonstration/experimentation purpose only. 61 | # 62 | # Organizations created are automatically removed after X * 24 hours. Where X is equal to the env var's 63 | # value. 64 | 65 | ### Local configuration 66 | 67 | localhost_domain="localhost" 68 | export WEB_APP_HOSTNAME="$localhost_domain" 69 | export APP_PORT="${APP_PORT:-"3000"}" 70 | export APP_EXTERNAL_PORT="" # If not set, will default to $APP_PORT 71 | export LANDING_APP_HOSTNAME="$localhost_domain" 72 | export LANDING_APP_PORT="${LANDING_APP_PORT:-"4000"}" 73 | export LANDING_APP_EXTERNAL_PORT="" # If not set, will default to $LANDING_APP_PORT 74 | 75 | export APP_PORT="${APP_PORT:-"3000"}" 76 | export LANDING_APP_PORT="${LANDING_APP_PORT:-"4000"}" 77 | 78 | # Landing Page Customizations 79 | export LANDING_PAGE_CUSTOM_SIGN_UP_MESSAGE="" 80 | export LANDING_PAGE_CUSTOM_SIGN_IN_MESSAGE="" 81 | 82 | # Accounts Settings 83 | export ALLOW_ACCOUNTS_TO_CHANGE_EMAIL="true" 84 | 85 | # Accounts Password 86 | export ALLOW_ACCOUNTS_PASSWORD_BASED_LOGIN="true" 87 | 88 | # Google OAuth 89 | export GOOGLE_OAUTH_LOGIN_ENABLED="false" 90 | export GOOGLE_OAUTH_LOGIN_ID="" 91 | export GOOGLE_OAUTH_LOGIN_SECRET="" 92 | 93 | # GA 94 | export GA_TRACKING_ID="" 95 | export GA_GEO_AWARE_COOKIE_BANNER="false" 96 | 97 | # Google Docs 98 | # 99 | # The following adds support to the JustDo Google Docs Plugin. 100 | # 101 | # You'll need to come up with Google Service Account credentials for the 102 | # GOOGLE_DOCS_CREDENTIALS variable below. To do that, follow these steps: 103 | # 104 | # 1. Go to https://console.developers.google.com/apis/credentials 105 | # 2. Create a new service account (click on the ' + Create Credentials' button 106 | # and select 'Service Account'). 107 | # 1. Give your service account a name and an optional description. 108 | # 2. Do not give your service account a role. 109 | # 3. Do not grant users access to this service account. 110 | # 3. Create a key for the service account and set it in this config.bash. 111 | # 1. Click on the account in your credentials dashboard (https://console.developers.google.com/apis/credentials) 112 | # 2. Click on the 'ADD KEY' dropdown and choose: 'Create new key' 113 | # 3. Choose json as the format 114 | # 4. A file will download with a .json extension 115 | # 5. In your shell, cd to the folder to which you downloaded the credentials 116 | # json and call the command: 117 | # 118 | # $ file="$(echo *.json)"; echo "export GOOGLE_DOCS_CREDENTIALS="'"'"$(cat "$file" | base64)"'"' 119 | # 120 | # 6. Replace below the GOOGLE_DOCS_CREDENTIALS line, with the output of that 121 | # command. 122 | # 7. You can remove the .json file downloaded. 123 | # 4. Go to https://console.developers.google.com/apis/library search for the 124 | # "Google Drive API" select it and Enable it. (It might take few minutes for 125 | # this operation to take effect). 126 | export GOOGLE_DOCS_ENABLED="false" # Set to "true" to enable 127 | export GOOGLE_DOCS_CREDENTIALS="" # Read instructions above to learn how to set this env var 128 | export GOOGLE_DOCS_FOLDER_ID="" # Optional, The IDs of the parent. 129 | # folders which contain the file. Read full documentation here: 130 | # https://developers.google.com/drive/api/v3/reference/files/create 131 | 132 | # Azure AD OAuth 133 | export AZURE_AD_OAUTH_LOGIN_ENABLED="false" 134 | export AZURE_AD_OAUTH_TENNANT_ID="" 135 | export AZURE_AD_OAUTH_CLIENT_ID="" 136 | export AZURE_AD_OAUTH_SECRET="" 137 | 138 | # Amazon machine info exposure to client under the pseudo collection JustdoSystem 139 | # {_id: "net-if"} set to true only on environment deployed to AWS. 140 | export QUERY_AND_EXPOSE_AWS_MACHINE_INFO_TO_NET_IF="false" # set to "true" to enable 141 | 142 | # Amazon Web Services Credentials 143 | export AWS_ACCESS_KEY_ID="" 144 | export AWS_SECRET_ACCESS_KEY="" 145 | 146 | # reCAPTCHA 147 | export RECAPTCHA_SUPPORTED="false" # Set to "true" to enable. Set the keys below after enabling 148 | export RECAPTCHA_MAX_ATTEMPTS_WITHOUT="3" # Sets The maximum failed login attempts to a 149 | # specific account before a captcha must be 150 | # solved to login to that account. 151 | export RECAPTCHA_V2_CHECKBOX_SITE_KEY="" 152 | export RECAPTCHA_V2_CHECKBOX_SERVER_KEY="" 153 | export RECAPTCHA_V2_ANDROID_SITE_KEY="" 154 | export RECAPTCHA_V2_ANDROID_SERVER_KEY="" 155 | 156 | # Password strength 157 | 158 | # Passowrds in JustDo *never* go on the wire unhashed, that means, the server 159 | # has no way to know any details about the entered password. 160 | # The following rules are to be enforced by the client side web/mobile 161 | # implementations, but can be circumvented with a direct API call. 162 | 163 | # Note: we *require* our clients to enforce the following rules, if the following 164 | # aren't enforced, it is a bug in JustDo mobile/web app, please report to our 165 | # security team on: admin@justdo.today 166 | # 167 | # * At least 1 upper case char and 1 lower case char. 168 | # * At least 1 special char or number. 169 | # * User's Name, and email, *parts* must mismatch the password john.doe@gmail.com 170 | # can't use john12345 as a password. 171 | 172 | export PASSWORD_STRENGTH_MINIMUM_CHARS="8" # We won't allow setting a number lower than 8, 173 | # and that will be the default, if no value is set. 174 | 175 | # User login token TTL 176 | export USER_LOGIN_RESUME_TOKEN_TTL_MS="" # Milliseconds, If unset/empty/0 will use Meteor's default. For 14 days use: ="$((1000 * 60 * 60 * 24 * 14))" 177 | 178 | # JustDo licensing 179 | export JUSTDO_LICENSING_LICENSE="XE-14A1F-11C-7H-9A-25A-24C-21E-17D-15E-13e1F-10J-9A-28D-22C-20E-18C4E3A3i1A-9C-27C-20B-13D-14D-11g1h1I2D1A4C-20C-14C-12E-13C-10BA-9F-8A-24A-21C-16E6E1C4D2I2D1B1C7E2C1C5F1F1D2G1B6D-23E-15C-11D-11HC-9I-10J-7B-28D-20D1B5C3E2I-8==" # Enter your JustDo license here 180 | 181 | # UI Customizations 182 | export UI_CUSTOMIZATIONS="" # Comma separated list of customizations 183 | # 184 | # The following are supported as of writing, additional 185 | # ones might be added in the future, in which case, we won't 186 | # necessarily update this config comment. check the online 187 | # manuals of JustDo. 188 | # 189 | # no-help - if added we won't show the help icon in the navbar 190 | # no-store - if added we won't show the store button 191 | 192 | # JustDo files (Mongo GridFS based files upload) 193 | export JUSTDO_FILES_ENABLED="true" # Set to "true" to enable 194 | export JUSTDO_FILES_MAX_FILESIZE="104857600" # In bytes (104857600 == 100MB) 195 | 196 | # Filestack 197 | export TASKS_FILES_UPLOAD_ENABLED="false" 198 | export FILESTACK_MAX_FILE_SIZE_BYTES="104857600" 199 | export FILESTACK_KEY="" 200 | export FILESTACK_SECRET="" 201 | export FILESTACK_S3_BUCKET_ID="" 202 | export FILESTACK_S3_BUCKET_REGION="" 203 | 204 | # JustDo User Active Position Plugin 205 | export USER_ACTIVE_POSITION_ENABLED="true" # Set to "true" to enable 206 | 207 | # I18n config 208 | # !!! IMPORTANT 209 | # Note, if you change this list, you'll also need to update: 210 | # 1. justdo-packages/shared-gists/lib/both/project-tap.i18n - Ensure to update both your web-app and landing-app 211 | # [Only if you manage JustDo Build, update also]: 212 | # 2. nodes/justdo-web-bundle/build-env-vars.bash (Relevant for JustDo SDK Builder only, skip if unfamiliar) 213 | # 3. justdo-devops/nodes-launchers/launchers/justdo-sdk/default-config.bash (Relevant for JustDo SDK Builder only, skip if unfamiliar) 214 | # !!! IMPORTANT 215 | export I18N_DEFAULT_LANGUAGE="en" 216 | export I18N_ALL_SUPPORTED_LANGUAGES="en,af,az,id,ms,be,bg,bs,ca,cs,sr,da,de,el,et,es,eu,fr,hr,it,kk,sw,ky,lv,lb,lt,hu,mk,nl,nb,uz,pl,pt-PT,pt-BR,ru,ro,sq,sk,sl,fi,sv,vi,tg,tr,uk,hy,yi,he,ar,am,ne,hi,bn,ta,th,km,ko,ja,zh-CN,zh-TW" 217 | export I18N_CORE_SUPPORTED_LANGUAGES="en,ar,es,fr,ja,ko,pt-BR,vi,ru,it,de,hi,tr,nl,pl,zh-CN,zh-TW,id,th,he,sv,ms" 218 | 219 | # Mailgun / Inbound emails 220 | export INBOUND_EMAILS_ENABLED="false" 221 | export INBOUND_EMAILS_MAX_ATTACHED_FILE_SIZE="1048576" # In bytes 222 | 223 | export MAILGUN_REGISTER_INBOUND_ROUTE="false" # set to "true" to register the inbound route of your environment 224 | # in your Mailgun account on the app init. If set to false, you 225 | # will have to set the inbound url manually to: 226 | # 227 | # https://:/__inbound_email__ 228 | # 229 | # This is the url on which the webapp is waiting for inbound messages from 230 | # Mailgun is. 231 | # 232 | # If you are forwarding requests from another domain to that url (for 233 | # example, if you use ngrok for development, or, if for configuration reasons, you want 234 | # to register your public ip:app-port as the inbound endpoint). 235 | # 236 | # You can ask to register custom domain under MAILGUN_REGISTER_INBOUND_ROUTE_CUSTOM_DOMAIN="" 237 | # below. 238 | 239 | export MAILGUN_REGISTER_INBOUND_ROUTE_CUSTOM_DOMAIN="" 240 | # Read comment for MAILGUN_REGISTER_INBOUND_ROUTE . This is the address Mailgun will callback to. 241 | # Include the protocol with which communication should happen: begin with: "http://" or "https://" . 242 | # Important! has no effect if MAILGUN_REGISTER_INBOUND_ROUTE is not "true" 243 | # Do not include the "/__inbound_email__" in the domain, we will add it 244 | # automatically. 245 | 246 | export MAILGUN_API_KEY="key-" # include "key-" prefix 247 | export MAILGUN_DOMAIN_NAME="" # The mailgun domain, as defined for the API_KEY. 248 | export MAILGUN_BASE_URL="https://api.mailgun.net/v3" # Most likely you won't need to change this option. 249 | # * No trailing / 250 | # * Do not add the mail domain name after the 251 | # version part. 252 | 253 | # MAILGUN_PROXY_TYPE_IN_USE 254 | # 255 | # Use this option, when you are using the JustDo proxies that supplant Mailgun 256 | # with alternatives in case Mailgun can't be used. 257 | # 258 | # Options are as follows: 259 | # 260 | # * If you simply use Mailgun use: "off" 261 | # 262 | # * If you use the maildo-imap-proxy proxy you can use: 263 | # * "imap-display-name" 264 | # * "imap-plus-addressing" 265 | # * "imap-email-body-reference" 266 | # 267 | # The proxies uses APIs compatible to Mailgun's to communicate with the JustDo 268 | # app, so the this option affect only the address *displayed* but has zero 269 | # effect on the logic when parsing the emails. 270 | export MAILGUN_PROXY_TYPE_IN_USE="off" 271 | export MAILGUN_PROXY_IMAP_PROXY_EMAIL_ADDRESS="" # Relevant only if MAILGUN_PROXY_TYPE_IN_USE is set to 272 | # "imap-display-name" or "imap-plus-addressing" 273 | # Set to the imap mailbox email address "E.g. justdo@abc.com" 274 | 275 | # The DEVOPS_PUBLIC_KEY is a public key we use to encrypt sensitive content 276 | # that only the holders of the private key will be able to access. 277 | # 278 | # To generate a key run the following commands: 279 | # 280 | # $ openssl genrsa -out mykey.pem 1024 # This is your private key, keep it safe! 281 | # $ openssl rsa -in mykey.pem -pubout > mykey.pub # This will generate a public key file. 282 | # 283 | # Open mykey.pub, paste its content between the two '' below, replace new 284 | # lines with \n: 285 | # 286 | # Should look like: 287 | # 288 | # export DEVOPS_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDxCb1lw86bmSRqN/AoPFMEQKfb\nj38o977yp69taOtS9pxubksV6dBZshgkJIsgrDqo/2lV/1Kc7rzj3kFU2Mp+PFtG\n4mSqhBc0eKXtNfKzE1qyvXAA7YKB+DAkBTMGyNvDDnq5H+yPcRleY65RoHJE9By+\nGzmhuIFKQEW8CfWLuwIDAQAB\n-----END PUBLIC KEY-----' 289 | export DEVOPS_PUBLIC_KEY='-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCXX/GMbt+j4Dr/T9hpLSY6gQuX\noNxE6b4BondJWw2X2lB367uztlmiZWtzCvhFbDceM/Nu0SbtYJ95j8eS6pBNi7U9\nLIvJizH17hhWfQrMGm+lkib55C8qfoNSdhlZlOhwrvqR4lynftyycQTKfiAv6ILK\n0pzsSYCYfjfCq4SOUQIDAQAB\n-----END PUBLIC KEY-----' 290 | 291 | # JustDo Analytics (not to be confused with Google Analytics) 292 | export JUSTDO_ANALYTICS_ENABLED="false" 293 | # JUSTDO_ANALYTICS_STORAGE is the endpoint to which we store analytics logs. 294 | # 295 | # Options are: 296 | # "console": logs will be printed to the console 297 | # "mysql": logs will be recorded to a MySQL DB. 298 | # 299 | # You are allowed to use commas to combine more than one storage options, example: "console,mysql" 300 | # 301 | # If empty/unspecified, we default to: "console" 302 | export JUSTDO_ANALYTICS_STORAGE="console" 303 | export JUSTDO_ANALYTICS_LOG_INCOMING_DDP="false" # Set to "true" to enable, if you enable, you MUST set 304 | # DEVOPS_PUBLIC_KEY above, as we don't allow the DDP 305 | # trace to be stored non-encrypted! 306 | export JUSTDO_ANALYTICS_LOG_MONGO_QUERIES="false" # Set to "true" to enable, if you enable, you MUST set 307 | # DEVOPS_PUBLIC_KEY above, as we don't allow the Mongo 308 | # queries to be stored non-encrypted! 309 | export JUSTDO_ANALYTICS_ADD_AWS_METADATA_TO_SERVER_ENV="false" # Set to "true" if you are running under 310 | # Amazon Web Services, and you want the 311 | # Justdo Server Session environment object 312 | # created for your server on load to include 313 | # information about your AWS instance. 314 | export JUSTDO_ANALYTICS_LOG_SERVER_STATUS="false" # Set to "true" to enable, if enabled, will save server 315 | # stats on set intervals - data is saved non-encrypted. 316 | export JUSTDO_ANALYTICS_LOG_SERVER_STATUS_INTERVAL_MS="15000" # The server status log time interval in miliseconds. 317 | # Relevant only if JUSTDO_ANALYTICS_LOG_SERVER_STATUS is 318 | # set to "true". 319 | export JUSTDO_ANALYTICS_SKIP_ENCRYPTION="false" # This environment variable can be set to true only on 320 | # the dev environment, we don't pass it to the Docker 321 | # even if it is set in the server config file to be true. 322 | # JustDo Analytics MySQL Storage Configuration (Relevant only if you list mysql 323 | # as a storage under: justdo_analytics_storage, and if justdo_analytics_enabled 324 | # is set to true) 325 | export JUSTDO_ANALYTICS_MYSQL_STORAGE_HOST="127.0.0.1" 326 | export JUSTDO_ANALYTICS_MYSQL_STORAGE_PORT="3306" 327 | export JUSTDO_ANALYTICS_MYSQL_STORAGE_USER="" 328 | export JUSTDO_ANALYTICS_MYSQL_STORAGE_PASSWORD="" 329 | export JUSTDO_ANALYTICS_MYSQL_STORAGE_DATABASE_NAME="JDAnalytics" 330 | 331 | # JustDo Usage Statistics 332 | export JUSTDO_USAGE_STATISTICS="basic" # Set to "none" to disable the ability to fetch usage statistics 333 | # Set to "all" to allow fetching of all the usage statistics categories 334 | # To allow specific usage statistics categories, set to a comma separated 335 | # list of categories 336 | 337 | # JustDo labs features enabled 338 | export JUSTDO_LABS_FEATURES_ENABLED="false" 339 | 340 | # JustDo Jobs Processor Conf 341 | export JUSTDO_JOBS_PROCESSOR_GROUP_ID="main::001" 342 | export JUSTDO_JOBS_PROCESSOR_CONF="justdo-chat-email-notifications;justdo-chat-firebase-mobile-notifications;justdo-google-docs-auto-save" 343 | 344 | # Site Admins 345 | # 346 | # Site admins have special privileges. They are useful for on-premise and 347 | # private cloud setups, to manage, among other things, the environment users, 348 | # gather statistics, and other powerful functionalities. 349 | # 350 | # Full details about the Site Admins feature can be found in the online manuals 351 | # of JustDo. 352 | # 353 | export SITE_ADMINS_EMAILS="" 354 | # SITE_ADMINS_EMAILS 355 | # 356 | # A comma separated list of emails whose users will be automatically set as 357 | # Site Admins on (every) server init. Site admins can nominate any list of 358 | # users to also be site admins from the Site Admin panel. 359 | # 360 | # The users whose emails are listed here are considered "Hard Coded" and, 361 | # unlike other users, can't lose their Site Admin designation by other Site 362 | # Admins. To revoke the Site Admin designation from users in that list you'll 363 | # have to: 364 | # 365 | # 1. Remove them from the SITE_ADMINS_EMAILS . 366 | # 2. Reinstall the JustDo Web App ( $ justdo install web-app ) 367 | # 3. Using one of the remaining Site Admins (can be non-hardcoded Site Admins), 368 | # remove the Site Admin designation from those users. 369 | # 370 | # The users with the set Site Admins emails must complete the email 371 | # verification process before the reinstall (if they register and complete 372 | # verification after install server restart is enough). 373 | # 374 | # We will log an error upon init for users that are either aren't registered 375 | # yet, or not verified. 376 | 377 | export SITE_ADMINS_CONF="" 378 | # SITE_ADMINS_CONF 379 | # 380 | # A comma separated list of configurations. 381 | # 382 | # Possible confs: 383 | # * admins-list-public - If included other non Site Admins can see the list of 384 | # Site Admins (useful for contact purpose). 385 | # 386 | # * admin-in-all - Upon init all the Site Admins (Hard coded, and non hard coded) 387 | # will be added as admins to all the existing JustDos + to any 388 | # JustDo that will be cretated while they are Site Admins. 389 | # Upon Site Admin designation removal, the user that was Site 390 | # Admin *Won't* be removed from the JustDos to which he was 391 | # added automatically while being a Site Admin. 392 | # 393 | # * proxy-users - Defines whether the UI of JustDo exposes the proxy-users feature (the 394 | # feature is always enabled, this only affects the UI). 395 | # 396 | # * IMPORTANT: There might be other possible confs, check the online manuals of JustDo. 397 | 398 | # Zendesk Integration 399 | export ZENDESK_ENABLED="false" 400 | export ZENDESK_HOST="" 401 | 402 | # Froala WYSIWYG Editor 403 | export FROALA_ACTIVATION_KEY="" 404 | 405 | # Bugmuncher Integration 406 | export BUGMUNCHER_API_KEY="" 407 | 408 | # Firebase 409 | export FIREBASE_ENABLED="false" # Set to true and set a server key to enable 410 | # To set up the FIREBASE_SERVER_KEY: 411 | 412 | # 1. Open Firebase Console in web browser, choose the corresponding Firebase project 413 | # 2. Go to Project Settings (cog icon in the top-left section), then select Service Accounts. 414 | # 3. Follow instructions on page to Create a Service Account if there isn't one yet. 415 | # 4. click on Generate New Key - this will download a JSON file with the key. 416 | # 5. Open the JSON file with your favourite text editor, and replace ALL double quotes with single quotes. 417 | # 6. Copy the content of the file and paste it in the FIREBASE_SERVER_KEY variable below. 418 | 419 | # Note, everytime you click on Generate New Private Key, a new key is generated the old ones are still valid 420 | # there mighy be multiple private keys for the same service account. 421 | 422 | # To manage the service account keys, go to the Google Cloud Console, IAM & Admin, Service Accounts (on the left menu). 423 | 424 | # You'll see a table with Service accounts for the project. 425 | 426 | # Select the service account with similar name to the name you see on Firebase 427 | # For example if on Firebase for the app you see: 428 | # https://console.firebase.google.com/u/1/project/justdo-today-xxxx/settings/serviceaccounts/adminsdk 429 | 430 | # Select the one in which you see the string "justdo-today-xxxx" in the name. 431 | 432 | # Then, under Keys tab, you'll see the keys that were generated for this service account - and you can delete them to revoke access. 433 | export FIREBASE_SERVER_KEY="" 434 | 435 | # Development Mode 436 | export DEVELOPMENT_MODE="false" # Set to "true" to enable 437 | 438 | # JustDo SEO 439 | export JUSTDO_SEO_ENABLED="false" # Set to "true" to enable 440 | export JUSTDO_SEO_RENDERER_ENDPOINT="" # We will append the full url that we want the renderer to render to that endpoint. 441 | # E.g if JUSTDO_SEO_RENDERER_ENDPOINT="https://crawler.com" 442 | # In case we want to render /news/xyz?a=b&c=3 we will call: 443 | # https://crawler.com/{{ROOT_URL}}/news/xyz?a=b&c=3 444 | export JUSTDO_SEO_RENDERER_CUSTOM_HTTP_HEADERS="" # Use a & separated list of url_encoded_key=url_encoded_value 445 | export ALLOW_SEARCH_ENGINES_INDEXING="false" # Set to "true" to enable 446 | 447 | # Justdo Anon Login 448 | export ALLOW_NON_REGISTER="false" # Anything other than "true" (case sensitive) will be regarded as "false" 449 | 450 | # Rollbar 451 | export ROLLBAR_ENABLED="false" 452 | # Important! on the development environment, the landing app and the webapp are 453 | # sharing the same access tokens. 454 | export ROLLBAR_CLIENT_ACCESS_TOKEN="" # Rollbar's POST_CLIENT_ITEM_ACCESS_TOKEN 455 | export ROLLBAR_SERVER_ACCESS_TOKEN="" # Rollbar's POST_SERVER_ITEM_ACCESS_TOKEN 456 | 457 | # Kadira 458 | export KADIRA_ENABLED="false" 459 | export KADIRA_APP_ID="" 460 | export KADIRA_APP_SECRET="" 461 | export KADIRA_END_POINT_URL="" 462 | 463 | # Facebook Pixel 464 | export FB_PIXEL_ENABLED="false" 465 | export FB_PIXEL_ID="" 466 | 467 | # Updates Popup 468 | export ALLOW_UPDATES_MODAL="true" 469 | 470 | # If set to true run-dev-environment.bash will run meteor with the 471 | # following flags: --extra-packages bundle-visualizer --production 472 | export BUNDLE_VISUALIZER="false" 473 | 474 | # If set to true run-dev-environment.bash will run meteor with the 475 | # following flag: --production 476 | export RUN_PRODUCTION_MODE="false" 477 | 478 | # Set to "landing-app"/"web-app" if you want us to run the meteor command for 479 | # the landing app/web-app with the debug command. At the moment, only one 480 | # environment can run with the debug command. Leave unset/empty/with any other 481 | # value will have no effect. 482 | export DEBUG_ENVIRONMENT="" 483 | 484 | ############################################################################# 485 | # 486 | # The rest of the configurations below only affect the behavior of the helper 487 | # "test-generated-sdk-and-bundle" of the development-helpers.bash 488 | # 489 | ############################################################################# 490 | 491 | export LANDING_APP_DOMAIN="" 492 | export WEB_APP_DOMAIN="" 493 | 494 | # The redirector settings are relevant only for the development-helpers.bash 495 | # "test-generated-redirector-launcher-and-redirector-bundle" 496 | # The specified domains will redirect to the corresponding domains defined 497 | # above 498 | export LANDING_APP_REDIRECTOR_DOMAIN="" 499 | export WEB_APP_REDIRECTOR_DOMAIN="" 500 | 501 | # export WEB_APP_PLUGINS_MODE="${WEB_APP_PLUGINS_MODE:-"off"}" 502 | export WEB_APP_PLUGINS_MODE="${WEB_APP_PLUGINS_MODE:-"on"}" 503 | 504 | # Node settings 505 | export LANDING_APP_NODE_MAX_OLD_SPACE_SIZE="" 506 | export WEB_APP_NODE_MAX_OLD_SPACE_SIZE="" 507 | 508 | # JustDo Performance 509 | 510 | # SUPPORT_JUSTDO_LOAD_PAGINATION Can be used to reduce the initial load 511 | # speed for JustDos with lots of tasks (> 50k) by increasing throughput. 512 | # The content is broken to multiple pages that are loaded simultaneously (with 513 | # a certain limit for max size per page + how many are loaded at the same time 514 | # set in a static vars for now). 515 | # By breaking the content to multiple pages, we also increase the chance that 516 | # the browser's cache will be reused, and the pages won't be requested again upon reload 517 | # until the cache expiration/clear. 518 | # IMPORTANT Since it dramatically increases CPU load, it should be set to true 519 | # only in environments in which you can separate the flow to 520 | # /ddp/pre-ready-payload/ to a different process. YOU ARE RISKING DENIAL OF 521 | # SERVICE OTHERWISE! 522 | export SUPPORT_JUSTDO_LOAD_PAGINATION="false" # Anything other than "true" (case sensitive) will be regarded as "false" 523 | 524 | # Jira 525 | # 526 | # REFER TO THE SDK default-config.bash for all the JIRA settings documentation 527 | export JIRA_INTEGRATION_TYPE="false" 528 | export JIRA_INTEGRATION_SERVER_HOST="" 529 | export JIRA_INTEGRATION_OAUTH_CLIENT_ID="" 530 | export JIRA_INTEGRATION_OAUTH_CLIENT_SECRET="" 531 | export JIRA_INTEGRATION_OAUTH_SECRET="" 532 | export JIRA_ROOT_URL_CUSTOM_DOMAIN="" 533 | # Applicable for all installation types, if empty defaults to '{}', otherwise 534 | # should be a single-quote JSONified JS object with the settings you want to edit. 535 | # IMPORTANT!!! You must only use single quotes in the JSON (instead of the valid double-quote) 536 | export JIRA_INTEGRATION_SETTINGS="" 537 | 538 | # Comma separated list of plugins you want to have available under the plugins 539 | # folder of the tested bundle. 540 | # 541 | # The plugins packages are copied from nodes/justdo-web-app/justdo-web- 542 | # app/modules/justdo-packages from its current git HEAD and state. 543 | # 544 | # The plugins names should be the packages folders names under this folder. 545 | # export PLUGINS_TO_TEST="tasks-file-manager-plugin,tasks-file-manager,justdo-toolbar-plugin" 546 | # export PLUGINS_TO_TEST="justdo-core-user-conf,meteor-accounts-ui-bootstrap-3,justdo-user-config-ui" 547 | # export PLUGINS_TO_TEST="justdo-members-managment-dialog" 548 | export PLUGINS_TO_TEST="" 549 | 550 | if [[ "$OSTYPE" == "darwin"* ]]; then 551 | # Mac OSX 552 | export VAR_PATH="/private/var/justdo" # For OSX use /private/var/justdo 553 | else 554 | # Linux 555 | export VAR_PATH="/var/justdo" 556 | fi --------------------------------------------------------------------------------