HowWorks
HowWorks

Everything begins with understanding.

Type your idea to discover matching projects. Start with what's already great so you never have to build from scratch. Build and inspire together—because greatness is never achieved alone.

Explore/DeepDive/

usememos/memos

This is a deep technical analysis of memos.

memos

memos

56.7k

An open-source, self-hosted note-taking service. Your thoughts, your data, your control — no tracking, no ads, no subscription fees.

byusememos
Detail →
Report Contents
Product — positioning, core features & user journeys
Assessment — architecture, tech stack & implementation
Assets — APIs, data models & key modules
Suggested Actions
Copy Prompt to send key insights to your AI coding assistant
Bookmark the project card to your workspace
Ask any follow-up questions below to dive deeper
AI-Generated • Verify Details
Knowledge Base
Code-to-Docs
usememos/memos
@c4176b4 · en

How usememos/memos Works

Memos positions itself as a direct, free, and open-source alternative to proprietary cloud-based note-taking services like Evernote or Notion. Its core competitive advantage is not a wider feature set, but a fundamentally different value proposition centered on data ownership, privacy, and cost-effectiveness. While cloud services offer convenience, Memos targets users who prioritize control, security, and developer-friendliness (via a comprehensive API), accepting the trade-off of self-hosting. It's a clone in concept (a note-taking app) but superior in its architectural principles of privacy and openness.

Overview

Memos positions itself as a direct, free, and open-source alternative to proprietary cloud-based note-taking services like Evernote or Notion. Its core competitive advantage is not a wider feature set, but a fundamentally different value proposition centered on data ownership, privacy, and cost-effectiveness. While cloud services offer convenience, Memos targets users who prioritize control, security, and developer-friendliness (via a comprehensive API), accepting the trade-off of self-hosting. It's a clone in concept (a note-taking app) but superior in its architectural principles of privacy and openness.

To provide a privacy-first, open-source, and self-hostable note-taking service that gives users full control over their data, functioning as a personal knowledge base or a team wiki.

Memos is a strong community-driven, self-hosted notes and knowledge base product with a modern API strategy and a pragmatic data/migration foundation that reduces operational toil for typical deployments. It is a good fit for organizations that value privacy, ownership, and extensibility via APIs, particularly in single-instance or controlled-network environments. The main decision risk is security hardening: the API gateway authentication includes a fail-open condition if routing metadata cannot be derived, and the web UI supports admin-injected scripts while storing access tokens in browser session storage, creating a credible account-takeover pathway in the presence of XSS. Pursue adoption if you can implement or upstream the security fixes and establish safe operational practices; otherwise limit use to low-risk internal contexts.

Address the two highest-impact security items first: make gateway authentication fail closed when the target method cannot be determined, and eliminate or strictly constrain script injection/token exposure in the web client.

How It Works: End-to-End Flows

First-time Setup and Creating the First Memo

This critical onboarding flow guides the administrator of a new Memos instance through securing their application and making their first post. Upon first visiting the URL of a freshly deployed instance, the system detects that no administrator account exists and automatically redirects them to the sign-up page. This prevents the instance from being left open. After creating their admin account, they are logged in and taken to the main homepage. Here, they can immediately use the primary memo editor to compose a note. The editor provides a resilient experience by automatically saving drafts to the local browser cache. Once they click 'Save', the memo is persisted to the server, their local draft is cleared, and the new memo appears at the top of their list, completing the initial user journey.

  1. New user visits the instance and is redirected to sign up because no admin exists
  2. User creates the first administrator account using a username and password
  3. User composes a note in the main editor, with content being autosaved locally
  4. User saves the new memo, which is persisted to the server and displayed in the list

User Creates a Private Memo with an Image Attachment

This flow covers the core user task of creating a rich, private note. The user begins by composing text in the memo editor. They then drag an image file from their desktop directly onto the editor. The application provides immediate feedback by displaying a local preview of the image without waiting for the upload to complete. The user sets the memo's visibility to 'PRIVATE' to ensure it is only accessible to them. Upon clicking 'Save', the application first uploads the image file to the configured storage backend. Once the upload is successful, it saves the memo content along with the link to the new attachment and the private visibility setting. The memo then appears in their personal feed, visible only to them.

  1. User types content into the memo editor, with progress being saved as a draft
  2. User drags and drops an image file, which appears as a local preview in the editor
  3. User changes the memo's visibility setting to 'PRIVATE'
  4. User saves the memo, triggering the file upload followed by the memo creation

User Logs in via SSO and Browses Protected Memos

This scenario demonstrates the seamless login experience using an external identity provider and how users can discover content shared within the logged-in community. A returning user chooses to sign in with their Google account (SSO). The application redirects them to Google for authentication and, upon successful authorization, redirects them back, logging them into Memos automatically. Now authenticated, the user navigates to the 'Explore' page. Because they are logged in, the system displays not only 'PUBLIC' memos but also 'PROTECTED' memos, which are visible to any authenticated user. They can then use the search and filter tools to navigate this expanded set of community-visible content.

  1. User initiates sign-in using an external OAuth2 provider (SSO)
  2. User is authenticated and their session is established within the app
  3. User navigates to the 'Explore' page to discover content
  4. The system displays both PUBLIC and PROTECTED memos because the user is logged in

