개발자를 위한 로컬 우선 간격 반복 학습 서비스.
배운 것을 잊기 직전에 다시 꺼내준다. 데이터는 내 컴퓨터의 SQLite 파일 하나에만 저장되고, 외부로 나가는 네트워크 요청은 없다.
Node.js만 있으면 된다. 설치할 의존성 0개, 빌드 단계 없음.
유지보수하지 않습니다. 실행에는 문제가 없고, 로컬에서 쓰기에는 그대로 동작합니다.
이 저장소는 "아이디어부터 최종 테스트까지 에이전트가 질문 없이 혼자 만든다" 는 실험의 결과물입니다. 2026-08-22 하루 만에 기획·설계·구현·테스트까지 끝냈고, 테스트 186건이 통과합니다. 이후 워크스페이스의 기준 스택이 Next.js + Cloudflare Workers + D1 로 바뀌면서 이 구조(의존성 0개 · 로컬 SQLite · 자체 비밀번호 인증)는 더 이상 이어지지 않습니다.
| 라이트 | 다크 |
|---|---|
![]() |
![]() |
npm start브라우저에서 http://127.0.0.1:4747 을 열고 계정을 한 번 만들면 끝이다.
첫 실행 시
node:sqlite의 실험 기능 경고가 뜰 수 있어npm start에는--disable-warning=ExperimentalWarning이 붙어 있다. 직접 실행하려면node bin/memoro.js.
요구 사항: Node.js 22.5 이상 (24 이상 권장)
개발자는 매일 새로운 걸 배우지만 대부분 3~7일 안에 잊고, 같은 걸 다시 검색한다. 노트 앱은 저장은 해주지만 다시 꺼내주지 않는다. Memoro는 SM-2 기반 간격 반복으로 "오늘 볼 카드"만 큐로 내놓는다.
- 30초 데일리 리뷰 — 무한 목록이 아니라 오늘 분량만
- 코드 카드 1급 지원 — 스니펫을 들여쓰기 그대로, 언어 표기와 함께
- 키보드 완주 —
Space로 답 보기,1~4로 평가,U로 되돌리기 - 데이터 소유 — SQLite 파일 하나 + 자동 백업 + JSON 내보내기
주제별 묶음이다. 덱마다 하루 신규 카드 수(기본 20)와 복습 수(기본 200)를 정할 수 있다.
질문 / 답 / (선택) 코드 · 언어 · 태그. 추가 창은 저장 후에도 열려 있어 연속으로 넣기 좋다.
여러 장을 한 번에 넣으려면 일괄 추가:
스택의 LIFO는? :: Last In First Out
큐의 FIFO는? :: First In First Out
| 키 | 동작 |
|---|---|
Space |
답 보기 → (공개 후) 보통으로 평가 |
1 |
다시 (기억나지 않음) |
2 |
어려움 |
3 |
보통 |
4 |
쉬움 |
U |
직전 평가 되돌리기 |
버튼에는 그 선택을 눌렀을 때 다음에 볼 시점(1분 / 10분 / 1일 / 4일 …)이 함께 표시된다.
설정 화면에서 JSON을 내보내고 가져올 수 있다. 서버도 부팅할 때와 24시간마다 자동으로 백업을 만들고 최근 7개를 유지한다.
SM-2에 학습 단계(learning steps)를 더한 방식이다.
new ──good/easy(졸업)──▶ review ──again──▶ relearning ──good──▶ review
│ ▲
└──again/hard──▶ learning ──good(마지막 단계)─────────────┘
- 학습 단계: 1분 → 10분 → 졸업(1일).
쉬움은 즉시 졸업(4일) - 복습 간격:
이전 간격 × EF(어려움 ×1.2, 쉬움 ×EF×1.3) - EF 갱신:
EF' = EF + (0.1 − (5−q)(0.08 + (5−q)0.02)), 하한 1.3 · 상한 3.0 - 망각 시: 간격 절반,
relearning으로 이동 - 상한 365일, 2일 이상 간격에는 ±5% 지터(같은 날 몰림 방지)
하루의 시작은 자정이 아니라 로컬 04:00이다. 새벽 학습은 전날로 집계된다.
| 변수 | 기본값 | 설명 |
|---|---|---|
MEMORO_PORT |
4747 |
포트 |
MEMORO_HOST |
127.0.0.1 |
바인딩 주소 |
MEMORO_DATA_DIR |
~/.memoro |
DB와 백업 위치 |
MEMORO_LOG_LEVEL |
info |
debug/info/warn/error/silent |
MEMORO_BACKUP_KEEP |
7 |
보관할 백업 개수 |
MEMORO_DAY_CUTOFF_HOUR |
4 |
하루 경계 시각(0~23) |
MEMORO_ALLOWED_HOSTS |
– | 추가로 허용할 Host 헤더(쉼표 구분) |
MEMORO_PORT=8080 MEMORO_DATA_DIR=./data npm start로컬 도구지만 로컬이라고 방치하지 않았다.
127.0.0.1에만 바인딩, Host 헤더 허용목록으로 DNS rebinding 차단- 비밀번호는 scrypt(N=16384) + 사용자별 salt, 세션 토큰은 sha256 해시로만 저장
- 세션 쿠키
HttpOnly+SameSite=Strict, 변경 요청은 Origin 검증(CSRF) - CSP로 인라인 스크립트 금지, 렌더는 전 구간
textContent(XSS) - 모든 SQL은 바인딩 파라미터, 모든 조회에 소유자 조건
- 로그인 15분 10회 / API 분당 600회 제한, 본문 1MB(가져오기 5MB) 상한
비밀번호를 잊으면 복구할 수 없다. 데이터 파일 자체는 암호화되지 않으므로 디스크 암호화(FileVault 등)를 함께 쓰는 것을 권한다.
npm test # 전체 186건
npm run test:unit # 순수 함수
npm run test:integration # 실제 HTTP 서버 + 임시 DBbin/memoro.js 실행 엔트리(시그널·종료 처리)
src/
config.js 환경변수 → 설정(단일 소스)
server.js 미들웨어 체인 + 라우팅 + 생명주기
http/ 라우터 · 정적 서빙 · 보안 미들웨어 · 라우트 핸들러
domain/ scheduler · validate · text · time (순수 함수, I/O 없음)
data/ db · migrations · repos(모든 SQL) · backup
services/ auth · decks · cards · review · stats · transfer
public/ 빌드 없는 ES Modules + CSS 토큰
tests/ unit · integration · helpers
docs/ 단계별 설계·검증 기록
의존 방향은 단방향이다: http → services → data, domain은 아무 층에도 의존하지 않는다.
SQL은 data/repos.js 밖에서 쓰지 않고, 렌더 코드에서 innerHTML을 쓰지 않는다.
| 문서 | 내용 |
|---|---|
| docs/00-idea.md | 문제 정의와 범위 |
| docs/01-naming.md | 서비스명 후보와 검증 |
| docs/02-plan.md | 기능·화면·데이터 흐름·예외 시나리오 |
| docs/03-architecture.md | 기술 선택 근거, 데이터 모델, API |
| docs/04-implementation.md | 구현 결정과 발견한 결함 |
| docs/05-design.md | 디자인 토큰·상태·접근성·명암비 |
| docs/06-test-report.md | 테스트 결과와 운영 검증 |
| docs/07-final-test.md | 최종 점검 |
| docs/persona-log.md | 8개 관점 검증 로그 52건 |
이미지/오디오 첨부, 클라우드 동기화, 멀티 디바이스, 공유 덱 마켓, 애드온, 마크다운 렌더링(XSS 표면 대비 이득이 적어 코드 블록으로 대체).
MIT

