From 4cddfcf2f3d34795c5fe2cf53d6f83aa3716954a Mon Sep 17 00:00:00 2001 From: wehub-resource-sync Date: Mon, 13 Jul 2026 12:02:24 +0800 Subject: [PATCH] chore: import upstream snapshot with attribution --- .dockerignore | 13 + .github/FUNDING.yml | 1 + .github/ISSUE_TEMPLATE/bug_report.yml | 162 + .github/ISSUE_TEMPLATE/config.yml | 8 + .github/ISSUE_TEMPLATE/feature_request.yml | 109 + .github/workflows/backend-tests.yml | 91 + .github/workflows/build-canary-image.yml | 180 + .github/workflows/demo-deploy.yml | 17 + .github/workflows/frontend-tests.yml | 76 + .github/workflows/proto-linter.yml | 40 + .github/workflows/release-please.yml | 37 + .github/workflows/release.yml | 384 + .github/workflows/stale.yml | 24 + .gitignore | 33 + .golangci.yaml | 101 + .release-please-manifest.json | 3 + AGENTS.md | 125 + CHANGELOG.md | 183 + CODEOWNERS | 2 + LICENSE | 21 + README.md | 88 + README.wehub.md | 7 + SECURITY.md | 41 + docs/identity-provider-bootstrap.md | 42 + .../definition.md | 35 + .../2026-03-23-memo-detail-outline/plan.md | 47 + .../definition.md | 98 + .../execution.md | 63 + .../2026-03-23-tag-blur-attribute/plan.md | 89 + .../definition.md | 41 + .../design.md | 63 + .../execution.md | 62 + .../plan.md | 106 + .../definition.md | 47 + .../2026-03-31-quick-voice-input/design.md | 58 + .../2026-03-31-quick-voice-input/execution.md | 40 + .../2026-03-31-quick-voice-input/plan.md | 63 + .../2026-04-06-memo-mentions/definition.md | 49 + docs/plans/2026-04-06-memo-mentions/design.md | 69 + .../2026-04-06-memo-mentions/execution.md | 37 + docs/plans/2026-04-06-memo-mentions/plan.md | 104 + .../definition.md | 70 + .../design.md | 173 + .../execution.md | 105 + .../plan.md | 328 + ...2026-05-02-activity-calendar-time-basis.md | 1018 +++ .../plans/2026-05-02-calendar-date-prefill.md | 738 ++ .../plans/2026-05-02-stt-audiollm-split.md | 1590 +++++ .../2026-05-02-transcription-settings.md | 1816 +++++ ...2026-05-12-first-screen-lazy-heavy-deps.md | 774 ++ .../plans/2026-05-12-placeholder-component.md | 776 ++ .../plans/2026-05-31-remove-react-use.md | 673 ++ .../plans/2026-06-08-openapi-mcp-support.md | 1562 ++++ .../2026-06-11-markdown-wysiwyg-editor.md | 2621 +++++++ ...2026-06-15-cel-filter-surface-expansion.md | 887 +++ ...-02-activity-calendar-time-basis-design.md | 124 + ...2026-05-02-calendar-date-prefill-design.md | 165 + .../2026-05-02-stt-audiollm-split-design.md | 511 ++ ...026-05-02-transcription-settings-design.md | 155 + ...-12-first-screen-lazy-heavy-deps-design.md | 113 + ...2026-05-12-placeholder-component-design.md | 282 + .../2026-05-31-remove-react-use-design.md | 82 + .../2026-06-08-openapi-mcp-support-design.md | 241 + ...26-06-11-markdown-wysiwyg-editor-design.md | 168 + ...-15-cel-filter-surface-expansion-design.md | 257 + go.mod | 154 + go.sum | 365 + internal/ai/ai.go | 20 + internal/ai/audio/webm.go | 158 + internal/ai/audio/webm_test.go | 48 + internal/ai/audiollm/audiollm.go | 41 + internal/ai/audiollm/gemini/gemini.go | 202 + internal/ai/audiollm/gemini/gemini_test.go | 106 + internal/ai/audiollm/options.go | 34 + internal/ai/errors.go | 17 + internal/ai/models.go | 22 + internal/ai/resolver.go | 16 + internal/ai/stt/openai/openai.go | 116 + internal/ai/stt/openai/openai_test.go | 68 + internal/ai/stt/options.go | 34 + internal/ai/stt/stt.go | 41 + internal/base/resource_name.go | 7 + internal/base/resource_name_test.go | 37 + internal/email/README.md | 507 ++ internal/email/client.go | 173 + internal/email/client_test.go | 121 + internal/email/config.go | 47 + internal/email/config_test.go | 80 + internal/email/doc.go | 98 + internal/email/email.go | 61 + internal/email/email_test.go | 127 + internal/email/message.go | 110 + internal/email/message_test.go | 204 + internal/filter/MAINTENANCE.md | 50 + internal/filter/README.md | 105 + internal/filter/engine.go | 124 + internal/filter/engine_test.go | 197 + internal/filter/functions_test.go | 377 + internal/filter/helpers.go | 25 + internal/filter/ir.go | 196 + internal/filter/parser.go | 1020 +++ internal/filter/render.go | 980 +++ internal/filter/schema.go | 327 + internal/filter/time_test.go | 100 + internal/httpgetter/html_meta.go | 227 + internal/httpgetter/html_meta_test.go | 189 + internal/httpgetter/http_getter.go | 1 + internal/httpgetter/image.go | 45 + internal/httpgetter/util.go | 15 + internal/idp/idp.go | 8 + internal/idp/oauth2/oauth2.go | 142 + internal/idp/oauth2/oauth2_test.go | 291 + internal/markdown/ast/mention.go | 28 + internal/markdown/ast/tag.go | 28 + internal/markdown/extensions/mention.go | 24 + internal/markdown/extensions/tag.go | 24 + internal/markdown/markdown.go | 489 ++ internal/markdown/markdown_test.go | 654 ++ internal/markdown/parser/mention.go | 87 + internal/markdown/parser/tag.go | 150 + internal/markdown/parser/tag_test.go | 263 + .../markdown/renderer/markdown_renderer.go | 270 + .../renderer/markdown_renderer_test.go | 176 + internal/motionphoto/motionphoto.go | 110 + internal/motionphoto/motionphoto_test.go | 25 + internal/profile/profile.go | 120 + internal/profile/profile_test.go | 24 + internal/scheduler/README.md | 367 + internal/scheduler/doc.go | 35 + internal/scheduler/example_test.go | 165 + internal/scheduler/integration_test.go | 393 ++ internal/scheduler/job.go | 58 + internal/scheduler/job_test.go | 90 + internal/scheduler/middleware.go | 121 + internal/scheduler/middleware_test.go | 146 + internal/scheduler/parser.go | 225 + internal/scheduler/parser_test.go | 127 + internal/scheduler/scheduler.go | 202 + internal/scheduler/scheduler_test.go | 165 + internal/storage/s3/s3.go | 126 + internal/testutil/motionphoto.go | 18 + internal/util/util.go | 73 + internal/util/util_test.go | 31 + internal/version/version.go | 56 + internal/version/version_test.go | 106 + internal/webhook/validate.go | 103 + internal/webhook/webhook.go | 196 + internal/webhook/webhook_test.go | 161 + proto/README.md | 17 + proto/api/v1/README.md | 3 + proto/api/v1/ai_service.proto | 46 + proto/api/v1/attachment_service.proto | 182 + proto/api/v1/auth_service.proto | 115 + proto/api/v1/common.proto | 23 + proto/api/v1/idp_service.proto | 147 + proto/api/v1/instance_service.proto | 360 + proto/api/v1/memo_service.proto | 656 ++ proto/api/v1/shortcut_service.proto | 127 + proto/api/v1/user_service.proto | 880 +++ proto/buf.gen.yaml | 30 + proto/buf.lock | 6 + proto/buf.yaml | 19 + proto/gen/api/v1/ai_service.pb.go | 292 + proto/gen/api/v1/ai_service.pb.gw.go | 157 + proto/gen/api/v1/ai_service_grpc.pb.go | 123 + .../api/v1/apiv1connect/ai_service.connect.go | 110 + .../attachment_service.connect.go | 267 + .../v1/apiv1connect/auth_service.connect.go | 217 + .../v1/apiv1connect/idp_service.connect.go | 237 + .../apiv1connect/instance_service.connect.go | 267 + .../v1/apiv1connect/memo_service.connect.go | 712 ++ .../apiv1connect/shortcut_service.connect.go | 240 + .../v1/apiv1connect/user_service.connect.go | 892 +++ proto/gen/api/v1/attachment_service.pb.go | 861 +++ proto/gen/api/v1/attachment_service.pb.gw.go | 587 ++ .../gen/api/v1/attachment_service_grpc.pb.go | 324 + proto/gen/api/v1/auth_service.pb.go | 628 ++ proto/gen/api/v1/auth_service.pb.gw.go | 343 + proto/gen/api/v1/auth_service_grpc.pb.go | 258 + proto/gen/api/v1/common.pb.go | 244 + proto/gen/api/v1/idp_service.pb.go | 805 +++ proto/gen/api/v1/idp_service.pb.gw.go | 507 ++ proto/gen/api/v1/idp_service_grpc.pb.go | 285 + proto/gen/api/v1/instance_service.pb.go | 2074 ++++++ proto/gen/api/v1/instance_service.pb.gw.go | 541 ++ proto/gen/api/v1/instance_service_grpc.pb.go | 324 + proto/gen/api/v1/memo_service.pb.go | 2694 +++++++ proto/gen/api/v1/memo_service.pb.gw.go | 1789 +++++ proto/gen/api/v1/memo_service_grpc.pb.go | 900 +++ proto/gen/api/v1/shortcut_service.pb.go | 497 ++ proto/gen/api/v1/shortcut_service.pb.gw.go | 543 ++ proto/gen/api/v1/shortcut_service_grpc.pb.go | 288 + proto/gen/api/v1/user_service.pb.go | 3864 ++++++++++ proto/gen/api/v1/user_service.pb.gw.go | 2357 +++++++ proto/gen/api/v1/user_service_grpc.pb.go | 1134 +++ proto/gen/openapi.yaml | 4057 +++++++++++ proto/gen/store/attachment.pb.go | 495 ++ proto/gen/store/idp.pb.go | 476 ++ proto/gen/store/inbox.pb.go | 351 + proto/gen/store/instance_setting.pb.go | 1513 ++++ proto/gen/store/memo.pb.go | 293 + proto/gen/store/user_setting.pb.go | 1159 +++ proto/openapi_embed.go | 11 + proto/store/attachment.proto | 56 + proto/store/idp.proto | 42 + proto/store/inbox.proto | 32 + proto/store/instance_setting.proto | 205 + proto/store/memo.proto | 29 + proto/store/user_setting.proto | 135 + release-please-config.json | 35 + scripts/Dockerfile | 56 + scripts/build.sh | 32 + scripts/compose.yaml | 8 + scripts/entrypoint.sh | 52 + scripts/entrypoint_test.sh | 131 + scripts/install.sh | 296 + server/auth/authenticator.go | 224 + server/auth/authenticator_test.go | 34 + server/auth/context.go | 99 + server/auth/extract.go | 33 + server/auth/token.go | 249 + server/auth/token_test.go | 306 + server/cors.go | 59 + server/cors_test.go | 155 + server/notification/email.go | 320 + server/router/api/v1/acl_config.go | 83 + server/router/api/v1/acl_config_test.go | 137 + server/router/api/v1/ai_service.go | 240 + server/router/api/v1/attachment_exif_test.go | 232 + server/router/api/v1/attachment_motion.go | 69 + server/router/api/v1/attachment_service.go | 455 ++ .../router/api/v1/attachment_service_image.go | 138 + .../api/v1/attachment_service_storage.go | 254 + server/router/api/v1/auth_service.go | 120 + .../api/v1/auth_service_client_info_test.go | 228 + server/router/api/v1/auth_service_session.go | 458 ++ server/router/api/v1/auth_service_sso.go | 246 + server/router/api/v1/authz.go | 90 + server/router/api/v1/authz_test.go | 56 + server/router/api/v1/common.go | 83 + server/router/api/v1/common_test.go | 46 + server/router/api/v1/connect_handler.go | 80 + server/router/api/v1/connect_interceptors.go | 239 + .../api/v1/connect_interceptors_test.go | 39 + server/router/api/v1/connect_services.go | 608 ++ server/router/api/v1/header_carrier.go | 124 + server/router/api/v1/health_service.go | 25 + server/router/api/v1/idp_service.go | 235 + server/router/api/v1/instance_service.go | 322 + .../api/v1/instance_service_converters.go | 349 + .../api/v1/instance_service_validation.go | 196 + server/router/api/v1/instance_stats.go | 165 + server/router/api/v1/instance_stats_test.go | 34 + server/router/api/v1/link_metadata_test.go | 103 + .../router/api/v1/memo_attachment_service.go | 241 + server/router/api/v1/memo_batch_helpers.go | 34 + .../api/v1/memo_comment_relations_test.go | 47 + server/router/api/v1/memo_mention_helpers.go | 146 + server/router/api/v1/memo_relation_service.go | 197 + server/router/api/v1/memo_service.go | 603 ++ server/router/api/v1/memo_service_comments.go | 285 + .../router/api/v1/memo_service_converter.go | 372 + server/router/api/v1/memo_service_filter.go | 1 + .../api/v1/memo_service_link_metadata.go | 57 + server/router/api/v1/memo_service_query.go | 67 + server/router/api/v1/memo_service_webhooks.go | 94 + server/router/api/v1/memo_share_service.go | 226 + server/router/api/v1/memo_update_helpers.go | 78 + server/router/api/v1/notification_email.go | 28 + server/router/api/v1/reaction_service.go | 181 + server/router/api/v1/resource_name.go | 149 + server/router/api/v1/shortcut_service.go | 360 + server/router/api/v1/sse_event_helpers.go | 40 + server/router/api/v1/sse_handler.go | 123 + server/router/api/v1/sse_hub.go | 144 + server/router/api/v1/sse_hub_test.go | 251 + server/router/api/v1/sse_service_test.go | 314 + server/router/api/v1/sso_username.go | 20 + server/router/api/v1/test/ai_service_test.go | 284 + .../api/v1/test/attachment_service_test.go | 371 + .../router/api/v1/test/auth_service_test.go | 271 + server/router/api/v1/test/auth_test.go | 682 ++ server/router/api/v1/test/authz_test.go | 81 + server/router/api/v1/test/idp_service_test.go | 613 ++ .../api/v1/test/instance_admin_cache_test.go | 54 + .../api/v1/test/instance_service_test.go | 969 +++ .../router/api/v1/test/instance_stats_test.go | 72 + .../v1/test/memo_attachment_service_test.go | 346 + .../api/v1/test/memo_relation_service_test.go | 169 + .../v1/test/memo_service_benchmark_test.go | 282 + .../router/api/v1/test/memo_service_test.go | 732 ++ .../api/v1/test/memo_share_service_test.go | 263 + .../api/v1/test/reaction_service_test.go | 235 + .../api/v1/test/shortcut_service_test.go | 838 +++ server/router/api/v1/test/sse_handler_test.go | 135 + server/router/api/v1/test/test_helper.go | 91 + .../api/v1/test/user_email_visibility_test.go | 113 + .../api/v1/test/user_notification_test.go | 526 ++ .../api/v1/test/user_resource_name_test.go | 197 + server/router/api/v1/test/user_search_test.go | 71 + .../api/v1/test/user_service_delete_test.go | 489 ++ .../test/user_service_email_username_test.go | 259 + .../v1/test/user_service_pagination_test.go | 103 + .../v1/test/user_service_registration_test.go | 387 + .../api/v1/test/user_service_stats_test.go | 202 + .../router/api/v1/test/user_setting_test.go | 206 + server/router/api/v1/user_resource_name.go | 59 + .../router/api/v1/user_resource_name_test.go | 116 + server/router/api/v1/user_service.go | 553 ++ .../api/v1/user_service_access_tokens.go | 152 + .../router/api/v1/user_service_converters.go | 286 + server/router/api/v1/user_service_filter.go | 114 + .../router/api/v1/user_service_identities.go | 151 + .../api/v1/user_service_notifications.go | 396 ++ server/router/api/v1/user_service_settings.go | 241 + server/router/api/v1/user_service_stats.go | 296 + server/router/api/v1/user_service_webhooks.go | 297 + server/router/api/v1/user_webhook_test.go | 73 + server/router/api/v1/v1.go | 147 + server/router/fileserver/README.md | 304 + server/router/fileserver/fileserver.go | 780 ++ server/router/fileserver/fileserver_test.go | 601 ++ server/router/frontend/frontend.go | 188 + server/router/frontend/frontend_test.go | 233 + server/router/mcp/README.md | 260 + server/router/mcp/adapter.go | 160 + server/router/mcp/adapter_test.go | 213 + server/router/mcp/catalog.go | 240 + server/router/mcp/catalog_test.go | 239 + server/router/mcp/evals/README.md | 67 + server/router/mcp/evals/memos_eval.xml | 62 + server/router/mcp/openapi.go | 252 + server/router/mcp/openapi_test.go | 192 + server/router/mcp/origin.go | 31 + server/router/mcp/result.go | 62 + server/router/mcp/service.go | 117 + server/router/mcp/service_test.go | 333 + server/router/mcp/validation.go | 226 + server/router/mcp/validation_test.go | 63 + server/router/rss/rss.go | 431 ++ server/router/rss/rss_test.go | 86 + server/runner/memopayload/runner.go | 88 + server/runner/s3presign/runner.go | 143 + server/runner/s3presign/runner_test.go | 34 + server/server.go | 243 + store/attachment.go | 298 + store/cache.go | 9 + store/cache/cache.go | 327 + store/cache/cache_test.go | 209 + store/common.go | 24 + store/db/db.go | 32 + store/db/mysql/attachment.go | 274 + store/db/mysql/common.go | 10 + store/db/mysql/idp.go | 130 + store/db/mysql/inbox.go | 150 + store/db/mysql/instance_setting.go | 65 + store/db/mysql/memo.go | 270 + store/db/mysql/memo_relation.go | 146 + store/db/mysql/memo_share.go | 121 + store/db/mysql/mysql.go | 80 + store/db/mysql/reaction.go | 113 + store/db/mysql/user.go | 197 + store/db/mysql/user_delete.go | 566 ++ store/db/mysql/user_delete_test.go | 11 + store/db/mysql/user_identity.go | 107 + store/db/mysql/user_setting.go | 109 + store/db/postgres/attachment.go | 254 + store/db/postgres/common.go | 26 + store/db/postgres/idp.go | 123 + store/db/postgres/inbox.go | 151 + store/db/postgres/instance_setting.go | 72 + store/db/postgres/memo.go | 255 + store/db/postgres/memo_relation.go | 173 + store/db/postgres/memo_share.go | 142 + store/db/postgres/postgres.go | 67 + store/db/postgres/reaction.go | 101 + store/db/postgres/user.go | 195 + store/db/postgres/user_delete.go | 529 ++ store/db/postgres/user_identity.go | 95 + store/db/postgres/user_setting.go | 137 + store/db/postgres/user_setting_test.go | 290 + store/db/sqlite/attachment.go | 254 + store/db/sqlite/common.go | 9 + store/db/sqlite/functions.go | 104 + store/db/sqlite/functions_test.go | 24 + store/db/sqlite/idp.go | 123 + store/db/sqlite/inbox.go | 141 + store/db/sqlite/instance_setting.go | 72 + store/db/sqlite/memo.go | 248 + store/db/sqlite/memo_relation.go | 159 + store/db/sqlite/memo_share.go | 144 + store/db/sqlite/reaction.go | 136 + store/db/sqlite/sqlite.go | 91 + store/db/sqlite/user.go | 205 + store/db/sqlite/user_delete.go | 529 ++ store/db/sqlite/user_identity.go | 95 + store/db/sqlite/user_setting.go | 125 + store/demo_seed_test.go | 53 + store/driver.go | 84 + store/idp.go | 186 + store/idp_bootstrap.go | 165 + store/idp_bootstrap_test.go | 180 + store/inbox.go | 75 + store/instance_setting.go | 327 + store/memo.go | 159 + store/memo_relation.go | 53 + store/memo_share.go | 47 + store/migration/mysql/0.17/00__inbox.sql | 9 + .../mysql/0.17/01__delete_activity.sql | 1 + .../migration/mysql/0.18/00__extend_text.sql | 3 + store/migration/mysql/0.18/01__webhook.sql | 10 + .../migration/mysql/0.18/02__user_setting.sql | 4 + .../mysql/0.19/00__add_resource_name.sql | 15 + store/migration/mysql/0.20/00__reaction.sql | 9 + .../mysql/0.21/00__user_description.sql | 1 + store/migration/mysql/0.21/01__rename_uid.sql | 3 + .../mysql/0.22/00__resource_storage_type.sql | 11 + store/migration/mysql/0.22/01__memo_tags.sql | 3 + .../migration/mysql/0.22/02__memo_payload.sql | 3 + store/migration/mysql/0.22/03__drop_tag.sql | 1 + store/migration/mysql/0.23/00__reactions.sql | 12 + store/migration/mysql/0.24/00__memo.sql | 2 + .../migration/mysql/0.24/01__memo_pinned.sql | 8 + .../mysql/0.24/02__s3_reference_length.sql | 2 + .../mysql/0.25/00__remove_webhook.sql | 1 + .../00__rename_resource_to_attachment.sql | 1 + .../mysql/0.26/01__drop_memo_organizer.sql | 1 + .../mysql/0.26/02__migrate_host_to_admin.sql | 1 + .../0.27/00__migrate_storage_setting.sql | 6 + .../migration/mysql/0.27/01__add_idp_uid.sql | 8 + .../02__migrate_inbox_message_payload.sql | 14 + .../mysql/0.27/03__drop_activity.sql | 1 + store/migration/mysql/0.27/04__memo_share.sql | 14 + .../mysql/0.28/00__user_identity.sql | 15 + .../mysql/0.30/00__user_tag_setting.sql | 10 + store/migration/mysql/LATEST.sql | 125 + .../postgres/0.19/00__add_resource_name.sql | 15 + .../migration/postgres/0.20/00__reaction.sql | 9 + .../postgres/0.21/00__user_description.sql | 1 + .../postgres/0.21/01__rename_uid.sql | 3 + .../0.22/00__resource_storage_type.sql | 11 + .../migration/postgres/0.22/01__memo_tags.sql | 1 + .../postgres/0.22/02__memo_payload.sql | 1 + .../migration/postgres/0.22/03__drop_tag.sql | 1 + .../migration/postgres/0.23/00__reactions.sql | 12 + store/migration/postgres/0.24/00__memo.sql | 2 + .../postgres/0.24/01__memo_pinned.sql | 8 + .../postgres/0.25/00__remove_webhook.sql | 1 + .../00__rename_resource_to_attachment.sql | 1 + .../postgres/0.26/01__drop_memo_organizer.sql | 1 + .../0.26/02__migrate_host_to_admin.sql | 1 + .../0.27/00__migrate_storage_setting.sql | 5 + .../postgres/0.27/01__add_idp_uid.sql | 8 + .../02__migrate_inbox_message_payload.sql | 13 + .../postgres/0.27/03__drop_activity.sql | 1 + .../postgres/0.27/04__memo_share.sql | 14 + .../postgres/0.28/00__user_identity.sql | 15 + .../postgres/0.30/00__user_tag_setting.sql | 11 + store/migration/postgres/LATEST.sql | 125 + store/migration/sqlite/0.10/00__activity.sql | 9 + .../migration/sqlite/0.11/00__user_avatar.sql | 4 + store/migration/sqlite/0.11/01__idp.sql | 8 + store/migration/sqlite/0.11/02__storage.sql | 7 + .../sqlite/0.12/00__user_setting.sql | 6 + .../sqlite/0.12/01__system_setting.sql | 69 + .../0.12/03__resource_internal_path.sql | 4 + .../sqlite/0.12/04__resource_public_id.sql | 18 + .../sqlite/0.13/00__memo_relation.sql | 7 + .../0.13/01__remove_memo_organizer_id.sql | 22 + .../0.14/00__drop_resource_public_id.sql | 25 + .../sqlite/0.14/01__create_indexes.sql | 5 + .../sqlite/0.15/00__drop_user_open_id.sql | 25 + .../0.16/00__add_memo_id_to_resource.sql | 13 + .../sqlite/0.16/01__drop_shortcut_table.sql | 1 + store/migration/sqlite/0.17/00__inbox.sql | 9 + .../sqlite/0.17/01__delete_activities.sql | 1 + store/migration/sqlite/0.18/00__webhook.sql | 12 + .../sqlite/0.18/01__user_setting.sql | 4 + .../sqlite/0.19/00__add_resource_name.sql | 11 + store/migration/sqlite/0.2/00__user_role.sql | 60 + .../sqlite/0.2/01__memo_visibility.sql | 4 + store/migration/sqlite/0.20/00__reaction.sql | 9 + .../sqlite/0.21/00__user_description.sql | 1 + .../migration/sqlite/0.21/01__rename_uid.sql | 3 + .../sqlite/0.22/00__resource_storage_type.sql | 17 + store/migration/sqlite/0.22/01__memo_tags.sql | 3 + .../sqlite/0.22/02__memo_payload.sql | 1 + store/migration/sqlite/0.22/03__drop_tag.sql | 1 + store/migration/sqlite/0.23/00__reactions.sql | 12 + store/migration/sqlite/0.24/00__memo.sql | 7 + .../migration/sqlite/0.24/01__memo_pinned.sql | 11 + .../sqlite/0.25/00__remove_webhook.sql | 1 + .../00__rename_resource_to_attachment.sql | 5 + .../sqlite/0.26/01__drop_memo_organizer.sql | 1 + .../sqlite/0.26/02__drop_indexes.sql | 4 + .../sqlite/0.26/03__alter_user_role.sql | 24 + .../sqlite/0.26/04__migrate_host_to_admin.sql | 1 + .../0.27/00__migrate_storage_setting.sql | 5 + .../migration/sqlite/0.27/01__add_idp_uid.sql | 8 + .../02__migrate_inbox_message_payload.sql | 25 + .../sqlite/0.27/03__drop_activity.sql | 1 + .../migration/sqlite/0.27/04__memo_share.sql | 14 + .../sqlite/0.28/00__user_identity.sql | 15 + .../0.3/00__memo_visibility_protected.sql | 43 + .../sqlite/0.30/00__user_tag_setting.sql | 10 + .../migration/sqlite/0.4/00__user_setting.sql | 9 + .../0.5/00__regenerate_foreign_keys.sql | 217 + .../sqlite/0.5/01__memo_resource.sql | 10 + .../sqlite/0.5/02__system_setting.sql | 7 + .../sqlite/0.5/03__resource_extermal_link.sql | 4 + .../sqlite/0.6/00__recreate_triggers.sql | 59 + store/migration/sqlite/0.7/00__remove_fk.sql | 191 + .../sqlite/0.7/01__remove_triggers.sql | 7 + .../sqlite/0.8/00__migration_history.sql | 5 + .../sqlite/0.8/01__user_username.sql | 50 + store/migration/sqlite/0.9/00__tag.sql | 6 + store/migration/sqlite/LATEST.sql | 126 + store/migrator.go | 417 ++ store/reaction.go | 41 + store/seed/sqlite/01__dump.sql | 63 + store/store.go | 65 + store/test/README.md | 13 + store/test/attachment_filter_test.go | 411 ++ store/test/attachment_test.go | 305 + store/test/containers.go | 382 + store/test/database_size_test.go | 19 + store/test/filter_helpers_test.go | 295 + store/test/idp_test.go | 468 ++ store/test/inbox_test.go | 613 ++ store/test/instance_setting_test.go | 459 ++ store/test/main_test.go | 50 + store/test/memo_filter_functions_test.go | 91 + store/test/memo_filter_test.go | 1174 ++++ store/test/memo_relation_test.go | 946 +++ store/test/memo_test.go | 478 ++ store/test/migrator_test.go | 294 + store/test/migrator_upgrade_test.go | 271 + store/test/reaction_test.go | 189 + store/test/store.go | 111 + store/test/user_delete_test.go | 248 + store/test/user_identity_test.go | 199 + store/test/user_setting_test.go | 993 +++ store/test/user_test.go | 278 + store/user.go | 181 + store/user_delete.go | 47 + store/user_identity.go | 59 + store/user_setting.go | 521 ++ web/.gitignore | 7 + web/biome.json | 202 + web/components.json | 21 + web/docs/auth-architecture.md | 55 + web/index.html | 24 + web/package.json | 114 + web/pnpm-lock.yaml | 6258 +++++++++++++++++ web/pnpm-workspace.yaml | 2 + web/public/android-chrome-192x192.png | Bin 0 -> 25014 bytes web/public/android-chrome-512x512.png | Bin 0 -> 141510 bytes web/public/apple-touch-icon.png | Bin 0 -> 22496 bytes web/public/full-logo.webp | Bin 0 -> 25152 bytes web/public/logo.webp | Bin 0 -> 37158 bytes web/public/site.webmanifest | 14 + web/src/App.tsx | 68 + web/src/auth-state.ts | 128 + .../ActivityCalendar/CalendarCell.tsx | 82 + .../ActivityCalendar/MonthCalendar.tsx | 87 + .../ActivityCalendar/YearCalendar.tsx | 118 + .../components/ActivityCalendar/constants.ts | 34 + web/src/components/ActivityCalendar/hooks.ts | 23 + web/src/components/ActivityCalendar/index.ts | 4 + web/src/components/ActivityCalendar/types.ts | 43 + .../ActivityCalendar/useCalendar.ts | 90 + web/src/components/ActivityCalendar/utils.ts | 75 + web/src/components/AttachmentIcon.tsx | 108 + .../AttachmentLibrary/AttachmentFileRows.tsx | 126 + .../AttachmentLibraryEmptyState.tsx | 57 + .../AttachmentLibraryPrimitives.tsx | 87 + .../AttachmentLibraryStates.tsx | 77 + .../AttachmentLibraryToolbar.tsx | 64 + .../AttachmentLibrary/AttachmentMediaGrid.tsx | 97 + web/src/components/AttachmentLibrary/index.ts | 6 + web/src/components/AuthFooter.tsx | 35 + .../components/ChangeMemberPasswordDialog.tsx | 114 + web/src/components/ClampedSection.tsx | 73 + web/src/components/ColumnGrid/ColumnGrid.tsx | 290 + web/src/components/ColumnGrid/index.ts | 4 + web/src/components/ConfirmDialog/README.md | 131 + web/src/components/ConfirmDialog/index.tsx | 59 + .../components/CreateAccessTokenDialog.tsx | 183 + .../CreateIdentityProviderDialog.tsx | 615 ++ web/src/components/CreateUserDialog.tsx | 150 + web/src/components/CreateWebhookDialog.tsx | 281 + web/src/components/DateTimeInput.tsx | 43 + web/src/components/ErrorBoundary.tsx | 103 + .../components/Inbox/MemoCommentMessage.tsx | 158 + .../components/Inbox/MemoMentionMessage.tsx | 164 + web/src/components/LearnMore.tsx | 31 + web/src/components/LocalePicker.tsx | 117 + web/src/components/LocaleSelect.tsx | 24 + .../MemoActionMenu/MemoActionMenu.tsx | 165 + .../MemoActionMenu/MemoShareImageDialog.tsx | 137 + .../MemoActionMenu/MemoShareImagePreview.tsx | 87 + web/src/components/MemoActionMenu/hooks.ts | 163 + web/src/components/MemoActionMenu/index.ts | 3 + .../MemoActionMenu/memoShareImage.ts | 117 + .../memoShareImagePreviewModel.ts | 58 + web/src/components/MemoActionMenu/types.ts | 8 + web/src/components/MemoCommentSection.tsx | 90 + web/src/components/MemoContent/CodeBlock.tsx | 156 + .../MemoContent/LinkMetadataCard.tsx | 70 + .../MemoContent/MarkdownRenderContext.tsx | 22 + .../MemoContent/MemoMarkdownRenderer.tsx | 167 + web/src/components/MemoContent/Mention.tsx | 41 + .../MemoContent/MentionResolutionContext.tsx | 41 + .../components/MemoContent/MermaidBlock.tsx | 101 + web/src/components/MemoContent/Table.tsx | 77 + web/src/components/MemoContent/Tag.tsx | 79 + .../components/MemoContent/TaskListItem.tsx | 70 + .../components/MemoContent/TrustedIframe.ts | 14 + web/src/components/MemoContent/constants.ts | 65 + web/src/components/MemoContent/index.tsx | 49 + .../MemoContent/markdown/AnchorLink.tsx | 54 + .../MemoContent/markdown/Blockquote.tsx | 19 + .../MemoContent/markdown/Heading.tsx | 23 + .../MemoContent/markdown/HorizontalRule.tsx | 12 + .../components/MemoContent/markdown/Image.tsx | 19 + .../MemoContent/markdown/InlineCode.tsx | 18 + .../components/MemoContent/markdown/Link.tsx | 19 + .../components/MemoContent/markdown/List.tsx | 116 + .../MemoContent/markdown/Paragraph.tsx | 63 + .../components/MemoContent/markdown/README.md | 19 + .../components/MemoContent/markdown/index.ts | 9 + .../components/MemoContent/markdown/types.ts | 9 + web/src/components/MemoContent/types.ts | 13 + web/src/components/MemoContent/utils.ts | 25 + .../MemoDetailSidebar/MemoDetailSidebar.tsx | 139 + .../MemoDetailSidebarDrawer.tsx | 36 + .../MemoDetailSidebar/MemoOutline.tsx | 52 + .../MemoDetailSidebar/MemoSharePanel.tsx | 158 + web/src/components/MemoDetailSidebar/index.ts | 4 + web/src/components/MemoDisplaySettingMenu.tsx | 151 + .../MemoEditor/Editor/controller.ts | 37 + .../components/MemoEditor/Editor/editor.css | 138 + .../MemoEditor/Editor/extensions.ts | 112 + .../MemoEditor/Editor/formatting.ts | 372 + .../MemoEditor/Editor/headingDecorations.ts | 24 + .../components/MemoEditor/Editor/index.tsx | 98 + .../MemoEditor/Editor/listIndent.ts | 121 + .../MemoEditor/Editor/tagAutocomplete.ts | 25 + .../Editor/tagMentionDecorations.ts | 34 + web/src/components/MemoEditor/Editor/theme.ts | 23 + .../MemoEditor/Editor/viewportDecorations.ts | 23 + web/src/components/MemoEditor/README.md | 125 + .../MemoEditor/Toolbar/EditorToolbar.tsx | 71 + .../MemoEditor/Toolbar/FormattingToolbar.tsx | 178 + .../MemoEditor/Toolbar/InsertMenu.tsx | 199 + .../MemoEditor/Toolbar/VisibilitySelector.tsx | 45 + .../components/MemoEditor/Toolbar/index.ts | 5 + .../components/AudioRecorderPanel.tsx | 100 + .../MemoEditor/components/EditorContent.tsx | 54 + .../MemoEditor/components/EditorMetadata.tsx | 32 + .../components/FocusModeOverlay.tsx | 20 + .../components/TimestampPopover.tsx | 90 + .../MemoEditor/components/VoiceWaveform.tsx | 34 + .../components/MemoEditor/components/index.ts | 7 + web/src/components/MemoEditor/constants.ts | 13 + .../MemoEditor/formatting/commands.ts | 186 + web/src/components/MemoEditor/hooks/index.ts | 14 + .../MemoEditor/hooks/useAudioRecorder.ts | 261 + .../MemoEditor/hooks/useAudioWaveform.ts | 99 + .../MemoEditor/hooks/useAutoSave.ts | 73 + .../MemoEditor/hooks/useBlobUrls.ts | 22 + .../MemoEditor/hooks/useEditorActiveState.ts | 37 + .../MemoEditor/hooks/useElementWidth.ts | 31 + .../MemoEditor/hooks/useFileUpload.ts | 98 + .../MemoEditor/hooks/useFocusMode.ts | 40 + .../MemoEditor/hooks/useLinkMemo.ts | 89 + .../MemoEditor/hooks/useLocation.ts | 87 + .../MemoEditor/hooks/useMemoInit.ts | 60 + .../MemoEditor/hooks/useMemoSave.ts | 113 + web/src/components/MemoEditor/index.tsx | 300 + .../MemoEditor/services/cacheService.ts | 83 + .../MemoEditor/services/errorService.ts | 18 + .../components/MemoEditor/services/index.ts | 6 + .../MemoEditor/services/memoService.ts | 145 + .../services/transcriptionService.ts | 23 + .../MemoEditor/services/uploadService.ts | 30 + .../MemoEditor/services/validationService.ts | 37 + .../components/MemoEditor/state/actions.ts | 57 + .../components/MemoEditor/state/context.tsx | 88 + web/src/components/MemoEditor/state/index.ts | 4 + .../components/MemoEditor/state/reducer.ts | 89 + web/src/components/MemoEditor/state/types.ts | 78 + .../components/MemoEditor/types/attachment.ts | 199 + .../components/MemoEditor/types/components.ts | 82 + .../MemoEditor/types/editorController.ts | 43 + web/src/components/MemoEditor/types/index.ts | 15 + .../components/MemoEditor/types/insertMenu.ts | 8 + .../utils/deriveDefaultCreateTime.ts | 26 + .../components/MemoExplorer/MemoExplorer.tsx | 87 + .../MemoExplorer/MemoExplorerDrawer.tsx | 42 + .../MemoExplorer/ShortcutsSection.tsx | 118 + .../components/MemoExplorer/TagsSection.tsx | 100 + web/src/components/MemoExplorer/index.ts | 5 + web/src/components/MemoFilters.tsx | 106 + .../Attachment/AttachmentCard.tsx | 45 + .../Attachment/AttachmentListEditor.tsx | 354 + .../Attachment/AttachmentListView.tsx | 278 + .../Attachment/AudioAttachmentItem.tsx | 191 + .../Attachment/attachmentHelpers.ts | 61 + .../Attachment/attachmentVisualClasses.ts | 33 + .../MemoMetadata/Attachment/index.ts | 4 + .../Attachment/visualGalleryLayout.ts | 72 + .../MemoMetadata/Location/LocationDialog.tsx | 113 + .../Location/LocationDisplayEditor.tsx | 42 + .../Location/LocationDisplayView.tsx | 43 + .../components/MemoMetadata/Location/index.ts | 3 + .../MemoMetadata/Location/locationHelpers.ts | 9 + .../MemoMetadata/MetadataSection.tsx | 24 + .../MemoMetadata/Relation/LinkMemoDialog.tsx | 90 + .../MemoMetadata/Relation/RelationCard.tsx | 16 + .../Relation/RelationListEditor.tsx | 71 + .../Relation/RelationListView.tsx | 78 + .../components/MemoMetadata/Relation/index.ts | 4 + .../MemoMetadata/Relation/relationHelpers.ts | 42 + .../Relation/useResolvedRelationMemos.ts | 62 + .../components/MemoMetadata/SectionHeader.tsx | 53 + web/src/components/MemoMetadata/index.ts | 7 + .../components/MemoPreview/MemoPreview.tsx | 166 + web/src/components/MemoPreview/index.ts | 1 + .../MemoReactionListView.tsx | 34 + .../MemoReactionListView/ReactionSelector.tsx | 63 + .../MemoReactionListView/ReactionView.tsx | 58 + .../components/MemoReactionListView/hooks.ts | 82 + .../components/MemoReactionListView/index.ts | 3 + web/src/components/MemoView/MemoView.tsx | 155 + .../components/MemoView/MemoViewContext.tsx | 66 + .../MemoView/components/MemoBody.tsx | 60 + .../components/MemoCommentListView.tsx | 58 + .../MemoView/components/MemoHeader.tsx | 178 + .../MemoView/components/MemoSnippetLink.tsx | 34 + .../components/MemoView/components/index.ts | 3 + web/src/components/MemoView/constants.ts | 4 + web/src/components/MemoView/hooks/index.ts | 3 + .../MemoView/hooks/useImagePreview.ts | 55 + .../MemoView/hooks/useMemoActions.ts | 13 + .../MemoView/hooks/useMemoHandlers.ts | 40 + web/src/components/MemoView/index.ts | 2 + web/src/components/MemoView/types.ts | 23 + web/src/components/MemosLogo.tsx | 26 + web/src/components/MobileHeader.tsx | 46 + web/src/components/MotionPhotoPlayer.tsx | 120 + web/src/components/MotionPhotoPreview.tsx | 88 + web/src/components/Navigation.tsx | 134 + web/src/components/NavigationDrawer.tsx | 38 + .../PagedMemoList/PagedMemoList.tsx | 329 + web/src/components/PagedMemoList/index.ts | 4 + .../PagedMemoList/memoCardHeight.ts | 110 + web/src/components/PasswordSignInForm.tsx | 118 + .../Placeholder/TileSpriteStrip.tsx | 67 + web/src/components/Placeholder/index.tsx | 34 + web/src/components/Placeholder/messages.ts | 10 + .../components/Placeholder/pieces/DESIGN.md | 49 + .../Placeholder/pieces/EagleIdle.svg | 122 + .../Placeholder/pieces/OwlBlink.svg | 85 + .../Placeholder/pieces/ToucanIdle.svg | 87 + web/src/components/Placeholder/tileSprites.ts | 43 + web/src/components/PreviewImageDialog.tsx | 331 + web/src/components/RequiredBadge.tsx | 11 + web/src/components/SearchBar.tsx | 50 + web/src/components/Settings/AISection.tsx | 547 ++ .../Settings/AccessTokenSection.tsx | 147 + web/src/components/Settings/InfoChip.tsx | 40 + .../components/Settings/InstanceSection.tsx | 180 + .../Settings/LinkedIdentitySection.tsx | 208 + web/src/components/Settings/MemberSection.tsx | 229 + .../Settings/MemoRelatedSettings.tsx | 153 + .../components/Settings/MyAccountSection.tsx | 114 + .../Settings/NotificationSection.tsx | 308 + .../Settings/PreferencesSection.tsx | 118 + .../Settings/ResourceStatsSection.tsx | 104 + web/src/components/Settings/SSOSection.tsx | 207 + .../components/Settings/SectionMenuItem.tsx | 25 + web/src/components/Settings/SettingGroup.tsx | 36 + web/src/components/Settings/SettingList.tsx | 95 + web/src/components/Settings/SettingRow.tsx | 47 + .../components/Settings/SettingSection.tsx | 33 + web/src/components/Settings/SettingTable.tsx | 80 + .../components/Settings/StorageSection.tsx | 358 + web/src/components/Settings/TagsSection.tsx | 289 + .../components/Settings/WebhookSection.tsx | 144 + .../components/Settings/settingSections.ts | 150 + web/src/components/Settings/sso-display.ts | 123 + .../Settings/useInstanceSettingUpdater.ts | 36 + .../StatisticsView/MonthNavigator.tsx | 84 + .../StatisticsView/StatisticsView.tsx | 40 + web/src/components/StatisticsView/index.ts | 1 + web/src/components/TagTree.tsx | 159 + web/src/components/ThemeSelect.tsx | 55 + web/src/components/UpdateAccountDialog.tsx | 226 + .../UpdateCustomizedProfileDialog.tsx | 154 + web/src/components/UserAvatar.tsx | 23 + .../components/UserMemoMap/UserMemoMap.tsx | 170 + web/src/components/UserMemoMap/index.ts | 1 + web/src/components/UserMenu.tsx | 186 + web/src/components/VideoPoster.tsx | 82 + web/src/components/VisibilityIcon.tsx | 28 + web/src/components/kit/OverflowTip.tsx | 40 + web/src/components/kit/SquareDiv.tsx | 45 + web/src/components/map/LazyLocationPicker.tsx | 29 + web/src/components/map/LocationPicker.tsx | 246 + web/src/components/map/index.ts | 1 + web/src/components/map/map-utils.tsx | 41 + web/src/components/map/types.ts | 4 + web/src/components/map/useReverseGeocoding.ts | 39 + web/src/components/ui/README.md | 50 + web/src/components/ui/badge.tsx | 43 + web/src/components/ui/button.tsx | 48 + web/src/components/ui/checkbox.tsx | 28 + web/src/components/ui/dialog.tsx | 122 + web/src/components/ui/dropdown-menu.tsx | 268 + web/src/components/ui/input.tsx | 18 + web/src/components/ui/label.tsx | 18 + web/src/components/ui/popover.tsx | 47 + web/src/components/ui/radio-group.tsx | 27 + web/src/components/ui/select.tsx | 148 + web/src/components/ui/separator.tsx | 25 + web/src/components/ui/sheet.tsx | 124 + web/src/components/ui/switch.tsx | 25 + web/src/components/ui/tabs.tsx | 99 + web/src/components/ui/textarea.tsx | 17 + web/src/components/ui/tooltip.tsx | 49 + web/src/components/ui/visually-hidden.tsx | 19 + web/src/connect.ts | 203 + web/src/contexts/AuthContext.tsx | 196 + web/src/contexts/InstanceContext.tsx | 222 + web/src/contexts/MemoFilterContext.tsx | 160 + web/src/contexts/NewMemoContext.tsx | 29 + web/src/contexts/ViewContext.tsx | 120 + web/src/hooks/index.ts | 14 + web/src/hooks/useAsyncEffect.ts | 9 + web/src/hooks/useAttachmentLibrary.ts | 203 + web/src/hooks/useAttachmentQueries.ts | 100 + web/src/hooks/useCurrentUser.ts | 8 + web/src/hooks/useDateFilterNavigation.ts | 19 + web/src/hooks/useDebouncedEffect.ts | 16 + web/src/hooks/useDelayedFlag.ts | 23 + web/src/hooks/useDialog.ts | 75 + web/src/hooks/useFilteredMemoStats.ts | 98 + web/src/hooks/useInstanceQueries.ts | 105 + web/src/hooks/useLiveMemoRefresh.ts | 254 + web/src/hooks/useLoading.ts | 35 + web/src/hooks/useLocalStorage.ts | 48 + web/src/hooks/useMediaQuery.ts | 34 + web/src/hooks/useMemoDetailError.ts | 32 + web/src/hooks/useMemoFilters.ts | 97 + web/src/hooks/useMemoQueries.ts | 311 + web/src/hooks/useMemoShareQueries.ts | 101 + web/src/hooks/useMemoSorting.ts | 66 + web/src/hooks/useNavigateTo.ts | 24 + web/src/hooks/useTokenRefreshOnFocus.ts | 49 + web/src/hooks/useUserLocale.ts | 35 + web/src/hooks/useUserQueries.ts | 311 + web/src/hooks/useUserTheme.ts | 37 + web/src/i18n.ts | 96 + web/src/index.css | 33 + web/src/layouts/MainLayout.tsx | 88 + web/src/layouts/RootLayout.tsx | 80 + web/src/lib/browser.ts | 39 + web/src/lib/calendar-utils.ts | 23 + web/src/lib/color.ts | 21 + web/src/lib/constants.ts | 9 + web/src/lib/error.ts | 38 + web/src/lib/markdownStyles.ts | 81 + web/src/lib/query-client.ts | 29 + web/src/lib/resource-names.ts | 60 + web/src/lib/tag.ts | 64 + web/src/lib/utils.ts | 6 + web/src/locales/ar.json | 548 ++ web/src/locales/bg.json | 820 +++ web/src/locales/ca.json | 820 +++ web/src/locales/cs.json | 820 +++ web/src/locales/da.json | 820 +++ web/src/locales/de.json | 820 +++ web/src/locales/el.json | 820 +++ web/src/locales/en-GB.json | 820 +++ web/src/locales/en.json | 862 +++ web/src/locales/es.json | 820 +++ web/src/locales/et.json | 820 +++ web/src/locales/fa.json | 548 ++ web/src/locales/fi.json | 820 +++ web/src/locales/fr.json | 820 +++ web/src/locales/gl.json | 820 +++ web/src/locales/hi.json | 548 ++ web/src/locales/hr.json | 820 +++ web/src/locales/hu.json | 820 +++ web/src/locales/id.json | 548 ++ web/src/locales/it.json | 820 +++ web/src/locales/ja.json | 846 +++ web/src/locales/ka-GE.json | 820 +++ web/src/locales/ko.json | 548 ++ web/src/locales/lt.json | 820 +++ web/src/locales/lv.json | 820 +++ web/src/locales/mr.json | 548 ++ web/src/locales/nb.json | 820 +++ web/src/locales/nl.json | 820 +++ web/src/locales/pl.json | 852 +++ web/src/locales/pt-BR.json | 548 ++ web/src/locales/pt-PT.json | 820 +++ web/src/locales/ro.json | 820 +++ web/src/locales/ru.json | 820 +++ web/src/locales/sk.json | 820 +++ web/src/locales/sl.json | 820 +++ web/src/locales/sr.json | 820 +++ web/src/locales/sv.json | 820 +++ web/src/locales/th.json | 548 ++ web/src/locales/tr.json | 820 +++ web/src/locales/uk.json | 820 +++ web/src/locales/vi.json | 548 ++ web/src/locales/zh-Hans.json | 863 +++ web/src/locales/zh-Hant.json | 814 +++ web/src/main.tsx | 80 + web/src/pages/About.tsx | 88 + web/src/pages/AdminSignIn.tsx | 23 + web/src/pages/Archived.tsx | 35 + web/src/pages/Attachments.tsx | 221 + web/src/pages/AuthCallback.tsx | 149 + web/src/pages/Explore.tsx | 41 + web/src/pages/Home.tsx | 43 + web/src/pages/Inboxes.tsx | 102 + web/src/pages/MemoDetail.tsx | 143 + web/src/pages/NotFound.tsx | 15 + web/src/pages/PermissionDenied.tsx | 15 + web/src/pages/Setting.tsx | 138 + web/src/pages/Shortcuts.tsx | 578 ++ web/src/pages/SignIn.tsx | 123 + web/src/pages/SignUp.tsx | 162 + web/src/pages/UserProfile.tsx | 139 + web/src/router/guards.tsx | 67 + web/src/router/index.tsx | 121 + web/src/router/routes.ts | 15 + web/src/themes/COLOR_GUIDE.md | 295 + web/src/themes/default-dark.css | 49 + web/src/themes/default.css | 97 + web/src/themes/paper.css | 36 + web/src/types/common.d.ts | 1 + web/src/types/common.ts | 13 + web/src/types/i18n.d.ts | 1 + web/src/types/markdown.ts | 90 + web/src/types/modules/setting.d.ts | 1 + web/src/types/proto/api/v1/ai_service_pb.ts | 119 + .../proto/api/v1/attachment_service_pb.ts | 443 ++ web/src/types/proto/api/v1/auth_service_pb.ts | 300 + web/src/types/proto/api/v1/common_pb.ts | 90 + web/src/types/proto/api/v1/idp_service_pb.ts | 376 + .../types/proto/api/v1/instance_service_pb.ts | 1055 +++ web/src/types/proto/api/v1/memo_service_pb.ts | 1448 ++++ .../types/proto/api/v1/shortcut_service_pb.ts | 253 + web/src/types/proto/api/v1/user_service_pb.ts | 2012 ++++++ .../types/proto/google/api/annotations_pb.ts | 39 + web/src/types/proto/google/api/client_pb.ts | 953 +++ .../proto/google/api/field_behavior_pb.ts | 157 + web/src/types/proto/google/api/http_pb.ts | 474 ++ .../types/proto/google/api/launch_stage_pb.ts | 118 + web/src/types/proto/google/api/resource_pb.ts | 354 + web/src/types/proto/google/type/color_pb.ts | 204 + web/src/types/relative-time-element.d.ts | 15 + web/src/types/statistics.ts | 17 + web/src/types/view.d.ts | 5 + web/src/utils/attachment.ts | 76 + web/src/utils/auth-redirect.ts | 53 + web/src/utils/format.ts | 76 + web/src/utils/i18n.ts | 157 + web/src/utils/markdown-manipulation.ts | 201 + web/src/utils/markdown-task-actions.ts | 147 + web/src/utils/media-item.ts | 192 + web/src/utils/memo.ts | 27 + web/src/utils/mention-grammar.ts | 30 + web/src/utils/oauth.ts | 160 + web/src/utils/redirect-safety.ts | 89 + .../utils/rehype-plugins/rehype-heading-id.ts | 37 + .../remark-plugins/remark-disable-setext.ts | 14 + .../utils/remark-plugins/remark-mention.ts | 97 + .../remark-plugins/remark-preserve-type.ts | 22 + .../remark-split-mixed-task-lists.ts | 67 + web/src/utils/remark-plugins/remark-tag.ts | 192 + web/src/utils/tag-grammar.ts | 37 + web/src/utils/theme.ts | 262 + web/src/utils/user.ts | 5 + web/src/utils/uuid.ts | 5 + web/tests/about-page.test.tsx | 34 + web/tests/activity-calendar-tooltip.test.ts | 26 + web/tests/auth-redirect.test.ts | 115 + .../calendar-cell-empty-clickable.test.tsx | 50 + web/tests/column-count.test.ts | 27 + web/tests/column-grid-planner.test.ts | 36 + web/tests/column-grid.test.tsx | 44 + web/tests/derive-default-create-time.test.ts | 75 + web/tests/editor-controller.test.ts | 32 + web/tests/editor-decorations.test.ts | 16 + web/tests/editor-formatting.test.ts | 56 + web/tests/editor-heading-decorations.test.ts | 19 + web/tests/editor-keys.test.ts | 125 + web/tests/editor-tag-autocomplete.test.ts | 25 + web/tests/editor.test.tsx | 64 + web/tests/filtered-memo-stats.test.ts | 109 + web/tests/formatting-toolbar.test.tsx | 79 + web/tests/guards.test.tsx | 192 + web/tests/hoist-new-memo.test.ts | 33 + web/tests/hooks.test.tsx | 194 + web/tests/i18n-locale-search.test.ts | 24 + web/tests/locale-picker.test.tsx | 14 + web/tests/location-picker.test.tsx | 73 + web/tests/markdown-task-actions.test.ts | 38 + web/tests/memo-body-compact.test.tsx | 100 + web/tests/memo-card-height.test.ts | 63 + web/tests/memo-content-link-preview.test.tsx | 57 + web/tests/memo-content-list.test.tsx | 77 + web/tests/memo-content-paragraph.test.tsx | 34 + web/tests/memo-content-security.test.tsx | 87 + web/tests/memo-editor-cache.test.ts | 57 + web/tests/memo-editor-extensions.test.ts | 74 + web/tests/memo-share-image.test.ts | 134 + web/tests/mermaid-block.test.tsx | 33 + web/tests/oauth.test.ts | 44 + web/tests/paged-memo-list.test.tsx | 130 + web/tests/password-sign-in-form.test.tsx | 30 + web/tests/placeholder-component.test.tsx | 85 + web/tests/placeholder-pool.test.ts | 36 + web/tests/preview-image-dialog.test.tsx | 118 + web/tests/redirect-safety.test.ts | 104 + web/tests/remark-tag.test.tsx | 90 + web/tests/router-config.test.tsx | 69 + web/tests/setup.ts | 83 + web/tests/toolbar-compact-width.test.ts | 17 + web/tests/use-auto-save.test.tsx | 85 + web/tests/video-poster.test.tsx | 47 + web/tests/view-context-columns.test.tsx | 46 + web/tsconfig.json | 24 + web/vite.config.mts | 63 + web/vitest.config.mts | 28 + 1040 files changed, 200957 insertions(+) create mode 100644 .dockerignore create mode 100644 .github/FUNDING.yml create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/workflows/backend-tests.yml create mode 100644 .github/workflows/build-canary-image.yml create mode 100644 .github/workflows/demo-deploy.yml create mode 100644 .github/workflows/frontend-tests.yml create mode 100644 .github/workflows/proto-linter.yml create mode 100644 .github/workflows/release-please.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/stale.yml create mode 100644 .gitignore create mode 100644 .golangci.yaml create mode 100644 .release-please-manifest.json create mode 100644 AGENTS.md create mode 100644 CHANGELOG.md create mode 100644 CODEOWNERS create mode 100644 LICENSE create mode 100644 README.md create mode 100644 README.wehub.md create mode 100644 SECURITY.md create mode 100644 docs/identity-provider-bootstrap.md create mode 100644 docs/plans/2026-03-23-memo-detail-outline/definition.md create mode 100644 docs/plans/2026-03-23-memo-detail-outline/plan.md create mode 100644 docs/plans/2026-03-23-tag-blur-attribute/definition.md create mode 100644 docs/plans/2026-03-23-tag-blur-attribute/execution.md create mode 100644 docs/plans/2026-03-23-tag-blur-attribute/plan.md create mode 100644 docs/plans/2026-03-24-user-resource-identifiers/definition.md create mode 100644 docs/plans/2026-03-24-user-resource-identifiers/design.md create mode 100644 docs/plans/2026-03-24-user-resource-identifiers/execution.md create mode 100644 docs/plans/2026-03-24-user-resource-identifiers/plan.md create mode 100644 docs/plans/2026-03-31-quick-voice-input/definition.md create mode 100644 docs/plans/2026-03-31-quick-voice-input/design.md create mode 100644 docs/plans/2026-03-31-quick-voice-input/execution.md create mode 100644 docs/plans/2026-03-31-quick-voice-input/plan.md create mode 100644 docs/plans/2026-04-06-memo-mentions/definition.md create mode 100644 docs/plans/2026-04-06-memo-mentions/design.md create mode 100644 docs/plans/2026-04-06-memo-mentions/execution.md create mode 100644 docs/plans/2026-04-06-memo-mentions/plan.md create mode 100644 docs/plans/2026-04-21-sso-user-identity-linkage/definition.md create mode 100644 docs/plans/2026-04-21-sso-user-identity-linkage/design.md create mode 100644 docs/plans/2026-04-21-sso-user-identity-linkage/execution.md create mode 100644 docs/plans/2026-04-21-sso-user-identity-linkage/plan.md create mode 100644 docs/superpowers/plans/2026-05-02-activity-calendar-time-basis.md create mode 100644 docs/superpowers/plans/2026-05-02-calendar-date-prefill.md create mode 100644 docs/superpowers/plans/2026-05-02-stt-audiollm-split.md create mode 100644 docs/superpowers/plans/2026-05-02-transcription-settings.md create mode 100644 docs/superpowers/plans/2026-05-12-first-screen-lazy-heavy-deps.md create mode 100644 docs/superpowers/plans/2026-05-12-placeholder-component.md create mode 100644 docs/superpowers/plans/2026-05-31-remove-react-use.md create mode 100644 docs/superpowers/plans/2026-06-08-openapi-mcp-support.md create mode 100644 docs/superpowers/plans/2026-06-11-markdown-wysiwyg-editor.md create mode 100644 docs/superpowers/plans/2026-06-15-cel-filter-surface-expansion.md create mode 100644 docs/superpowers/specs/2026-05-02-activity-calendar-time-basis-design.md create mode 100644 docs/superpowers/specs/2026-05-02-calendar-date-prefill-design.md create mode 100644 docs/superpowers/specs/2026-05-02-stt-audiollm-split-design.md create mode 100644 docs/superpowers/specs/2026-05-02-transcription-settings-design.md create mode 100644 docs/superpowers/specs/2026-05-12-first-screen-lazy-heavy-deps-design.md create mode 100644 docs/superpowers/specs/2026-05-12-placeholder-component-design.md create mode 100644 docs/superpowers/specs/2026-05-31-remove-react-use-design.md create mode 100644 docs/superpowers/specs/2026-06-08-openapi-mcp-support-design.md create mode 100644 docs/superpowers/specs/2026-06-11-markdown-wysiwyg-editor-design.md create mode 100644 docs/superpowers/specs/2026-06-15-cel-filter-surface-expansion-design.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/ai/ai.go create mode 100644 internal/ai/audio/webm.go create mode 100644 internal/ai/audio/webm_test.go create mode 100644 internal/ai/audiollm/audiollm.go create mode 100644 internal/ai/audiollm/gemini/gemini.go create mode 100644 internal/ai/audiollm/gemini/gemini_test.go create mode 100644 internal/ai/audiollm/options.go create mode 100644 internal/ai/errors.go create mode 100644 internal/ai/models.go create mode 100644 internal/ai/resolver.go create mode 100644 internal/ai/stt/openai/openai.go create mode 100644 internal/ai/stt/openai/openai_test.go create mode 100644 internal/ai/stt/options.go create mode 100644 internal/ai/stt/stt.go create mode 100644 internal/base/resource_name.go create mode 100644 internal/base/resource_name_test.go create mode 100644 internal/email/README.md create mode 100644 internal/email/client.go create mode 100644 internal/email/client_test.go create mode 100644 internal/email/config.go create mode 100644 internal/email/config_test.go create mode 100644 internal/email/doc.go create mode 100644 internal/email/email.go create mode 100644 internal/email/email_test.go create mode 100644 internal/email/message.go create mode 100644 internal/email/message_test.go create mode 100644 internal/filter/MAINTENANCE.md create mode 100644 internal/filter/README.md create mode 100644 internal/filter/engine.go create mode 100644 internal/filter/engine_test.go create mode 100644 internal/filter/functions_test.go create mode 100644 internal/filter/helpers.go create mode 100644 internal/filter/ir.go create mode 100644 internal/filter/parser.go create mode 100644 internal/filter/render.go create mode 100644 internal/filter/schema.go create mode 100644 internal/filter/time_test.go create mode 100644 internal/httpgetter/html_meta.go create mode 100644 internal/httpgetter/html_meta_test.go create mode 100644 internal/httpgetter/http_getter.go create mode 100644 internal/httpgetter/image.go create mode 100644 internal/httpgetter/util.go create mode 100644 internal/idp/idp.go create mode 100644 internal/idp/oauth2/oauth2.go create mode 100644 internal/idp/oauth2/oauth2_test.go create mode 100644 internal/markdown/ast/mention.go create mode 100644 internal/markdown/ast/tag.go create mode 100644 internal/markdown/extensions/mention.go create mode 100644 internal/markdown/extensions/tag.go create mode 100644 internal/markdown/markdown.go create mode 100644 internal/markdown/markdown_test.go create mode 100644 internal/markdown/parser/mention.go create mode 100644 internal/markdown/parser/tag.go create mode 100644 internal/markdown/parser/tag_test.go create mode 100644 internal/markdown/renderer/markdown_renderer.go create mode 100644 internal/markdown/renderer/markdown_renderer_test.go create mode 100644 internal/motionphoto/motionphoto.go create mode 100644 internal/motionphoto/motionphoto_test.go create mode 100644 internal/profile/profile.go create mode 100644 internal/profile/profile_test.go create mode 100644 internal/scheduler/README.md create mode 100644 internal/scheduler/doc.go create mode 100644 internal/scheduler/example_test.go create mode 100644 internal/scheduler/integration_test.go create mode 100644 internal/scheduler/job.go create mode 100644 internal/scheduler/job_test.go create mode 100644 internal/scheduler/middleware.go create mode 100644 internal/scheduler/middleware_test.go create mode 100644 internal/scheduler/parser.go create mode 100644 internal/scheduler/parser_test.go create mode 100644 internal/scheduler/scheduler.go create mode 100644 internal/scheduler/scheduler_test.go create mode 100644 internal/storage/s3/s3.go create mode 100644 internal/testutil/motionphoto.go create mode 100644 internal/util/util.go create mode 100644 internal/util/util_test.go create mode 100644 internal/version/version.go create mode 100644 internal/version/version_test.go create mode 100644 internal/webhook/validate.go create mode 100644 internal/webhook/webhook.go create mode 100644 internal/webhook/webhook_test.go create mode 100644 proto/README.md create mode 100644 proto/api/v1/README.md create mode 100644 proto/api/v1/ai_service.proto create mode 100644 proto/api/v1/attachment_service.proto create mode 100644 proto/api/v1/auth_service.proto create mode 100644 proto/api/v1/common.proto create mode 100644 proto/api/v1/idp_service.proto create mode 100644 proto/api/v1/instance_service.proto create mode 100644 proto/api/v1/memo_service.proto create mode 100644 proto/api/v1/shortcut_service.proto create mode 100644 proto/api/v1/user_service.proto create mode 100644 proto/buf.gen.yaml create mode 100644 proto/buf.lock create mode 100644 proto/buf.yaml create mode 100644 proto/gen/api/v1/ai_service.pb.go create mode 100644 proto/gen/api/v1/ai_service.pb.gw.go create mode 100644 proto/gen/api/v1/ai_service_grpc.pb.go create mode 100644 proto/gen/api/v1/apiv1connect/ai_service.connect.go create mode 100644 proto/gen/api/v1/apiv1connect/attachment_service.connect.go create mode 100644 proto/gen/api/v1/apiv1connect/auth_service.connect.go create mode 100644 proto/gen/api/v1/apiv1connect/idp_service.connect.go create mode 100644 proto/gen/api/v1/apiv1connect/instance_service.connect.go create mode 100644 proto/gen/api/v1/apiv1connect/memo_service.connect.go create mode 100644 proto/gen/api/v1/apiv1connect/shortcut_service.connect.go create mode 100644 proto/gen/api/v1/apiv1connect/user_service.connect.go create mode 100644 proto/gen/api/v1/attachment_service.pb.go create mode 100644 proto/gen/api/v1/attachment_service.pb.gw.go create mode 100644 proto/gen/api/v1/attachment_service_grpc.pb.go create mode 100644 proto/gen/api/v1/auth_service.pb.go create mode 100644 proto/gen/api/v1/auth_service.pb.gw.go create mode 100644 proto/gen/api/v1/auth_service_grpc.pb.go create mode 100644 proto/gen/api/v1/common.pb.go create mode 100644 proto/gen/api/v1/idp_service.pb.go create mode 100644 proto/gen/api/v1/idp_service.pb.gw.go create mode 100644 proto/gen/api/v1/idp_service_grpc.pb.go create mode 100644 proto/gen/api/v1/instance_service.pb.go create mode 100644 proto/gen/api/v1/instance_service.pb.gw.go create mode 100644 proto/gen/api/v1/instance_service_grpc.pb.go create mode 100644 proto/gen/api/v1/memo_service.pb.go create mode 100644 proto/gen/api/v1/memo_service.pb.gw.go create mode 100644 proto/gen/api/v1/memo_service_grpc.pb.go create mode 100644 proto/gen/api/v1/shortcut_service.pb.go create mode 100644 proto/gen/api/v1/shortcut_service.pb.gw.go create mode 100644 proto/gen/api/v1/shortcut_service_grpc.pb.go create mode 100644 proto/gen/api/v1/user_service.pb.go create mode 100644 proto/gen/api/v1/user_service.pb.gw.go create mode 100644 proto/gen/api/v1/user_service_grpc.pb.go create mode 100644 proto/gen/openapi.yaml create mode 100644 proto/gen/store/attachment.pb.go create mode 100644 proto/gen/store/idp.pb.go create mode 100644 proto/gen/store/inbox.pb.go create mode 100644 proto/gen/store/instance_setting.pb.go create mode 100644 proto/gen/store/memo.pb.go create mode 100644 proto/gen/store/user_setting.pb.go create mode 100644 proto/openapi_embed.go create mode 100644 proto/store/attachment.proto create mode 100644 proto/store/idp.proto create mode 100644 proto/store/inbox.proto create mode 100644 proto/store/instance_setting.proto create mode 100644 proto/store/memo.proto create mode 100644 proto/store/user_setting.proto create mode 100644 release-please-config.json create mode 100644 scripts/Dockerfile create mode 100755 scripts/build.sh create mode 100644 scripts/compose.yaml create mode 100755 scripts/entrypoint.sh create mode 100755 scripts/entrypoint_test.sh create mode 100755 scripts/install.sh create mode 100644 server/auth/authenticator.go create mode 100644 server/auth/authenticator_test.go create mode 100644 server/auth/context.go create mode 100644 server/auth/extract.go create mode 100644 server/auth/token.go create mode 100644 server/auth/token_test.go create mode 100644 server/cors.go create mode 100644 server/cors_test.go create mode 100644 server/notification/email.go create mode 100644 server/router/api/v1/acl_config.go create mode 100644 server/router/api/v1/acl_config_test.go create mode 100644 server/router/api/v1/ai_service.go create mode 100644 server/router/api/v1/attachment_exif_test.go create mode 100644 server/router/api/v1/attachment_motion.go create mode 100644 server/router/api/v1/attachment_service.go create mode 100644 server/router/api/v1/attachment_service_image.go create mode 100644 server/router/api/v1/attachment_service_storage.go create mode 100644 server/router/api/v1/auth_service.go create mode 100644 server/router/api/v1/auth_service_client_info_test.go create mode 100644 server/router/api/v1/auth_service_session.go create mode 100644 server/router/api/v1/auth_service_sso.go create mode 100644 server/router/api/v1/authz.go create mode 100644 server/router/api/v1/authz_test.go create mode 100644 server/router/api/v1/common.go create mode 100644 server/router/api/v1/common_test.go create mode 100644 server/router/api/v1/connect_handler.go create mode 100644 server/router/api/v1/connect_interceptors.go create mode 100644 server/router/api/v1/connect_interceptors_test.go create mode 100644 server/router/api/v1/connect_services.go create mode 100644 server/router/api/v1/header_carrier.go create mode 100644 server/router/api/v1/health_service.go create mode 100644 server/router/api/v1/idp_service.go create mode 100644 server/router/api/v1/instance_service.go create mode 100644 server/router/api/v1/instance_service_converters.go create mode 100644 server/router/api/v1/instance_service_validation.go create mode 100644 server/router/api/v1/instance_stats.go create mode 100644 server/router/api/v1/instance_stats_test.go create mode 100644 server/router/api/v1/link_metadata_test.go create mode 100644 server/router/api/v1/memo_attachment_service.go create mode 100644 server/router/api/v1/memo_batch_helpers.go create mode 100644 server/router/api/v1/memo_comment_relations_test.go create mode 100644 server/router/api/v1/memo_mention_helpers.go create mode 100644 server/router/api/v1/memo_relation_service.go create mode 100644 server/router/api/v1/memo_service.go create mode 100644 server/router/api/v1/memo_service_comments.go create mode 100644 server/router/api/v1/memo_service_converter.go create mode 100644 server/router/api/v1/memo_service_filter.go create mode 100644 server/router/api/v1/memo_service_link_metadata.go create mode 100644 server/router/api/v1/memo_service_query.go create mode 100644 server/router/api/v1/memo_service_webhooks.go create mode 100644 server/router/api/v1/memo_share_service.go create mode 100644 server/router/api/v1/memo_update_helpers.go create mode 100644 server/router/api/v1/notification_email.go create mode 100644 server/router/api/v1/reaction_service.go create mode 100644 server/router/api/v1/resource_name.go create mode 100644 server/router/api/v1/shortcut_service.go create mode 100644 server/router/api/v1/sse_event_helpers.go create mode 100644 server/router/api/v1/sse_handler.go create mode 100644 server/router/api/v1/sse_hub.go create mode 100644 server/router/api/v1/sse_hub_test.go create mode 100644 server/router/api/v1/sse_service_test.go create mode 100644 server/router/api/v1/sso_username.go create mode 100644 server/router/api/v1/test/ai_service_test.go create mode 100644 server/router/api/v1/test/attachment_service_test.go create mode 100644 server/router/api/v1/test/auth_service_test.go create mode 100644 server/router/api/v1/test/auth_test.go create mode 100644 server/router/api/v1/test/authz_test.go create mode 100644 server/router/api/v1/test/idp_service_test.go create mode 100644 server/router/api/v1/test/instance_admin_cache_test.go create mode 100644 server/router/api/v1/test/instance_service_test.go create mode 100644 server/router/api/v1/test/instance_stats_test.go create mode 100644 server/router/api/v1/test/memo_attachment_service_test.go create mode 100644 server/router/api/v1/test/memo_relation_service_test.go create mode 100644 server/router/api/v1/test/memo_service_benchmark_test.go create mode 100644 server/router/api/v1/test/memo_service_test.go create mode 100644 server/router/api/v1/test/memo_share_service_test.go create mode 100644 server/router/api/v1/test/reaction_service_test.go create mode 100644 server/router/api/v1/test/shortcut_service_test.go create mode 100644 server/router/api/v1/test/sse_handler_test.go create mode 100644 server/router/api/v1/test/test_helper.go create mode 100644 server/router/api/v1/test/user_email_visibility_test.go create mode 100644 server/router/api/v1/test/user_notification_test.go create mode 100644 server/router/api/v1/test/user_resource_name_test.go create mode 100644 server/router/api/v1/test/user_search_test.go create mode 100644 server/router/api/v1/test/user_service_delete_test.go create mode 100644 server/router/api/v1/test/user_service_email_username_test.go create mode 100644 server/router/api/v1/test/user_service_pagination_test.go create mode 100644 server/router/api/v1/test/user_service_registration_test.go create mode 100644 server/router/api/v1/test/user_service_stats_test.go create mode 100644 server/router/api/v1/test/user_setting_test.go create mode 100644 server/router/api/v1/user_resource_name.go create mode 100644 server/router/api/v1/user_resource_name_test.go create mode 100644 server/router/api/v1/user_service.go create mode 100644 server/router/api/v1/user_service_access_tokens.go create mode 100644 server/router/api/v1/user_service_converters.go create mode 100644 server/router/api/v1/user_service_filter.go create mode 100644 server/router/api/v1/user_service_identities.go create mode 100644 server/router/api/v1/user_service_notifications.go create mode 100644 server/router/api/v1/user_service_settings.go create mode 100644 server/router/api/v1/user_service_stats.go create mode 100644 server/router/api/v1/user_service_webhooks.go create mode 100644 server/router/api/v1/user_webhook_test.go create mode 100644 server/router/api/v1/v1.go create mode 100644 server/router/fileserver/README.md create mode 100644 server/router/fileserver/fileserver.go create mode 100644 server/router/fileserver/fileserver_test.go create mode 100644 server/router/frontend/frontend.go create mode 100644 server/router/frontend/frontend_test.go create mode 100644 server/router/mcp/README.md create mode 100644 server/router/mcp/adapter.go create mode 100644 server/router/mcp/adapter_test.go create mode 100644 server/router/mcp/catalog.go create mode 100644 server/router/mcp/catalog_test.go create mode 100644 server/router/mcp/evals/README.md create mode 100644 server/router/mcp/evals/memos_eval.xml create mode 100644 server/router/mcp/openapi.go create mode 100644 server/router/mcp/openapi_test.go create mode 100644 server/router/mcp/origin.go create mode 100644 server/router/mcp/result.go create mode 100644 server/router/mcp/service.go create mode 100644 server/router/mcp/service_test.go create mode 100644 server/router/mcp/validation.go create mode 100644 server/router/mcp/validation_test.go create mode 100644 server/router/rss/rss.go create mode 100644 server/router/rss/rss_test.go create mode 100644 server/runner/memopayload/runner.go create mode 100644 server/runner/s3presign/runner.go create mode 100644 server/runner/s3presign/runner_test.go create mode 100644 server/server.go create mode 100644 store/attachment.go create mode 100644 store/cache.go create mode 100644 store/cache/cache.go create mode 100644 store/cache/cache_test.go create mode 100644 store/common.go create mode 100644 store/db/db.go create mode 100644 store/db/mysql/attachment.go create mode 100644 store/db/mysql/common.go create mode 100644 store/db/mysql/idp.go create mode 100644 store/db/mysql/inbox.go create mode 100644 store/db/mysql/instance_setting.go create mode 100644 store/db/mysql/memo.go create mode 100644 store/db/mysql/memo_relation.go create mode 100644 store/db/mysql/memo_share.go create mode 100644 store/db/mysql/mysql.go create mode 100644 store/db/mysql/reaction.go create mode 100644 store/db/mysql/user.go create mode 100644 store/db/mysql/user_delete.go create mode 100644 store/db/mysql/user_delete_test.go create mode 100644 store/db/mysql/user_identity.go create mode 100644 store/db/mysql/user_setting.go create mode 100644 store/db/postgres/attachment.go create mode 100644 store/db/postgres/common.go create mode 100644 store/db/postgres/idp.go create mode 100644 store/db/postgres/inbox.go create mode 100644 store/db/postgres/instance_setting.go create mode 100644 store/db/postgres/memo.go create mode 100644 store/db/postgres/memo_relation.go create mode 100644 store/db/postgres/memo_share.go create mode 100644 store/db/postgres/postgres.go create mode 100644 store/db/postgres/reaction.go create mode 100644 store/db/postgres/user.go create mode 100644 store/db/postgres/user_delete.go create mode 100644 store/db/postgres/user_identity.go create mode 100644 store/db/postgres/user_setting.go create mode 100644 store/db/postgres/user_setting_test.go create mode 100644 store/db/sqlite/attachment.go create mode 100644 store/db/sqlite/common.go create mode 100644 store/db/sqlite/functions.go create mode 100644 store/db/sqlite/functions_test.go create mode 100644 store/db/sqlite/idp.go create mode 100644 store/db/sqlite/inbox.go create mode 100644 store/db/sqlite/instance_setting.go create mode 100644 store/db/sqlite/memo.go create mode 100644 store/db/sqlite/memo_relation.go create mode 100644 store/db/sqlite/memo_share.go create mode 100644 store/db/sqlite/reaction.go create mode 100644 store/db/sqlite/sqlite.go create mode 100644 store/db/sqlite/user.go create mode 100644 store/db/sqlite/user_delete.go create mode 100644 store/db/sqlite/user_identity.go create mode 100644 store/db/sqlite/user_setting.go create mode 100644 store/demo_seed_test.go create mode 100644 store/driver.go create mode 100644 store/idp.go create mode 100644 store/idp_bootstrap.go create mode 100644 store/idp_bootstrap_test.go create mode 100644 store/inbox.go create mode 100644 store/instance_setting.go create mode 100644 store/memo.go create mode 100644 store/memo_relation.go create mode 100644 store/memo_share.go create mode 100644 store/migration/mysql/0.17/00__inbox.sql create mode 100644 store/migration/mysql/0.17/01__delete_activity.sql create mode 100644 store/migration/mysql/0.18/00__extend_text.sql create mode 100644 store/migration/mysql/0.18/01__webhook.sql create mode 100644 store/migration/mysql/0.18/02__user_setting.sql create mode 100644 store/migration/mysql/0.19/00__add_resource_name.sql create mode 100644 store/migration/mysql/0.20/00__reaction.sql create mode 100644 store/migration/mysql/0.21/00__user_description.sql create mode 100644 store/migration/mysql/0.21/01__rename_uid.sql create mode 100644 store/migration/mysql/0.22/00__resource_storage_type.sql create mode 100644 store/migration/mysql/0.22/01__memo_tags.sql create mode 100644 store/migration/mysql/0.22/02__memo_payload.sql create mode 100644 store/migration/mysql/0.22/03__drop_tag.sql create mode 100644 store/migration/mysql/0.23/00__reactions.sql create mode 100644 store/migration/mysql/0.24/00__memo.sql create mode 100644 store/migration/mysql/0.24/01__memo_pinned.sql create mode 100644 store/migration/mysql/0.24/02__s3_reference_length.sql create mode 100644 store/migration/mysql/0.25/00__remove_webhook.sql create mode 100644 store/migration/mysql/0.26/00__rename_resource_to_attachment.sql create mode 100644 store/migration/mysql/0.26/01__drop_memo_organizer.sql create mode 100644 store/migration/mysql/0.26/02__migrate_host_to_admin.sql create mode 100644 store/migration/mysql/0.27/00__migrate_storage_setting.sql create mode 100644 store/migration/mysql/0.27/01__add_idp_uid.sql create mode 100644 store/migration/mysql/0.27/02__migrate_inbox_message_payload.sql create mode 100644 store/migration/mysql/0.27/03__drop_activity.sql create mode 100644 store/migration/mysql/0.27/04__memo_share.sql create mode 100644 store/migration/mysql/0.28/00__user_identity.sql create mode 100644 store/migration/mysql/0.30/00__user_tag_setting.sql create mode 100644 store/migration/mysql/LATEST.sql create mode 100644 store/migration/postgres/0.19/00__add_resource_name.sql create mode 100644 store/migration/postgres/0.20/00__reaction.sql create mode 100644 store/migration/postgres/0.21/00__user_description.sql create mode 100644 store/migration/postgres/0.21/01__rename_uid.sql create mode 100644 store/migration/postgres/0.22/00__resource_storage_type.sql create mode 100644 store/migration/postgres/0.22/01__memo_tags.sql create mode 100644 store/migration/postgres/0.22/02__memo_payload.sql create mode 100644 store/migration/postgres/0.22/03__drop_tag.sql create mode 100644 store/migration/postgres/0.23/00__reactions.sql create mode 100644 store/migration/postgres/0.24/00__memo.sql create mode 100644 store/migration/postgres/0.24/01__memo_pinned.sql create mode 100644 store/migration/postgres/0.25/00__remove_webhook.sql create mode 100644 store/migration/postgres/0.26/00__rename_resource_to_attachment.sql create mode 100644 store/migration/postgres/0.26/01__drop_memo_organizer.sql create mode 100644 store/migration/postgres/0.26/02__migrate_host_to_admin.sql create mode 100644 store/migration/postgres/0.27/00__migrate_storage_setting.sql create mode 100644 store/migration/postgres/0.27/01__add_idp_uid.sql create mode 100644 store/migration/postgres/0.27/02__migrate_inbox_message_payload.sql create mode 100644 store/migration/postgres/0.27/03__drop_activity.sql create mode 100644 store/migration/postgres/0.27/04__memo_share.sql create mode 100644 store/migration/postgres/0.28/00__user_identity.sql create mode 100644 store/migration/postgres/0.30/00__user_tag_setting.sql create mode 100644 store/migration/postgres/LATEST.sql create mode 100644 store/migration/sqlite/0.10/00__activity.sql create mode 100644 store/migration/sqlite/0.11/00__user_avatar.sql create mode 100644 store/migration/sqlite/0.11/01__idp.sql create mode 100644 store/migration/sqlite/0.11/02__storage.sql create mode 100644 store/migration/sqlite/0.12/00__user_setting.sql create mode 100644 store/migration/sqlite/0.12/01__system_setting.sql create mode 100644 store/migration/sqlite/0.12/03__resource_internal_path.sql create mode 100644 store/migration/sqlite/0.12/04__resource_public_id.sql create mode 100644 store/migration/sqlite/0.13/00__memo_relation.sql create mode 100644 store/migration/sqlite/0.13/01__remove_memo_organizer_id.sql create mode 100644 store/migration/sqlite/0.14/00__drop_resource_public_id.sql create mode 100644 store/migration/sqlite/0.14/01__create_indexes.sql create mode 100644 store/migration/sqlite/0.15/00__drop_user_open_id.sql create mode 100644 store/migration/sqlite/0.16/00__add_memo_id_to_resource.sql create mode 100644 store/migration/sqlite/0.16/01__drop_shortcut_table.sql create mode 100644 store/migration/sqlite/0.17/00__inbox.sql create mode 100644 store/migration/sqlite/0.17/01__delete_activities.sql create mode 100644 store/migration/sqlite/0.18/00__webhook.sql create mode 100644 store/migration/sqlite/0.18/01__user_setting.sql create mode 100644 store/migration/sqlite/0.19/00__add_resource_name.sql create mode 100644 store/migration/sqlite/0.2/00__user_role.sql create mode 100644 store/migration/sqlite/0.2/01__memo_visibility.sql create mode 100644 store/migration/sqlite/0.20/00__reaction.sql create mode 100644 store/migration/sqlite/0.21/00__user_description.sql create mode 100644 store/migration/sqlite/0.21/01__rename_uid.sql create mode 100644 store/migration/sqlite/0.22/00__resource_storage_type.sql create mode 100644 store/migration/sqlite/0.22/01__memo_tags.sql create mode 100644 store/migration/sqlite/0.22/02__memo_payload.sql create mode 100644 store/migration/sqlite/0.22/03__drop_tag.sql create mode 100644 store/migration/sqlite/0.23/00__reactions.sql create mode 100644 store/migration/sqlite/0.24/00__memo.sql create mode 100644 store/migration/sqlite/0.24/01__memo_pinned.sql create mode 100644 store/migration/sqlite/0.25/00__remove_webhook.sql create mode 100644 store/migration/sqlite/0.26/00__rename_resource_to_attachment.sql create mode 100644 store/migration/sqlite/0.26/01__drop_memo_organizer.sql create mode 100644 store/migration/sqlite/0.26/02__drop_indexes.sql create mode 100644 store/migration/sqlite/0.26/03__alter_user_role.sql create mode 100644 store/migration/sqlite/0.26/04__migrate_host_to_admin.sql create mode 100644 store/migration/sqlite/0.27/00__migrate_storage_setting.sql create mode 100644 store/migration/sqlite/0.27/01__add_idp_uid.sql create mode 100644 store/migration/sqlite/0.27/02__migrate_inbox_message_payload.sql create mode 100644 store/migration/sqlite/0.27/03__drop_activity.sql create mode 100644 store/migration/sqlite/0.27/04__memo_share.sql create mode 100644 store/migration/sqlite/0.28/00__user_identity.sql create mode 100644 store/migration/sqlite/0.3/00__memo_visibility_protected.sql create mode 100644 store/migration/sqlite/0.30/00__user_tag_setting.sql create mode 100644 store/migration/sqlite/0.4/00__user_setting.sql create mode 100644 store/migration/sqlite/0.5/00__regenerate_foreign_keys.sql create mode 100644 store/migration/sqlite/0.5/01__memo_resource.sql create mode 100644 store/migration/sqlite/0.5/02__system_setting.sql create mode 100644 store/migration/sqlite/0.5/03__resource_extermal_link.sql create mode 100644 store/migration/sqlite/0.6/00__recreate_triggers.sql create mode 100644 store/migration/sqlite/0.7/00__remove_fk.sql create mode 100644 store/migration/sqlite/0.7/01__remove_triggers.sql create mode 100644 store/migration/sqlite/0.8/00__migration_history.sql create mode 100644 store/migration/sqlite/0.8/01__user_username.sql create mode 100644 store/migration/sqlite/0.9/00__tag.sql create mode 100644 store/migration/sqlite/LATEST.sql create mode 100644 store/migrator.go create mode 100644 store/reaction.go create mode 100644 store/seed/sqlite/01__dump.sql create mode 100644 store/store.go create mode 100644 store/test/README.md create mode 100644 store/test/attachment_filter_test.go create mode 100644 store/test/attachment_test.go create mode 100644 store/test/containers.go create mode 100644 store/test/database_size_test.go create mode 100644 store/test/filter_helpers_test.go create mode 100644 store/test/idp_test.go create mode 100644 store/test/inbox_test.go create mode 100644 store/test/instance_setting_test.go create mode 100644 store/test/main_test.go create mode 100644 store/test/memo_filter_functions_test.go create mode 100644 store/test/memo_filter_test.go create mode 100644 store/test/memo_relation_test.go create mode 100644 store/test/memo_test.go create mode 100644 store/test/migrator_test.go create mode 100644 store/test/migrator_upgrade_test.go create mode 100644 store/test/reaction_test.go create mode 100644 store/test/store.go create mode 100644 store/test/user_delete_test.go create mode 100644 store/test/user_identity_test.go create mode 100644 store/test/user_setting_test.go create mode 100644 store/test/user_test.go create mode 100644 store/user.go create mode 100644 store/user_delete.go create mode 100644 store/user_identity.go create mode 100644 store/user_setting.go create mode 100644 web/.gitignore create mode 100644 web/biome.json create mode 100644 web/components.json create mode 100644 web/docs/auth-architecture.md create mode 100644 web/index.html create mode 100644 web/package.json create mode 100644 web/pnpm-lock.yaml create mode 100644 web/pnpm-workspace.yaml create mode 100644 web/public/android-chrome-192x192.png create mode 100644 web/public/android-chrome-512x512.png create mode 100644 web/public/apple-touch-icon.png create mode 100644 web/public/full-logo.webp create mode 100644 web/public/logo.webp create mode 100644 web/public/site.webmanifest create mode 100644 web/src/App.tsx create mode 100644 web/src/auth-state.ts create mode 100644 web/src/components/ActivityCalendar/CalendarCell.tsx create mode 100644 web/src/components/ActivityCalendar/MonthCalendar.tsx create mode 100644 web/src/components/ActivityCalendar/YearCalendar.tsx create mode 100644 web/src/components/ActivityCalendar/constants.ts create mode 100644 web/src/components/ActivityCalendar/hooks.ts create mode 100644 web/src/components/ActivityCalendar/index.ts create mode 100644 web/src/components/ActivityCalendar/types.ts create mode 100644 web/src/components/ActivityCalendar/useCalendar.ts create mode 100644 web/src/components/ActivityCalendar/utils.ts create mode 100644 web/src/components/AttachmentIcon.tsx create mode 100644 web/src/components/AttachmentLibrary/AttachmentFileRows.tsx create mode 100644 web/src/components/AttachmentLibrary/AttachmentLibraryEmptyState.tsx create mode 100644 web/src/components/AttachmentLibrary/AttachmentLibraryPrimitives.tsx create mode 100644 web/src/components/AttachmentLibrary/AttachmentLibraryStates.tsx create mode 100644 web/src/components/AttachmentLibrary/AttachmentLibraryToolbar.tsx create mode 100644 web/src/components/AttachmentLibrary/AttachmentMediaGrid.tsx create mode 100644 web/src/components/AttachmentLibrary/index.ts create mode 100644 web/src/components/AuthFooter.tsx create mode 100644 web/src/components/ChangeMemberPasswordDialog.tsx create mode 100644 web/src/components/ClampedSection.tsx create mode 100644 web/src/components/ColumnGrid/ColumnGrid.tsx create mode 100644 web/src/components/ColumnGrid/index.ts create mode 100644 web/src/components/ConfirmDialog/README.md create mode 100644 web/src/components/ConfirmDialog/index.tsx create mode 100644 web/src/components/CreateAccessTokenDialog.tsx create mode 100644 web/src/components/CreateIdentityProviderDialog.tsx create mode 100644 web/src/components/CreateUserDialog.tsx create mode 100644 web/src/components/CreateWebhookDialog.tsx create mode 100644 web/src/components/DateTimeInput.tsx create mode 100644 web/src/components/ErrorBoundary.tsx create mode 100644 web/src/components/Inbox/MemoCommentMessage.tsx create mode 100644 web/src/components/Inbox/MemoMentionMessage.tsx create mode 100644 web/src/components/LearnMore.tsx create mode 100644 web/src/components/LocalePicker.tsx create mode 100644 web/src/components/LocaleSelect.tsx create mode 100644 web/src/components/MemoActionMenu/MemoActionMenu.tsx create mode 100644 web/src/components/MemoActionMenu/MemoShareImageDialog.tsx create mode 100644 web/src/components/MemoActionMenu/MemoShareImagePreview.tsx create mode 100644 web/src/components/MemoActionMenu/hooks.ts create mode 100644 web/src/components/MemoActionMenu/index.ts create mode 100644 web/src/components/MemoActionMenu/memoShareImage.ts create mode 100644 web/src/components/MemoActionMenu/memoShareImagePreviewModel.ts create mode 100644 web/src/components/MemoActionMenu/types.ts create mode 100644 web/src/components/MemoCommentSection.tsx create mode 100644 web/src/components/MemoContent/CodeBlock.tsx create mode 100644 web/src/components/MemoContent/LinkMetadataCard.tsx create mode 100644 web/src/components/MemoContent/MarkdownRenderContext.tsx create mode 100644 web/src/components/MemoContent/MemoMarkdownRenderer.tsx create mode 100644 web/src/components/MemoContent/Mention.tsx create mode 100644 web/src/components/MemoContent/MentionResolutionContext.tsx create mode 100644 web/src/components/MemoContent/MermaidBlock.tsx create mode 100644 web/src/components/MemoContent/Table.tsx create mode 100644 web/src/components/MemoContent/Tag.tsx create mode 100644 web/src/components/MemoContent/TaskListItem.tsx create mode 100644 web/src/components/MemoContent/TrustedIframe.ts create mode 100644 web/src/components/MemoContent/constants.ts create mode 100644 web/src/components/MemoContent/index.tsx create mode 100644 web/src/components/MemoContent/markdown/AnchorLink.tsx create mode 100644 web/src/components/MemoContent/markdown/Blockquote.tsx create mode 100644 web/src/components/MemoContent/markdown/Heading.tsx create mode 100644 web/src/components/MemoContent/markdown/HorizontalRule.tsx create mode 100644 web/src/components/MemoContent/markdown/Image.tsx create mode 100644 web/src/components/MemoContent/markdown/InlineCode.tsx create mode 100644 web/src/components/MemoContent/markdown/Link.tsx create mode 100644 web/src/components/MemoContent/markdown/List.tsx create mode 100644 web/src/components/MemoContent/markdown/Paragraph.tsx create mode 100644 web/src/components/MemoContent/markdown/README.md create mode 100644 web/src/components/MemoContent/markdown/index.ts create mode 100644 web/src/components/MemoContent/markdown/types.ts create mode 100644 web/src/components/MemoContent/types.ts create mode 100644 web/src/components/MemoContent/utils.ts create mode 100644 web/src/components/MemoDetailSidebar/MemoDetailSidebar.tsx create mode 100644 web/src/components/MemoDetailSidebar/MemoDetailSidebarDrawer.tsx create mode 100644 web/src/components/MemoDetailSidebar/MemoOutline.tsx create mode 100644 web/src/components/MemoDetailSidebar/MemoSharePanel.tsx create mode 100644 web/src/components/MemoDetailSidebar/index.ts create mode 100644 web/src/components/MemoDisplaySettingMenu.tsx create mode 100644 web/src/components/MemoEditor/Editor/controller.ts create mode 100644 web/src/components/MemoEditor/Editor/editor.css create mode 100644 web/src/components/MemoEditor/Editor/extensions.ts create mode 100644 web/src/components/MemoEditor/Editor/formatting.ts create mode 100644 web/src/components/MemoEditor/Editor/headingDecorations.ts create mode 100644 web/src/components/MemoEditor/Editor/index.tsx create mode 100644 web/src/components/MemoEditor/Editor/listIndent.ts create mode 100644 web/src/components/MemoEditor/Editor/tagAutocomplete.ts create mode 100644 web/src/components/MemoEditor/Editor/tagMentionDecorations.ts create mode 100644 web/src/components/MemoEditor/Editor/theme.ts create mode 100644 web/src/components/MemoEditor/Editor/viewportDecorations.ts create mode 100644 web/src/components/MemoEditor/README.md create mode 100644 web/src/components/MemoEditor/Toolbar/EditorToolbar.tsx create mode 100644 web/src/components/MemoEditor/Toolbar/FormattingToolbar.tsx create mode 100644 web/src/components/MemoEditor/Toolbar/InsertMenu.tsx create mode 100644 web/src/components/MemoEditor/Toolbar/VisibilitySelector.tsx create mode 100644 web/src/components/MemoEditor/Toolbar/index.ts create mode 100644 web/src/components/MemoEditor/components/AudioRecorderPanel.tsx create mode 100644 web/src/components/MemoEditor/components/EditorContent.tsx create mode 100644 web/src/components/MemoEditor/components/EditorMetadata.tsx create mode 100644 web/src/components/MemoEditor/components/FocusModeOverlay.tsx create mode 100644 web/src/components/MemoEditor/components/TimestampPopover.tsx create mode 100644 web/src/components/MemoEditor/components/VoiceWaveform.tsx create mode 100644 web/src/components/MemoEditor/components/index.ts create mode 100644 web/src/components/MemoEditor/constants.ts create mode 100644 web/src/components/MemoEditor/formatting/commands.ts create mode 100644 web/src/components/MemoEditor/hooks/index.ts create mode 100644 web/src/components/MemoEditor/hooks/useAudioRecorder.ts create mode 100644 web/src/components/MemoEditor/hooks/useAudioWaveform.ts create mode 100644 web/src/components/MemoEditor/hooks/useAutoSave.ts create mode 100644 web/src/components/MemoEditor/hooks/useBlobUrls.ts create mode 100644 web/src/components/MemoEditor/hooks/useEditorActiveState.ts create mode 100644 web/src/components/MemoEditor/hooks/useElementWidth.ts create mode 100644 web/src/components/MemoEditor/hooks/useFileUpload.ts create mode 100644 web/src/components/MemoEditor/hooks/useFocusMode.ts create mode 100644 web/src/components/MemoEditor/hooks/useLinkMemo.ts create mode 100644 web/src/components/MemoEditor/hooks/useLocation.ts create mode 100644 web/src/components/MemoEditor/hooks/useMemoInit.ts create mode 100644 web/src/components/MemoEditor/hooks/useMemoSave.ts create mode 100644 web/src/components/MemoEditor/index.tsx create mode 100644 web/src/components/MemoEditor/services/cacheService.ts create mode 100644 web/src/components/MemoEditor/services/errorService.ts create mode 100644 web/src/components/MemoEditor/services/index.ts create mode 100644 web/src/components/MemoEditor/services/memoService.ts create mode 100644 web/src/components/MemoEditor/services/transcriptionService.ts create mode 100644 web/src/components/MemoEditor/services/uploadService.ts create mode 100644 web/src/components/MemoEditor/services/validationService.ts create mode 100644 web/src/components/MemoEditor/state/actions.ts create mode 100644 web/src/components/MemoEditor/state/context.tsx create mode 100644 web/src/components/MemoEditor/state/index.ts create mode 100644 web/src/components/MemoEditor/state/reducer.ts create mode 100644 web/src/components/MemoEditor/state/types.ts create mode 100644 web/src/components/MemoEditor/types/attachment.ts create mode 100644 web/src/components/MemoEditor/types/components.ts create mode 100644 web/src/components/MemoEditor/types/editorController.ts create mode 100644 web/src/components/MemoEditor/types/index.ts create mode 100644 web/src/components/MemoEditor/types/insertMenu.ts create mode 100644 web/src/components/MemoEditor/utils/deriveDefaultCreateTime.ts create mode 100644 web/src/components/MemoExplorer/MemoExplorer.tsx create mode 100644 web/src/components/MemoExplorer/MemoExplorerDrawer.tsx create mode 100644 web/src/components/MemoExplorer/ShortcutsSection.tsx create mode 100644 web/src/components/MemoExplorer/TagsSection.tsx create mode 100644 web/src/components/MemoExplorer/index.ts create mode 100644 web/src/components/MemoFilters.tsx create mode 100644 web/src/components/MemoMetadata/Attachment/AttachmentCard.tsx create mode 100644 web/src/components/MemoMetadata/Attachment/AttachmentListEditor.tsx create mode 100644 web/src/components/MemoMetadata/Attachment/AttachmentListView.tsx create mode 100644 web/src/components/MemoMetadata/Attachment/AudioAttachmentItem.tsx create mode 100644 web/src/components/MemoMetadata/Attachment/attachmentHelpers.ts create mode 100644 web/src/components/MemoMetadata/Attachment/attachmentVisualClasses.ts create mode 100644 web/src/components/MemoMetadata/Attachment/index.ts create mode 100644 web/src/components/MemoMetadata/Attachment/visualGalleryLayout.ts create mode 100644 web/src/components/MemoMetadata/Location/LocationDialog.tsx create mode 100644 web/src/components/MemoMetadata/Location/LocationDisplayEditor.tsx create mode 100644 web/src/components/MemoMetadata/Location/LocationDisplayView.tsx create mode 100644 web/src/components/MemoMetadata/Location/index.ts create mode 100644 web/src/components/MemoMetadata/Location/locationHelpers.ts create mode 100644 web/src/components/MemoMetadata/MetadataSection.tsx create mode 100644 web/src/components/MemoMetadata/Relation/LinkMemoDialog.tsx create mode 100644 web/src/components/MemoMetadata/Relation/RelationCard.tsx create mode 100644 web/src/components/MemoMetadata/Relation/RelationListEditor.tsx create mode 100644 web/src/components/MemoMetadata/Relation/RelationListView.tsx create mode 100644 web/src/components/MemoMetadata/Relation/index.ts create mode 100644 web/src/components/MemoMetadata/Relation/relationHelpers.ts create mode 100644 web/src/components/MemoMetadata/Relation/useResolvedRelationMemos.ts create mode 100644 web/src/components/MemoMetadata/SectionHeader.tsx create mode 100644 web/src/components/MemoMetadata/index.ts create mode 100644 web/src/components/MemoPreview/MemoPreview.tsx create mode 100644 web/src/components/MemoPreview/index.ts create mode 100644 web/src/components/MemoReactionListView/MemoReactionListView.tsx create mode 100644 web/src/components/MemoReactionListView/ReactionSelector.tsx create mode 100644 web/src/components/MemoReactionListView/ReactionView.tsx create mode 100644 web/src/components/MemoReactionListView/hooks.ts create mode 100644 web/src/components/MemoReactionListView/index.ts create mode 100644 web/src/components/MemoView/MemoView.tsx create mode 100644 web/src/components/MemoView/MemoViewContext.tsx create mode 100644 web/src/components/MemoView/components/MemoBody.tsx create mode 100644 web/src/components/MemoView/components/MemoCommentListView.tsx create mode 100644 web/src/components/MemoView/components/MemoHeader.tsx create mode 100644 web/src/components/MemoView/components/MemoSnippetLink.tsx create mode 100644 web/src/components/MemoView/components/index.ts create mode 100644 web/src/components/MemoView/constants.ts create mode 100644 web/src/components/MemoView/hooks/index.ts create mode 100644 web/src/components/MemoView/hooks/useImagePreview.ts create mode 100644 web/src/components/MemoView/hooks/useMemoActions.ts create mode 100644 web/src/components/MemoView/hooks/useMemoHandlers.ts create mode 100644 web/src/components/MemoView/index.ts create mode 100644 web/src/components/MemoView/types.ts create mode 100644 web/src/components/MemosLogo.tsx create mode 100644 web/src/components/MobileHeader.tsx create mode 100644 web/src/components/MotionPhotoPlayer.tsx create mode 100644 web/src/components/MotionPhotoPreview.tsx create mode 100644 web/src/components/Navigation.tsx create mode 100644 web/src/components/NavigationDrawer.tsx create mode 100644 web/src/components/PagedMemoList/PagedMemoList.tsx create mode 100644 web/src/components/PagedMemoList/index.ts create mode 100644 web/src/components/PagedMemoList/memoCardHeight.ts create mode 100644 web/src/components/PasswordSignInForm.tsx create mode 100644 web/src/components/Placeholder/TileSpriteStrip.tsx create mode 100644 web/src/components/Placeholder/index.tsx create mode 100644 web/src/components/Placeholder/messages.ts create mode 100644 web/src/components/Placeholder/pieces/DESIGN.md create mode 100644 web/src/components/Placeholder/pieces/EagleIdle.svg create mode 100644 web/src/components/Placeholder/pieces/OwlBlink.svg create mode 100644 web/src/components/Placeholder/pieces/ToucanIdle.svg create mode 100644 web/src/components/Placeholder/tileSprites.ts create mode 100644 web/src/components/PreviewImageDialog.tsx create mode 100644 web/src/components/RequiredBadge.tsx create mode 100644 web/src/components/SearchBar.tsx create mode 100644 web/src/components/Settings/AISection.tsx create mode 100644 web/src/components/Settings/AccessTokenSection.tsx create mode 100644 web/src/components/Settings/InfoChip.tsx create mode 100644 web/src/components/Settings/InstanceSection.tsx create mode 100644 web/src/components/Settings/LinkedIdentitySection.tsx create mode 100644 web/src/components/Settings/MemberSection.tsx create mode 100644 web/src/components/Settings/MemoRelatedSettings.tsx create mode 100644 web/src/components/Settings/MyAccountSection.tsx create mode 100644 web/src/components/Settings/NotificationSection.tsx create mode 100644 web/src/components/Settings/PreferencesSection.tsx create mode 100644 web/src/components/Settings/ResourceStatsSection.tsx create mode 100644 web/src/components/Settings/SSOSection.tsx create mode 100644 web/src/components/Settings/SectionMenuItem.tsx create mode 100644 web/src/components/Settings/SettingGroup.tsx create mode 100644 web/src/components/Settings/SettingList.tsx create mode 100644 web/src/components/Settings/SettingRow.tsx create mode 100644 web/src/components/Settings/SettingSection.tsx create mode 100644 web/src/components/Settings/SettingTable.tsx create mode 100644 web/src/components/Settings/StorageSection.tsx create mode 100644 web/src/components/Settings/TagsSection.tsx create mode 100644 web/src/components/Settings/WebhookSection.tsx create mode 100644 web/src/components/Settings/settingSections.ts create mode 100644 web/src/components/Settings/sso-display.ts create mode 100644 web/src/components/Settings/useInstanceSettingUpdater.ts create mode 100644 web/src/components/StatisticsView/MonthNavigator.tsx create mode 100644 web/src/components/StatisticsView/StatisticsView.tsx create mode 100644 web/src/components/StatisticsView/index.ts create mode 100644 web/src/components/TagTree.tsx create mode 100644 web/src/components/ThemeSelect.tsx create mode 100644 web/src/components/UpdateAccountDialog.tsx create mode 100644 web/src/components/UpdateCustomizedProfileDialog.tsx create mode 100644 web/src/components/UserAvatar.tsx create mode 100644 web/src/components/UserMemoMap/UserMemoMap.tsx create mode 100644 web/src/components/UserMemoMap/index.ts create mode 100644 web/src/components/UserMenu.tsx create mode 100644 web/src/components/VideoPoster.tsx create mode 100644 web/src/components/VisibilityIcon.tsx create mode 100644 web/src/components/kit/OverflowTip.tsx create mode 100644 web/src/components/kit/SquareDiv.tsx create mode 100644 web/src/components/map/LazyLocationPicker.tsx create mode 100644 web/src/components/map/LocationPicker.tsx create mode 100644 web/src/components/map/index.ts create mode 100644 web/src/components/map/map-utils.tsx create mode 100644 web/src/components/map/types.ts create mode 100644 web/src/components/map/useReverseGeocoding.ts create mode 100644 web/src/components/ui/README.md create mode 100644 web/src/components/ui/badge.tsx create mode 100644 web/src/components/ui/button.tsx create mode 100644 web/src/components/ui/checkbox.tsx create mode 100644 web/src/components/ui/dialog.tsx create mode 100644 web/src/components/ui/dropdown-menu.tsx create mode 100644 web/src/components/ui/input.tsx create mode 100644 web/src/components/ui/label.tsx create mode 100644 web/src/components/ui/popover.tsx create mode 100644 web/src/components/ui/radio-group.tsx create mode 100644 web/src/components/ui/select.tsx create mode 100644 web/src/components/ui/separator.tsx create mode 100644 web/src/components/ui/sheet.tsx create mode 100644 web/src/components/ui/switch.tsx create mode 100644 web/src/components/ui/tabs.tsx create mode 100644 web/src/components/ui/textarea.tsx create mode 100644 web/src/components/ui/tooltip.tsx create mode 100644 web/src/components/ui/visually-hidden.tsx create mode 100644 web/src/connect.ts create mode 100644 web/src/contexts/AuthContext.tsx create mode 100644 web/src/contexts/InstanceContext.tsx create mode 100644 web/src/contexts/MemoFilterContext.tsx create mode 100644 web/src/contexts/NewMemoContext.tsx create mode 100644 web/src/contexts/ViewContext.tsx create mode 100644 web/src/hooks/index.ts create mode 100644 web/src/hooks/useAsyncEffect.ts create mode 100644 web/src/hooks/useAttachmentLibrary.ts create mode 100644 web/src/hooks/useAttachmentQueries.ts create mode 100644 web/src/hooks/useCurrentUser.ts create mode 100644 web/src/hooks/useDateFilterNavigation.ts create mode 100644 web/src/hooks/useDebouncedEffect.ts create mode 100644 web/src/hooks/useDelayedFlag.ts create mode 100644 web/src/hooks/useDialog.ts create mode 100644 web/src/hooks/useFilteredMemoStats.ts create mode 100644 web/src/hooks/useInstanceQueries.ts create mode 100644 web/src/hooks/useLiveMemoRefresh.ts create mode 100644 web/src/hooks/useLoading.ts create mode 100644 web/src/hooks/useLocalStorage.ts create mode 100644 web/src/hooks/useMediaQuery.ts create mode 100644 web/src/hooks/useMemoDetailError.ts create mode 100644 web/src/hooks/useMemoFilters.ts create mode 100644 web/src/hooks/useMemoQueries.ts create mode 100644 web/src/hooks/useMemoShareQueries.ts create mode 100644 web/src/hooks/useMemoSorting.ts create mode 100644 web/src/hooks/useNavigateTo.ts create mode 100644 web/src/hooks/useTokenRefreshOnFocus.ts create mode 100644 web/src/hooks/useUserLocale.ts create mode 100644 web/src/hooks/useUserQueries.ts create mode 100644 web/src/hooks/useUserTheme.ts create mode 100644 web/src/i18n.ts create mode 100644 web/src/index.css create mode 100644 web/src/layouts/MainLayout.tsx create mode 100644 web/src/layouts/RootLayout.tsx create mode 100644 web/src/lib/browser.ts create mode 100644 web/src/lib/calendar-utils.ts create mode 100644 web/src/lib/color.ts create mode 100644 web/src/lib/constants.ts create mode 100644 web/src/lib/error.ts create mode 100644 web/src/lib/markdownStyles.ts create mode 100644 web/src/lib/query-client.ts create mode 100644 web/src/lib/resource-names.ts create mode 100644 web/src/lib/tag.ts create mode 100644 web/src/lib/utils.ts create mode 100644 web/src/locales/ar.json create mode 100644 web/src/locales/bg.json create mode 100644 web/src/locales/ca.json create mode 100644 web/src/locales/cs.json create mode 100644 web/src/locales/da.json create mode 100644 web/src/locales/de.json create mode 100644 web/src/locales/el.json create mode 100644 web/src/locales/en-GB.json create mode 100644 web/src/locales/en.json create mode 100644 web/src/locales/es.json create mode 100644 web/src/locales/et.json create mode 100644 web/src/locales/fa.json create mode 100644 web/src/locales/fi.json create mode 100644 web/src/locales/fr.json create mode 100644 web/src/locales/gl.json create mode 100644 web/src/locales/hi.json create mode 100644 web/src/locales/hr.json create mode 100644 web/src/locales/hu.json create mode 100644 web/src/locales/id.json create mode 100644 web/src/locales/it.json create mode 100644 web/src/locales/ja.json create mode 100644 web/src/locales/ka-GE.json create mode 100644 web/src/locales/ko.json create mode 100644 web/src/locales/lt.json create mode 100644 web/src/locales/lv.json create mode 100644 web/src/locales/mr.json create mode 100644 web/src/locales/nb.json create mode 100644 web/src/locales/nl.json create mode 100644 web/src/locales/pl.json create mode 100644 web/src/locales/pt-BR.json create mode 100644 web/src/locales/pt-PT.json create mode 100644 web/src/locales/ro.json create mode 100644 web/src/locales/ru.json create mode 100644 web/src/locales/sk.json create mode 100644 web/src/locales/sl.json create mode 100644 web/src/locales/sr.json create mode 100644 web/src/locales/sv.json create mode 100644 web/src/locales/th.json create mode 100644 web/src/locales/tr.json create mode 100644 web/src/locales/uk.json create mode 100644 web/src/locales/vi.json create mode 100644 web/src/locales/zh-Hans.json create mode 100644 web/src/locales/zh-Hant.json create mode 100644 web/src/main.tsx create mode 100644 web/src/pages/About.tsx create mode 100644 web/src/pages/AdminSignIn.tsx create mode 100644 web/src/pages/Archived.tsx create mode 100644 web/src/pages/Attachments.tsx create mode 100644 web/src/pages/AuthCallback.tsx create mode 100644 web/src/pages/Explore.tsx create mode 100644 web/src/pages/Home.tsx create mode 100644 web/src/pages/Inboxes.tsx create mode 100644 web/src/pages/MemoDetail.tsx create mode 100644 web/src/pages/NotFound.tsx create mode 100644 web/src/pages/PermissionDenied.tsx create mode 100644 web/src/pages/Setting.tsx create mode 100644 web/src/pages/Shortcuts.tsx create mode 100644 web/src/pages/SignIn.tsx create mode 100644 web/src/pages/SignUp.tsx create mode 100644 web/src/pages/UserProfile.tsx create mode 100644 web/src/router/guards.tsx create mode 100644 web/src/router/index.tsx create mode 100644 web/src/router/routes.ts create mode 100644 web/src/themes/COLOR_GUIDE.md create mode 100644 web/src/themes/default-dark.css create mode 100644 web/src/themes/default.css create mode 100644 web/src/themes/paper.css create mode 100644 web/src/types/common.d.ts create mode 100644 web/src/types/common.ts create mode 100644 web/src/types/i18n.d.ts create mode 100644 web/src/types/markdown.ts create mode 100644 web/src/types/modules/setting.d.ts create mode 100644 web/src/types/proto/api/v1/ai_service_pb.ts create mode 100644 web/src/types/proto/api/v1/attachment_service_pb.ts create mode 100644 web/src/types/proto/api/v1/auth_service_pb.ts create mode 100644 web/src/types/proto/api/v1/common_pb.ts create mode 100644 web/src/types/proto/api/v1/idp_service_pb.ts create mode 100644 web/src/types/proto/api/v1/instance_service_pb.ts create mode 100644 web/src/types/proto/api/v1/memo_service_pb.ts create mode 100644 web/src/types/proto/api/v1/shortcut_service_pb.ts create mode 100644 web/src/types/proto/api/v1/user_service_pb.ts create mode 100644 web/src/types/proto/google/api/annotations_pb.ts create mode 100644 web/src/types/proto/google/api/client_pb.ts create mode 100644 web/src/types/proto/google/api/field_behavior_pb.ts create mode 100644 web/src/types/proto/google/api/http_pb.ts create mode 100644 web/src/types/proto/google/api/launch_stage_pb.ts create mode 100644 web/src/types/proto/google/api/resource_pb.ts create mode 100644 web/src/types/proto/google/type/color_pb.ts create mode 100644 web/src/types/relative-time-element.d.ts create mode 100644 web/src/types/statistics.ts create mode 100644 web/src/types/view.d.ts create mode 100644 web/src/utils/attachment.ts create mode 100644 web/src/utils/auth-redirect.ts create mode 100644 web/src/utils/format.ts create mode 100644 web/src/utils/i18n.ts create mode 100644 web/src/utils/markdown-manipulation.ts create mode 100644 web/src/utils/markdown-task-actions.ts create mode 100644 web/src/utils/media-item.ts create mode 100644 web/src/utils/memo.ts create mode 100644 web/src/utils/mention-grammar.ts create mode 100644 web/src/utils/oauth.ts create mode 100644 web/src/utils/redirect-safety.ts create mode 100644 web/src/utils/rehype-plugins/rehype-heading-id.ts create mode 100644 web/src/utils/remark-plugins/remark-disable-setext.ts create mode 100644 web/src/utils/remark-plugins/remark-mention.ts create mode 100644 web/src/utils/remark-plugins/remark-preserve-type.ts create mode 100644 web/src/utils/remark-plugins/remark-split-mixed-task-lists.ts create mode 100644 web/src/utils/remark-plugins/remark-tag.ts create mode 100644 web/src/utils/tag-grammar.ts create mode 100644 web/src/utils/theme.ts create mode 100644 web/src/utils/user.ts create mode 100644 web/src/utils/uuid.ts create mode 100644 web/tests/about-page.test.tsx create mode 100644 web/tests/activity-calendar-tooltip.test.ts create mode 100644 web/tests/auth-redirect.test.ts create mode 100644 web/tests/calendar-cell-empty-clickable.test.tsx create mode 100644 web/tests/column-count.test.ts create mode 100644 web/tests/column-grid-planner.test.ts create mode 100644 web/tests/column-grid.test.tsx create mode 100644 web/tests/derive-default-create-time.test.ts create mode 100644 web/tests/editor-controller.test.ts create mode 100644 web/tests/editor-decorations.test.ts create mode 100644 web/tests/editor-formatting.test.ts create mode 100644 web/tests/editor-heading-decorations.test.ts create mode 100644 web/tests/editor-keys.test.ts create mode 100644 web/tests/editor-tag-autocomplete.test.ts create mode 100644 web/tests/editor.test.tsx create mode 100644 web/tests/filtered-memo-stats.test.ts create mode 100644 web/tests/formatting-toolbar.test.tsx create mode 100644 web/tests/guards.test.tsx create mode 100644 web/tests/hoist-new-memo.test.ts create mode 100644 web/tests/hooks.test.tsx create mode 100644 web/tests/i18n-locale-search.test.ts create mode 100644 web/tests/locale-picker.test.tsx create mode 100644 web/tests/location-picker.test.tsx create mode 100644 web/tests/markdown-task-actions.test.ts create mode 100644 web/tests/memo-body-compact.test.tsx create mode 100644 web/tests/memo-card-height.test.ts create mode 100644 web/tests/memo-content-link-preview.test.tsx create mode 100644 web/tests/memo-content-list.test.tsx create mode 100644 web/tests/memo-content-paragraph.test.tsx create mode 100644 web/tests/memo-content-security.test.tsx create mode 100644 web/tests/memo-editor-cache.test.ts create mode 100644 web/tests/memo-editor-extensions.test.ts create mode 100644 web/tests/memo-share-image.test.ts create mode 100644 web/tests/mermaid-block.test.tsx create mode 100644 web/tests/oauth.test.ts create mode 100644 web/tests/paged-memo-list.test.tsx create mode 100644 web/tests/password-sign-in-form.test.tsx create mode 100644 web/tests/placeholder-component.test.tsx create mode 100644 web/tests/placeholder-pool.test.ts create mode 100644 web/tests/preview-image-dialog.test.tsx create mode 100644 web/tests/redirect-safety.test.ts create mode 100644 web/tests/remark-tag.test.tsx create mode 100644 web/tests/router-config.test.tsx create mode 100644 web/tests/setup.ts create mode 100644 web/tests/toolbar-compact-width.test.ts create mode 100644 web/tests/use-auto-save.test.tsx create mode 100644 web/tests/video-poster.test.tsx create mode 100644 web/tests/view-context-columns.test.tsx create mode 100644 web/tsconfig.json create mode 100644 web/vite.config.mts create mode 100644 web/vitest.config.mts diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d465134 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +web/node_modules +web/dist +.git +.github +build/ +tmp/ +memos +*.md +.gitignore +.golangci.yaml +.dockerignore +docs/ +.DS_Store \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..f9af238 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: usememos diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..c95fcf3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,162 @@ +name: Bug Report +description: Report reproducible behavior that is broken in the current version +type: Bug +body: + - type: markdown + attributes: + value: | + Thanks for reporting a bug. Please help maintainers reproduce it on current code. + + Before submitting: + - Search [existing issues](https://github.com/usememos/memos/issues) to avoid duplicates. + - Upgrade and retest with the [latest release](https://github.com/usememos/memos/releases/latest), current `main`, or the [demo site](https://demo.usememos.com/). + - Use [Discussions](https://github.com/usememos/memos/discussions) for questions, setup help, or configuration troubleshooting. + + Maintainers normally fix bugs in current code and future releases, not older released versions. + + - type: checkboxes + id: pre-check + attributes: + label: Pre-submission Checklist + options: + - label: I have searched existing issues and confirmed this has not already been reported + required: true + - label: I have reproduced this bug on the latest Memos release, current `main`, or the demo site, or this report is specifically about upgrading to the latest release + required: true + - label: This is a bug report, not a question or configuration request + required: true + + - type: dropdown + id: area + attributes: + label: Affected Area + description: Choose the main area where the bug appears. + multiple: true + options: + - Web UI + - API + - Authentication / SSO + - Database / migration + - Resources / attachments + - Search / filters + - Markdown / editor + - Deployment / startup + - Other + validations: + required: true + + - type: dropdown + id: reproduced-on + attributes: + label: Reproduced On + description: Where did you confirm the issue still happens? + options: + - Latest release + - Current main branch + - Demo site + - Upgrade to latest release + - I cannot test the latest version + validations: + required: true + + - type: input + id: version + attributes: + label: Memos Version Tested + description: Report the exact version where you reproduced the bug. Use the version shown in **Settings > System**, the container image tag, the release binary version, or `memos --version`. Please do not write `latest` only. + placeholder: "v0.29.x, ghcr.io/usememos/memos:v0.29.x, main@abcdef, or demo site" + validations: + required: true + + - type: input + id: previous-version + attributes: + label: Previous Version + description: If this happened after an upgrade, enter the version you upgraded from. Leave blank if not applicable. + placeholder: "v0.28.x, unknown, or not applicable" + + - type: textarea + id: environment + attributes: + label: Environment Details + description: Include the deployment, database, client, and network details that apply. + placeholder: | + - Deployment: Docker / binary / source / demo site + - Database: SQLite / PostgreSQL / MySQL + - Browser: Firefox 126 on macOS 15 + - Server OS: Ubuntu 24.04 + - Reverse proxy: nginx / Caddy / Traefik / none + - Related settings: SSO / SMTP / storage / webhooks / none + validations: + required: true + + - type: dropdown + id: frequency + attributes: + label: Reproduction Frequency + description: How reliably can you reproduce this? + options: + - Always + - Often + - Sometimes + - Once + - Unknown + validations: + required: true + + - type: textarea + id: reproduction-steps + attributes: + label: Steps to Reproduce + description: Provide minimal, numbered steps that start from a clean page/session when possible. + placeholder: | + 1. Open ... + 2. Click ... + 3. Enter ... + 4. Wait for ... + 5. See ... + validations: + required: true + + - type: textarea + id: current-behavior + attributes: + label: Current Behavior + description: What happened? Include exact error messages, status codes, or visible UI state if available. + placeholder: The application ... + validations: + required: true + + - type: textarea + id: expected-behavior + attributes: + label: Expected Behavior + description: What did you expect to happen instead? + placeholder: I expected... + validations: + required: true + + - type: textarea + id: regression + attributes: + label: Regression Information + description: If this worked before, describe when it last worked and what changed before it broke. + placeholder: | + This last worked in ... + It started after ... + + - type: textarea + id: logs + attributes: + label: Logs + description: Paste relevant server logs, browser console output, or network errors. Remove secrets before submitting. + render: shell + placeholder: | + Paste logs here. + + - type: textarea + id: additional-context + attributes: + label: Additional Context + description: Attach screenshots, screen recordings, sample data, exports, or links to related issues. + placeholder: Drag and drop files here or add any extra context. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..99c57ec --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Questions & Support + url: https://github.com/usememos/memos/discussions + about: Ask questions or get help in GitHub Discussions — please don't open issues for questions + - name: Documentation + url: https://www.usememos.com/docs + about: Check the documentation before opening an issue diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..2903a16 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,109 @@ +name: Feature Request +description: Propose a product improvement with a clear use case +type: Feature +body: + - type: markdown + attributes: + value: | + Thanks for suggesting an improvement. Please describe the problem and workflow first so maintainers can evaluate the request. + + Before submitting: + - Search [existing feature requests](https://github.com/usememos/memos/issues?q=label%3Aenhancement) to avoid duplicates. + - Use [Discussions](https://github.com/usememos/memos/discussions) for broad ideas, setup help, or questions. + - Keep one feature request focused on one user problem. + + - type: checkboxes + id: pre-check + attributes: + label: Pre-submission Checklist + options: + - label: I have searched existing issues and confirmed this has not already been requested + required: true + - label: This is a feature request, not a bug report or support question + required: true + + - type: dropdown + id: area + attributes: + label: Area + description: Choose the main area this request affects. + multiple: true + options: + - Web UI + - Mobile / responsive experience + - API + - Authentication / SSO + - Administration + - Memo editor + - Search / filters + - Tags / organization + - Resources / attachments + - Import / export + - Deployment / operations + - Other + validations: + required: true + + - type: textarea + id: problem + attributes: + label: Problem or Use Case + description: What problem does this solve? Describe the user need, not just the proposed UI or API. + placeholder: | + I often need to ... + Today, this is difficult because ... + validations: + required: true + + - type: textarea + id: users + attributes: + label: Who Would Use This? + description: Describe the user, role, team, or workflow that would benefit. + placeholder: | + This helps ... + They currently ... + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed Solution + description: Describe the behavior you would like Memos to support. Include UI, API, or configuration details if relevant. + placeholder: | + Memos should ... + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives Considered + description: Existing workarounds, related tools, or simpler alternatives you considered. + placeholder: | + I tried ... + It does not work well because ... + + - type: textarea + id: compatibility + attributes: + label: Compatibility and Migration + description: Note any expected impact on existing users, APIs, storage, permissions, or deployments. + placeholder: | + This should not affect existing memos because ... + Existing API clients may need ... + + - type: textarea + id: examples + attributes: + label: Examples + description: Link to screenshots, mockups, API sketches, related apps, or existing issues that show the desired behavior. + placeholder: Drag and drop files here or add links/examples. + + - type: textarea + id: additional-context + attributes: + label: Additional Context + description: Add any extra context that does not fit above. + placeholder: Any other details. diff --git a/.github/workflows/backend-tests.yml b/.github/workflows/backend-tests.yml new file mode 100644 index 0000000..3f52fed --- /dev/null +++ b/.github/workflows/backend-tests.yml @@ -0,0 +1,91 @@ +name: Backend Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + paths: + - "go.mod" + - "go.sum" + - "**.go" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + GO_VERSION: "1.26.2" + +jobs: + static-checks: + name: Static Checks + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Go + uses: actions/setup-go@v6 + with: + go-version: ${{ env.GO_VERSION }} + cache: true + cache-dependency-path: go.sum + + - name: Verify go.mod is tidy + run: | + go mod tidy -go=${{ env.GO_VERSION }} + git diff --exit-code + + - name: Run golangci-lint + uses: golangci/golangci-lint-action@v9 + with: + version: v2.11.3 + args: --timeout=3m + + tests: + name: Tests (${{ matrix.test-group }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + test-group: [store, server, internal, other] + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Go + uses: actions/setup-go@v6 + with: + go-version: ${{ env.GO_VERSION }} + cache: true + cache-dependency-path: go.sum + + - name: Run tests + run: | + case "${{ matrix.test-group }}" in + store) + # Run store tests for all drivers (sqlite, mysql, postgres) + go test -v -coverprofile=coverage.out -covermode=atomic ./store/... + ;; + server) + go test -v -race -coverprofile=coverage.out -covermode=atomic ./server/... + ;; + internal) + go test -v -race -coverprofile=coverage.out -covermode=atomic ./internal/... + ;; + other) + go test -v -race -coverprofile=coverage.out -covermode=atomic \ + ./cmd/... ./internal/... ./proto/... + ;; + esac + env: + DRIVER: ${{ matrix.test-group == 'store' && '' || 'sqlite' }} + + - name: Upload coverage + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + uses: codecov/codecov-action@v5 + with: + files: ./coverage.out + flags: ${{ matrix.test-group }} + fail_ci_if_error: false diff --git a/.github/workflows/build-canary-image.yml b/.github/workflows/build-canary-image.yml new file mode 100644 index 0000000..d380616 --- /dev/null +++ b/.github/workflows/build-canary-image.yml @@ -0,0 +1,180 @@ +name: Build Canary Image + +on: + push: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.repository }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + build-frontend: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - uses: pnpm/action-setup@v4.2.0 + with: + version: 11.0.1 + - uses: actions/setup-node@v6 + with: + node-version: "24" + cache: pnpm + cache-dependency-path: "web/pnpm-lock.yaml" + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + - name: Setup pnpm cache + uses: actions/cache@v5 + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('web/pnpm-lock.yaml') }} + restore-keys: ${{ runner.os }}-pnpm-store- + - run: pnpm install --frozen-lockfile + working-directory: web + - name: Run frontend build + run: pnpm release + working-directory: web + + - name: Upload frontend artifacts + uses: actions/upload-artifact@v6 + with: + name: frontend-dist + path: server/router/frontend/dist + retention-days: 1 + + build-push: + needs: build-frontend + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + strategy: + fail-fast: false + matrix: + platform: + - linux/amd64 + - linux/arm64 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Resolve version from latest tag + id: version + run: | + version="$(git describe --tags --abbrev=0 2>/dev/null || echo dev)" + echo "version=${version#v}" >> "$GITHUB_OUTPUT" + + - name: Download frontend artifacts + uses: actions/download-artifact@v7 + with: + name: frontend-dist + path: server/router/frontend/dist + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} + + - name: Build and push by digest + id: build + uses: docker/build-push-action@v6 + with: + context: . + file: ./scripts/Dockerfile + platforms: ${{ matrix.platform }} + build-args: | + VERSION=${{ steps.version.outputs.version }} + COMMIT=${{ github.sha }} + cache-from: type=gha,scope=build-${{ matrix.platform }} + cache-to: type=gha,mode=max,scope=build-${{ matrix.platform }} + outputs: type=image,name=neosmemo/memos,push-by-digest=true,name-canonical=true,push=true + + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v6 + with: + name: digests-${{ strategy.job-index }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + needs: build-push + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Download digests + uses: actions/download-artifact@v7 + with: + pattern: digests-* + merge-multiple: true + path: /tmp/digests + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + neosmemo/memos + ghcr.io/usememos/memos + flavor: | + latest=false + tags: | + type=raw,value=canary + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} + + - name: Create manifest list and push + working-directory: /tmp/digests + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf 'neosmemo/memos@sha256:%s ' *) + env: + DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta.outputs.json }} + + - name: Inspect images + run: | + docker buildx imagetools inspect neosmemo/memos:canary + docker buildx imagetools inspect ghcr.io/usememos/memos:canary diff --git a/.github/workflows/demo-deploy.yml b/.github/workflows/demo-deploy.yml new file mode 100644 index 0000000..4ff6a37 --- /dev/null +++ b/.github/workflows/demo-deploy.yml @@ -0,0 +1,17 @@ +name: Demo Deploy + +on: + workflow_dispatch: + +jobs: + deploy-demo: + runs-on: ubuntu-latest + steps: + - name: Trigger Render Deploy + run: | + curl -X POST "${{ secrets.RENDER_DEPLOY_HOOK }}" \ + -H "Content-Type: application/json" \ + -d '{"trigger": "github_action"}' + + - name: Deployment Status + run: echo "Demo deployment triggered successfully on Render" diff --git a/.github/workflows/frontend-tests.yml b/.github/workflows/frontend-tests.yml new file mode 100644 index 0000000..d616c62 --- /dev/null +++ b/.github/workflows/frontend-tests.yml @@ -0,0 +1,76 @@ +name: Frontend Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + paths: + - "web/**" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + NODE_VERSION: "24" + PNPM_VERSION: "11.0.1" + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup pnpm + uses: pnpm/action-setup@v4.2.0 + with: + version: ${{ env.PNPM_VERSION }} + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: ${{ env.NODE_VERSION }} + cache: pnpm + cache-dependency-path: web/pnpm-lock.yaml + + - name: Install dependencies + working-directory: web + run: pnpm install --frozen-lockfile + + - name: Run lint + working-directory: web + run: pnpm lint + + - name: Run unit tests + working-directory: web + run: pnpm test + + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup pnpm + uses: pnpm/action-setup@v4.2.0 + with: + version: ${{ env.PNPM_VERSION }} + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: ${{ env.NODE_VERSION }} + cache: pnpm + cache-dependency-path: web/pnpm-lock.yaml + + - name: Install dependencies + working-directory: web + run: pnpm install --frozen-lockfile + + - name: Build frontend + working-directory: web + run: pnpm build diff --git a/.github/workflows/proto-linter.yml b/.github/workflows/proto-linter.yml new file mode 100644 index 0000000..a642234 --- /dev/null +++ b/.github/workflows/proto-linter.yml @@ -0,0 +1,40 @@ +name: Proto Linter + +on: + push: + branches: [main] + pull_request: + branches: [main] + paths: + - "proto/**" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + name: Lint Protos + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Setup buf + uses: bufbuild/buf-setup-action@v1 + with: + github_token: ${{ github.token }} + + - name: Run buf lint + uses: bufbuild/buf-lint-action@v1 + with: + input: proto + + - name: Check buf format + run: | + if [[ $(buf format -d) ]]; then + echo "❌ Proto files are not formatted. Run 'buf format -w' to fix." + exit 1 + fi diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..e6cb58c --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,37 @@ +name: Release Please + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: write + issues: write + pull-requests: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - name: Check release token + env: + RELEASE_PLEASE_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN }} + run: | + if [ -z "$RELEASE_PLEASE_TOKEN" ]; then + echo "RELEASE_PLEASE_TOKEN must be set to a fine-grained PAT so release-please tags can trigger release.yml." >&2 + exit 1 + fi + + - name: Run release-please + uses: googleapis/release-please-action@v4 + with: + # Use a fine-grained PAT so generated tags trigger release.yml. + token: ${{ secrets.RELEASE_PLEASE_TOKEN }} + config-file: release-please-config.json + manifest-file: .release-please-manifest.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2d0c396 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,384 @@ +name: Release + +on: + push: + tags: + - "v*.*.*" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +env: + GO_VERSION: "1.26.2" + NODE_VERSION: "24" + PNPM_VERSION: "11.0.1" + ARTIFACT_RETENTION_DAYS: 60 + ARTIFACT_PREFIX: memos + +jobs: + prepare: + name: Extract Version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + tag: ${{ steps.version.outputs.tag }} + major_minor: ${{ steps.version.outputs.major_minor }} + is_prerelease: ${{ steps.version.outputs.is_prerelease }} + steps: + - name: Extract version + id: version + env: + REF_NAME: ${{ github.ref_name }} + EVENT_NAME: ${{ github.event_name }} + run: | + if [ "$EVENT_NAME" = "workflow_dispatch" ]; then + echo "tag=" >> "$GITHUB_OUTPUT" + echo "version=manual-${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" + echo "major_minor=" >> "$GITHUB_OUTPUT" + echo "is_prerelease=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + if [[ ! "$REF_NAME" =~ ^v([0-9]+\.[0-9]+\.[0-9]+)(-rc\.[0-9]+)?$ ]]; then + echo "Unsupported release tag format: $REF_NAME" >&2 + exit 1 + fi + + version="${BASH_REMATCH[1]}${BASH_REMATCH[2]}" + major_minor="${BASH_REMATCH[1]%.*}" + is_prerelease=false + if [ -n "${BASH_REMATCH[2]}" ]; then + is_prerelease=true + fi + + echo "tag=${REF_NAME}" >> "$GITHUB_OUTPUT" + echo "version=${version}" >> "$GITHUB_OUTPUT" + echo "major_minor=${major_minor}" >> "$GITHUB_OUTPUT" + echo "is_prerelease=${is_prerelease}" >> "$GITHUB_OUTPUT" + + build-frontend: + name: Build Frontend + needs: prepare + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup pnpm + uses: pnpm/action-setup@v4.2.0 + with: + version: ${{ env.PNPM_VERSION }} + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: ${{ env.NODE_VERSION }} + cache: pnpm + cache-dependency-path: web/pnpm-lock.yaml + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: echo "STORE_PATH=$(pnpm store path)" >> "$GITHUB_OUTPUT" + + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('web/pnpm-lock.yaml') }} + restore-keys: ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + working-directory: web + run: pnpm install --frozen-lockfile + + - name: Build frontend release assets + working-directory: web + run: pnpm release + + - name: Upload frontend artifacts + uses: actions/upload-artifact@v4 + with: + name: frontend-dist + path: server/router/frontend/dist + retention-days: 1 + + build-binaries: + name: Build ${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.goarm && format('v{0}', matrix.goarm) || '' }} + needs: [prepare, build-frontend] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - goos: linux + goarch: amd64 + - goos: linux + goarch: arm64 + - goos: linux + goarch: arm + goarm: "7" + - goos: darwin + goarch: amd64 + - goos: darwin + goarch: arm64 + - goos: windows + goarch: amd64 + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Go + uses: actions/setup-go@v6 + with: + go-version: ${{ env.GO_VERSION }} + cache: true + + - name: Download frontend artifacts + uses: actions/download-artifact@v4 + with: + name: frontend-dist + path: server/router/frontend/dist + + - name: Build binary + env: + GOOS: ${{ matrix.goos }} + GOARCH: ${{ matrix.goarch }} + GOARM: ${{ matrix.goarm }} + CGO_ENABLED: "0" + run: | + output_name="memos" + if [ "$GOOS" = "windows" ]; then + output_name="memos.exe" + fi + + mkdir -p build + + go build \ + -trimpath \ + -ldflags="-s -w -X github.com/usememos/memos/internal/version.Version=${{ needs.prepare.outputs.version }} -X github.com/usememos/memos/internal/version.Commit=${{ github.sha }} -extldflags '-static'" \ + -tags netgo,osusergo \ + -o "build/${output_name}" \ + ./cmd/memos + + - name: Package binary + env: + VERSION: ${{ needs.prepare.outputs.version }} + GOOS: ${{ matrix.goos }} + GOARCH: ${{ matrix.goarch }} + GOARM: ${{ matrix.goarm }} + run: | + cd build + + package_name="${ARTIFACT_PREFIX}_${VERSION}_${GOOS}_${GOARCH}" + if [ -n "$GOARM" ]; then + package_name="${package_name}v${GOARM}" + fi + + if [ "$GOOS" = "windows" ]; then + artifact_name="${package_name}.zip" + zip -q "${artifact_name}" memos.exe + else + artifact_name="${package_name}.tar.gz" + tar czf "${artifact_name}" memos + fi + + echo "artifact_name=${artifact_name}" >> "$GITHUB_ENV" + + - name: Upload binary artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ env.artifact_name }} + path: build/${{ env.artifact_name }} + retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} + + checksums: + name: Generate Checksums + needs: [prepare, build-binaries] + runs-on: ubuntu-latest + steps: + - name: Download binary artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + pattern: ${{ env.ARTIFACT_PREFIX }}_* + merge-multiple: true + + - name: Generate checksums + working-directory: artifacts + run: sha256sum * > checksums.txt + + - name: Upload checksum artifact + uses: actions/upload-artifact@v4 + with: + name: checksums + path: artifacts/checksums.txt + retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} + + release: + name: Publish GitHub Release + needs: [prepare, build-binaries, checksums] + if: github.event_name != 'workflow_dispatch' + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Download binary artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + pattern: ${{ env.ARTIFACT_PREFIX }}_* + merge-multiple: true + + - name: Download checksum artifact + uses: actions/download-artifact@v4 + with: + name: checksums + path: artifacts + + - name: Publish release assets + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ needs.prepare.outputs.tag }} + name: ${{ needs.prepare.outputs.tag }} + prerelease: ${{ needs.prepare.outputs.is_prerelease == 'true' }} + files: artifacts/* + + build-push: + name: Build Image ${{ matrix.platform }} + needs: [prepare, build-frontend] + if: github.event_name != 'workflow_dispatch' + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + strategy: + fail-fast: false + matrix: + platform: + - linux/amd64 + - linux/arm/v7 + - linux/arm64 + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Download frontend artifacts + uses: actions/download-artifact@v4 + with: + name: frontend-dist + path: server/router/frontend/dist + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} + + - name: Build and push by digest + id: build + uses: docker/build-push-action@v6 + with: + context: . + file: ./scripts/Dockerfile + platforms: ${{ matrix.platform }} + build-args: | + VERSION=${{ needs.prepare.outputs.version }} + COMMIT=${{ github.sha }} + cache-from: type=gha,scope=release-${{ matrix.platform }} + cache-to: type=gha,mode=max,scope=release-${{ matrix.platform }} + outputs: type=image,name=neosmemo/memos,push-by-digest=true,name-canonical=true,push=true + + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ strategy.job-index }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge-images: + name: Publish Release Image Tags + needs: [prepare, build-push] + if: github.event_name != 'workflow_dispatch' + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + pattern: digests-* + merge-multiple: true + path: /tmp/digests + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} + + - name: Create manifest list and push + working-directory: /tmp/digests + run: | + version="${{ needs.prepare.outputs.version }}" + if [ "${{ needs.prepare.outputs.is_prerelease }}" = "true" ]; then + docker buildx imagetools create \ + -t "neosmemo/memos:${version}" \ + -t "ghcr.io/usememos/memos:${version}" \ + $(printf 'neosmemo/memos@sha256:%s ' *) + exit 0 + fi + + docker buildx imagetools create \ + -t "neosmemo/memos:${version}" \ + -t "neosmemo/memos:${{ needs.prepare.outputs.major_minor }}" \ + -t "neosmemo/memos:stable" \ + -t "ghcr.io/usememos/memos:${version}" \ + -t "ghcr.io/usememos/memos:${{ needs.prepare.outputs.major_minor }}" \ + -t "ghcr.io/usememos/memos:stable" \ + $(printf 'neosmemo/memos@sha256:%s ' *) + + - name: Inspect images + run: | + docker buildx imagetools inspect neosmemo/memos:${{ needs.prepare.outputs.version }} + if [ "${{ needs.prepare.outputs.is_prerelease }}" = "true" ]; then + exit 0 + fi + + docker buildx imagetools inspect neosmemo/memos:stable diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..18991fe --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,24 @@ +name: Close Stale + +on: + schedule: + - cron: "0 */8 * * *" # Every 8 hours + +jobs: + close-stale: + name: Close Stale Issues and PRs + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - name: Mark and close stale issues and PRs + uses: actions/stale@v10.1.1 + with: + # Issues: mark stale after 14 days of inactivity, close after 3 more days + days-before-issue-stale: 14 + days-before-issue-close: 3 + + # Pull requests: mark stale after 14 days of inactivity, close after 3 more days + days-before-pr-stale: 14 + days-before-pr-close: 3 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6b0f279 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# temp folder +tmp + +# Frontend asset +web/dist + +# Build artifacts +build/ +bin/ +memos + +.DS_Store + +# Jetbrains +.idea + +# Docker Compose Environment File +.env + +dist + +# VSCode settings +.vscode + +# Git worktrees +.worktrees/ + +# Local pnpm store (project-scoped, created when --config.store-dir is set +# without an existing store; contains a symlink back to the workspace). +.pnpm-store/ + +# Frontend test coverage output (Vitest + @vitest/coverage-v8). +web/coverage/ diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..b97938f --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,101 @@ +version: "2" + +linters: + enable: + - revive + - govet + - staticcheck + - misspell + - gocritic + - sqlclosecheck + - rowserrcheck + - nilerr + - godot + - forbidigo + - mirror + - bodyclose + disable: + - errcheck + settings: + exhaustive: + explicit-exhaustive-switch: false + staticcheck: + checks: + - all + - -ST1000 + - -ST1003 + - -ST1021 + - -QF1003 + revive: + # Default to run all linters so that new rules in the future could automatically be added to the static check. + enable-all-rules: true + rules: + # The following rules are too strict and make coding harder. We do not enable them for now. + - name: file-header + disabled: true + - name: line-length-limit + disabled: true + - name: function-length + disabled: true + - name: max-public-structs + disabled: true + - name: function-result-limit + disabled: true + - name: banned-characters + disabled: true + - name: argument-limit + disabled: true + - name: cognitive-complexity + disabled: true + - name: cyclomatic + disabled: true + - name: confusing-results + disabled: true + - name: add-constant + disabled: true + - name: flag-parameter + disabled: true + - name: nested-structs + disabled: true + - name: import-shadowing + disabled: true + - name: early-return + disabled: true + - name: use-any + disabled: true + - name: exported + disabled: true + - name: unhandled-error + disabled: true + - name: if-return + disabled: true + - name: max-control-nesting + disabled: true + - name: redefines-builtin-id + disabled: true + - name: package-comments + disabled: true + gocritic: + disabled-checks: + - ifElseChain + govet: + settings: + printf: # The name of the analyzer, run `go tool vet help` to see the list of all analyzers + funcs: # Run `go tool vet help printf` to see the full configuration of `printf`. + - common.Errorf + enable-all: true + disable: + - fieldalignment + - shadow + forbidigo: + forbid: + - pattern: 'fmt\.Errorf(# Please use errors\.Wrap\|Wrapf\|Errorf instead)?' + - pattern: 'ioutil\.ReadDir(# Please use os\.ReadDir)?' + +formatters: + enable: + - goimports + settings: + goimports: + local-prefixes: + - github.com/usememos/memos diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..712789e --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.29.1" +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..2a1414d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,125 @@ +# AGENTS.md + +Repository instructions for AI coding agents. Keep this file short, concrete, and tied to commands that actually work in this +repo. If a fact here conflicts with source files or CI config, trust the source file and update this guide. + +## Project Snapshot + +Memos is a self-hosted note-taking app. + +- Backend: Go 1.26.2, Echo v5, Connect RPC, gRPC-Gateway, Protocol Buffers. +- Frontend: React 19, TypeScript 6, Vite 8, Tailwind CSS v4, React Query v5. +- Storage: SQLite, MySQL, PostgreSQL. +- Generated API outputs: `proto/gen/` for Go/OpenAPI, `web/src/types/proto/` for TypeScript. + +## Working Rules + +- Read relevant code before editing; prefer local patterns over new abstractions. +- Keep diffs scoped. Do not do repo-wide cleanup, dependency churn, or generated-file rewrites unless the task requires it. +- Do not hand-edit generated proto outputs. Change `.proto` files, then run `buf generate`. +- Add migrations for all database drivers when schema changes, and update each driver's `LATEST.sql`. +- Add public API endpoints to `server/router/api/v1/acl_config.go`. +- Ask before adding heavy dependencies, changing auth/token behavior, or altering Docker/release workflows. + +## Commands + +Run from the repository root unless a command starts with `cd`. + +```bash +# Backend +go run ./cmd/memos --port 8081 # Start backend dev server +go test ./... # Run all Go tests +go test -v ./store/... # Store tests, including DB drivers via TestContainers +go test -v -race ./server/... # Server tests with race detector +go test -v -race ./internal/... # Internal package tests with race detector +go test -v -run TestFoo ./pkg/... # Run matching Go tests +go mod tidy -go=1.26.2 # Match CI tidy check +golangci-lint run # Go lint, config: .golangci.yaml +golangci-lint run --fix # Auto-fix lint, including goimports + +# Frontend +cd web && pnpm install # Install dependencies +cd web && pnpm dev # Dev server on :3001, proxying API to :8081 +cd web && pnpm lint # Type check + Biome lint +cd web && pnpm test # Vitest unit tests +cd web && pnpm build # Production build +cd web && pnpm release # Build SPA into server/router/frontend/dist + +# Protocol Buffers +cd proto && buf generate # Regenerate Go + TypeScript + OpenAPI +cd proto && buf lint # Lint proto files +cd proto && buf format -w # Format proto files +``` + +## Code Map + +| Path | Purpose | +| --- | --- | +| `cmd/memos/main.go` | Cobra/Viper CLI setup and server startup | +| `server/server.go` | Echo HTTP server and background runner wiring | +| `server/auth/` | JWT access tokens, refresh tokens, PAT handling | +| `server/router/api/v1/` | Connect/gRPC-Gateway services, ACL config, SSE hub | +| `server/router/frontend/` | Static SPA serving | +| `server/router/fileserver/` | Native HTTP file serving, thumbnails, range requests | +| `server/runner/` | Background memo processing and S3 presign refresh | +| `store/` | Store facade, cache, migrations, driver interface | +| `store/db/{sqlite,mysql,postgres}/` | Database-specific drivers and SQL | +| `proto/api/v1/` | Public API service definitions | +| `proto/store/` | Internal storage proto messages | +| `internal/` | App-private packages: scheduler, cron, email, CEL filter, markdown, idp, S3 | +| `web/src/connect.ts` | Connect RPC clients, auth interceptor, access-token refresh | +| `web/src/auth-state.ts` | Token storage and BroadcastChannel cross-tab sync | +| `web/src/hooks/` | React Query hooks for server state | +| `web/src/contexts/` | React context for client/UI state | +| `web/src/components/` | Radix/Tailwind UI components and feature components | +| `web/src/themes/` | CSS themes using OKLch color tokens | + +## Change Routing + +| Change | Update | Verify | +| --- | --- | --- | +| Go service or router behavior | Service code under `server/`, tests near package | `go test -v -race ./server/...` | +| Store or migration behavior | `store/`, all three DB driver migrations, `LATEST.sql` | `go test -v ./store/...` | +| Internal package logic | Relevant `internal/` package tests | `go test -v -race ./internal/...` | +| Frontend behavior | Components/hooks/contexts under `web/src/` | `cd web && pnpm lint && pnpm test` | +| Frontend production output | Vite config or release-sensitive UI | `cd web && pnpm build` or `pnpm release` | +| Proto API | `.proto` source plus generated outputs | `cd proto && buf generate && buf lint` | +| Public unauthenticated route | `server/router/api/v1/acl_config.go` | Targeted server test or manual route check | + +## Go Conventions + +- Wrap errors with `errors.Wrap(err, "context")` from `github.com/pkg/errors`; do not use `fmt.Errorf`. +- Return service errors with `status.Errorf(codes.X, "message")`. +- Keep imports grouped as stdlib, third-party, then `github.com/usememos/memos`; goimports is run by golangci-lint. +- Add doc comments for exported identifiers; godot enforces exported comment punctuation. +- Avoid package-level mutable state unless the surrounding package already uses that pattern. + +## Frontend Conventions + +- Use `@/` for absolute imports. +- Follow Biome formatting: 2-space indent, double quotes, semicolons, 140-character line width. +- Put server data in React Query hooks under `web/src/hooks/`; keep UI-only state in contexts or component state. +- Use Tailwind CSS v4 utilities, `cn()` for class merging, and CVA for variants. +- Reuse Radix primitives and existing components before adding new UI primitives. +- Keep generated proto TypeScript under `web/src/types/proto/` out of manual edits and Biome rewrites. + +## Database And Proto Rules + +- Schema changes require SQLite, MySQL, and PostgreSQL migrations plus `LATEST.sql` updates. +- Fresh-install SQL and incremental migrations must stay equivalent. +- Proto field changes must preserve compatibility unless the task explicitly allows a breaking API change. +- Regenerate after proto edits and include both Go/OpenAPI and TypeScript generated outputs. + +## Verification Policy + +- Run the narrowest relevant checks while iterating. +- Before finishing, run the checks that match the changed surface from "Change Routing". +- For docs-only changes, `git diff --check` is sufficient unless the docs include runnable examples that should be tested. +- If a required check cannot run locally, report the reason and the exact command that remains. + +## CI Reference + +- Backend CI: Go 1.26.2, `go mod tidy -go=1.26.2`, golangci-lint v2.11.3, test groups `store`, `server`, `internal`, `other`. +- Frontend CI: Node 24, pnpm 11.0.1, `pnpm lint`, `pnpm test`, `pnpm build`. +- Proto CI: `buf lint` and `buf format` check. +- Docker: `scripts/Dockerfile`, Alpine 3.21 runtime, non-root user, port 5230, multi-arch amd64/arm64/arm/v7. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8832d6e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,183 @@ +# Changelog + +## [0.29.1](https://github.com/usememos/memos/compare/v0.29.0...v0.29.1) (2026-06-04) + + +### Bug Fixes + +* **markdown:** keep task item content in one grid column ([7c3bff4](https://github.com/usememos/memos/commit/7c3bff4e98223fb99a5d49f093e3cd57dd140ba4)) +* support <meta name=description> in link previews ([#6000](https://github.com/usememos/memos/issues/6000)) ([e8d32e8](https://github.com/usememos/memos/commit/e8d32e87d1d6e4927250ad5794ba5965e0260153)) +* **web:** render video attachment posters on mobile ([0e2a9a9](https://github.com/usememos/memos/commit/0e2a9a9c0ce0e2da63535210c553b3ae2f79b239)) + +## [0.29.0](https://github.com/usememos/memos/compare/v0.28.0...v0.29.0) (2026-05-27) + + +### Features + +* **about:** add about page with bird sprites ([411ba7b](https://github.com/usememos/memos/commit/411ba7b34c0c23ad217a7897835097887a28a036)) +* **activity-calendar:** aggregate by ViewContext.timeBasis ([8daef1d](https://github.com/usememos/memos/commit/8daef1dc89544512fff78fd64d8216b2babc2e42)) +* add <Placeholder> component with ASCII bird states ([#5949](https://github.com/usememos/memos/issues/5949)) ([8c16ffa](https://github.com/usememos/memos/commit/8c16ffa1f1410f9413cb57ebe251b4b604f9aeff)) +* add configurable `--log-level` flag ([#5934](https://github.com/usememos/memos/issues/5934)) ([f1e2a06](https://github.com/usememos/memos/commit/f1e2a06b46c7f45ba6562c308d2703fdfb4067b0)) +* add dedicated shortcuts page ([#5942](https://github.com/usememos/memos/issues/5942)) ([1df6479](https://github.com/usememos/memos/commit/1df6479443c334732b862d60a0f76e61f00ebb89)) +* add link metadata endpoints ([9c5c604](https://github.com/usememos/memos/commit/9c5c604944428d3f682f35c9d05a87c1d4c3152f)) +* **frontend:** add pixel bird tilemaps ([cf55f11](https://github.com/usememos/memos/commit/cf55f1107273c928e7c2d6bc26df5f3efea26458)) +* **memo:** add task list quick actions ([#5983](https://github.com/usememos/memos/issues/5983)) ([648b3bd](https://github.com/usememos/memos/commit/648b3bd812e5bf2b1abb9f8b3529efefe4734e7c)) +* **memo:** create memos on the selected calendar date ([#5925](https://github.com/usememos/memos/issues/5925)) ([ef55013](https://github.com/usememos/memos/commit/ef55013418d68e2d6a24a6d02a0365c1ffff03d7)) +* **notification:** add smtp email settings ([cd4f28a](https://github.com/usememos/memos/commit/cd4f28ae1058a125e245ea0a6eae16aea71b8f9d)) +* **placeholder:** add woodpecker tilemap ([638e4f3](https://github.com/usememos/memos/commit/638e4f398e90c556f70af150a79538312c8fc760)) +* render link metadata cards ([0bc5669](https://github.com/usememos/memos/commit/0bc56694b0ca347ab1eb083f62997a22007b763d)) +* **stats:** admin instance resource statistics ([ea0625d](https://github.com/usememos/memos/commit/ea0625da45a419e08158ab4102051f3fe5e59b87)) +* **stats:** support filtered all-user stats ([88ac3ec](https://github.com/usememos/memos/commit/88ac3ec31ee3e808db82663c04a31cf730d1221e)) +* **transcription:** explicit STT settings with provider, model, prompt ([#5926](https://github.com/usememos/memos/issues/5926)) ([238f27d](https://github.com/usememos/memos/commit/238f27dea149492a78a8994470b0aac55fece78d)) + + +### Bug Fixes + +* avoid update event on memo create attachments ([#5961](https://github.com/usememos/memos/issues/5961)) ([3c3382a](https://github.com/usememos/memos/commit/3c3382a3c652bed3b58058931ff3cbf1d875b9a8)) +* delete user cleanup ([#5981](https://github.com/usememos/memos/issues/5981)) ([e53b7d9](https://github.com/usememos/memos/commit/e53b7d96e70965529ba3b04ea720ea6966f77b60)) +* **editor:** wrap selected text when pasting URL ([e0bb3a2](https://github.com/usememos/memos/commit/e0bb3a2e684e932309df2f9fb0ff774ce8e6b692)) +* **fileserver:** preserve HDR image metadata in thumbnails ([c724232](https://github.com/usememos/memos/commit/c7242324a18962e453e7f2a0309a7c07b358bdbe)) +* **frontend:** correct static cache headers ([084f40b](https://github.com/usememos/memos/commit/084f40bc9e5922ff2d41c08dce837b96696437aa)) +* **frontend:** use correct url path for memos in sitemap.xml ([#5921](https://github.com/usememos/memos/issues/5921)) ([603781f](https://github.com/usememos/memos/commit/603781f792b2603fbda93146988a64a93c92d760)) +* **httpgetter:** prevent DNS rebinding in link metadata fetch ([078488c](https://github.com/usememos/memos/commit/078488ca818626fbcab69bdfb4b93b58dca6b6eb)) +* **markdown:** align list items with checkboxes ([e008b1a](https://github.com/usememos/memos/commit/e008b1a23c77945eff87707eb15578d4d6d74e4c)) +* **memo:** enforce parent visibility for comments ([4a1e401](https://github.com/usememos/memos/commit/4a1e401bd99c7850ac48e9693b25c9ebeecfb042)) +* **s3presign:** preserve motion media payload ([7f1f53f](https://github.com/usememos/memos/commit/7f1f53ffc417962f6930d1e6e3783eacd911003d)) +* **security:** enforce attachment ownership on memo updates ([35bf761](https://github.com/usememos/memos/commit/35bf761b8c2c3f155bdc06e9b373b6076116a725)) +* **sse:** stream initial response and refresh tokens ([21303e8](https://github.com/usememos/memos/commit/21303e879d2c7a857306206d2cbdae83f61983e6)) +* **user:** omit internal settings from list responses ([#5917](https://github.com/usememos/memos/issues/5917)) ([1df3fe7](https://github.com/usememos/memos/commit/1df3fe79559ccf94b6c71e9ffb58e870ed43820d)) +* **web:** sync avatar changes immediately after profile update ([#5903](https://github.com/usememos/memos/issues/5903)) ([328396a](https://github.com/usememos/memos/commit/328396a97f2219592032e8418c383e0ab7edaca6)) + + +### Performance Improvements + +* lazy load heavy first-screen dependencies ([#5947](https://github.com/usememos/memos/issues/5947)) ([a6024ee](https://github.com/usememos/memos/commit/a6024eebf129c4b8fb65ee0cba09c6657274bfde)) + +## [0.28.0](https://github.com/usememos/memos/compare/v0.27.1...v0.28.0) (2026-04-27) + + +### Features + +* **auth:** add SSO user identity linkage ([#5883](https://github.com/usememos/memos/issues/5883)) ([d688914](https://github.com/usememos/memos/commit/d688914b2864791eeadbf21c882608632875f17c)) +* **memos:** choose created or updated time for memos ([#5894](https://github.com/usememos/memos/issues/5894)) ([c268551](https://github.com/usememos/memos/commit/c268551a16929a2cbea6891951feff91926bba59)) +* redesign account and SSO management ([#5886](https://github.com/usememos/memos/issues/5886)) ([ee17998](https://github.com/usememos/memos/commit/ee1799851e88674a6920c7a56d93428fcf95e662)) + + +### Bug Fixes + +* **auth:** harden authorization and username validation ([#5890](https://github.com/usememos/memos/issues/5890)) ([0fb83a7](https://github.com/usememos/memos/commit/0fb83a745dd5057ade45a3caad2c444af2239113)) +* disable modal prop on DropdownMenu to prevent scroll disappearing ([#5861](https://github.com/usememos/memos/issues/5861)) ([d98f665](https://github.com/usememos/memos/commit/d98f6659190b8d1a8252e64549d9120d85e05d33)) +* fix legacy username auth flows ([#5885](https://github.com/usememos/memos/issues/5885)) ([30c0611](https://github.com/usememos/memos/commit/30c0611a82f9254952a74650095105254f2940e4)) +* **markdown:** split mixed task and bullet lists ([e2c6084](https://github.com/usememos/memos/commit/e2c60845eaff9a78b8d8eb3ccc9a067ef5690976)) +* reduce list memo query overhead ([#5880](https://github.com/usememos/memos/issues/5880)) ([5063804](https://github.com/usememos/memos/commit/50638040f618b02b0c6d010e1d41554c75067517)) +* **web:** preserve task checkbox state ([#5867](https://github.com/usememos/memos/issues/5867)) ([b5863d7](https://github.com/usememos/memos/commit/b5863d76be3cfbf3e0f8237d8e762122b5a0a679)) + +## [0.27.1](https://github.com/usememos/memos/compare/v0.27.0...v0.27.1) (2026-04-19) + + +### Bug Fixes + +* mixed-case user resource names ([#5853](https://github.com/usememos/memos/issues/5853)) ([01be01f](https://github.com/usememos/memos/commit/01be01f4b7676af41bdd1758b1e9b096aa922546)) +* **release:** inject build version into artifacts ([f8a304b](https://github.com/usememos/memos/commit/f8a304bae33086320b39095d631288156eec4249)) +* user resource names can be uuidv4 from idp sub claim ([#5856](https://github.com/usememos/memos/issues/5856)) ([bbded58](https://github.com/usememos/memos/commit/bbded584ce85a856d863485768e08b53adec7244)) + +## [0.27.0](https://github.com/usememos/memos/compare/v0.26.2...v0.27.0) (2026-04-18) + + +### Features + +* add --allow-private-webhooks flag to bypass SSRF protection ([#5694](https://github.com/usememos/memos/issues/5694)) ([cd5816c](https://github.com/usememos/memos/commit/cd5816c428931f56561f7d48b649a33858812539)) +* add blur_content attribute to tag metadata settings ([#5767](https://github.com/usememos/memos/issues/5767)) ([45b2153](https://github.com/usememos/memos/commit/45b21530d9ebbc730e77bcbcf407f4c295b52e93)) +* add Gemini transcription provider ([#5830](https://github.com/usememos/memos/issues/5830)) ([d87539a](https://github.com/usememos/memos/commit/d87539a1e1261590ab355220e33fa0ae00bd9431)) +* add GitHub release installer and release workflow ([1ed542c](https://github.com/usememos/memos/commit/1ed542c21db421e9aa0cc47417a92c6bd103e257)) +* add live refresh via Server-Sent Events (SSE) with visual indicator ([#5638](https://github.com/usememos/memos/issues/5638)) ([ea0892a](https://github.com/usememos/memos/commit/ea0892a8b26d8806a093e3a942562dfc22794f68)) +* add MCP server with PAT authentication ([47d9414](https://github.com/usememos/memos/commit/47d9414702dc18966af385352b960bfe451511b7)) +* add outline navigation to memo detail sidebar ([#5771](https://github.com/usememos/memos/issues/5771)) ([6b30579](https://github.com/usememos/memos/commit/6b3057990396f9cb6f21706c2e99dddebc35ffd5)) +* **ai:** add BYOK audio transcription ([#5832](https://github.com/usememos/memos/issues/5832)) ([101704c](https://github.com/usememos/memos/commit/101704c8eac17c7f34508d8db6c53bc972061cdb)) +* **ai:** add instance AI providers and transcription ([#5829](https://github.com/usememos/memos/issues/5829)) ([83ed32f](https://github.com/usememos/memos/commit/83ed32f1195841d2d6c057c3e00086a3147879a2)) +* **attachments:** add Live Photo and Motion Photo support ([#5810](https://github.com/usememos/memos/issues/5810)) ([4b4e719](https://github.com/usememos/memos/commit/4b4e719470184e49cd62084b1aa53c9a777a9fec)) +* **cli:** add version subcommand ([#5731](https://github.com/usememos/memos/issues/5731)) ([0ba4c0f](https://github.com/usememos/memos/commit/0ba4c0f397c532a5a314f35ddeb3ce3633e84d42)) +* **editor:** add voice note recording to the memo composer ([#5801](https://github.com/usememos/memos/issues/5801)) ([c0d5854](https://github.com/usememos/memos/commit/c0d5854f678f357cf4054d448e0311f2ee90f8ac)) +* extract title from first H1 heading into memo property ([#5726](https://github.com/usememos/memos/issues/5726)) ([1e688b2](https://github.com/usememos/memos/commit/1e688b2a5d78c2972f4b0078a7b033dae5d1cbf3)) +* **i18n:** update sse connect label in Chinese ([#5732](https://github.com/usememos/memos/issues/5732)) ([89c6902](https://github.com/usememos/memos/commit/89c69028953fa33dbb6e0e257d764636c0fc2d09)) +* **instance:** add canonical tag metadata setting ([#5736](https://github.com/usememos/memos/issues/5736)) ([65d14fb](https://github.com/usememos/memos/commit/65d14fbb63053fc1fbf1f63881c81adbc9d01671)) +* **instance:** add notification transport setting ([#5737](https://github.com/usememos/memos/issues/5737)) ([a249d06](https://github.com/usememos/memos/commit/a249d06e2e0f33e0e3fea34471a891352dacc466)) +* **mcp:** enhance MCP server with full capabilities and new tools ([#5720](https://github.com/usememos/memos/issues/5720)) ([b8e9ee2](https://github.com/usememos/memos/commit/b8e9ee2b26a59e1b19aab6db3ca39656fc18785a)) +* **mcp:** harden tool exposure and side effects ([#5850](https://github.com/usememos/memos/issues/5850)) ([583c3d2](https://github.com/usememos/memos/commit/583c3d24f4d785faa5e034c1b88ed90eda119baa)) +* **mcp:** refactor MCP server to standard protocol structure ([803d488](https://github.com/usememos/memos/commit/803d488a5f8f55477cd3ad4cc4cf0fac98901dd3)) +* **memo-editor:** add compact live waveform recorder panel ([#5817](https://github.com/usememos/memos/issues/5817)) ([e51985a](https://github.com/usememos/memos/commit/e51985a29ffeeecd318b2fb793358ed45bb0eff4)) +* **memo-preview:** support comment metadata in previews ([#5768](https://github.com/usememos/memos/issues/5768)) ([e176b28](https://github.com/usememos/memos/commit/e176b28c801cc3bb3718208a96a7d64c36620d0f)) +* **memo:** add image sharing in detail view ([38fc22b](https://github.com/usememos/memos/commit/38fc22b7541b8a9ddcd848cf77054fcf844eb87f)) +* **memo:** add share links for private memos ([#5742](https://github.com/usememos/memos/issues/5742)) ([3f3133d](https://github.com/usememos/memos/commit/3f3133d6e2f404061e147f9dd2424680dc0303a3)) +* **mentions:** add memo mention parsing, notifications, and rendering ([#5811](https://github.com/usememos/memos/issues/5811)) ([24fc8ab](https://github.com/usememos/memos/commit/24fc8ab8ca68d092e7b12a5d51c48ca9420f72b5)) +* replace auto-increment ID with UID for identity provider resource names ([#5687](https://github.com/usememos/memos/issues/5687)) ([92d937b](https://github.com/usememos/memos/commit/92d937b1aa87365152edc005a3b736e6bf9b9e45)) +* show inline comment preview in list view ([3a5d3c8](https://github.com/usememos/memos/commit/3a5d3c8ff92ae5c24559dc4574300d6475820a87)) +* **store:** change default storage type to local filesystem ([78efa68](https://github.com/usememos/memos/commit/78efa6802e2fd96c981e86c5b658fb4b5c05091f)) +* treat tag setting keys as anchored regex patterns ([#5759](https://github.com/usememos/memos/issues/5759)) ([9e04049](https://github.com/usememos/memos/commit/9e04049632e63f1cf53535773f170c1aa5af7168)) +* **ui:** allow navigating between images with arrows in preview dialog ([#5669](https://github.com/usememos/memos/issues/5669)) ([104d2ec](https://github.com/usememos/memos/commit/104d2ec0a6973e983c46724165fdc0916515ad16)) +* **user:** add per-user tag metadata settings ([#5735](https://github.com/usememos/memos/issues/5735)) ([330291d](https://github.com/usememos/memos/commit/330291d4d9fa95649e940001898929b4f6f0367e)) +* **web:** add demo mode banner ([#5836](https://github.com/usememos/memos/issues/5836)) ([35504cc](https://github.com/usememos/memos/commit/35504cc8bd6f9921291fb565633d549388a3f948)) +* **webhook:** dispatch webhook on memo comment creation ([7c1defb](https://github.com/usememos/memos/commit/7c1defba01fbc91cc81e1a0841cecb6738056db7)) + + +### Bug Fixes + +* access token refresh on web app ([#5681](https://github.com/usememos/memos/issues/5681)) ([3010f10](https://github.com/usememos/memos/commit/3010f10eafb49af5aadd71a94b3ef7a6ec71f617)) +* add unix socket file permission setting (755 -> 660) ([#5849](https://github.com/usememos/memos/issues/5849)) ([0fc1dab](https://github.com/usememos/memos/commit/0fc1dab28b33f7fdbe9a21cd3bd3affe75dd7f19)) +* **api:** appease image size lint ([ff6389a](https://github.com/usememos/memos/commit/ff6389a5ef73772fcb5c132bf1cb169fb4744c00)) +* **api:** improve SSE hub design and fix double-broadcast on comments ([c53677f](https://github.com/usememos/memos/commit/c53677fcba202a8eed35c8ecdfaacea5152b8691)) +* **api:** make credentials write-only and restrict sensitive settings to admins ([9d3a74b](https://github.com/usememos/memos/commit/9d3a74bcccf934aa2fa95ee240b56cc3b3a25776)) +* **api:** reduce memory pressure in backend paths ([c456637](https://github.com/usememos/memos/commit/c45663761d148e94d3e1b30f4810922e7c2571ab)) +* **api:** remove public activity service ([#5734](https://github.com/usememos/memos/issues/5734)) ([04f239a](https://github.com/usememos/memos/commit/04f239a2fc74f7090c779a6a7b8a08238fd31b88)) +* **api:** restrict user email exposure to self and admins ([#5784](https://github.com/usememos/memos/issues/5784)) ([a24d420](https://github.com/usememos/memos/commit/a24d4209222814e4a8bedfc0392e91462bc855ad)) +* **api:** switch user resource names to usernames ([#5779](https://github.com/usememos/memos/issues/5779)) ([acddef1](https://github.com/usememos/memos/commit/acddef1f3dcca44806bcbb85e9dc5cae7daa5285)) +* **api:** tolerate missing related users in memo conversions ([#5809](https://github.com/usememos/memos/issues/5809)) ([25feef3](https://github.com/usememos/memos/commit/25feef3aadd34bfd474d7e3b685815a6509bc4c6)) +* **auth:** recover session via refresh cookie when localStorage is empty ([#5748](https://github.com/usememos/memos/issues/5748)) ([551ee1d](https://github.com/usememos/memos/commit/551ee1d81f398abdcaf73a0c2b782c8379b0e3f2)) +* backend tests action ([065e817](https://github.com/usememos/memos/commit/065e817470b1d3b6b00222525791b85d825c1492)) +* clear content search filter when selecting shortcut ([#5499](https://github.com/usememos/memos/issues/5499)) ([2c3f9e3](https://github.com/usememos/memos/commit/2c3f9e3bfbe09e5d0028d1525c1df83c03f547c9)) +* correct typos in comments, error messages, and identifiers ([#5704](https://github.com/usememos/memos/issues/5704)) ([8f43e80](https://github.com/usememos/memos/commit/8f43e8075b62706f99da4005ab04b165b35215f6)) +* detect legacy installations with empty schema version ([9628d3d](https://github.com/usememos/memos/commit/9628d3de21289e887ffeb6cc4b6710913a0de44e)) +* **editor:** show newly linked memos when editing a memo with attachments ([026ea92](https://github.com/usememos/memos/commit/026ea92f7b4005c30ca84340c22018740659ab51)) +* ensure comment divs span full width in MemoDetail ([ce44164](https://github.com/usememos/memos/commit/ce441644af34ffff156f1793c40011c2b82e8d5f)) +* **fileserver:** render SVG attachment previews ([40fd700](https://github.com/usememos/memos/commit/40fd700fb8be27a8d7a300a2636cf4f366572176)) +* **filter:** enforce CEL syntax semantics ([0e89407](https://github.com/usememos/memos/commit/0e89407ee91deda87e0df7464a89d26d1e9a88b3)) +* **frontend:** restore sitemap and robots routes ([fee7fcd](https://github.com/usememos/memos/commit/fee7fcd6608b9d07da1f146c33c9bb8f898f708f)) +* handle chunk load errors after redeployment with auto-reload ([#5703](https://github.com/usememos/memos/issues/5703)) ([bdd3554](https://github.com/usememos/memos/commit/bdd3554b897246bac5c1e6fd801495c24b6a656e)) +* harden memo content iframe and HTML sanitization ([7e21b72](https://github.com/usememos/memos/commit/7e21b728b346e80023c93e8986130f83e70584f9)) +* hide transcribe button without AI provider ([ab53329](https://github.com/usememos/memos/commit/ab5332901fd6626f0a2ae6b99671af9663f68078)) +* improve image preview dialog and live photo trigger ([aafcc21](https://github.com/usememos/memos/commit/aafcc21ae6f96a313fb372365dd1af8a1a69d1ba)) +* improve installer compatibility and docs ([f90d9a4](https://github.com/usememos/memos/commit/f90d9a49a78d0764a6c5cf8f6720e69ea1164b25)) +* improve KaTeX and Mermaid error handling and overflow ([6b37fcc](https://github.com/usememos/memos/commit/6b37fcc01b5dcded6a2ec254fbaf895f7812d072)) +* include plain URLs and tags in memo snippet generation ([#5688](https://github.com/usememos/memos/issues/5688)) ([3d4f793](https://github.com/usememos/memos/commit/3d4f793f97b567bda823a60b7fe10e09e14499ce)) +* **lint:** correct goimports struct literal alignment after removing write-only credential fields ([#5794](https://github.com/usememos/memos/issues/5794)) ([9610ed8](https://github.com/usememos/memos/commit/9610ed8fc809b3e7aa4b93e4909634957fa94cf7)) +* **map:** align dark mode map styling ([7ac9989](https://github.com/usememos/memos/commit/7ac9989d43f3967b466f340da3841290d86b20f1)) +* **map:** refine Leaflet controls and memo map styling ([894b3eb](https://github.com/usememos/memos/commit/894b3eb045c7d2c2acce847c34a85295c909dcf7)) +* **markdown:** support height/width attributes on img elements ([737acbb](https://github.com/usememos/memos/commit/737acbba2f5e3dd911da3a77d2d5d1cde1bf8ba1)) +* **memo-editor:** scope Cmd+Enter save to the active editor ([#5745](https://github.com/usememos/memos/issues/5745)) ([05810e7](https://github.com/usememos/memos/commit/05810e7882cb03d448d9d8fa84bc6ca54eafbed0)) +* **mysql:** handle CreateMemo custom timestamps with FROM_UNIXTIME ([#5673](https://github.com/usememos/memos/issues/5673)) ([09d73e8](https://github.com/usememos/memos/commit/09d73e8b6e16c43a61767817909a472916c83daa)) +* normalize attachment MIME types before validation ([c3e7e2c](https://github.com/usememos/memos/commit/c3e7e2c316d01bf857931c38303efc87307f2a19)) +* preserve draft content when tab is suspended or editor remounts ([9ca7122](https://github.com/usememos/memos/commit/9ca71229a6c0dfad44b76ed06fced46c5bef49c7)) +* prevent local attachment uploads from overwriting files ([4add9b0](https://github.com/usememos/memos/commit/4add9b04ad5d0b7608c985281f5975dc39f9a572)) +* prevent stale comment drafts from being restored ([e520b63](https://github.com/usememos/memos/commit/e520b637fd8d0f6331674003abe72f9dfbae8231)) +* remove duplicate Japanese locale keys ([efeb28c](https://github.com/usememos/memos/commit/efeb28c872a2bd6edd28fa3b68bd0b15af923d50)) +* render audio attachments as inline players ([#5699](https://github.com/usememos/memos/issues/5699)) ([2ccb98a](https://github.com/usememos/memos/commit/2ccb98a6cbc40544e81eeeca2a2cbbaf8348f45e)) +* restrict archived memo access to creator only ([#5707](https://github.com/usememos/memos/issues/5707)) ([f4154d0](https://github.com/usememos/memos/commit/f4154d090be3896c8e0dd83440f24953bbeb308c)) +* **routing:** redirect unauthenticated users to /explore when public visibility is allowed ([98859eb](https://github.com/usememos/memos/commit/98859eb5e5065a7c12ada983b7c38c5af5035bb6)) +* **server:** close SSE clients during shutdown ([a5ddd5a](https://github.com/usememos/memos/commit/a5ddd5adafef282f00b23e00e145119d4316f24f)) +* sync html lang attribute with active locale ([#5753](https://github.com/usememos/memos/issues/5753)) ([be00abe](https://github.com/usememos/memos/commit/be00abe852479820b7c574e15e276d70961ab7bd)) +* tag parsing truncates emojis with variation selectors ([#5496](https://github.com/usememos/memos/issues/5496)) ([3ea6ea3](https://github.com/usememos/memos/commit/3ea6ea3108f58dc34f39fa6f21d761bd2e97732b)) +* **tags:** allow blur-only tag metadata ([#5800](https://github.com/usememos/memos/issues/5800)) ([1921b57](https://github.com/usememos/memos/commit/1921b57662c2129d179930f71e5c42caf9070a19)) +* toggle focus mode do not reset editor height ([#5504](https://github.com/usememos/memos/issues/5504)) ([0729779](https://github.com/usememos/memos/commit/0729779e0427c68bdbc5b6b711a5683f66ba9bbc)) +* **ui:** show comment editor above the comment list ([#5662](https://github.com/usememos/memos/issues/5662)) ([6b0736b](https://github.com/usememos/memos/commit/6b0736b29325ff7698b7395dc761f2ca41e6521c)) +* **ui:** unify metadata component styles across MemoView and MemoEditor ([664b8c5](https://github.com/usememos/memos/commit/664b8c56290026ba2beb7b75db24c684824b8670)) +* unify live photo previews around LIVE badge playback ([6b0487d](https://github.com/usememos/memos/commit/6b0487dcd857ba72189ca0624cb4985961f08f25)) +* **webhooks:** trigger memo updates for attachment and relation changes ([#5795](https://github.com/usememos/memos/issues/5795)) ([acbc914](https://github.com/usememos/memos/commit/acbc914dea8d4e533028b03929193a4af1ac32b4)) +* **web:** prevent MemoContent prop leaks ([22519b5](https://github.com/usememos/memos/commit/22519b57a0a971ab927a03015c994c63b8c3f1da)) +* **web:** refine attachment media layout ([a0d83e1](https://github.com/usememos/memos/commit/a0d83e1a9e9d0ba50a0103e594adb011728faf8c)) +* **web:** refresh memo detail cache after editor save ([333c9df](https://github.com/usememos/memos/commit/333c9df233240a843a9e62d17c6ff464690636f8)) +* **web:** use BroadcastChannel to sync token refreshes across tabs ([bbdc998](https://github.com/usememos/memos/commit/bbdc998646e8093223a448378a2c29690f0d8612)) + + +### Performance Improvements + +* batch load memo relations when listing memos ([#5692](https://github.com/usememos/memos/issues/5692)) ([1e82714](https://github.com/usememos/memos/commit/1e82714a52c72455a6ba02605cc641d7ad4fbf1a)) diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..b75ef17 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,2 @@ +# These owners will be the default owners for everything in the repo. +* @usememos/moderators diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ad324ee --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Memos + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..78cf9b8 --- /dev/null +++ b/README.md @@ -0,0 +1,88 @@ +> ✨ Featured Sponsor: [CodeRabbit](https://coderabbit.link/usememos) — Cut code review time & bugs in half, instantly. + +# Memos + +Memos + +Open-source, self-hosted note-taking tool built for quick capture. Markdown-native, lightweight, and fully yours. + +[![Home](https://img.shields.io/badge/🏠-usememos.com-blue?style=flat-square)](https://usememos.com) +[![Live Demo](https://img.shields.io/badge/✨-Try%20Demo-orange?style=flat-square)](https://demo.usememos.com/) +[![Docs](https://img.shields.io/badge/📚-Documentation-green?style=flat-square)](https://usememos.com/docs) +[![Discord](https://img.shields.io/badge/💬-Discord-5865f2?style=flat-square&logo=discord&logoColor=white)](https://discord.gg/tfPJa4UmAv) +[![Docker Pulls](https://img.shields.io/docker/pulls/neosmemo/memos?style=flat-square&logo=docker)](https://hub.docker.com/r/neosmemo/memos) + +Memos Demo Screenshot + +## Features + +- **Instant Capture** — Timeline-first UI. Open, write, done — no folders to navigate. +- **Total Data Ownership** — Self-hosted on your infrastructure. Notes stored in Markdown, always portable. Zero telemetry. +- **Radical Simplicity** — Single Go binary, ~20MB Docker image. One command to deploy with SQLite, MySQL, or PostgreSQL. +- **Open & Extensible** — MIT-licensed with full REST and gRPC APIs for integration. + +## Quick Start + +### Docker (Recommended) + +```bash +docker run -d \ + --name memos \ + -p 5230:5230 \ + -v ~/.memos:/var/opt/memos \ + neosmemo/memos:stable +``` + +Open `http://localhost:5230` and start writing! + +### Native Binary + +```bash +curl -fsSL https://raw.githubusercontent.com/usememos/memos/main/scripts/install.sh | sh +``` + +### Try the Live Demo + +Don't want to install yet? Try our [live demo](https://demo.usememos.com/) first! + +### Other Installation Methods + +- **Docker Compose** - Recommended for production deployments +- **Pre-built Binaries** - Available for Linux, macOS, and Windows +- **Kubernetes** - Helm charts and manifests available +- **Build from Source** - For development and customization + +See our [installation guide](https://usememos.com/docs/deploy) for detailed instructions. + +## Contributing + +Contributions are welcome — bug reports, feature suggestions, pull requests, documentation, and translations. + +- [Report bugs](https://github.com/usememos/memos/issues/new?template=bug_report.md) +- [Suggest features](https://github.com/usememos/memos/issues/new?template=feature_request.md) +- [Submit pull requests](https://github.com/usememos/memos/pulls) +- [Improve documentation](https://github.com/usememos/dotcom) +- [Help with translations](https://github.com/usememos/memos/tree/main/web/src/locales) + +## Sponsors +* [**CodeRabbit** - Cut code review time & bugs in half, instantly](https://coderabbit.link/usememos) +* [**SSD Nodes** - Affordable VPS hosting for self-hosters](https://ssdnodes.com/?utm_source=memos&utm_medium=sponsor) +* [**InstaPods** - Get your app online in seconds](https://instapods.com/?utm_source=memos&utm_medium=sponsor) • [Deploy Memos in 30 Seconds](https://instapods.com/apps/memos/?utm_source=memos&utm_medium=sponsor) + +Love Memos? [Sponsor us on GitHub](https://github.com/sponsors/usememos) to help keep the project growing! + +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=usememos/memos&type=Date)](https://star-history.com/#usememos/memos&Date) + +## License + +Memos is open-source software licensed under the [MIT License](LICENSE). See our [Privacy Policy](https://usememos.com/privacy) for details on data handling. + +--- + +**[Website](https://usememos.com)** • **[Documentation](https://usememos.com/docs)** • **[Demo](https://demo.usememos.com/)** • **[Discord](https://discord.gg/tfPJa4UmAv)** • **[X/Twitter](https://x.com/usememos)** + + + Vercel OSS Program + diff --git a/README.wehub.md b/README.wehub.md new file mode 100644 index 0000000..6073243 --- /dev/null +++ b/README.wehub.md @@ -0,0 +1,7 @@ +# WeHub 来源说明 + +- 原始项目:`usememos/memos` +- 原始仓库:https://github.com/usememos/memos +- 导入方式:上游默认分支的最新快照 +- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准 +- 本文件仅用于记录来源,不代表 WeHub 是原项目作者 diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..4464620 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ +# Security Policy + +## Supported Versions + +Memos is currently a `0.x` project. Security fixes are only provided for the latest release. Older releases are not supported for security updates, and fixes are not backported. + +If you run Memos in production, keep your instance updated to the latest release. + +## Reporting a Vulnerability + +Please report security issues privately by email: `dev@usememos.com` + +Do not open public GitHub issues, discussions, or pull requests for suspected vulnerabilities. + +Please include: + +- A clear description of the issue +- Steps to reproduce +- Affected version or commit +- Deployment details that matter to reproduction +- Your assessment of impact + +We will review reports as time permits and fix valid issues in regular releases. + +## Disclosure and CVEs + +Memos is self-hosted software and is still in the `0.x` stage. At this stage, we do not run a formal disclosure program, publish separate security advisories for every issue, or request CVE IDs. + +Security fixes may be shipped directly in normal releases or noted briefly in release notes and changelogs. + +## Self-Hosted Deployment Notes + +The security posture of a Memos instance depends heavily on how it is deployed and operated. In particular: + +- Keep Memos updated +- Put it behind a properly configured reverse proxy when exposed to the internet +- Require authentication for any non-public deployment +- Use TLS in production +- Limit access to trusted users and administrators + +Reports that depend entirely on intentionally unsafe deployment choices, unsupported local patches, or administrator actions may be treated as deployment issues rather than product vulnerabilities. diff --git a/docs/identity-provider-bootstrap.md b/docs/identity-provider-bootstrap.md new file mode 100644 index 0000000..1d04883 --- /dev/null +++ b/docs/identity-provider-bootstrap.md @@ -0,0 +1,42 @@ +# Identity Provider Bootstrap + +Memos automatically reconciles OAuth2 identity providers from JSON files before the server starts. This is useful when a deployment platform provides configuration as mounted secret files. + +By default, Memos scans `/etc/secrets` for files named `memos-idp-*.json`: + +```bash +memos +``` + +For example, `/etc/secrets/memos-idp-primary.json` can contain: + +```json +{ + "uid": "primary-sso", + "name": "Company SSO", + "type": "OAUTH2", + "identifierFilter": "", + "config": { + "oauth2Config": { + "clientId": "client-id", + "clientSecret": "client-secret", + "authUrl": "https://idp.example.com/oauth/authorize", + "tokenUrl": "https://idp.example.com/oauth/token", + "userInfoUrl": "https://idp.example.com/oauth/userinfo", + "scopes": ["profile", "email"], + "fieldMapping": { + "identifier": "sub", + "displayName": "name", + "email": "email", + "avatarUrl": "picture" + } + } + } +} +``` + +Each file contains exactly one `memos.store.IdentityProvider` encoded as protobuf JSON. The database-generated numeric `id` must be omitted; `uid` is the provider's stable identifier. + +After database migrations and demo seeding, Memos reads all matching files in filename order and validates every provider before writing anything. Each provider is then created or updated by its stable `uid`; providers omitted from the files are left unchanged. Reapplying the files is safe and updates credentials on restart, which supports secret rotation. Duplicate provider UIDs across files are rejected. + +A missing directory or a directory without matching files is a normal no-op. If a matching file is unreadable, oversized, or invalid, Memos does not start. Files with other names are ignored so the directory can safely contain unrelated secrets. Keep files containing `clientSecret` outside source control and provide them through the deployment platform's secret-management facility. diff --git a/docs/plans/2026-03-23-memo-detail-outline/definition.md b/docs/plans/2026-03-23-memo-detail-outline/definition.md new file mode 100644 index 0000000..58a7b70 --- /dev/null +++ b/docs/plans/2026-03-23-memo-detail-outline/definition.md @@ -0,0 +1,35 @@ +## Background & Context + +The MemoDetail page (`web/src/pages/MemoDetail.tsx`) renders a memo's full content with a right sidebar (`MemoDetailSidebar`) on desktop. The sidebar currently shows share controls, timestamps, property badges (links, to-do, code), and tags. Memo content is rendered via `react-markdown` with custom heading components (h1–h6) in `MemoContent/markdown/Heading.tsx`. The page already has hash-based scroll-to-element infrastructure for comments (lines 39–43 of MemoDetail.tsx). + +## Issue Statement + +When viewing a memo with structured headings, there is no outline or table of contents in the MemoDetail sidebar, so readers cannot see the document structure at a glance or jump to specific sections. Heading elements rendered by the `Heading` component do not have `id` attributes, preventing any anchor-based navigation to them. + +## Current State + +- **`web/src/pages/MemoDetail.tsx`** (93 lines) — MemoDetail page. Hash-based `scrollIntoView` logic exists at lines 39–43 but only targets comment elements. The sidebar is rendered at lines 82–86 as ``. +- **`web/src/components/MemoDetailSidebar/MemoDetailSidebar.tsx`** (109 lines) — Desktop sidebar. Contains sections: Share (lines 58–65), Created-at (lines 67–76), Properties (lines 78–89), Tags (lines 91–102). Uses a reusable `SidebarSection` helper (lines 24–32). No outline section exists. +- **`web/src/components/MemoDetailSidebar/MemoDetailSidebarDrawer.tsx`** (36 lines) — Mobile drawer wrapper for the sidebar. +- **`web/src/components/MemoContent/markdown/Heading.tsx`** (30 lines) — Renders h1–h6 with Tailwind classes. Does not generate `id` attributes on heading elements. +- **`web/src/components/MemoContent/index.tsx`** (157 lines) — ReactMarkdown renderer. Maps h1–h6 to the `Heading` component (lines 72–101). No rehype-slug or equivalent plugin is installed. +- **`web/src/utils/markdown-manipulation.ts`** (143 lines) — Contains `fromMarkdown()` MDAST parsing with GFM extensions. Used for task extraction; no heading extraction exists. + +## Non-Goals + +- Redesigning the overall MemoDetail layout or sidebar structure beyond adding the outline section. +- Supporting outline for the mobile drawer — the outline section should appear in the desktop sidebar only for now. +- Adding active heading highlighting on scroll (scroll-spy behavior). +- Supporting outline in the memo list/timeline view (compact mode). +- Changing the existing heading visual styles in the content area. + +## Open Questions + +- Which heading levels to include in the outline? (default: h1–h4, matching user request) +- How to generate slug IDs — install `rehype-slug` or custom implementation? (default: lightweight custom slug generation in the Heading component to avoid a new dependency) +- Should the outline section be hidden when no headings exist? (default: yes, hide entirely like Properties/Tags sections) +- Should duplicate heading text produce unique slugs (e.g. `my-heading`, `my-heading-1`)? (default: yes, append numeric suffix for duplicates) + +## Scope + +**M** — Touches 3–4 files (Heading component, MemoDetailSidebar, possibly a new outline component, and a slug utility). Existing patterns (SidebarSection, hash scrolling) apply directly. No new subsystem or novel approach required. diff --git a/docs/plans/2026-03-23-memo-detail-outline/plan.md b/docs/plans/2026-03-23-memo-detail-outline/plan.md new file mode 100644 index 0000000..3c03967 --- /dev/null +++ b/docs/plans/2026-03-23-memo-detail-outline/plan.md @@ -0,0 +1,47 @@ +## Task List + +T1: Add heading extraction utility [S] — T2: Add slug IDs to Heading component [S] — T3: Create MemoOutline sidebar component [M] — T4: Integrate outline into MemoDetailSidebar [S] + +### T1: Add heading extraction utility [S] + +**Objective**: Provide a function to extract h1–h4 headings from markdown content with slugified IDs, reusing the existing MDAST parsing pattern from `markdown-manipulation.ts`. +**Files**: `web/src/utils/markdown-manipulation.ts` +**Implementation**: Add `HeadingItem` interface (text, level, slug) and `extractHeadings(markdown: string): HeadingItem[]` function. Use existing `fromMarkdown()` + `visit()` pattern. Visit `"heading"` nodes with depth 1–4, extract text from children, generate slug via `slugify()` helper (lowercase, replace non-alphanumeric with hyphens, deduplicate). Export both. +**Validation**: `cd web && pnpm lint` — no new errors + +### T2: Add slug IDs to Heading component [S] + +**Objective**: Generate deterministic `id` attributes on h1–h6 elements so outline links can scroll to them via `#hash`. +**Files**: `web/src/components/MemoContent/markdown/Heading.tsx` +**Implementation**: In `Heading` (~line 13), extract text from `children` using a `getTextContent(children)` helper that recursively extracts string content from React children. Generate slug with the same `slugify` logic. Apply `id={slug}` to the rendered ``. +**Validation**: `cd web && pnpm lint` — no new errors + +### T3: Create MemoOutline sidebar component [M] + +**Objective**: Create a modern, Claude/Linear-style outline component that renders h1–h4 headings as anchor links with indentation by level. +**Size**: M (new component file, modern styling) +**Files**: +- Create: `web/src/components/MemoDetailSidebar/MemoOutline.tsx` +**Implementation**: +1. Props: `{ headings: HeadingItem[] }` from `markdown-manipulation.ts` +2. Render a `