Files
k-notes/ARCHITECTURE.MD

3.5 KiB

K-Note

Executive Summary

A high-performance, self-hosted note-taking engine designed to replicate the Google Keep experience. Built with Rust, it prioritizes speed, memory safety, and long-term maintainability through Hexagonal Architecture (Ports and Adapters). The system is designed to be "storage-agnostic" and "format-blind," allowing users to own their data in simple formats like Markdown.

Architecture Pattern: Hexagonal (Ports & Adapters)

We are decoupling the Domain Logic (the "What") from the Infrastructure (the "How").

  • The Core: Contains Note and User entities and the business rules (e.g., "A note cannot have more than 10 tags").
  • Ports: Traits that define how the core communicates with the outside world (e.g., NoteRepository or AuthService).
  • Adapters: Concrete implementations (e.g., SqliteNoteRepository, Argon2Auth).
  • Why: This allows us to start with REST/SQLite today and pivot to WebSockets/PostgreSQL tomorrow by simply writing a new adapter.

Tech Stack

Component Primary Recommendation Alternative
Language Rust (1.75+) Go
API Framework Axum Actix-Web
Database SQLite (via SQLx) PostgreSQL
Search SQLite FTS5 Meilisearch
Vector Search Qdrant Pgvector
Authentication Axum Login OIDC (Keycloak/Authelia)
Frontend React + Tailwind + Shadcn/ui Vue + Radix

Data Model (Entity Relationship)

Code snippet

erDiagram
    USER ||--o{ NOTE : owns
    USER {
        uuid id PK
        string email
        string password_hash
    }
    NOTE ||--o{ TAG : contains
    NOTE {
        uuid id PK
        uuid user_id FK
        string title
        text content
        datetime created_at
        datetime updated_at
        boolean is_pinned
        boolean is_archived
    }
    TAG {
        uuid id PK
        string name
        uuid user_id FK
    }

Folder Structure (Workspace Layout)

We will use a Cargo Workspace to enforce strict boundaries.

Plaintext

.
├── Cargo.toml
├── Makefile                 # Task runner for DB migrations, builds, and tests
├── crates
│   ├── domain               # Pure logic, Traits (Ports), and Entities (No SQLx here)
│   ├── infra                # Adapters: SQLx implementations, Email, Auth logic
│   └── api                  # Axum routes, Request/Response DTOs, Middleware
├── migrations               # SQLx migration files
└── docker-compose.yaml      # For easy self-hosting deployment

API Design (MVP)

  • GET /api/v1/notes - List notes (with filter for archived/pinned).
  • POST /api/v1/notes - Create a new note (Accepts Markdown).
  • PATCH /api/v1/notes/:id - Partial updates.
  • GET /api/v1/search?q=query - Full-text search via FTS5.
  • GET /api/v1/notes/:id/related - Get semantically related notes.

Guidelines & Principles

  • Error Handling: Use thiserror for internal library errors and anyhow for high-level application flow. Map domain errors to specific HTTP status codes in the API layer.
  • Dependency Injection: We will use Atomic References (Arc<dyn Repository>) to inject adapters into Axum state.
  • Validation: All incoming data must be validated at the API boundary using validator crate before reaching the Domain.
  • DX (Developer Experience): A Makefile is mandatory for one-command setups: make setup, make dev, make test.