Skip to content

Repository files navigation

Memento - A Notion Clone

A lightweight note-taking application built with Next.js and SQLite. Create an account, sign in, and save your thoughts securely to a local database.

πŸš€ Getting Started

Prerequisites

  • Node.js 16+ installed
  • npm or yarn

Installation & Running

  1. Install dependencies:
npm install
  1. Run the development server:
npm run dev
  1. Open your browser: Navigate to http://localhost:3000

The app will automatically redirect you to the sign-in page. Create an account or sign in to access your notes.

πŸ“ Project Structure

my-app/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ api/                 # API routes
β”‚   β”‚   β”‚   β”œβ”€β”€ auth/           # Authentication endpoints
β”‚   β”‚   β”‚   └── notes/          # Notes CRUD endpoints
β”‚   β”‚   β”œβ”€β”€ signin/             # Sign in/up page
β”‚   β”‚   β”œβ”€β”€ dashboard/          # Main notes dashboard
β”‚   β”‚   β”œβ”€β”€ page.js             # Root page (redirects to signin/dashboard)
β”‚   β”‚   β”œβ”€β”€ layout.js           # Root layout
β”‚   β”‚   └── globals.css         # Global styles
β”‚   β”œβ”€β”€ components/             # Reusable React components
β”‚   β”‚   β”œβ”€β”€ NoteEditor.js       # Note editor with auto-save
β”‚   β”‚   └── NoteList.js         # List of user's notes
β”‚   └── lib/
β”‚       β”œβ”€β”€ db.js               # SQLite database setup
β”‚       └── auth.js             # Password hashing utilities
β”œβ”€β”€ middleware.js               # Auth middleware for route protection
β”œβ”€β”€ notion.db                   # SQLite database (auto-generated)
└── package.json

πŸ”Œ API Routes

Authentication Routes

POST /api/auth

Handles user sign up and sign in.

Request Body:

{
  "email": "user@example.com",
  "password": "password123",
  "action": "signup" or "signin"
}

Responses:

  • 201 (Sign Up Success): User created and logged in
  • 200 (Sign In Success): User authenticated
  • 400 (Bad Request): Missing email/password or user already exists
  • 401 (Unauthorized): Invalid credentials
  • 500 (Server Error): Database error

Example:

# Sign Up
curl -X POST http://localhost:3000/api/auth \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"pass123","action":"signup"}'

# Sign In
curl -X POST http://localhost:3000/api/auth \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","password":"pass123","action":"signin"}'

Notes Routes

GET /api/notes

Retrieves all notes for the authenticated user.

Query Parameters:

  • userId (required): The user's ID from the session cookie

Response:

[
  {
    "id": 1,
    "title": "My First Note",
    "content": "Note content here...",
    "created_at": "2024-01-22T10:30:00Z",
    "updated_at": "2024-01-22T11:45:00Z"
  }
]

Responses:

  • 200: List of notes
  • 400: Missing user ID
  • 500: Server error

Example:

curl -X GET "http://localhost:3000/api/notes?userId=1"

POST /api/notes

Creates a new note for the authenticated user.

Request Body:

{
  "userId": 1,
  "title": "New Note",
  "content": "Note content..."
}

Response:

{
  "id": 2,
  "title": "New Note",
  "content": "Note content...",
  "created_at": "2024-01-22T10:30:00Z"
}

Responses:

  • 201: Note created successfully
  • 401: User not authenticated
  • 404: User not found
  • 500: Server error

Example:

curl -X POST http://localhost:3000/api/notes \
  -H "Content-Type: application/json" \
  -d '{
    "userId": 1,
    "title": "Shopping List",
    "content": "Milk, eggs, bread"
  }'

PUT /api/notes/[id]

Updates an existing note.

URL Parameters:

  • id (required): Note ID to update

Request Body:

{
  "userId": 1,
  "title": "Updated Title",
  "content": "Updated content..."
}

Response:

{
  "success": true
}

Responses:

  • 200: Note updated successfully
  • 401: User not authenticated
  • 403: Unauthorized (note doesn't belong to user)
  • 404: Note not found
  • 500: Server error

Example:

curl -X PUT http://localhost:3000/api/notes/2 \
  -H "Content-Type: application/json" \
  -d '{
    "userId": 1,
    "title": "Updated Shopping List",
    "content": "Milk, eggs, bread, cheese"
  }'

DELETE /api/notes/[id]

Deletes a note.

URL Parameters:

  • id (required): Note ID to delete

Query Parameters:

  • userId (required): The user's ID for authorization

Response:

{
  "success": true
}

Responses:

  • 200: Note deleted successfully
  • 401: User not authenticated
  • 403: Unauthorized (note doesn't belong to user)
  • 404: Note not found
  • 500: Server error

Example:

curl -X DELETE "http://localhost:3000/api/notes/2?userId=1"

πŸ“„ Pages & Routes

Route Description Auth Required
/ Root page - Redirects to /signin or /dashboard No
/signin Sign in/up page No
/dashboard Main notes dashboard Yes

πŸ—„οΈ Database Schema

Users Table

CREATE TABLE users (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  email TEXT UNIQUE NOT NULL,
  password_hash TEXT NOT NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)

Notes Table

CREATE TABLE notes (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  user_id INTEGER NOT NULL,
  title TEXT NOT NULL DEFAULT 'Untitled',
  content TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)

πŸ› οΈ Making Changes

Adding a New Feature

  1. Create API Route (if needed):

    • Add file in src/app/api/your-feature/route.js
    • Export GET, POST, PUT, or DELETE functions
    • Use getDatabase() from src/lib/db.js to access SQLite
  2. Create/Update Components:

    • Add React component in src/components/YourComponent.js
    • Use 'use client' directive for client-side interactivity
    • Import and use in pages
  3. Update Pages:

    • Modify files in src/app/ (e.g., src/app/dashboard/page.js)
    • Pages are Server Components by default, use 'use client' for interactivity
  4. Update Database:

    • Modify src/lib/db.js in the initializeDatabase() function
    • Add new tables or columns as needed

Adding New Authentication

To add OAuth or other auth methods:

  1. Modify src/app/api/auth/route.js
  2. Update src/app/signin/page.js with new auth UI
  3. Add necessary dependencies to package.json

Styling

The project uses Tailwind CSS. Customize styling in component className attributes. Global styles are in src/app/globals.css.

πŸ”’ Security Features

  • βœ… Password hashing with bcrypt
  • βœ… HTTP-only secure cookies for sessions
  • βœ… Middleware protection for dashboard routes
  • βœ… User ownership validation on notes (can't access others' notes)
  • βœ… CSRF protection with SameSite cookies

πŸ“¦ Dependencies

  • Next.js - React framework
  • better-sqlite3 - SQLite database
  • bcrypt - Password hashing
  • Tailwind CSS - Styling

πŸ› Troubleshooting

"Database is locked" error:

  • Close any other instances of the app
  • Delete notion.db-shm and notion.db-wal files and restart

Sign in redirects to sign in page:

  • Check browser cookies are enabled
  • Verify the API request completed successfully
  • Check browser console for errors

Notes not saving:

  • Open browser DevTools (F12) and check Network tab for API errors
  • Ensure you're signed in (check cookies in Application tab)
  • Check terminal for server-side errors

About

This is Notion like clone were users can take quick notes with the formatting similar to Notion. I was inspired to make this project for myself after seeing pricing of similar software. I wanted to make it practical enough to replace my current note taking platform of choice.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages