Kai
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.

      Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

      Explore these features while you wait
      Complete general settings
      Bookmark and like published notes
      Write a few more notes
      Complete general settings
      Write a few more notes
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note No publishing access yet

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.

    Your account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Your team account was recently created. Publishing will be available soon, allowing you to share notes on your public page and in search results.

    Explore these features while you wait
    Complete general settings
    Bookmark and like published notes
    Write a few more notes
    Complete general settings
    Write a few more notes
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    After the context is provided in the Kiro chatroom, the system generates three files in sequence: requirements, design, and tasks. Each file is reviewed to ensure the content aligns with expectations. If any issues are found, the file is updated directly, then update the file to trigger regeneration of the related files. Once all files are finalized, work begins from the task file. It presents a list of tasks with action buttons, which are executed sequentially to validate the correctness of the AI-generated code. ### 1. Requirements ![截圖 2026-01-21 上午10.42.34](https://hackmd.io/_uploads/H1NFp3pHWl.png) ```markdown! # Feature Requirements: Add Feeder School Logs to Daily Digest ## Overview Add feeder school reference logs to the daily digest email to maintain consistency with the latest activity feed. This feature was requested after OA-22554 added feeder school logs to the latest activity, but they were not included in the daily digest. ## Background - **Related Ticket**: OA-22554 (Add feeder school logs into latest activity) - **Current State**: Feeder school logs appear in the latest activity feed but not in the daily digest - **Desired State**: Feeder school logs should appear in both latest activity and daily digest for consistency ## User Stories ### 1. As a school administrator **I want** to see feeder school reference activities in my daily digest email **So that** I can stay informed about feeder school reference submissions without checking the dashboard ### 2. As a school administrator **I want** the daily digest to show the same types of activities as the latest activity feed **So that** I have a consistent experience across different notification channels ## Acceptance Criteria ### 1.1 Feeder School Activities in Daily Digest - **Given** a school has feeder schools enabled - **And** feeder school reference activities occurred within the digest time period - **When** the daily digest email is generated - **Then** feeder school reference activities should be included in the "Other Activities" section - **And** the activities should display with the same format as in the latest activity feed ### 1.2 Feeder School Feature Flag Respect - **Given** a school does NOT have feeder schools enabled - **When** the daily digest email is generated - **Then** feeder school reference activities should NOT be included in the digest ### 1.3 Activity Types Included - **Given** feeder school activities exist - **When** collecting activities for the daily digest - **Then** both `FeederSchoolReference` and `FeederSchoolReferenceBatch` activity types should be included - **And** they should follow the same filtering rules as other activities (exclude 'sent' verb for FeederSchoolReference) ### 1.4 Consistency with Latest Activity - **Given** the same time period - **When** comparing activities in the daily digest vs latest activity feed - **Then** the same feeder school activities should appear in both places - **And** the activity descriptions should be identical ## Technical Requirements ### 2.1 Code Changes Required - Modify `ViewObject::Admin::DailyDigest` to include feeder school activity classes when the school has feeder schools enabled - Ensure the same filtering logic from `DashboardActivities` is applied (exclude 'sent' verb for FeederSchoolReference) - Follow the existing pattern used in `StudentActivities` and `DashboardActivities` ### 2.2 Testing Requirements - Add unit tests for `ViewObject::Admin::DailyDigest` to verify feeder school activities are included - Test that feeder school activities are excluded when the feature is disabled - Test that the 'sent' verb is properly filtered out for FeederSchoolReference - Ensure existing daily digest functionality is not broken ## Non-Functional Requirements ### 3.1 Performance - Adding feeder school activities should not significantly impact daily digest generation time - Use the same efficient query patterns as existing activity collection ### 3.2 Maintainability - Follow the existing code patterns in `StudentActivities` and `DashboardActivities` - Use the same constant definitions for activity classes - Maintain consistency in how feature flags are checked ## Out of Scope - Changing the visual design of the daily digest email - Adding new types of feeder school activities beyond what's already in latest activity - Modifying how feeder school activities are logged or tracked - Changes to the latest activity feed itself ## Dependencies - Existing feeder school reference functionality - `enable_feeder_schools?` feature flag on School model - Activity tracking system (`ActsAsActivity`) - Daily digest email system ## Success Metrics - Feeder school activities appear in daily digest when feature is enabled - No regression in existing daily digest functionality - Test coverage for new functionality - Consistent behavior between latest activity and daily digest ``` ### 2. Design ![截圖 2026-01-21 上午10.42.48](https://hackmd.io/_uploads/SJ23ahTrZe.png) ```markdown! # Design Document: Add Feeder School Logs to Daily Digest ## Overview This document outlines the design for adding feeder school reference activities to the daily digest email, ensuring consistency with the latest activity feed implementation. ## Architecture ### Current Implementation Analysis #### Latest Activity Implementation The latest activity feed already includes feeder school activities through two view objects: 1. **`ViewObject::Admin::StudentActivities`** (Student profile activity feed) - Defines `FEEDER_SCHOOL_ACTIVITY_CLASSES = %w(FeederSchoolReference)` - Conditionally adds these classes when `@school.enable_feeder_schools?` is true - Used for individual student activity views 2. **`ViewObject::Admin::DashboardActivities`** (Dashboard activity feed) - Defines `FEEDER_SCHOOL_ACTIVITY_CLASSES = %w(FeederSchoolReference FeederSchoolReferenceBatch)` - Includes both individual references and batch operations - Filters out `sent` verb: `.where.not(trackable_type: 'FeederSchoolReference', verb: 'sent')` - Conditionally includes in filter options when feeder schools are enabled #### Daily Digest Implementation **`ViewObject::Admin::DailyDigest`** currently: - Collects activities using `VISIBLE_ACTIVITY_CLASSES` from `StudentActivities` - Does NOT include feeder school activity classes - Filters activities by time range and various exclusion rules - Maps activities to `DashboardActivities::ActivityPresenter` ### Design Decision **Approach**: Extend `ViewObject::Admin::DailyDigest` to conditionally include feeder school activity classes, following the same pattern as `DashboardActivities`. **Rationale**: 1. Maintains consistency with existing implementations 2. Respects the school's feature flag 3. Minimal code changes required 4. Follows established patterns in the codebase ## Implementation Details ### 1. Modify `ViewObject::Admin::DailyDigest#activity_presenters` **Current Code Location**: `app/extras/view_object/admin/daily_digest.rb` **Changes Required**: def activity_presenters return @activity_presenters if @activity_presenters # Build the list of visible activity classes visible_activity_classes = ViewObject::Admin::StudentActivities::VISIBLE_ACTIVITY_CLASSES # Add feeder school activities if enabled if @school.enable_feeder_schools? visible_activity_classes += ViewObject::Admin::DashboardActivities::FEEDER_SCHOOL_ACTIVITY_CLASSES end activities = @school.activities .includes([:actor, :trackable]) .where(created_at: @start_time..@end_time) .where('trackable_type IN (?)', visible_activity_classes) .where.not(trackable_id: nil) .where('actor_name IS NULL OR actor_name != ?', Activity::PARENT_EMAIL_ACTIVITY_ACTOR_NAME) .where.not(trackable_type: 'EsignatureDocument', verb: 'view') .where.not(trackable_type: 'FeederSchoolReference', verb: 'sent') # NEW: Filter out 'sent' verb .where.not(content: nil) .where.not(verb: nil) # ... rest of the method remains the same end **Key Changes**: 1. Build `visible_activity_classes` array dynamically 2. Conditionally add `FEEDER_SCHOOL_ACTIVITY_CLASSES` when feature is enabled 3. Add filter to exclude `FeederSchoolReference` activities with `sent` verb (consistent with `DashboardActivities`) ### 2. Activity Classes Included When feeder schools are enabled, the following activity types will be included: - `FeederSchoolReference` - Individual feeder school reference activities (excluding 'sent' verb) - `FeederSchoolReferenceBatch` - Batch feeder school reference operations ### 3. Filtering Rules The following filtering rules apply to feeder school activities (consistent with existing implementation): 1. **Time Range**: Only activities within `@start_time..@end_time` 2. **Trackable Present**: Must have a valid `trackable_id` 3. **Actor Present**: Must have a valid actor (checked later in the method) 4. **Content Present**: Must have non-nil content 5. **Verb Present**: Must have non-nil verb 6. **Exclude Parent Activities**: Filter out activities with `actor_name = 'parent_email'` 7. **Exclude 'sent' Verb**: For `FeederSchoolReference`, exclude activities with verb 'sent' ### 4. Display Format Feeder school activities will appear in the "Other Activities" section of the daily digest email, using the same `ActivityPresenter` as other activities. The presentation logic is already handled by: - `ViewObject::Admin::DashboardActivities::ActivityPresenter` - `ViewObject::Admin::StudentActivitiesContext::FeederSchoolReference` (if exists) - `ViewObject::Admin::StudentActivitiesContext::FeederSchoolReferenceBatch` (if exists) ## Testing Strategy ### Unit Tests **File**: `spec/extras/view_object/admin/daily_digest_spec.rb` #### Test Cases to Add: 1. **Test: Feeder school activities included when feature enabled** - Given: School has `enable_feeder_schools?` = true - And: FeederSchoolReference activity exists in time range - When: `activity_presenters` is called - Then: Activity should be included in results 2. **Test: Feeder school activities excluded when feature disabled** - Given: School has `enable_feeder_schools?` = false - And: FeederSchoolReference activity exists in time range - When: `activity_presenters` is called - Then: Activity should NOT be included in results 3. **Test: FeederSchoolReference 'sent' verb is filtered out** - Given: School has feeder schools enabled - And: FeederSchoolReference activity with verb 'sent' exists - When: `activity_presenters` is called - Then: Activity should NOT be included in results 4. **Test: FeederSchoolReference other verbs are included** - Given: School has feeder schools enabled - And: FeederSchoolReference activity with verb 'completed' exists - When: `activity_presenters` is called - Then: Activity should be included in results 5. **Test: FeederSchoolReferenceBatch activities are included** - Given: School has feeder schools enabled - And: FeederSchoolReferenceBatch activity exists - When: `activity_presenters` is called - Then: Activity should be included in results ### Integration Tests **File**: `spec/mailers/user_mailer_spec.rb` #### Test Cases to Add: 1. **Test: Daily digest email includes feeder school activities** - Given: School has feeder schools enabled - And: FeederSchoolReference activity exists - When: Daily digest email is generated - Then: Email should contain feeder school activity description ## Code Style Considerations ### Ruby Style - Use 2-space indentation (per project standards) - Follow existing patterns in `DailyDigest` class - Use descriptive variable names - Keep methods focused and readable ### Testing Style - Follow RSpec best practices - Use factory_bot for test data creation - Use descriptive test names with `it 'should ...'` format - Group related tests with `describe` and `context` blocks - Use `let` for test data setup - Follow existing test patterns in `daily_digest_spec.rb` ## Rollout Plan ### Phase 1: Implementation 1. Modify `ViewObject::Admin::DailyDigest#activity_presenters` 2. Write unit tests 3. Verify all tests pass ### Phase 2: Testing 1. Manual testing with schools that have feeder schools enabled 2. Verify daily digest emails contain feeder school activities 3. Verify schools without feeder schools don't see these activities ### Phase 3: Deployment 1. Deploy to staging environment 2. Test with real data 3. Deploy to production 4. Monitor for any issues ## Risk Assessment ### Low Risk - Changes are isolated to one method - Following established patterns - Feature flag provides safety net - Comprehensive test coverage ### Potential Issues 1. **Performance**: Adding more activity types could slow down digest generation - **Mitigation**: Use same efficient queries as existing code 2. **Email Size**: More activities could make emails larger - **Mitigation**: Existing 50-activity limit still applies 3. **Missing Context Classes**: If `StudentActivitiesContext` modules don't exist for feeder school types - **Mitigation**: Graceful error handling already exists in `ActivityPresenter` ## Success Criteria 1. ✅ Feeder school activities appear in daily digest when feature is enabled 2. ✅ Feeder school activities are excluded when feature is disabled 3. ✅ 'sent' verb is properly filtered out 4. ✅ All existing tests continue to pass 5. ✅ New tests provide adequate coverage 6. ✅ No performance degradation 7. ✅ Consistent behavior with latest activity feed ## References - **Related Files**: - `app/extras/view_object/admin/daily_digest.rb` - `app/extras/view_object/admin/dashboard_activities.rb` - `app/extras/view_object/admin/student_activities.rb` - `app/models/feeder_school_reference.rb` - `app/models/feeder_school_reference_batch.rb` - `spec/extras/view_object/admin/daily_digest_spec.rb` - **Related Tickets**: - OA-22554: Add feeder school logs into latest activity ``` ### 3. Tasks ![截圖 2026-01-21 上午10.42.54](https://hackmd.io/_uploads/H1QlyaaSZx.png) ```markdown! # Implementation Tasks: Add Feeder School Logs to Daily Digest ## Task List - [ ] 1. Write failing tests for feeder school activities in daily digest - [ ] 1.1 Add test for feeder school activities included when feature enabled - [ ] 1.2 Add test for feeder school activities excluded when feature disabled - [ ] 1.3 Add test for FeederSchoolReference 'sent' verb filtered out - [ ] 1.4 Add test for FeederSchoolReference other verbs included - [ ] 1.5 Add test for FeederSchoolReferenceBatch activities included - [ ] 2. Implement feeder school activities in DailyDigest - [ ] 2.1 Modify `activity_presenters` method to build visible_activity_classes dynamically - [ ] 2.2 Add conditional logic to include feeder school classes when enabled - [ ] 2.3 Add filter to exclude FeederSchoolReference 'sent' verb - [ ] 3. Verify all tests pass - [ ] 3.1 Run new tests and verify they pass - [ ] 3.2 Run existing daily digest tests to ensure no regression - [ ] 3.3 Run full test suite for related files - [ ] 4. Manual testing and verification - [ ] 4.1 Test with school that has feeder schools enabled - [ ] 4.2 Test with school that has feeder schools disabled - [ ] 4.3 Verify email content matches latest activity feed ## Task Details ### Task 1: Write failing tests for feeder school activities in daily digest **File**: `spec/extras/view_object/admin/daily_digest_spec.rb` **Description**: Following TDD principles, write tests first that define the expected behavior. These tests should initially fail since the functionality doesn't exist yet. **Test Structure**: describe '#activity_presenters' do context 'with feeder school activities' do # Test cases for feeder school functionality end end **Subtasks**: #### 1.1 Add test for feeder school activities included when feature enabled - Create a school with `enable_feeder_schools?` returning true - Create a FeederSchoolReference activity with a non-'sent' verb (e.g., 'completed') - Verify the activity appears in `activity_presenters` #### 1.2 Add test for feeder school activities excluded when feature disabled - Create a school with `enable_feeder_schools?` returning false - Create a FeederSchoolReference activity - Verify the activity does NOT appear in `activity_presenters` #### 1.3 Add test for FeederSchoolReference 'sent' verb filtered out - Create a school with feeder schools enabled - Create a FeederSchoolReference activity with verb 'sent' - Verify the activity does NOT appear in `activity_presenters` #### 1.4 Add test for FeederSchoolReference other verbs included - Create a school with feeder schools enabled - Create a FeederSchoolReference activity with verb 'completed' - Verify the activity appears in `activity_presenters` #### 1.5 Add test for FeederSchoolReferenceBatch activities included - Create a school with feeder schools enabled - Create a FeederSchoolReferenceBatch activity - Verify the activity appears in `activity_presenters` **Acceptance Criteria**: - All 5 test cases are written - Tests follow existing patterns in the spec file - Tests use factory_bot for data creation - Tests are descriptive and clear - Tests initially fail (red phase of TDD) --- ### Task 2: Implement feeder school activities in DailyDigest **File**: `app/extras/view_object/admin/daily_digest.rb` **Description**: Modify the `activity_presenters` method to include feeder school activities when the feature is enabled, following the same pattern as `DashboardActivities`. **Subtasks**: #### 2.1 Modify `activity_presenters` method to build visible_activity_classes dynamically - Change from using constant directly to building an array - Start with `ViewObject::Admin::StudentActivities::VISIBLE_ACTIVITY_CLASSES` #### 2.2 Add conditional logic to include feeder school classes when enabled - Check `@school.enable_feeder_schools?` - If true, add `ViewObject::Admin::DashboardActivities::FEEDER_SCHOOL_ACTIVITY_CLASSES` - Use the `+=` operator to append to the array #### 2.3 Add filter to exclude FeederSchoolReference 'sent' verb - Add `.where.not(trackable_type: 'FeederSchoolReference', verb: 'sent')` to the query chain - Place it after the existing `.where.not` clauses for consistency **Implementation Pattern**: def activity_presenters return @activity_presenters if @activity_presenters visible_activity_classes = ViewObject::Admin::StudentActivities::VISIBLE_ACTIVITY_CLASSES visible_activity_classes += ViewObject::Admin::DashboardActivities::FEEDER_SCHOOL_ACTIVITY_CLASSES if @school.enable_feeder_schools? activities = @school.activities .includes([:actor, :trackable]) .where(created_at: @start_time..@end_time) .where('trackable_type IN (?)', visible_activity_classes) .where.not(trackable_id: nil) .where('actor_name IS NULL OR actor_name != ?', Activity::PARENT_EMAIL_ACTIVITY_PARENT_EMAIL_ACTIVITY_ACTOR_NAME) .where.not(trackable_type: 'EsignatureDocument', verb: 'view') .where.not(trackable_type: 'FeederSchoolReference', verb: 'sent') .where.not(content: nil) .where.not(verb: nil) # ... rest of method unchanged end **Acceptance Criteria**: - Code follows existing patterns in the file - Uses 2-space indentation - Respects the feature flag - Includes proper filtering for 'sent' verb - No other functionality is changed --- ### Task 3: Verify all tests pass **Description**: Run tests to verify the implementation is correct and no regressions were introduced. **Subtasks**: #### 3.1 Run new tests and verify they pass - Run: `bundle exec rspec spec/extras/view_object/admin/daily_digest_spec.rb` - Verify all new tests pass (green phase of TDD) - Fix any failing tests #### 3.2 Run existing daily digest tests to ensure no regression - Verify all existing tests in `daily_digest_spec.rb` still pass - Check that no existing functionality was broken #### 3.3 Run full test suite for related files - Run: `bundle exec rspec spec/mailers/user_mailer_spec.rb` - Run: `bundle exec rspec spec/extras/view_object/admin/dashboard_activities_spec.rb` (if exists) - Verify no regressions in related functionality **Acceptance Criteria**: - All new tests pass - All existing tests pass - No test failures or errors - Test output is clean --- ### Task 4: Manual testing and verification **Description**: Manually test the feature to ensure it works correctly in a real-world scenario. **Subtasks**: #### 4.1 Test with school that has feeder schools enabled - Use Rails console to create test data - Generate a daily digest for a user - Verify feeder school activities appear in the email #### 4.2 Test with school that has feeder schools disabled - Use a school without feeder schools enabled - Generate a daily digest - Verify feeder school activities do NOT appear #### 4.3 Verify email content matches latest activity feed - Compare activities in daily digest with latest activity dashboard - Ensure descriptions are identical - Verify 'sent' activities are excluded from both **Acceptance Criteria**: - Feeder school activities appear correctly when enabled - Activities are excluded when feature is disabled - Email content is consistent with latest activity feed - No errors or exceptions occur --- ## Testing Commands # Run specific spec file bundle exec rspec spec/extras/view_object/admin/daily_digest_spec.rb # Run with specific test bundle exec rspec spec/extras/view_object/admin/daily_digest_spec.rb:LINE_NUMBER # Run all related specs bundle exec rspec spec/extras/view_object/admin/ bundle exec rspec spec/mailers/user_mailer_spec.rb # Run full test suite (optional) bundle exec rspec ## Definition of Done - [ ] All tests written and passing - [ ] Implementation complete and follows design - [ ] No regressions in existing functionality - [ ] Code follows project style guidelines - [ ] Manual testing completed successfully - [ ] Feature works consistently with latest activity feed - [ ] Documentation updated (if needed) ```

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password
    or
    Sign in via Facebook Sign in via X(Twitter) Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    By signing in, you agree to our terms of service.

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully