Harden API, data layer, and autosave; add validation, pagination, migrations
Build and Push Docker Image / build (push) Successful in 2m26s

- Enforce task ownership on PATCH/DELETE /api/tasks (was: any signed-in
  user could edit or delete anyone's tasks)
- Validate all API request bodies with zod; escape user content and
  restrict links to http(s) in the Drive export; block reverting a
  SUBMITTED report
- Add @@unique([userId, date]) on Report with upsert to eliminate the
  duplicate-daily-report race; switch startup from
  `prisma db push --accept-data-loss` to `prisma migrate deploy` with
  automatic baselining of existing databases (dedup migration merges
  any pre-existing duplicates)
- Autosave: re-queue and retry failed task saves with a visible
  saving/error indicator instead of silently dropping edits
- Paginate and filter GET /api/reports (?date, ?mine, ?q, ?take,
  ?cursor); report form fetches only today's report, admin dashboard
  uses server-side search + Load more
- Type the frontend and lib layer (DTOs in src/types/api.ts); zero
  eslint errors
- Update README and Unraid guide for migrations, upgrade path, and API

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 19:43:36 -05:00
parent d8efa71992
commit a9df9c0cf4
22 changed files with 636 additions and 148 deletions
+31 -2
View File
@@ -9,9 +9,10 @@ A sleek, modern, and dockerized web application for employees to track and submi
- **Multi-Step Reporting**:
- **Morning**: Log planned tasks, time estimates, and initial notes.
- **Evening**: Review achievements, update statuses, and submit links to completed work.
- **Reliable Autosave**: Task edits are debounced and saved automatically; failed saves are retried and surfaced in the UI so no edit is ever silently lost.
- **Smart Admin Logic**:
- The first user to log in is automatically granted the **ADMIN** role.
- Exclusive **Admin Panel** to search and review all employee reports.
- Exclusive **Admin Panel** with server-side search and paginated report browsing, user role management, and settings.
- **Google Drive Integration**:
- Automatically exports completed reports as Google Docs.
- Admins can designate a specific folder for all exports.
@@ -41,12 +42,40 @@ docker run -p 3000:3000 \
wfh-report
```
## 🗄️ Database & Migrations
The schema is managed with **Prisma Migrate**. On every container start, `entrypoint.sh` runs `prisma migrate deploy`, which applies any pending migrations from `prisma/migrations/` — additive and safe, unlike the old `db push --accept-data-loss` approach.
- **Fresh installs**: all migrations are applied automatically to the new database.
- **Upgrading an existing deployment** (created before migrations were introduced): the first boot logs a one-time `P3005` error, then automatically *baselines* the database (marks `0_init` as applied) and applies the remaining migrations. This is expected — no manual action needed.
- Reports are unique per user per day (`@@unique([userId, date])`); the migration merges any pre-existing duplicate reports, keeping the earliest and moving its tasks.
To add a schema change during development:
```bash
npx prisma migrate dev --name describe_your_change
```
## 🔌 API Overview
All endpoints require a session; admin endpoints require the `ADMIN` role. Request bodies are validated with zod (invalid input returns `400` with field details).
| Endpoint | Notes |
| :--- | :--- |
| `GET /api/reports` | Returns `{ reports, nextCursor }`. Query params: `date` (YYYY-MM-DD), `mine=1` (own reports only, matters for admins), `q` (search by employee/manager, admin), `take` (page size, max 100), `cursor` (pagination). |
| `POST /api/reports` | Creates or resumes the day's report (upsert — safe against double-submits). |
| `GET/PATCH /api/reports/[id]` | Owner (or admin for GET) only. A `SUBMITTED` report cannot be reverted. |
| `POST /api/reports/[id]/export` | Exports/re-exports the report to Google Drive. User content is HTML-escaped; only `http(s)` links are rendered. |
| `POST/PATCH/DELETE /api/tasks` | Scoped to tasks on the caller's own reports. |
| `GET/POST /api/admin/settings` | Admin only. Allowed keys: `GOOGLE_DRIVE_FOLDER_ID`. |
| `GET/PATCH /api/admin/users` | Admin only. Role management; self-demotion is blocked. |
## 🏡 Unraid Installation
For specific instructions on installing this on Unraid (including volume mapping and Unraid UI configuration), please refer to our [Unraid Installation Guide](https://git.alwisp.com/jason/wfh/src/branch/master/unraid_install.md).
## 🛠️ Tech Stack
- **Framework**: [Next.js](https://nextjs.org/) (App Router)
- **Database**: [SQLite](https://sqlite.org/) via [Prisma ORM](https://www.prisma.io/)
- **Database**: [SQLite](https://sqlite.org/) via [Prisma ORM](https://www.prisma.io/) (Prisma Migrate for schema management)
- **Auth**: [NextAuth.js](https://next-auth.js.org/)
- **Validation**: [Zod](https://zod.dev/) on all API request bodies
- **Styles**: Vanilla CSS & TailwindCSS (for utility)
- **Icons**: [Lucide React](https://lucide.dev/)