Developer Automates Memo Archiving with a Personal Access Token

This flow highlights the extensibility of Memos for power users and developers. A developer wants to write a script that automatically archives old memos. First, they log into the Memos web UI and navigate to their 'My Account' settings. They generate a new Personal Access Token (PAT) for their script, copying the token presented to them. In their script, they make an API call to the 'ListMemos' endpoint, authenticating by providing the PAT in the 'Authorization' header. They filter for memos created before a certain date. For each memo found, they make a subsequent API call to the 'UpdateMemo' endpoint, setting the memo's state to 'ARCHIVED'. This allows them to programmatically manage their content without any manual UI interaction.

  1. User generates a Personal Access Token (PAT) from their account settings page
  2. An external script lists memos using the API, authenticating with the PAT
  3. The script identifies memos to be archived based on a date filter
  4. The script calls the API again to update the state of each identified memo to 'ARCHIVED'

Key Features

User Onboarding & Authentication

This module orchestrates the entire user entry and session management lifecycle. It ensures that new, uninitialized instances are properly secured by forcing the creation of an admin account. It provides flexible authentication methods, including standard password-based accounts and integration with external identity providers via OAuth2. The system employs a robust, modern token-based session strategy to balance security and user convenience, making it suitable for both web browser and programmatic access.

  • Forced First-User Admin Setup — 【User Value】Prevents a newly deployed instance from being left open and insecure without any user accounts.\n\n【Design Strategy】Implement a mandatory setup flow on the very first application run. The system checks for the existence of an administrator account at startup.\n\n【Business Logic】\n- Step 1: On application load, the frontend makes a request to the backend to get the instance profile.\n- Step 2: The system checks if an 'admin' user is defined in the profile response.\n- Step 3: If no admin user exists, the frontend application immediately and automatically redirects the user to the '/auth/signup' page, forcing them to create the first account, which will be granted administrator privileges.\n- Step 4: Normal application access is blocked until this first user is created.
  • Password-Based Account Management — 【User Value】Provides a standard, familiar way for users to create accounts and sign in.\n\n【Design Strategy】Offer separate sign-up and sign-in forms that interact with dedicated API endpoints for user creation and authentication.\n\n【Business Logic】\n- Step 1 (Sign-up): The user fills a form with a username and password. The client performs basic non-empty validation and sends a request to create the user. Upon success, it automatically triggers a sign-in request.\n- Step 2 (Sign-in): The user provides their credentials. The client sends an authentication request.\n- Step 3 (Token Handling): Upon successful sign-in, the server returns a short-lived access token and a long-lived refresh token. The client stores the access token in the browser's session storage (cleared when the tab closes) and the refresh token is handled via a secure, HttpOnly cookie.\n- Step 4 (Initialization): The client initializes the user's session by fetching their profile, settings, and shortcuts, then redirects them to the main application interface.
  • Single Sign-On (SSO) with OAuth2 — 【User Value】Allows users to sign in using their existing accounts from other services (e.g., Google, GitHub), simplifying registration and reducing password fatigue.\n\n【Design Strategy】Implement a full OAuth2 authorization code flow with security best practices like state-based CSRF protection and PKCE.\n\n【Business Logic】\n- Step 1 (Initiation): A user clicks an SSO provider button. The client generates a unique, unguessable 'state' string and, if in a secure context (HTTPS), a PKCE 'code verifier' and 'code challenge'. This information is stored in session storage with a 10-minute expiry.\n- Step 2 (Redirect): The user is redirected to the provider's authorization page, with the 'state' and PKCE 'code challenge' included in the URL parameters.\n- Step 3 (Callback): After the user authorizes, the provider redirects back to the application's callback URL with an authorization 'code' and the original 'state'.\n- Step 4 (Validation & Token Exchange): The client validates that the returned 'state' matches the one in session storage (CSRF protection). It then sends the 'code' and the PKCE 'code verifier' to the backend.\n- Step 5 (Finalization): The backend securely exchanges the code for user information with the provider and completes the sign-in, issuing its own access and refresh tokens to the client.

Core Note-Taking Experience

This is the heart of the product, focused on the creation and editing of notes (memos). It features a rich editor designed for both quick thoughts and structured content. To ensure a reliable user experience, it includes a resilient local draft-saving mechanism to prevent data loss. The editor supports modern features like slash commands for quick actions, inline suggestions, and a seamless workflow for attaching files and images. Users can also create rich, interconnected knowledge graphs by linking memos together and engage with content through comments and reactions.

  • Resilient Draft Autosave — 【User Value】Prevents loss of work during composition due to accidental browser refreshes, crashes, or connectivity issues.\n\n【Design Strategy】Implement a local-first autosave system that persists the state of each editor instance independently in the user's browser.\n\n【Business Logic】\n- Step 1: Each memo editor component is assigned a unique key, typically based on the current user and the memo being edited (or a static key for a new memo editor).\n- Step 2: As the user types or modifies the memo content (including attachments or other metadata), the changes are automatically saved to the browser's local cache on a frequent basis.\n- Step 3: When an editor component is loaded, it first checks if a saved draft exists in the local cache for its unique key.\n- Step 4: If a draft is found, the editor's state is rehydrated from the cache, restoring the user's work exactly as they left it.\n- Step 5: Upon successful saving of the memo to the server, the corresponding local draft is cleared from the cache.
  • Rich Editor with Slash Commands — 【User Value】Speeds up the writing process by allowing users to insert complex elements or trigger actions using simple, intuitive inline commands.\n\n【Design Strategy】Create a command palette that appears within the editor when a trigger character (e.g., '/') is typed, offering a filterable list of available commands.\n\n【Business Logic】\n- Step 1: The editor's text area monitors user input for a '/' character followed by a command word.\n- Step 2: When a trigger is detected, a suggestions popup appears with a list of available commands (e.g., embedding content, adding code blocks, inserting timestamps).\n- Step 3: As the user types, the list is filtered to match their query.\n- Step 4: When a user selects a command (via click or keyboard), the editor executes a predefined action, which typically involves removing the trigger text and inserting the corresponding formatted content or element into the memo.
  • File & Image Attachments — 【User Value】Allows users to enrich their notes with supporting files, such as images, PDFs, and other documents.\n\n【Design Strategy】Provide a responsive UI for file selection (including drag-and-drop) that shows local previews immediately, and handles the upload process in the background.\n\n【Business Logic】\n- Step 1 (Selection): The user either drags files onto the editor or selects them via a file input button.\n- Step 2 (Local Preview): The client immediately generates temporary local URLs (blob URLs) for the selected files and displays them as previews within the editor. This provides instant feedback without waiting for an upload.\n- Step 3 (Upload): When the user saves the memo, the client initiates the upload of the new files to the server via an attachments API.\n- Step 4 (Linking): Upon successful upload, the server returns unique identifiers for the attachments. The client then includes these identifiers in the main memo creation/update request, formally linking the files to the memo.
  • Lightweight Social Interactions — 【User Value】Fosters engagement and feedback through simple, non-intrusive social features like emoji reactions and threaded comments.\n\n【Design Strategy】Implement reactions as a lightweight association between a user, a memo, and an emoji. Reuse the core 'memo' data model to represent comments, linking them to a parent memo.\n\n【Business Logic】\n- Step 1 (Reactions): A user clicks the reaction button on a memo. A selector appears, showing available emojis. The client's UI highlights emojis the current user has already added. Selecting an emoji sends a request to the server to create or delete the user's reaction for that memo.\n- Step 2 (Comments): When a user adds a comment to a memo, the system creates a new, separate memo for the comment content. This new comment-memo is then linked to the original parent memo using a 'COMMENT' type relation.\n- Step 3 (Notifications): If the commenter is not the memo's original author and the comment is not private, the system automatically creates a notification and sends it to the memo owner's inbox.

Content Organization & Discovery

This module provides the tools for users to manage, find, and consume their notes effectively. It is built around a flexible visibility system that allows authors to control access to each memo. To facilitate discovery, it includes a powerful server-side filtering and search capability, which is exposed through curated views like a personal homepage and a public 'Explore' feed. For external consumption and integration, the system can automatically generate RSS feeds for public content.

  • Granular Visibility Control — 【User Value】Gives authors precise control over who can see their notes, enabling a mix of personal journaling, team collaboration, and public sharing within the same system.\n\n【Design Strategy】Define a simple but powerful set of visibility levels for each memo, enforced by the server during any read operation.\n\n【Business Logic】\n- Step 1: When creating or editing a memo, the author can select one of three visibility levels:\n - `PRIVATE`: Only the author can see the memo.\n - `PROTECTED`: Any logged-in user can see the memo.\n - `PUBLIC`: Anyone, including anonymous visitors, can see the memo.\n- Step 2: The selected visibility level is stored as metadata with the memo.\n- Step 3: When any user attempts to list or view memos, the backend API enforces these rules. For example, an anonymous user's request will only ever return `PUBLIC` memos, while a logged-in user requesting another user's content will only see their `PUBLIC` and `PROTECTED` memos.
  • Server-Side Filtering and Search — 【User Value】Enables users to quickly find specific notes from a large collection using various criteria like content, tags, or creator.\n\n【Design Strategy】Provide a flexible filtering mechanism in the API that accepts a structured filter expression, which is then translated into an efficient database query on the server.\n\n【Business Logic】\n- Step 1: The client UI (e.g., a search bar or tag cloud) constructs a filter string based on user input. This string can combine multiple conditions, such as `creator == 'users/101' && visibility == 'PUBLIC'` or `content : 'search term'`.\n- Step 2: The filter string is sent as a parameter in the API request to list memos.\n- Step 3: The server validates the filter expression and applies it directly to the database query, ensuring that filtering is performed efficiently at the data layer before pagination is applied.\n- Step 4: The API returns only the memos that match the specified criteria and the user's visibility permissions.
  • RSS Feed Generation — 【User Value】Allows users and external services to subscribe to public content updates using standard RSS readers, enabling syndication and integration.\n\n【Design Strategy】Create dedicated RSS endpoints that query for public memos and render them in a standard RSS/XML format, complete with caching for performance.\n\n【Business Logic】\n- Step 1: A user or service requests an RSS feed URL (e.g., `/explore/rss.xml` or `/u/username/rss.xml`).\n- Step 2: The server first checks an in-memory cache. If a fresh, valid feed exists and the request's ETag matches, it returns a `304 Not Modified` response to save bandwidth.\n- Step 3: If no valid cache entry exists, the server queries the database for the latest 100 `PUBLIC` memos for that feed.\n- Step 4: It renders the memo list into an RSS/XML structure. The memo's markdown is converted to HTML for the content. The first line of the memo is used as the title, and the first attachment (if any) is included as an enclosure.\n- Step 5: The generated XML is served with appropriate caching headers (e.g., 1-hour public cache) and stored in the in-memory cache for future requests.

Extensibility & Automation

This module transforms Memos from a simple note-taking app into a programmable platform. It is built on an API-first principle, exposing its entire functionality through a comprehensive, well-defined API. To facilitate programmatic access, it supports long-lived Personal Access Tokens (PATs) for scripts and third-party applications. Furthermore, it enables event-driven workflows through user-configurable webhooks, allowing Memos to actively notify external systems of changes.

  • Comprehensive & Multi-Protocol API — 【User Value】Enables developers to build custom clients, integrations, and automation on top of Memos, treating it as a content backend.\n\n【Design Strategy】Define the entire API surface using Protocol Buffers as a single source of truth, and automatically generate code for multiple protocols (gRPC, Connect, REST/JSON) and languages (Go, TypeScript).\n\n【Business Logic】\n- Step 1 (Design): The API is structured around resources (Memos, Users, Attachments, etc.) with standard methods like Create, Get, List, Update, Delete.\n- Step 2 (Consistency): All 'List' operations use consistent cursor-based pagination (`page_size`, `page_token`) and Common Expression Language (CEL) for filtering. Partial updates are handled using field masks.\n- Step 3 (Generation): Using this design, the system auto-generates: Go code for the backend services; TypeScript clients for the official web frontend; and a standard OpenAPI (Swagger) specification for third-party REST API consumers.
  • Personal Access Tokens (PATs) — 【User Value】Provides a secure way for scripts, command-line tools, or other non-browser applications to authenticate with the Memos API without using a user's password.\n\n【Design Strategy】Allow users to generate long-lived tokens that can be easily revoked, and store them securely on the server using a one-way hash.\n\n【Business Logic】\n- Step 1 (Generation): A logged-in user navigates to their settings and creates a new PAT, optionally setting an expiration date.\n- Step 2 (Display): The system generates a random token string and displays it to the user exactly once. The server does not store the token in plaintext.\n- Step 3 (Storage): The server calculates a SHA-256 hash of the token and stores this hash in the database, associated with the user.\n- Step 4 (Authentication): When a client makes an API request using the PAT in the Authorization header, the server hashes the provided token and looks up the hash in the database to identify and authenticate the user.\n- Step 5 (Revocation): The user can revoke a PAT at any time from their settings, which immediately deletes the corresponding hash record from the database, invalidating the token.

Instance Administration

This module provides instance owners (administrators) with the tools to configure, customize, and manage the entire Memos application. It allows for deep customization of the instance's behavior and appearance, including the ability to set global policies like disabling public sharing or injecting custom branding. A key feature is the flexibility to configure different backends for file storage, allowing administrators to choose between local hosting, a central database, or a cloud object store like S3 to fit their infrastructure and scaling needs.

  • Global Instance Policies — 【User Value】Allows administrators to enforce instance-wide rules and behaviors to match their security or community guidelines.\n\n【Design Strategy】Expose a set of configuration options through the API and admin UI that control core application logic.\n\n【Business Logic】\n- Step 1: An administrator accesses the instance settings panel.\n- Step 2: They can configure various policies, such as:\n - `Disallow public visibility`: Prevents any user from creating `PUBLIC` memos.\n - `Disallow user registration`: Turns off the sign-up page, making the instance invite-only.\n - `Content length limit`: Sets a maximum character count for any single memo.\n- Step 3: These settings are stored globally and are checked by the backend API whenever a relevant action (like creating or updating a memo) is performed.
  • Pluggable Attachment Storage — 【User Value】Gives administrators the flexibility to choose the most appropriate and cost-effective storage solution for file attachments based on their scale and infrastructure.\n\n【Design Strategy】Abstract the storage logic behind a common interface and allow the active implementation to be selected via a configuration setting.\n\n【Business Logic】\n- Step 1: The administrator navigates to the storage settings.\n- Step 2: They can choose one of three storage types:\n - `DATABASE`: Stores file blobs directly in the main database. Simple, but can be inefficient.\n - `LOCAL`: Stores files on the local filesystem of the server. Default and easy for single-node setups.\n - `S3`: Stores files in an S3-compatible object storage bucket. Scalable and ideal for cloud-native or large-scale deployments.\n- Step 3: If S3 is chosen, the administrator provides the bucket name, region, endpoint, and credentials.\n- Step 4: The backend API uses this setting to direct all file upload and retrieval operations to the configured storage provider.
  • Instance Appearance Customization — 【User Value】Enables administrators to brand their Memos instance with a custom name, logo, and even custom styling or analytics scripts.\n\n【Design Strategy】Provide settings that allow an admin to inject content directly into the served HTML page.\n\n【Business Logic】\n- Step 1: An administrator accesses the instance's general settings.\n- Step 2: They can set a custom instance title and logo URL, which updates the browser tab's title and favicon.\n- Step 3: They can provide custom CSS code in an 'Additional Style' field. This CSS is dynamically injected into a `<style>` tag in the application's HTML, overriding default styles.\n- Step 4: They can provide JavaScript code in an 'Additional Script' field. This script is injected into a `<script>` tag, allowing for things like custom analytics tracking or other dynamic behaviors. The frontend applies these settings upon loading.

