# LifeOS API Reference

Base URL: `https://api.yourdomain.com` (or `/api` if mounted under a path).

All authenticated endpoints require:
```
Authorization: Bearer <JWT>
```
All bodies and responses are JSON. Successful responses look like:
```json
{ "ok": true, "data": { ... } }
```
Errors:
```json
{ "ok": false, "error": "code", "extra": null }
```

## Auth
| Method | Path | Auth | Body |
|---|---|---|---|
| POST | `/auth/signup` | — | `{email, password, full_name?}` → `{token, user}` |
| POST | `/auth/login` | — | `{email, password}` → `{token, user}` |
| GET  | `/auth/me` | ✅ | — → current user |
| POST | `/auth/forgot-password` | — | `{email}` → always 200 |
| POST | `/auth/reset-password` | — | `{token, password}` |
| POST | `/auth/change-password` | ✅ | `{current_password, new_password}` |

## Bills (EMI / recurring payments)
| Method | Path | Body |
|---|---|---|
| GET    | `/bills` | — |
| GET    | `/bills/{id}` | — |
| POST   | `/bills` | `{name, amount, next_due_date, category?, due_day?, is_recurring?, notes?, reminder_days_before?}` |
| PATCH  | `/bills/{id}` | any subset of the above |
| DELETE | `/bills/{id}` | — |

## Time logs
| Method | Path | Notes |
|---|---|---|
| GET    | `/time-logs?from=YYYY-MM-DD&to=YYYY-MM-DD` | defaults: last 30 days |
| POST   | `/time-logs` | `{task, duration_seconds, type, log_date?, start_hour?, end_hour?, time_label?}` |
| DELETE | `/time-logs/{id}` | — |

## App usage
| GET    | `/app-usage?date=YYYY-MM-DD` |
| POST   | `/app-usage` |

## Trips
| Method | Path |
|---|---|
| GET/POST | `/trips`, `/trips/{id}` |
| GET/POST | `/trips/{id}/checklist`, `/trips/{id}/expenses`, `/trips/{id}/itinerary`, `/trips/{id}/lessons` |
| PATCH/DELETE | `/trips/{id}` |

## Dashboard
| GET | `/dashboard/stats` → `{today_focus_seconds, today_screen_seconds, bills_due_within_7d, active_trips}` |

## Settings
| GET/PATCH | `/settings/profile` |
| POST      | `/settings/avatar` (multipart `file=...`) |

## Android app blocker
| GET    | `/blocker/apps` |
| POST   | `/blocker/apps` `{package_name, app_label, is_blocked?, daily_limit_minutes?}` |
| PATCH  | `/blocker/apps/{id}` |
| DELETE | `/blocker/apps/{id}` |
| POST   | `/blocker/sync` `{apps: [...]}` — bulk upsert from device |

## Payments (manual UPI)
| GET    | `/payments/plans` (public) |
| POST   | `/payments/submit` `{transaction_id, amount, plan_id?}` |

## Admin
| GET   | `/admin/users` |
| GET   | `/admin/payments` |
| PATCH | `/admin/payments/{id}` `{status: approved|rejected|pending, admin_note?}` |

## Account
| POST   | `/account/delete` `{reason?}` — schedules deletion 30 days out |
| DELETE | `/account/delete` — cancels pending deletion |

## Health
| GET | `/health` (public) — sanity check + DB connectivity |

---

## Tasks (Daily Priorities)
| Method | Path | Body / Query |
|---|---|---|
| GET    | `/tasks?date=YYYY-MM-DD` or `?from=...&to=...` | defaults to today |
| GET    | `/tasks/{id}` | — |
| POST   | `/tasks` | `{title, task_date?, goal_id?, notes?, priority_order?, is_completed?}` |
| PATCH  | `/tasks/{id}` | any subset above; toggling `is_completed` auto-stamps `completed_at` |
| DELETE | `/tasks/{id}` | — |

## Goals
| Method | Path | Notes |
|---|---|---|
| GET    | `/goals` | returns each goal + `total_tasks` and `completed_tasks` |
| GET    | `/goals/{id}` | includes nested `tasks` array |
| POST   | `/goals` | `{title, description?, category?, target_value?, current_value?, unit?, deadline?, status?, priority?}` |
| PATCH  | `/goals/{id}` | any subset above |
| DELETE | `/goals/{id}` | tasks linked to this goal are detached (`goal_id=NULL`), not deleted |

## Habits
| Method | Path | Notes |
|---|---|---|
| GET    | `/habits` | each habit includes `completions_30d` and `current_streak` |
| GET    | `/habits/{id}` | includes `recent_logs` (last 90 days) |
| POST   | `/habits` | `{name, icon?, color?, frequency?, target_per_period?, reminder_time?}` |
| PATCH  | `/habits/{id}` | any subset above |
| DELETE | `/habits/{id}` | also deletes all logs for this habit |

## Habit logs
| Method | Path | Notes |
|---|---|---|
| GET    | `/habits/{id}/logs?from=...&to=...` | defaults to last 90 days |
| POST   | `/habits/{id}/logs` | `{log_date?, count?, notes?}` — upsert (one row per habit per day) |
| DELETE | `/habits/{id}/logs?date=YYYY-MM-DD` | removes that day's entry |

## Bulk import (one-time localStorage migration)
| POST | `/import/local` | Body: `{ tasks:[...], goals:[...], habits:[{...habit, logs:[{date,count}]}] }` |

Returns counts per imported entity. Designed to be called **once** on first authenticated load after the frontend is migrated. Uses `INSERT IGNORE` so retries are safe.

**Linking tasks to imported goals:** include `client_id` on each goal (any string) and `goal_client_id` on each task — the import will translate it to the new server UUID.
