# MEMOS - PROJECT INFO (Bahasa Indonesia) ## 📋 STRUKTUR PROYEK ### Arsitektur Utama Proyek Memos adalah aplikasi catatan pribadi berbasis web yang dibangun dengan: - **Backend**: Go (Golang) versi 1.25 - **Frontend**: React 18.3 + TypeScript - **Protokol API**: gRPC + Connect RPC - **Database**: SQLite (default), MySQL, PostgreSQL ### Struktur Direktori Utama ``` memos/ ├── cmd/memos/ # Entry point aplikasi │ └── main.go # File utama untuk menjalankan server ├── server/ # Server HTTP dan routing │ ├── server.go # Konfigurasi Echo server │ ├── router/ # Routing API dan frontend │ │ ├── api/v1/ # Implementasi service gRPC │ │ ├── frontend/ # Serving file statis React │ │ └── fileserver/ # Serving file media │ └── auth/ # Autentikasi (JWT, PAT) ├── store/ # Layer data dan database │ ├── db/ # Driver database (sqlite/mysql/postgres) │ ├── migration/ # File migrasi database │ └── *.go # Model dan operasi data ├── proto/ # Definisi Protocol Buffer │ ├── api/v1/ # Service dan message definitions │ └── gen/ # Kode yang di-generate ├── web/ # Aplikasi frontend React │ ├── src/ # Source code TypeScript │ ├── package.json # Dependencies frontend │ └── vite.config.mts # Konfigurasi Vite └── plugin/ # Plugin tambahan ├── markdown/ # Parsing markdown ├── email/ # Pengiriman email ├── scheduler/ # Cron jobs └── webhook/ # Webhook integration ``` ## 🔧 CARA PEMBUATAN API ### 1. Definisi Protokol Buffer (.proto) API didefinisikan dalam file `.proto` di direktori `proto/api/v1/`: Contoh: `memo_service.proto` ```protobuf syntax = "proto3"; package memos.api.v1; service MemoService { rpc CreateMemo(CreateMemoRequest) returns (Memo) { option (google.api.http) = { post: "/api/v1/memos" body: "memo" }; } rpc ListMemos(ListMemosRequest) returns (ListMemosResponse) { option (google.api.http) = {get: "/api/v1/memos"}; } } message Memo { string name = 1; string content = 7 [(google.api.field_behavior) = REQUIRED]; Visibility visibility = 9 [(google.api.field_behavior) = REQUIRED]; } ``` ### 2. Generate Kode dari Proto Jalankan perintah: ```bash cd proto && buf generate ``` Ini akan menghasilkan: - Kode Go di `proto/gen/api/v1/` (untuk backend) - Kode TypeScript di `web/src/types/proto/api/v1/` (untuk frontend) ### 3. Implementasi Service Backend File: `server/router/api/v1/memo_service.go` ```go func (s *APIV1Service) CreateMemo(ctx context.Context, request *v1pb.CreateMemoRequest) (*v1pb.Memo, error) { // 1. Validasi user user, err := s.fetchCurrentUser(ctx) if err != nil { return nil, status.Errorf(codes.Unauthenticated, "user not authenticated") } // 2. Mapping ke model store create := &store.Memo{ UID: shortuuid.New(), CreatorID: user.ID, Content: request.Memo.Content, Visibility: convertVisibilityToStore(request.Memo.Visibility), } // 3. Simpan ke database memo, err := s.Store.CreateMemo(ctx, create) if err != nil { return nil, err } // 4. Convert ke response proto return s.convertMemoFromStore(ctx, memo, nil, nil) } ``` ### 4. Registrasi Service File: `server/router/api/v1/v1.go` ```go // Register gRPC gateway if err := apiV1Service.RegisterGateway(ctx, echoServer); err != nil { return nil, errors.Wrap(err, "failed to register gRPC gateway") } // Register Connect handlers connectHandlers := v1pbconnect.NewMemoServiceHandler(apiV1Service) echoServer.POST("/memos.api.v1.MemoService/CreateMemo", connect.NewHandler(connectHandlers.CreateMemo)) ``` ### 5. Middleware dan Interceptor Autentikasi dilakukan melalui interceptor: - **Connect Interceptor**: `connect_interceptors.go` - **gRPC Gateway Interceptor**: Middleware Echo ## 🖥️ FRONTEND MENGGUNAKAN TEKNOLOGI ### Framework dan Library Utama 1. **React 18.3** - Library UI utama 2. **TypeScript** - Typing untuk JavaScript 3. **Vite 7** - Build tool dan development server 4. **Tailwind CSS 4** - Styling utility-first 5. **React Query (TanStack Query) v5** - State management server 6. **Connect RPC** - Komunikasi dengan backend ### State Management #### 1. Server State (React Query) ```typescript // hooks/useMemoQueries.ts export const useMemos = (filters: MemoFilters) => { return useQuery({ queryKey: memoKeys.list(filters), queryFn: () => memoServiceClient.listMemos({ filter: filters.query }), }); }; export const useCreateMemo = () => { const queryClient = useQueryClient(); return useMutation({ mutationFn: (memo: CreateMemoRequest) => memoServiceClient.createMemo(memo), onSuccess: () => { queryClient.invalidateQueries({ queryKey: memoKeys.all }); }, }); }; ``` #### 2. Client State (React Context) ```typescript // contexts/AuthContext.tsx const AuthContext = createContext(null); export function AuthProvider({ children }: { children: ReactNode }) { const [currentUser, setCurrentUser] = useState(); const logout = useCallback(async () => { await authServiceClient.signOut({}); setCurrentUser(undefined); }, []); return ( {children} ); } ``` ### Komunikasi API File: `web/src/connect.ts` ```typescript // Transport dengan autentikasi const transport = createConnectTransport({ baseUrl: window.location.origin, useBinaryFormat: true, interceptors: [authInterceptor], // Menangani JWT token }); // Client service export const memoServiceClient = createClient(MemoService, transport); export const userServiceClient = createClient(UserService, transport); ``` ### Routing Menggunakan React Router DOM v7: ```typescript // router/index.tsx const router = createBrowserRouter([ { path: "/", element: , children: [ { index: true, element: }, { path: "/m/:memoId", element: }, { path: "/auth", element: }, ], }, ]); ``` ### Styling Menggunakan Tailwind CSS dengan komponen UI: ```tsx // components/ui/button.tsx import { cva, type VariantProps } from "class-variance-authority"; const buttonVariants = cva( "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors", { variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/90", destructive: "bg-destructive text-destructive-foreground", outline: "border border-input bg-background hover:bg-accent", }, size: { default: "h-10 px-4 py-2", sm: "h-9 rounded-md px-3", lg: "h-11 rounded-md px-8", }, }, defaultVariants: { variant: "default", size: "default", }, } ); ``` ## ⚙️ ARSITEKTUR API DUAL PROTOCOL ### 1. Connect RPC (Untuk Browser) - Path: `/memos.api.v1.MemoService/*` - Format: Binary protocol buffers - Digunakan oleh frontend React ### 2. gRPC-Gateway (REST API) - Path: `/api/v1/memos` - Format: JSON over HTTP - Berguna untuk integrasi eksternal Keduanya menggunakan implementasi service yang sama, sehingga konsisten. ## 🔐 AUTENTIKASI ### Metode Token 1. **JWT Access Token V2** - Stateless, 15 menit expiry 2. **Personal Access Token (PAT)** - Stateful, long-lived ### Flow Autentikasi ```typescript // Frontend interceptor const authInterceptor: Interceptor = (next) => async (req) => { const token = getAccessToken(); if (token) { req.header.set("Authorization", `Bearer ${token}`); } try { return await next(req); } catch (error) { if (error.code === Code.Unauthenticated) { // Refresh token otomatis await refreshAccessToken(); // Retry request return await next(req); } throw error; } }; ``` ## 🗃️ DATABASE ### Layer Abstraksi ```go type Driver interface { CreateMemo(ctx context.Context, create *Memo) (*Memo, error) ListMemos(ctx context.Context, find *FindMemo) ([]*Memo, error) UpdateMemo(ctx context.Context, update *UpdateMemo) error DeleteMemo(ctx context.Context, delete *DeleteMemo) error } ``` ### Implementasi: - SQLite: `store/db/sqlite/` - MySQL: `store/db/mysql/` - PostgreSQL: `store/db/postgres/` ### Caching: Menggunakan in-memory cache untuk: - Pengaturan instance - Data user - Pengaturan user ## 🚀 DEVELOPMENT WORKFLOW ### Backend Development ```bash # Jalankan server development go run ./cmd/memos --port 8081 # Testing go test ./... # Linting golangci-lint run ``` ### Frontend Development ```bash cd web pnpm install pnpm dev # Server jalan di port 3001, proxy ke 8081 ``` ### Generate Proto ```bash cd proto buf generate ``` ## 📦 DEPLOYMENT ### Opsi Deployment: 1. **Docker** (Direkomendasikan) 2. **Binary langsung** 3. **Docker Compose** 4. **Kubernetes** ### Contoh Docker: ```bash docker run -d \ --name memos \ -p 5230:5230 \ -v ~/.memos:/var/opt/memos \ neosmemo/memos:stable ``` --- **Ringkasan Teknologi Utama:** - **Bahasa**: Go + TypeScript - **Framework**: React 18 + Echo (Go) - **API**: gRPC + Connect RPC + REST - **Database**: SQLite/MySQL/PostgreSQL - **Build Tool**: Vite + buf (proto) - **State Management**: React Query + Context - **Styling**: Tailwind CSS