Files
2026-05-23 13:58:27 +02:00

225 lines
10 KiB
Markdown

<div align="center">
<img src="public/logo.png" alt="PatchPilot" width="120" />
<h1>PatchPilot</h1>
<p><strong>Repair café tool inventory & AI repair assistant.</strong></p>
<p>
<img alt="Next.js" src="https://img.shields.io/badge/Next.js-13.4-black?logo=next.js" />
<img alt="React" src="https://img.shields.io/badge/React-18-149eca?logo=react" />
<img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-5-3178c6?logo=typescript" />
<img alt="Material UI" src="https://img.shields.io/badge/MUI-5-007fff?logo=mui" />
<img alt="License" src="https://img.shields.io/badge/license-MIT-green" />
</p>
</div>
PatchPilot is a small but complete web app for a repair café. It combines a
**tool inventory with a reservation system** and an **AI assistant** that helps
diagnose problems, suggest repair approaches and answer questions about the
tool database. It's designed to feel like a real product, not a wireframe.
---
## 🏆 About this project
This project was built during the **Jade Hochschule AI Hackathon in May 2026**
and reached **3rd place** as a team submission.
The challenge: **vibe-code an app idea around sustainability and/or health**
in a single day. A digital companion for repair cafés fits
squarely in the sustainability bucket — repair cafés extend the lifespan of
broken things instead of sending them to landfill, and the bottleneck is
almost always tool access, expertise and coordination. PatchPilot tries to
chip away at all three at once.
---
## ✨ Features
### For everyone
- **Tool inventory** — 12 tools across 8 categories with search, filter, location, training requirements and rental period.
- **Reservation flow** — modal with date picker, live availability calendar, validation against the maximum rental period.
- **AI assistant (RepairBuddy)** — describe a problem in plain language and get a structured, Markdown-formatted answer. Supports image uploads for visual diagnosis.
- **Multi-language** — German / English with browser locale detection and persistent choice.
- **Dark / light mode** — with system-preference detection.
- **Responsive** — full mobile layout with drawers, full-screen modals and collapsing sidebars.
### For admins
- **Dashboard** with live stats (tools, users, active reservations, pending requests).
- **Pending-requests banner** with one-click approve / reject.
- **Tool CRUD** — add / edit / delete with category, emoji, location, training requirements.
- **Knowledge base** — upload manuals that are surfaced to the AI as context.
- **Reservation calendar** — month / week / day view, colour-coded by status.
### Behind the scenes
- **Role-aware AI** — the system prompt is built per request and injects a live snapshot of tools + reservations. Admins see borrower names; regular users only see availability & return dates. Same backend, different views.
- **Vision via OpenAI-compatible API** — image uploads are auto-downscaled (>2.5 MB → 1600 px JPEG) and sent as multimodal content.
- **Mock fallback** — works without an API key. The chat engine drops back to a deterministic local responder if `GEMINI_API_KEY` is missing or the upstream fails.
---
## 🚀 Getting started
### 1. Clone & install
```bash
git clone git@github.com:MrFrostDev/patch-pilot.git
cd patch-pilot
npm install
```
### 2. Configure the AI provider
PatchPilot expects an **OpenAI-compatible chat endpoint**. It has been tested
with [Requesty](https://requesty.ai) routing to Google Gemini 3 Flash, but any
OpenAI-compatible provider works (OpenRouter, LiteLLM, vLLM, your own gateway…).
Copy the example file and fill in your credentials:
```bash
cp .env.example .env.local
```
```env
REQUESTY_BASE_URL=https://router.requesty.ai/v1
GEMINI_API_KEY=your-key-here
PATCHPILOT_MODEL=vertex/gemini-3-flash-preview # optional, this is the default
```
If you leave the variables empty, PatchPilot uses its built-in **mock engine**
useful for demos without burning API credits.
### 3. Run
```bash
npm run dev
```
Open [http://localhost:3000](http://localhost:3000).
### 4. Sign in
Three demo accounts are bundled in the mock database:
| Username | Password | Role | Notes |
| -------- | -------- | ------------- | ------------------------------------------- |
| `admin` | `admin` | Administrator | Full access, tool CRUD, reservation actions |
| `staff` | `staff` | Staff | Has drill + soldering training |
| `guest` | `guest` | Guest | Read-only, no training |
---
## 🛠 Tech stack
| Layer | Choice |
| ------------------ | --------------------------------------------------------------- |
| Framework | **Next.js 13** (App Router) |
| Language | **TypeScript** (strict-ish, `strict: false` for hack speed) |
| UI library | **Material UI v5** with custom theme |
| Animation | **Framer Motion 12** |
| State | **Zustand 4** with `persist` middleware (localStorage) |
| Calendar | **FullCalendar** (dayGrid, timeGrid, interaction) |
| Icons | **lucide-react** |
| Markdown | **react-markdown** + `remark-gfm` |
| AI API | OpenAI-compatible (e.g. Requesty → Gemini 3 Flash, multimodal) |
| Fonts | **Inter** via `next/font/google` |
---
## 📁 Project structure
```
src/
├── app/
│ ├── api/chat/route.ts # Chat API — routes to live LLM or mock
│ ├── globals.css # Custom properties, FullCalendar theming
│ ├── layout.tsx # Metadata, font, providers shell
│ ├── page.tsx # AppBar + drawer + view switch + login
│ └── providers.tsx # Client-side providers (theme, i18n)
├── components/
│ ├── AIInput.tsx # Single-shell chat input with attachments
│ ├── AdminCalendar.tsx # Admin reservation calendar
│ ├── AdminDashboard.tsx # Stats + CRUD + approvals
│ ├── AnimatedBackground.tsx # GPU-composited blob background
│ ├── AvailabilityCalendar.tsx # In-modal availability view
│ ├── ChatSidebar.tsx # Session list with rename / delete
│ ├── ChatWindow.tsx # Messages, scroll-to-bottom, mode badge
│ ├── HeroSection.tsx # Landing hero with AI input
│ ├── Logo.tsx # Logo component (used everywhere)
│ ├── MarkdownMessage.tsx # Styled Markdown renderer
│ ├── Onboarding.tsx # Interactive 4-step walkthrough
│ ├── ReservationModal.tsx # Booking modal with sticky footer
│ └── ToolCard.tsx # Inventory card with hover shine
├── config/theme.ts # MUI theme (light/dark, glassmorphism)
├── services/
│ ├── auth-store.ts # Mock auth + persist
│ ├── chat-engine.ts # System prompt builder + live + mock + multimodal
│ ├── chat-store.ts # Sessions, messages, attachments
│ ├── color-mode.tsx # Theme provider with localStorage
│ ├── file-utils.ts # Image → DataURL with auto-downscale
│ ├── i18n.tsx # DE/EN dictionary + provider
│ ├── mock-data.ts # Initial tools, users, manuals
│ ├── reservation-store.ts # Reservations + status updates
│ └── tools-store.ts # Tool CRUD with persist
└── types/index.ts # Tool, User, Reservation, Category types
```
---
## 🧠 How the AI integration works
1. **The system prompt is built per request** (`buildSystemPrompt` in `chat-engine.ts`).
2. The current **user role** (`admin` → "Verwalter", everyone else → "Nutzer") and a **Markdown table of the live tool database** (with current reservations) are injected. This is essentially poor-man's RAG without an embedding store.
3. **Multimodal**: if the user message has image attachments, the request payload is sent as an OpenAI-style content array (`{type: 'text'}`, `{type: 'image_url'}`).
4. **Role-aware redaction is enforced by the prompt**, not by post-processing — admins see borrower names, regular users see only availability + due date. The same backend data, two views.
5. If the upstream fails (or no key is configured), the request transparently falls back to a deterministic local **mock responder** so the demo never breaks.
The system prompt itself is based on a "RepairBuddy" specification that
prioritises safety: emergency redirection to 112 / utility hotlines, no
step-by-step guides for gas / mains electricity / load-bearing structures,
honest uncertainty markers.
---
## 🖼 Image upload
- Up to 5 files per message
- Images > 2.5 MB are automatically downscaled to max 1600 px JPEG (q 0.85)
- Stored as Data-URLs in the chat store and persisted across reloads
- Rendered as clickable thumbnails inside the user bubble
---
## 🎨 Design notes
- **One source of truth** — colours, shadows and radii live in `theme.ts` and `globals.css` custom properties.
- **Glassmorphism AppBar** with `backdrop-filter: saturate(180%) blur(12px)`.
- **GPU-composited background** — four blurred radial blobs animated via CSS keyframes (no JS per frame). Vignette + grid pattern for foreground readability.
- **No double borders** — `AIInput` is a single shell with focus-ring; the hero just wraps it in a max-width container.
---
## 📦 Scripts
```bash
npm run dev # development server on :3000
npm run build # production build
npm run start # serve production build
npm run lint # next lint
```
---
## 🗺 Roadmap ideas
- Real auth (NextAuth + provider)
- Persistent database (Postgres + Prisma) instead of the mock store
- Real RAG with an embeddings store for manuals
- Email confirmations for approved reservations
- QR code on each tool that opens the reservation flow
- iCal export for personal reservations
---
## 📄 License
[MIT](./LICENSE) — do whatever you like, just don't hold me liable.