# API Contracts - keep-notes (Memento Web App)

## Overview

The keep-notes web application exposes REST API endpoints via Next.js App Router. All endpoints return JSON responses with a consistent format.

**Base URL:** `/api`
**Authentication:** NextAuth session-based (required for most endpoints)
**Response Format:**
```json
{
  "success": true|false,
  "data": any,
  "error": string  // only present when success: false
}
```

---

## Notes Endpoints

### GET /api/notes
Get all notes with optional filtering.

**Authentication:** Not required (currently)

**Query Parameters:**
- `archived` (boolean, optional): Include archived notes. Default: `false`
- `search` (string, optional): Search in title and content (case-insensitive)

**Response (200 OK):**
```json
{
  "success": true,
  "data": [
    {
      "id": "clxxxxxxx",
      "title": "string or null",
      "content": "string",
      "color": "default|red|orange|yellow|green|teal|blue|purple|pink|gray",
      "isPinned": boolean,
      "isArchived": boolean,
      "type": "text|checklist",
      "checkItems": [
        {
          "id": "string",
          "text": "string",
          "checked": boolean
        }
      ] | null,
      "labels": ["string"] | null,
      "images": ["string"] | null,
      "reminder": "ISO8601 datetime" | null,
      "isReminderDone": boolean,
      "reminderRecurrence": "none|daily|weekly|monthly|custom" | null,
      "reminderLocation": "string" | null,
      "isMarkdown": boolean,
      "size": "small|medium|large",
      "embedding": "JSON string" | null,
      "order": number,
      "createdAt": "ISO8601 datetime",
      "updatedAt": "ISO8601 datetime"
    }
  ]
}
```

**Error Response (500):**
```json
{
  "success": false,
  "error": "Failed to fetch notes"
}
```

---

### POST /api/notes
Create a new note.

**Authentication:** Not required (currently)

**Request Body:**
```json
{
  "title": "string (optional)",
  "content": "string (required unless type=checklist)",
  "color": "string (optional, default: 'default')",
  "type": "text|checklist (optional, default: 'text')",
  "checkItems": [
    {
      "id": "string",
      "text": "string",
      "checked": boolean
    }
  ] (optional),
  "labels": ["string"] (optional),
  "images": ["string"] (optional, base64 encoded)
}
```

**Response (201 Created):**
```json
{
  "success": true,
  "data": { /* note object */ }
}
```

**Error Responses:**
- `400 Bad Request`: Content is required
- `500 Internal Server Error`: Failed to create note

---

### PUT /api/notes
Update an existing note.

**Authentication:** Not required (currently)

**Request Body:**
```json
{
  "id": "string (required)",
  "title": "string (optional)",
  "content": "string (optional)",
  "color": "string (optional)",
  "type": "text|checklist (optional)",
  "checkItems": [...] (optional),
  "labels": ["string"] (optional),
  "isPinned": boolean (optional),
  "isArchived": boolean (optional),
  "images": ["string"] (optional)
}
```

**Response (200 OK):**
```json
{
  "success": true,
  "data": { /* updated note object */ }
}
```

**Error Responses:**
- `400 Bad Request`: Note ID is required
- `500 Internal Server Error`: Failed to update note

---

### DELETE /api/notes?id=xxx
Delete a note by ID.

**Authentication:** Not required (currently)

**Query Parameters:**
- `id` (string, required): Note ID

**Response (200 OK):**
```json
{
  "success": true,
  "message": "Note deleted successfully"
}
```

**Error Responses:**
- `400 Bad Request`: Note ID is required
- `500 Internal Server Error`: Failed to delete note

---

## Labels Endpoints

### GET /api/labels
Get all labels for the authenticated user.

**Authentication:** Required (NextAuth session)

**Response (200 OK):**
```json
{
  "success": true,
  "data": [
    {
      "id": "clxxxxxxx",
      "name": "string",
      "color": "red|orange|yellow|green|teal|blue|purple|pink|gray",
      "userId": "string",
      "createdAt": "ISO8601 datetime",
      "updatedAt": "ISO8601 datetime"
    }
  ]
}
```

**Error Response (401 Unauthorized):**
```json
{
  "error": "Unauthorized"
}
```

---

### POST /api/labels
Create a new label.

**Authentication:** Required (NextAuth session)

**Request Body:**
```json
{
  "name": "string (required)",
  "color": "string (optional, random color if not provided)"
}
```

**Response (200 OK):**
```json
{
  "success": true,
  "data": { /* label object */ }
}
```

**Error Responses:**
- `400 Bad Request`: Label name is required
- `401 Unauthorized`: Not authenticated
- `409 Conflict`: Label already exists for this user
- `500 Internal Server Error`: Failed to create label

---

### DELETE /api/labels/{id}
Delete a label by ID.

**Authentication:** Required (NextAuth session)

**URL Parameters:**
- `id` (string): Label ID

**Response (200 OK):**
```json
{
  "success": true,
  "message": "Label deleted successfully"
}
```

**Error Responses:**
- `401 Unauthorized`: Not authenticated
- `500 Internal Server Error`: Failed to delete label

---

## Authentication Endpoints

### GET/POST /api/auth/[...nextauth]
NextAuth.js authentication handler.

**Authentication:** Not required (this is the auth endpoint)

All NextAuth operations are handled by this route:
- Sign in
- Sign out
- Session management
- OAuth callbacks
- Email verification

**Implementation:** Delegates to `@/auth` configuration

---

## AI Endpoints

### POST /api/ai/tags
Generate intelligent tags for a note using AI.

**Authentication:** Not specified (likely required)

**Request Body:** (to be determined from implementation)

**Response:** (to be determined from implementation)

---

### POST /api/ai/test
Test AI integration.

**Authentication:** Not specified (likely required)

**Request Body:** (to be determined from implementation)

**Response:** (to be determined from implementation)

---

## Admin Endpoints

### POST /api/admin/randomize-labels
Randomize label colors (admin functionality).

**Authentication:** Required (admin role)

**Request Body:** (to be determined from implementation)

**Response:** (to be determined from implementation)

---

### POST /api/admin/sync-labels
Synchronize labels across the system (admin functionality).

**Authentication:** Required (admin role)

**Request Body:** (to be determined from implementation)

**Response:** (to be determined from implementation)

---

## Upload Endpoint

### POST /api/upload
Upload files (e.g., images for notes).

**Authentication:** Not specified

**Request Body:** multipart/form-data

**Response:** (to be determined from implementation)

---

## Cron/Reminder Endpoint

### POST /api/cron/reminders
Scheduled job for handling reminders.

**Authentication:** Not required (cron job)

**Request Body:** (to be determined from implementation)

**Response:** (to be determined from implementation)

---

## Debug Endpoints

### POST /api/debug/search
Debug search functionality.

**Authentication:** Not specified (admin/debug only)

**Request Body:** (to be determined from implementation)

**Response:** (to be determined from implementation)

---

## Data Models

### Note Model (Prisma)
```prisma
model Note {
  id                  String    @id @default(cuid())
  title               String?
  content             String
  color               String    @default("default")
  isPinned            Boolean   @default(false)
  isArchived          Boolean   @default(false)
  type                String    @default("text")
  checkItems          String?   // JSON array
  labels              String?   // JSON array
  images              String?   // JSON array
  links               String?   // JSON array
  reminder            DateTime?
  isReminderDone      Boolean   @default(false)
  reminderRecurrence  String?
  reminderLocation    String?
  isMarkdown          Boolean   @default(false)
  size                String    @default("small")
  embedding           String?   // JSON vector
  userId              String?
  user                User?     @relation(fields: [userId], references: [id])
  order               Int       @default(0)
  createdAt           DateTime  @default(now())
  updatedAt           DateTime  @updatedAt

  @@index([isPinned])
  @@index([isArchived])
  @@index([order])
  @@index([reminder])
  @@index([userId])
}
```

### Label Model (Prisma)
```prisma
model Label {
  id        String   @id @default(cuid())
  name      String
  color     String   @default("gray")
  userId    String?
  user      User?    @relation(fields: [userId], references: [id])
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@unique([name, userId])
  @@index([userId])
}
```

### User Model (Prisma)
```prisma
model User {
  id            String    @id @default(cuid())
  name          String?
  email         String    @unique
  emailVerified DateTime?
  password      String?
  role          String    @default("USER")
  image         String?
  theme         String    @default("light")
  resetToken    String?   @unique
  resetTokenExpiry DateTime?
  accounts      Account[]
  sessions      Session[]
  notes         Note[]
  labels        Label[]
  createdAt     DateTime  @default(now())
  updatedAt     DateTime  @updatedAt
}
```

---

## Notes

- **State Management**: Server actions and API routes (no dedicated state management library detected)
- **Database**: SQLite via Prisma ORM with better-sqlite3 adapter
- **Authentication**: NextAuth.js v5 with Prisma adapter
- **Error Handling**: All endpoints return consistent error format
- **JSON Parsing**: Arrays (checkItems, labels, images) stored as JSON strings in DB, parsed in API layer
- **Ordering**: Notes sorted by `isPinned DESC`, then `order ASC`, then `updatedAt DESC`
- **Search**: Case-insensitive search across title and content fields
