Recall is a calm notes and reminders app for people who want their notes to lead somewhere. Write a thought, turn it into a reminder, and let the Android app nudge you when it matters.
The web app is the writing desk. The Android app is the place that actually reminds you.
Live app: https://recall-aevum-s-projects1.vercel.app
Recall keeps notes, reminders, tags, and sync in one small system. It is not trying to be an AI workspace or a project manager. It is meant to be simple, durable, and useful every day.
The basic flow is:
- Write a Markdown note.
- Add a reminder manually, or use Fetch reminders to find dates in the note.
- Sync across web and Android.
- Get notified on Android.
- Snooze, complete, edit, or keep writing.
| Area | Web | Android |
|---|---|---|
| Email and password auth | Yes | Yes |
| Markdown notes | Yes | Yes |
| Markdown toolbar and rich preview | Yes | Yes |
| Dark mode toggle | Yes | Uses app theme |
| Tags | Yes | Yes |
| Reminders and repeats | Yes | Yes |
| Fetch reminders from note text | Yes | Yes |
| Today timeline | Yes | Yes |
| Offline-first local storage | PWA basics | Room database |
| Cross-device sync | Yes | Yes |
| Notifications with snooze and complete | No | Yes |
| Home screen widget | No | Yes |
| JSON backup import and export | Yes | Yes |
| Debug reports | View reports | Send reports |
| In-app APK update | No | Yes |
Web app API and database Android app
Next.js on Vercel -> Next.js API routes <- Jetpack Compose
Markdown editor Postgres on Neon Room, WorkManager
PWA shell Auth, sync, backups AlarmManager
The repository is split into three main parts:
web/contains the Next.js 16 app, API routes, auth, sync, docs, and tests.android/contains the Kotlin app, local database, notifications, widget, and sync worker.shared/contains reminder detection fixtures used by tests.
Notes support Markdown on both web and Android. The web editor includes a formatting toolbar, retry toasts for failed saves, and a virtualized list for large collections.
Reminders can be one-time or repeating. Recall understands common patterns like daily, weekly, monthly, and yearly. Android notifications can be snoozed or completed from the notification shade.
Fetch reminders scans a note for dates and time phrases. It can find exact dates, relative phrases, and likely reminder candidates. You stay in control, since detected reminders are suggestions until you add them.
Sync uses a dirty-upload model. Clients upload changed notes, reminders, tags, and note-tag links. The server applies ownership checks and last-writer-wins merging, then returns the current catalog.
The sync API also supports catalog pagination for large accounts. Android keeps retryable failures separate from permanent failures, and permanently failed rows can be reviewed in Settings.
Recall includes:
- Bcrypt password hashing.
- Short-lived access tokens.
- Rotating refresh tokens.
- CSRF checks for cookie-based refresh flows.
- Account lockout after repeated failed login attempts.
- Redis-backed rate limiting when Upstash is configured, with a local fallback for development.
- Request ID tracing on API responses.
- Health checks for database access and required auth secrets.
You will need:
- Node.js 20 or newer.
- A Postgres database. Neon works well.
- JDK 17 or Android Studio for the Android app.
cd web
cp .env.example .env.localSet these values in web/.env.local:
DATABASE_URL=
JWT_SECRET=
REFRESH_PEPPER=
REGISTER_SECRET=
NEXT_PUBLIC_APP_URL=http://localhost:3000JWT_SECRET and REFRESH_PEPPER must each be at least 32 characters.
Then install, push the schema, and start the app:
npm install
npm run db:push
npm run devOpen http://localhost:3000.
Useful web commands:
npm run lint
npm test
npm run buildOpen android/ in Android Studio, or use the Gradle wrapper with JDK 17.
Copy the local properties file:
cp android/local.properties.example android/local.propertiesFor an emulator talking to your local web app:
API_BASE_URL=http://10.0.2.2:3000/api/v1For a physical device, use your LAN IP or the production API:
API_BASE_URL=https://recall-aevum-s-projects1.vercel.app/api/v1Then run the app from Android Studio, or build from the command line:
cd android
./gradlew :app:assembleDebugThe latest debug APK is published from main when Android changes land.
After installing once, use Settings, Update to install newer builds from inside the app.
.
├── android/ Kotlin app, Room database, notifications, widget
├── docs/ OpenAPI spec, ADRs, and operational notes
├── shared/ Shared reminder detection fixtures
├── web/ Next.js app and API
├── TESTING.md Manual test checklist
└── README.md
The API lives under /api/v1.
The OpenAPI spec is in docs/openapi.yaml.
Versioning notes are in docs/API_VERSIONING.md.
| Area | Endpoints |
|---|---|
| Auth | POST /auth/register, POST /auth/login, POST /auth/refresh, POST /auth/logout, GET /auth/me |
| Notes | GET /notes, POST /notes, POST /notes/bulk, GET /notes/:id, PATCH /notes/:id, DELETE /notes/:id |
| Tags | GET /tags, POST /tags, POST /tags/bulk, PATCH /tags/:id, DELETE /tags/:id |
| Reminders | POST /notes/:id/reminders, PATCH /reminders/:id, DELETE /reminders/:id, POST /reminders/:id/complete, POST /reminders/:id/snooze |
| Sync | POST /sync, GET /sync/status |
| Backup | POST /backup/import |
| Debug | POST /debug/report, GET /debug/reports |
| Health | GET /health |
The production app runs on Vercel with web/ as the project root.
Required environment variables:
DATABASE_URL=
JWT_SECRET=
REFRESH_PEPPER=
REGISTER_SECRET=
NEXT_PUBLIC_APP_URL=
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=Upstash is optional. If it is not configured, rate limiting falls back to an in-memory limiter.
When the database schema changes, run:
cd web
npm run db:pushIf Android sync returns HTTP 400, the server response includes validation details.
Common causes are invalid UUIDs, orphan reminders, unknown tags, or empty fire_at values.
Android sanitizes dirty rows before upload and records skipped rows for review. Use Settings, Send debug report on Android, then open Settings, Debug reports on the web app.
Also check that API_BASE_URL ends with /api/v1.
curl https://recall-aevum-s-projects1.vercel.app/api/v1/healthA healthy response looks like:
{ "status": "ok", "db": "connected" }Recall is released under the MIT License.
For contribution notes, see CONTRIBUTING.md.