diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index b2eb009..22dbdee 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -1,44 +1,17 @@ name: Build and Push Docker Images on: - push: - branches: - - main + release: + types: [published] workflow_dispatch: env: REGISTRY: ghcr.io jobs: - detect-changes: - name: Detect Changed Folders - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' && github.repository == 'braydenidzenga/ZettaNote' - outputs: - backend: ${{ steps.filter.outputs.backend }} - frontend: ${{ steps.filter.outputs.frontend }} - nginx: ${{ steps.filter.outputs.nginx }} - # admin-portal: ${{ steps.filter.outputs.admin-portal }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Check changed paths - uses: dorny/paths-filter@v3 - id: filter - with: - filters: | - backend: - - 'backend/**' - frontend: - - 'frontend/**' - nginx: - - 'nginx/**' - build-and-push-backend: runs-on: ubuntu-latest - # needs: detect-changes - if: github.ref == 'refs/heads/main' && github.repository == 'braydenidzenga/ZettaNote' + if: github.repository == 'braydenidzenga/ZettaNote' permissions: contents: read packages: write @@ -65,9 +38,10 @@ jobs: with: images: ${{ env.REGISTRY }}/${{ steps.repo-owner.outputs.owner_lc }}/zettanote-backend tags: | - type=ref,event=branch - type=sha,prefix={{branch}}- - type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/v2-CI' }} + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=raw,value=latest - name: Build and push backend image uses: docker/build-push-action@v5 @@ -80,8 +54,7 @@ jobs: build-and-push-frontend: runs-on: ubuntu-latest - # needs: detect-changes - if: github.ref == 'refs/heads/main' && github.repository == 'braydenidzenga/ZettaNote' + if: github.repository == 'braydenidzenga/ZettaNote' permissions: contents: read packages: write @@ -108,9 +81,10 @@ jobs: with: images: ${{ env.REGISTRY }}/${{ steps.repo-owner.outputs.owner_lc }}/zettanote-frontend tags: | - type=ref,event=branch - type=sha,prefix={{branch}}- - type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/v2-CI' }} + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=raw,value=latest - name: Build and push frontend image uses: docker/build-push-action@v5 @@ -125,8 +99,7 @@ jobs: build-and-push-nginx: runs-on: ubuntu-latest - # needs: detect-changes - if: github.ref == 'refs/heads/main' && github.repository == 'braydenidzenga/ZettaNote' + if: github.repository == 'braydenidzenga/ZettaNote' permissions: contents: read packages: write @@ -153,9 +126,10 @@ jobs: with: images: ${{ env.REGISTRY }}/${{ steps.repo-owner.outputs.owner_lc }}/zettanote-nginx tags: | - type=ref,event=branch - type=sha,prefix={{branch}}- - type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/v2-CI' }} + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=raw,value=latest - name: Build and push nginx image uses: docker/build-push-action@v5 @@ -232,25 +206,33 @@ jobs: deploy: runs-on: ubuntu-latest needs: - - detect-changes - build-and-push-backend - build-and-push-frontend - build-and-push-nginx steps: + - name: Get release version + id: version + run: | + if [ "${{ github.event_name }}" == "release" ]; then + echo "version=${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT + else + echo "version=latest" >> $GITHUB_OUTPUT + fi + - name: Deploy to server via SSH uses: appleboy/ssh-action@v1.0.3 with: host: ${{ secrets.SERVER_HOST }} - username: ${{ secrets.SERVER_USER || 'root' }} + username: ${{ secrets.SERVER_USER }} key: ${{ secrets.SERVER_SSH_KEY }} - port: ${{ secrets.SERVER_PORT || '22' }} + port: ${{ secrets.SERVER_PORT }} timeout: 30s command_timeout: 10m script: | - echo "🚀 Starting deployment..." + echo "🚀 Starting deployment for version ${{ steps.version.outputs.version }}..." # Navigate to deployment directory - cd ${{ secrets.DEPLOY_PATH || '~/prod' }} + cd ${{ secrets.DEPLOY_PATH }} echo "📥 Pulling latest Docker images..." docker compose pull @@ -267,3 +249,6 @@ jobs: echo "" echo "📊 Container Status:" docker compose ps + + echo "" + echo "🏷️ Deployed version: ${{ steps.version.outputs.version }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e69d3a4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,319 @@ +name: Release Management + +on: + push: + branches: + - main + paths: + - "package.json" + - "backend/package.json" + - "frontend/package.json" + workflow_dispatch: + inputs: + bump_type: + description: "Version bump type" + required: true + default: "patch" + type: choice + options: + - patch + - minor + - major + +permissions: + contents: write + packages: write + +jobs: + check-version-change: + name: Check Version Change + runs-on: ubuntu-latest + if: github.repository == 'braydenidzenga/ZettaNote' + outputs: + version_changed: ${{ steps.check.outputs.changed }} + new_version: ${{ steps.check.outputs.version }} + should_bump: ${{ steps.check.outputs.should_bump }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Check if version changed + id: check + run: | + # Get current version from package.json + CURRENT_VERSION=$(jq -r '.version' package.json) + echo "Current version: $CURRENT_VERSION" + + # Check if this is a manual dispatch (bump request) + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + echo "Manual bump requested: ${{ inputs.bump_type }}" + echo "should_bump=true" >> $GITHUB_OUTPUT + echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + echo "changed=false" >> $GITHUB_OUTPUT + exit 0 + fi + + # Check if package.json was actually modified in the last commit + CHANGED_FILES=$(git diff --name-only HEAD^ HEAD) + if ! echo "$CHANGED_FILES" | grep -q "package.json"; then + echo "package.json not changed in this commit" + echo "changed=false" >> $GITHUB_OUTPUT + echo "should_bump=false" >> $GITHUB_OUTPUT + exit 0 + fi + + # Get previous version + git checkout HEAD^ + PREVIOUS_VERSION=$(jq -r '.version' package.json) + git checkout - + + echo "Previous version: $PREVIOUS_VERSION" + + if [ "$CURRENT_VERSION" != "$PREVIOUS_VERSION" ]; then + echo "Version changed from $PREVIOUS_VERSION to $CURRENT_VERSION" + echo "changed=true" >> $GITHUB_OUTPUT + echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + echo "should_bump=false" >> $GITHUB_OUTPUT + else + echo "Version not changed, will auto-bump patch version" + echo "changed=false" >> $GITHUB_OUTPUT + echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + echo "should_bump=true" >> $GITHUB_OUTPUT + fi + + bump-version: + name: Auto Bump Version + runs-on: ubuntu-latest + needs: check-version-change + if: needs.check-version-change.outputs.should_bump == 'true' + outputs: + new_version: ${{ steps.bump.outputs.version }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Configure Git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Bump version + id: bump + run: | + CURRENT_VERSION=$(jq -r '.version' package.json) + BUMP_TYPE="${{ inputs.bump_type || 'patch' }}" + + echo "Current version: $CURRENT_VERSION" + echo "Bump type: $BUMP_TYPE" + + # Parse version + IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION" + + # Bump based on type + case $BUMP_TYPE in + major) + MAJOR=$((MAJOR + 1)) + MINOR=0 + PATCH=0 + ;; + minor) + MINOR=$((MINOR + 1)) + PATCH=0 + ;; + patch) + PATCH=$((PATCH + 1)) + ;; + esac + + NEW_VERSION="$MAJOR.$MINOR.$PATCH" + echo "New version: $NEW_VERSION" + + # Update package.json files + jq --arg ver "$NEW_VERSION" '.version = $ver' package.json > package.json.tmp + mv package.json.tmp package.json + + jq --arg ver "$NEW_VERSION" '.version = $ver' backend/package.json > backend/package.json.tmp + mv backend/package.json.tmp backend/package.json + + jq --arg ver "$NEW_VERSION" '.version = $ver' frontend/package.json > frontend/package.json.tmp + mv frontend/package.json.tmp frontend/package.json + + echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT + + create-release: + name: Create GitHub Release + runs-on: ubuntu-latest + needs: [check-version-change, bump-version] + if: | + always() && + (needs.check-version-change.outputs.version_changed == 'true' || + needs.bump-version.result == 'success') + outputs: + release_created: ${{ steps.create_release.outcome == 'success' }} + version: ${{ steps.version.outputs.tag }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Configure Git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Determine version + id: version + run: | + if [ "${{ needs.bump-version.result }}" == "success" ]; then + VERSION="${{ needs.bump-version.outputs.new_version }}" + else + VERSION="${{ needs.check-version-change.outputs.new_version }}" + fi + echo "tag=v$VERSION" >> $GITHUB_OUTPUT + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Check if release exists + id: check_release + run: | + if gh release view ${{ steps.version.outputs.tag }} >/dev/null 2>&1; then + echo "exists=true" >> $GITHUB_OUTPUT + echo "Release ${{ steps.version.outputs.tag }} already exists" + else + echo "exists=false" >> $GITHUB_OUTPUT + echo "Release ${{ steps.version.outputs.tag }} does not exist" + fi + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Update version files if bumped + if: needs.bump-version.result == 'success' + run: | + VERSION="${{ needs.bump-version.outputs.new_version }}" + + # Update package.json files + jq --arg ver "$VERSION" '.version = $ver' package.json > package.json.tmp + mv package.json.tmp package.json + + jq --arg ver "$VERSION" '.version = $ver' backend/package.json > backend/package.json.tmp + mv backend/package.json.tmp backend/package.json + + jq --arg ver "$VERSION" '.version = $ver' frontend/package.json > frontend/package.json.tmp + mv frontend/package.json.tmp frontend/package.json + + - name: Update CHANGELOG + if: steps.check_release.outputs.exists == 'false' + run: | + VERSION="${{ steps.version.outputs.version }}" + DATE=$(date +%Y-%m-%d) + + # Get the latest tag + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") + + # Create new changelog entry + { + echo "# Changelog" + echo "" + echo "All notable changes to this project will be documented in this file." + echo "" + echo "The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)," + echo "and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)." + echo "" + echo "## [$VERSION] - $DATE" + echo "" + + if [ -z "$LATEST_TAG" ]; then + echo "### Added" + echo "" + echo "- Initial release" + else + # Parse commits and categorize them + echo "### Changes" + echo "" + git log $LATEST_TAG..HEAD --pretty=format:"- %s" --no-merges | while read -r line; do + echo "$line" + done + fi + + echo "" + + # Append existing changelog content (skip old header) + if [ -f CHANGELOG.md ]; then + sed -n '/^## \[/,$p' CHANGELOG.md + fi + } > CHANGELOG.md.new + + mv CHANGELOG.md.new CHANGELOG.md + + - name: Commit version and changelog updates + if: steps.check_release.outputs.exists == 'false' + run: | + VERSION="${{ steps.version.outputs.version }}" + + git add package.json backend/package.json frontend/package.json CHANGELOG.md + + # Check if there are changes to commit + if git diff --staged --quiet; then + echo "No changes to commit" + else + git commit -m "chore: release v$VERSION" + git push + fi + + - name: Generate release notes + id: notes + if: steps.check_release.outputs.exists == 'false' + run: | + VERSION="${{ steps.version.outputs.version }}" + + # Get the latest tag + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") + + # Generate release notes + { + echo "## Release v$VERSION" + echo "" + + if [ -z "$LATEST_TAG" ]; then + echo "### 🎉 First Release" + echo "" + echo "This is the first release of ZettaNote." + echo "" + echo "### Recent Changes" + git log --pretty=format:"- %s (%h)" --no-merges | head -20 + else + echo "### What's Changed" + echo "" + git log $LATEST_TAG..HEAD --pretty=format:"- %s (%h)" --no-merges + echo "" + echo "" + echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/$LATEST_TAG...${{ steps.version.outputs.tag }}" + fi + } > release_notes.md + + echo "Release notes generated" + + - name: Create Release + id: create_release + if: steps.check_release.outputs.exists == 'false' + run: | + VERSION="${{ steps.version.outputs.tag }}" + + gh release create "$VERSION" \ + --title "Release $VERSION" \ + --notes-file release_notes.md \ + --latest + + echo "Release $VERSION created successfully" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9259f6d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,231 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [4.4.0] - 2025-11-02 + +### Added + +- **BullMQ Integration**: Migrated from Motia to BullMQ for background job processing + - Implemented comprehensive queue management system + - Added scheduled task reminders with email notifications + - Implemented image cleanup jobs (orphaned and marked images) + - Added page save processing with async operations + - Created 25+ integration tests for BullMQ functionality +- **Redis Integration**: Added Redis support for BullMQ queues with optional fallback + - Graceful degradation when Redis is unavailable + - Redis port mapping in Docker Compose + - Redis URL configuration for local development + +### Changed + +- **CI/CD Pipeline**: Cleaned up GitHub Actions workflow + - Removed Motia building from docker-build.yml + - Streamlined deployment process for active services only +- **Background Jobs**: Made BullMQ optional with conditional initialization + - Jobs only run when Redis is properly configured + - Clear logging for job scheduling status + +### Fixed + +- Redis connectivity issues in Docker setup +- BullMQ initialization errors when Redis unavailable +- Docker Compose Redis service configuration + +## [4.3.0] - 2024-12-XX + +### Added + +- **Markdown Parser**: Implemented markdown-it parser for rich text rendering + - Syntax highlighting support + - Task lists and definition lists + - Code block parsing with proper formatting +- **Search Optimization**: Added caching for frontend and backend search queries + - Page indexing for faster search results + - Redis caching for query optimization +- **Profile Management**: Added profile update routes and functionality +- **Task Management System**: Complete task management with email reminders + - Task creation, editing, and deletion + - Email notifications via Resend + - Task scheduling and reminders +- **Image Management**: Paste and upload functionality with Cloudinary integration + - Direct image paste in editor + - Cloudinary storage and optimization + - Image cleanup jobs + +### Changed + +- **Dashboard UI**: Major upgrade to dashboard interface + - Improved navigation and layout + - Better responsive design + - Enhanced user experience +- **Toolbar**: Added floating toolbar with custom table insertion modal +- **Rate Limiting**: Added rate limiters for signup and login endpoints + +### Fixed + +- Date selection experience in add reminder modal +- Note editor container growing indefinitely +- Public link sharing functionality +- Share page editing by shared users +- Page save without data validation + +## [4.2.0] - 2024-11-XX + +### Added + +- **Redis Caching**: Cache pages in Redis for improved performance +- **Download Control**: Allow/disallow download toggle for shared pages +- **Mobile Menu**: New mobile menu design for better UX on small devices +- **Syntax Highlighting**: Reordered code block parsing with improved highlighting + +### Changed + +- **Navbar**: Enhanced navbar with drawer for small devices +- **Home Page**: UI/UX enhancements for homepage features section + - Added animations on hover + - Improved layout and responsiveness + +### Fixed + +- Download button visibility after disabling downloads +- Offcenter bullet points in Markdown lists +- Note popup opening in side section +- Core features card height consistency + +## [4.1.0] - 2024-10-XX + +### Added + +- **ESLint Configuration**: Added ESLint rules for backend and frontend + - No debug statements in production code + - Consistent code formatting + - Import organization rules +- **Hybrid Authentication**: Google and GitHub OAuth login + - GitHub authentication integration + - Google authentication integration + - OAuth callback handling +- **Private Sharing**: Share pages with specific users + +### Changed + +- **Input Components**: Refactored login and signup with reusable Input component +- **Documentation**: Updated docs to include latest changes and endpoints +- **Toast Notifications**: Enhanced toast styling and positioning + +### Fixed + +- Missing example environment files +- Toast notification issues +- User undefined error when signed up +- Navbar UI/UX improvements + +## [4.0.0] - 2024-09-XX + +### Added + +- **Backend Refactoring**: Complete backend restructure + - Organized routes, controllers, and middleware + - Added API versioning system + - Improved error handling + - Better code organization +- **Admin Portal**: New admin management portal + - Admin dashboard + - User management + - System monitoring +- **Mailer Utilities**: Resend mailer client integration + - Email sending functionality + - Template support +- **Testing Framework**: Jest and Supertest setup + - Basic backend tests + - Test utilities and setup +- **Docker Support**: Complete Docker setup + - Multi-service Docker Compose + - Production-optimized Dockerfiles + - Nginx reverse proxy configuration +- **CI/CD**: GitHub Actions workflows + - Auto deployment on push + - Code quality checks + - Building checks for frontend and backend + - PR auto-labeling + +### Changed + +- **Authentication**: Use HTTP Cookies for JWT Authentication +- **HTTP Client**: Replaced Fetch with Axios +- **File Structure**: Improved project organization + - Separated concerns + - Better module structure + - Cleaner imports + +### Fixed + +- Logout functionality +- Validation bugs during registration +- Redirect and multiple toasts after creating new page + +## [3.9.0] - 2024-08-XX + +### Added + +- **Page Management**: Rename pages functionality +- **Public Sharing**: Public share links for pages + - Copy button for share links + - Public view without authentication +- **Delete Functionality**: Delete pages and users + - Delete page button + - Delete user route +- **Auto-save**: Save on change with debouncing +- **Rich Text Editor**: Markdown rich text editor implementation + +### Changed + +- **Theme**: Added theme switch button +- **Favicon**: Added custom favicon +- **Landing Page**: Enhanced with modern UI and animations + - Hero section improvements + - Feature showcase + - Responsive design + +### Fixed + +- Password validation on signup +- Email indexing and bcrypt optimization +- Page save without data +- Redirect issues + +## Earlier Versions + +### [3.0.0] - 2024-07-XX + +- Initial public release +- Basic authentication (signup/login) +- Page creation and editing +- JWT token management +- MongoDB integration +- React frontend setup +- Express backend setup + +--- + +## Legend + +- **Added**: New features +- **Changed**: Changes to existing functionality +- **Deprecated**: Soon-to-be removed features +- **Removed**: Removed features +- **Fixed**: Bug fixes +- **Security**: Security improvements + +## Links + +- [GitHub Repository](https://github.com/braydenidzenga/ZettaNote) +- [Issue Tracker](https://github.com/braydenidzenga/ZettaNote/issues) +- [Documentation](./docs/) + +## Contributors + +Thanks to all our contributors! See the [Contributors List](https://github.com/braydenidzenga/ZettaNote/graphs/contributors) for everyone who has helped make ZettaNote better.