Core Technical Capabilities

Unified Multi-Protocol API via Code Generation

Problem: How to provide a consistent, strongly-typed API for a Go backend, a React/TypeScript frontend, and third-party developers without the massive overhead of writing and maintaining separate specifications and implementations for gRPC, REST/JSON, and client libraries?

Solution: The system uses Protocol Buffers as the single source of truth for all API definitions. A build tool (Buf) then orchestrates a code generation pipeline:\n- Step 1: It generates Go data structures and server interface stubs for the backend.\n- Step 2: It generates client stubs for multiple Go protocols, including modern ConnectRPC and standard gRPC.\n- Step 3: It generates a gRPC-Gateway, which acts as a reverse proxy to automatically translate RESTful JSON API calls into backend gRPC calls, effectively creating a REST API for free.\n- Step 4: From the same definitions, it generates an OpenAPI (Swagger) specification for documenting the REST API.\n- Step 5: It generates TypeScript client libraries and type definitions for the React frontend, ensuring the client and server are always in sync.\nThis approach provides maximum flexibility for API consumers while minimizing development effort and eliminating inconsistency.

Technologies: Protocol Buffers (proto3), Buf, ConnectRPC, gRPC-Gateway, OpenAPI

Boundaries & Risks: The main dependency is on the Protobuf ecosystem and the Buf toolchain. While powerful, it introduces a level of abstraction and build complexity. The quality of the generated REST API and OpenAPI spec is dependent on the quality of the annotations in the proto files, and may not perfectly capture all HTTP nuances without careful design.

Transactional and Safe Automated Database Schema Migrations

Problem: How to reliably manage database schema changes across multiple application versions and different database systems (SQLite, MySQL, PostgreSQL) without requiring manual intervention from the administrator or risking data corruption during upgrades or downgrades?

Solution: The system embeds all necessary SQL migration files directly into the application binary.\n- Step 1 (Initialization): For a new installation, it executes a single 'LATEST.sql' file which contains the complete schema for the current version. This is extremely fast and avoids replaying a long history of changes.\n- Step 2 (Upgrade): On startup, the application compares the schema version stored in the database against the version embedded in its code.\n- Step 3 (Execution): If the database version is older, the application finds all incremental migration scripts (e.g., '01__add_users_table.sql', '02__add_pinned_column.sql') that are newer than the database's current version. It executes all required scripts in lexicographical order within a single database transaction. This ensures that the upgrade is atomic; if any script fails, the entire schema change is rolled back.\n- Step 4 (Protection): The system explicitly prevents downgrades. If it detects that the database schema is newer than the code expects, it will refuse to start, preventing potential data corruption.

Technologies: Go embed.FS, Database Transactions, Semantic Versioning

Boundaries & Risks: This strategy relies on developers correctly naming and ordering migration files. A misnamed file could be applied out of order, though the transactional nature mitigates some risk. In a multi-instance deployment, there is a risk of a race condition where two instances attempt to run the migration simultaneously, as there is no advisory lock mechanism.

Flexible and Secure Multi-Tiered Authentication System

Problem: How to provide a secure authentication system that is convenient for interactive web users (long sessions), robust for stateless API calls, and suitable for third-party scripts and automation?

Solution: The system implements three distinct but complementary token-based mechanisms:\n- Step 1 (Access Tokens): For regular API calls from the web client, it uses short-lived (15-minute) JWT access tokens. These are stateless and validated quickly by the server, but their short life limits the window of exposure if one is compromised.\n- Step 2 (Refresh Tokens): To maintain a user's session without requiring them to log in every 15 minutes, the system issues a long-lived (30-day) refresh token. This token is stored in a secure, HttpOnly cookie, making it inaccessible to client-side JavaScript. It can be exchanged for a new access token and, importantly, can be revoked on the server (e.g., on sign-out).\n- Step 3 (Personal Access Tokens - PATs): For automation, it allows users to generate long-lived PATs. The raw token is shown to the user only once. The server stores only a SHA-256 hash of the token, preventing token theft from a database breach. Authentication is done by hashing the incoming PAT and comparing it to the stored hashes.

Technologies: JWT (JSON Web Tokens), HttpOnly Cookies, SHA-256 Hashing

Boundaries & Risks: The stateless nature of the short-lived access tokens means they cannot be revoked immediately; if a token is stolen, it remains valid for up to 15 minutes. Session hijacking is still possible if the refresh token cookie is stolen, although its revocation on the server provides a mitigation path.

Optimized and Secure Dynamic File Serving

Problem: How to serve user-uploaded files (images, videos, documents) that might be stored in different locations (local disk, S3) while enforcing access control, preventing cross-site scripting (XSS) from malicious files, and enabling efficient media playback (streaming)?

Solution: A single file-serving endpoint handles all requests with layered logic:\n- Step 1 (Permission Check): It first loads the file's metadata and checks the visibility of the memo it's attached to. It denies access if the current user (or anonymous guest) does not have permission to view the parent memo.\n- Step 2 (Content-Type Sanitization): To prevent XSS, it maintains a denylist of dangerous MIME types (e.g., `text/html`, `image/svg+xml`). If a file matches, it overrides the content type to `application/octet-stream`, forcing the browser to download it instead of rendering it.\n- Step 3 (Optimized Delivery): For video and audio files, it uses delivery methods that support HTTP range requests, enabling streaming and seeking. For local files, it uses `http.ServeFile`. For files in S3, it generates a temporary S3 presigned URL and issues an HTTP redirect, offloading the bandwidth to S3.\n- Step 4 (Thumbnail Generation): For images, it supports on-demand thumbnail generation with a semaphore to limit concurrent image processing operations to 3, preventing memory exhaustion under high load. Generated thumbnails are cached on disk.

Technologies: HTTP Range Requests, Content Security Policy (CSP), S3 Presigned URLs, Concurrency Limiting (Semaphore)

Boundaries & Risks: The thumbnail cache is keyed by attachment ID and may become stale if the underlying attachment content is updated without changing its ID. The S3 presigned URL refresh job runs every 12 hours; a failure in this job could lead to broken links after the 5-day expiry.

Technical Assessment

Business Viability — 2/10 (Community Driven)

Credible community open-source product with clear adoption signals, but commercial upside is not yet proven from the available evidence.

Memos is positioned as an open-source, self-hosted note-taking and knowledge base product with strong privacy messaging (no tracking, no ads, MIT license) and offers a live demo and documentation, which signals real adoption intent. The presence of public sponsorships and operational artifacts (Docker images, Kubernetes/Helm mentioned in README) supports the view that this is more than a hobby project. However, there is no evidence in the provided materials of a commercial product tier, enterprise support model, or revenue engine beyond sponsorship. As a result, the project is attractive for self-hosting and community-led adoption, but long-term commercial predictability depends on continued maintainer and sponsor momentum.

Recommendation: For usage: adopt for internal teams or privacy-focused deployments, but require a security hardening review before external-facing or regulated deployments. For investment: treat as an ecosystem/community play unless you can validate paid support or hosted-offering demand beyond sponsorship. For partnership: consider integration partnerships leveraging its strong API surface, while jointly addressing the high-impact security risks identified.

Technical Maturity — 3/10 (Creative Approach)

Well-engineered core with strong API and migration foundations, but security hardening is required for high-trust production use.

Technically, Memos shows above-average engineering discipline for an open-source app: a single Protocol Buffer source of truth generates Connect, gRPC, HTTP/JSON gateway handlers, OpenAPI, and typed TypeScript models for the web client. The data layer supports multiple relational databases and includes embedded first-run schema setup plus transactional migrations with downgrade prevention. Security posture is mixed: token-based authentication and SSO with PKCE exist, and file serving includes strong browser-hardening headers, but there is a documented fail-open condition in gateway authentication when the RPC method cannot be determined, and the web client supports admin-provided script injection while storing access tokens in browser session storage. In practice, it looks close to production-grade for many self-hosted scenarios, but the security design needs tightening for enterprise or internet-exposed deployments.

Recommendation: Suitable for: self-hosted personal/team knowledge bases where operators control the environment and can apply secure configuration (TLS, restricted admin access). Avoid for: multi-tenant hosted SaaS or high-compliance deployments until authentication fail-open behavior and token/XSS exposure are addressed. If adopting at scale, prioritize security fixes and add operational controls (DB health checks, migration locking, and cross-node cache strategy).

Adoption Readiness — 3/10 (Ready with Effort)

Easy to stand up for single-instance use, but needs additional operational safeguards for horizontal scaling and production rollouts.

Deployment is designed to be straightforward (Docker-first, self-contained server that also serves the frontend, and supports SQLite/MySQL/PostgreSQL), which lowers time-to-value for small teams. The upgrade path is reasonably automated via embedded schema and migrations, reducing operational burden for self-hosters. For larger or multi-replica deployments, there are readiness gaps: migrations do not show advisory locking to prevent concurrent upgrades, and the Store uses in-process caches without cross-node invalidation, which can cause inconsistent behavior across replicas. Operational observability also has a gap in that the health endpoint responds “ready” without verifying database connectivity.

Recommendation: Adopt with a staged rollout: start single-instance, then move to multi-replica only after adding migration mutual exclusion and clarifying cache consistency behavior. Put a reverse proxy/TLS in front and restrict administrative settings if using UI customization features. For enterprise rollout, add a stronger health check (including database reachability) and validate upgrade procedures in a blue/green deployment rehearsal.

Operating Economics — 3/10 (Balanced)

Cost-effective for self-hosted deployments, with predictable scaling costs but some operational inefficiencies in multi-replica scenarios.

The Go backend and embedded frontend distribution support a relatively low infrastructure footprint, especially in SQLite mode for small teams. Costs increase predictably with usage when using managed databases and object storage (S3-compatible) for attachments, but the architecture does not show unusual compute-heavy components. Some design choices can increase operational friction at scale, such as per-process caches (multi-replica consistency costs) and potentially expensive server-side filtering if user-provided expressions are not constrained. Overall, economics are favorable for self-hosting, with scaling costs mainly driven by database and file storage rather than application compute.

Recommendation: Keep costs low by using SQLite for personal/small-team use and moving to Postgres/MySQL only when concurrency and growth demand it. If exposing advanced filtering broadly, implement filter complexity limits to protect against performance abuse. For high-availability setups, plan for shared caching or shorter TTLs and add deployment controls to prevent concurrent migrations.

Architecture Overview

Web Client (Single-Page App)
React + TypeScript single-page application with routing and stateful contexts for instance initialization and authentication. Supports password login and OAuth-based SSO, and applies instance-wide customization (theme/locale plus optional injected script/style).
API Edge and Transport Layer
Go server exposes a unified API surface over multiple transports (Connect RPC, gRPC, and HTTP/JSON via gRPC-Gateway) driven by shared Protocol Buffer contracts. Transport-level authentication is enforced via centralized “public endpoint” policy and middleware/interceptors.
Core Product Services (Notes, Users, Settings)
Go application services implement memo creation, listing, updates, comments, reactions, and instance policies (visibility rules and content limits). Services enrich responses with related entities (attachments and reactions) and provide automation hooks such as webhooks and personal access tokens.
Data Persistence and Upgrade System
A single Store abstraction hides database-specific details while supporting SQLite, MySQL, and PostgreSQL. Database schema is bootstrapped from an embedded latest schema file and upgraded through transactional migrations with schema version tracking and downgrade prevention.
Files, Media Delivery, and Background Jobs
Dedicated routes serve attachments and avatars with permission checks and browser-hardening headers; media streaming supports range requests and S3 redirects. Background runners refresh S3 presigned URLs to keep external downloads working, and RSS endpoints provide cached public feeds.

Key Strengths

One API Design Powers Web, Automation, and Integrations Without Duplication

A single, consistent API contract enables reliable integrations across multiple protocols and client types.

User Benefit: The same API definitions drive the backend services, HTTP/JSON access, and strongly-typed web client models, which reduces integration friction and lowers the risk of mismatched client/server behavior. This benefits organizations that want to build internal tools, scripts, or integrations (webhooks, personal access tokens, external clients) without reverse-engineering undocumented endpoints.

Competitive Moat: Maintaining a consistent multi-transport API surface requires disciplined schema governance and tooling (code generation across multiple stacks). While not unique in the industry, implementing it well across server and frontend typically requires sustained engineering effort and strong API design practices.

Low-Drama Self-Hosted Upgrades With Automated Schema Setup and Downgrade Safety

Safer upgrades for self-hosters: automatic setup, transactional migrations, and downgrade prevention.

User Benefit: New installations can initialize quickly using an embedded full schema, and upgrades apply transactional migrations with schema version tracking and downgrade prevention. For operators, this reduces manual database work and lowers the risk of running incompatible code against an outdated database.

Competitive Moat: Getting upgrades right across multiple databases and historical versions requires careful engineering and testing. Competitors can replicate the concept, but the operational polish (first-run schema, version gating, and transactional application) typically takes meaningful time to implement and validate.

Attachment Delivery Designed to Reduce Browser Exploit Risk

Built-in safe file serving helps prevent uploaded content from becoming a browser security incident.

User Benefit: Attachments are served with permission checks and defensive browser headers, and risky content types are forced to download instead of rendering. This reduces the likelihood that a malicious upload turns into a browser-based compromise for users viewing content.

Competitive Moat: Secure file serving is often underestimated; doing it comprehensively requires threat modeling across MIME types, content sniffing, framing protections, and storage backends (local, database, S3). It is replicable, but usually takes sustained security-focused engineering to get right.

Multiple Authentication Options for Real-World Operations and Automation

SSO plus automation-friendly tokens enable both end-user access and integration workflows.

User Benefit: The platform supports standard interactive login, OAuth-based SSO, and long-lived automation credentials via personal access tokens, enabling both human and programmatic usage. Refresh tokens support revocation checks, and personal access tokens are stored hashed rather than in plaintext, improving operational security if the database is exposed.

Competitive Moat: Combining SSO, token lifecycles, and secure token storage patterns is a multi-surface implementation challenge. While these are known patterns, delivering them cohesively across web UI and APIs typically requires non-trivial security expertise and ongoing maintenance.

Risks

Protected API Operations May Become Public Under Routing Edge Cases (Commercial Blocker)

The API gateway authentication middleware explicitly allows requests to pass through when the target RPC method cannot be determined, relying on service-layer checks to enforce access control. If method detection fails unexpectedly for a protected endpoint, transport-level authentication enforcement may not trigger consistently.

Business Impact: In the worst case, a misconfiguration or edge-case route could expose protected actions without authentication. For any production deployment that handles sensitive notes or team knowledge, this is a trust-breaking security risk.

Account Takeover Risk From Script Injection Combined With Browser Token Storage (Commercial Blocker)

The web client injects administrator-configured scripts and styles directly into the page, and access tokens are stored in browser session storage. Any script running in the page (including injected scripts or an XSS payload) can read session storage and exfiltrate access tokens.

Business Impact: A malicious or compromised script could impersonate users and access private notes, creating a high-severity security incident. This is especially problematic for organizations using Memos as a team knowledge base or exposing it to the internet.

User-Provided Filtering Could Be Abused to Degrade Performance (Scale Blocker)

List APIs accept user-provided filter expressions (CEL-style). Without explicit complexity limits, expensive expressions may consume disproportionate server resources.

Business Impact: A small number of abusive requests can slow down the service for everyone, increasing downtime risk and infrastructure cost as usage grows.

Single Sign-On Security Is Weaker When Accessed Over Non-Secure HTTP (Scale Blocker)

PKCE (an OAuth security enhancement) is only used when the browser crypto APIs are available (commonly HTTPS or localhost). In non-secure contexts, the SSO flow can proceed without PKCE.

Business Impact: Organizations that run the service without TLS (or in risky network environments) face increased risk of interception during SSO sign-in, which may violate security requirements and slow broader rollout.

High-Availability Deployments Risk Concurrent Database Migrations (Scale Blocker)

Database migrations run in a transaction but do not show database-level advisory locking to prevent multiple server instances from attempting migrations simultaneously during rolling deploys.

Business Impact: In multi-replica deployments, upgrades may become unreliable and could lead to schema inconsistencies or extended downtime during releases.

Multi-Replica Deployments Can Show Inconsistent Settings and User Data (Notable)

The persistence layer uses in-process caches for instance settings and user data with time-based expiration. There is no evidence of cross-node invalidation in the provided slice, so different replicas may serve different values until cache expiry.

Business Impact: Users may see inconsistent behavior across requests when traffic is load-balanced across replicas (for example, settings changes not taking effect immediately), complicating enterprise deployments.

Database Upgrades Can Become Confusing if Version Tracking Update Fails (Notable)

After applying migrations, schema version is updated after the migration transaction commits. If updating the stored schema version fails post-commit, the database schema may be upgraded but the recorded version may remain old.

Business Impact: Operators may experience repeated migrations or confusing upgrade diagnostics, increasing the risk of extended maintenance windows.

Lost Authentication Tokens Cannot Be Immediately Invalidated for a Short Window (Notable)

Short-lived access tokens are validated statelessly (signature and claims only) and are not checked against a revocation list. Compromised tokens remain usable until expiration.

Business Impact: Incident response has a built-in delay: administrators may need to wait for access tokens to expire before the system fully contains an access-token leak.

SQLite Deployments May Accumulate Silent Data Integrity Problems (Notable)

SQLite is opened with foreign key enforcement disabled via runtime pragmas. If the schema assumes relational integrity, the database will not prevent invalid references.

Business Impact: Data corruption can accumulate silently in smaller deployments, increasing the chance of unexpected behavior and harder recovery later.

Database Capacity Tuning Is Hard Without Exposed Connection Pool Controls (Notable)

Database drivers open connections using default settings and do not expose operator-tunable pool configuration (such as maximum open connections and connection lifetime) in the provided evidence.

Business Impact: Under higher concurrency, operators may encounter avoidable latency or connection exhaustion, but cannot tune the system without modifying code.

Service Health Checks May Stay Green While the Database Is Down (Notable)

The health endpoint returns a static success response without verifying database connectivity.

Business Impact: Load balancers and orchestrators may keep routing traffic to instances that cannot serve requests, increasing outage duration and operational confusion.

Shutdown May Drop In-Flight Requests During Load Spikes (Notable)

Server shutdown uses a fixed 10-second timeout, regardless of current load or long-running operations.

Business Impact: Large uploads or slow requests may be terminated mid-flight during deployments, causing user-visible errors and potential partial workflows.

Migrations Can Run Even With Malformed Script Filenames (Notable)

Migration script naming convention is validated, but invalid names only generate warnings rather than blocking execution, increasing the chance of mis-ordered or mis-versioned migrations slipping into releases.

Business Impact: Upgrades become less predictable, raising the risk of release-day incidents for operators.

Automation Webhooks May Silently Miss Events (Notable)

Webhook dispatch is best-effort and does not fail core operations when delivery fails; errors are logged as warnings and delivery is asynchronous, with durability and retry behavior dependent on the webhook plugin implementation.

Business Impact: Integrations that depend on webhooks (sync, downstream automation) may miss updates without clear operator visibility, causing data drift and support burden.

Activity Feeds May Not Scale Due to Missing Pagination (Notable)

Activity listing indicates pagination support is incomplete (next page token is marked as a future task).

Business Impact: As activity volume grows, users and integrations may struggle to browse or synchronize history efficiently.

Related Projects

Discover more public DeepDive reports to compare architecture decisions.

  • selop/pokebox2a11d7da068a - en
  • imanian/appointmate66f1c0a89b98 - en
  • bytedance/UI-TARS-desktop3f254968e627 - en
  • calcom/cal.com0b0a5478fb39 - en
  • ItzCrazyKns/Perplexicad7b020e5bb64 - en
  • openclaw/openclaw74fbbda2833e - en
Browse all public DeepDive reports