87dadf1def
Embedded Web App for EV charging slot bookings. Express backend with JWT auth and AMPECO Public API proxy. React SPA with booking CRUD, availability checking, and runtime design token theming. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
163 lines
6.6 KiB
Markdown
163 lines
6.6 KiB
Markdown
# Booking EWA
|
|
|
|
Embedded Web App (EWA) for managing EV charging station bookings. The application provides a mobile-optimized UI for creating, viewing, updating, and cancelling charger bookings. It is designed to be embedded within a native mobile app via a JWT-based session handoff.
|
|
|
|
## Architecture Overview
|
|
|
|
The application consists of two parts:
|
|
|
|
- **Backend** -- Express.js server (port 3001) that validates JWT tokens, manages sessions, and proxies API requests to the AMPECO public API.
|
|
- **Frontend** -- React SPA (Vite dev server on port 5173) using Tailwind CSS and the `@ampeco/ewa-ui` design system. Uses `HashRouter` for client-side routing.
|
|
|
|
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the full architecture document.
|
|
|
|
## Prerequisites
|
|
|
|
- Node.js >= 18
|
|
- npm >= 9
|
|
- Local sibling packages (linked via `file:` references in `package.json`):
|
|
- `@ampeco/design-tokens` at `../design-tokens`
|
|
- `@ampeco/ewa-ui` at `../ewa-ui`
|
|
|
|
## Setup
|
|
|
|
1. Clone the repository and ensure sibling packages are present:
|
|
|
|
```
|
|
parent-directory/
|
|
booking-ewa/ <-- this project
|
|
design-tokens/ <-- @ampeco/design-tokens
|
|
ewa-ui/ <-- @ampeco/ewa-ui
|
|
```
|
|
|
|
2. Copy the example environment file and configure it:
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
|
|
3. Edit `.env` with your values:
|
|
|
|
```
|
|
API_BASE_URL=https://your-instance.charge.ampeco.tech/public-api
|
|
API_TOKEN=your-api-token-here
|
|
JWT_SECRET=your-jwt-secret-here
|
|
PORT=3001
|
|
NODE_ENV=development
|
|
```
|
|
|
|
| Variable | Description |
|
|
|----------------|----------------------------------------------------------------|
|
|
| `API_BASE_URL` | Base URL of the AMPECO public API instance |
|
|
| `API_TOKEN` | Bearer token for authenticating with the public API |
|
|
| `JWT_SECRET` | Shared secret for signing/verifying HS256 JWT tokens |
|
|
| `PORT` | Port for the Express backend server (default: `3001`) |
|
|
| `NODE_ENV` | Set to `development` to enable dev fallback session and `/dev/jwt` endpoint |
|
|
|
|
4. Install dependencies:
|
|
|
|
```bash
|
|
npm install
|
|
```
|
|
|
|
5. Start the development servers:
|
|
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
This starts both the Vite dev server (http://localhost:5173) and the Express backend (http://localhost:3001) concurrently.
|
|
|
|
## Available Scripts
|
|
|
|
| Script | Description |
|
|
|-----------------|-------------------------------------------------------------|
|
|
| `npm run dev` | Start Vite frontend and Express backend in parallel |
|
|
| `npm run build` | Build the frontend (Vite) and compile the backend (TypeScript) |
|
|
| `npm run typecheck` | Run TypeScript type checking (no emit) |
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
booking-ewa/
|
|
.env.example # Environment variable template
|
|
index.html # Vite HTML entry point
|
|
package.json # Dependencies and scripts
|
|
vite.config.ts # Vite config (proxy /api and /dev to backend)
|
|
tailwind.config.ts # Tailwind CSS with ewa-ui plugin
|
|
postcss.config.js # PostCSS (Tailwind + Autoprefixer)
|
|
tsconfig.json # Frontend TypeScript config
|
|
|
|
backend/
|
|
tsconfig.json # Backend TypeScript config
|
|
src/
|
|
index.ts # Express server entry, JWT middleware, dev fallback
|
|
jwt.ts # JWT verification and dev token creation
|
|
proxy.ts # Generic API proxy utility
|
|
routes.ts # Route definitions (session, bookings, availability)
|
|
types.ts # Backend type definitions (JwtPayload, SessionData)
|
|
|
|
src/
|
|
main.tsx # React entry point
|
|
App.tsx # Root component (SessionProvider + routing guard)
|
|
app.css # Global styles (design-tokens CSS variables, Tailwind)
|
|
env.d.ts # TypeScript ambient declarations
|
|
|
|
api/
|
|
client.ts # Fetch wrapper with error handling (ApiRequestError)
|
|
bookings.ts # Booking list/detail API functions
|
|
bookingRequests.ts # Create/update/cancel booking request API
|
|
availability.ts # Check availability API
|
|
|
|
context/
|
|
SessionContext.tsx # React context for session state and theme application
|
|
|
|
hooks/
|
|
useSession.ts # Hook to consume SessionContext
|
|
useBookings.ts # Hooks for booking list and detail (with polling)
|
|
useAvailability.ts # Hook for availability checking
|
|
|
|
components/
|
|
Layout/Layout.tsx # App shell with bottom tab navigation
|
|
BookingCard/BookingCard.tsx # Booking summary card
|
|
AvailabilitySlots/AvailabilitySlots.tsx # Slot selection grid
|
|
DateTimePicker/DateTimePicker.tsx # datetime-local input wrapper
|
|
|
|
pages/
|
|
Home/Home.tsx # Dashboard with upcoming bookings
|
|
CreateBooking/CreateBooking.tsx # Two-step booking creation flow
|
|
MyBookings/MyBookings.tsx # Upcoming/Past tabs
|
|
BookingDetail/BookingDetail.tsx # Detail view with cancel action
|
|
UpdateBooking/UpdateBooking.tsx # Edit booking time range
|
|
UserIdFallback/UserIdFallback.tsx # Manual user ID entry (dev mode)
|
|
|
|
router/
|
|
index.tsx # HashRouter route definitions
|
|
|
|
types/
|
|
index.ts # Frontend type definitions (Booking, BookingRequest, etc.)
|
|
|
|
i18n/
|
|
init.ts # i18next initialization
|
|
locales/
|
|
en.json # English translations
|
|
```
|
|
|
|
## Key Dependencies
|
|
|
|
| Package | Purpose |
|
|
|-------------------------|------------------------------------------------------|
|
|
| `@ampeco/design-tokens` | CSS custom properties for theming (LIGHT/DARK) |
|
|
| `@ampeco/ewa-ui` | Shared UI component library and Tailwind plugin |
|
|
| `react-router-dom` | Client-side routing (HashRouter) |
|
|
| `i18next` / `react-i18next` | Internationalization |
|
|
| `lucide-react` | Icon library |
|
|
| `express` | Backend HTTP server |
|
|
| `jsonwebtoken` | JWT signing and verification |
|
|
|
|
## Development Notes
|
|
|
|
- In `development` mode, if no JWT is provided, the backend falls back to a default session with `userId: 775`.
|
|
- If the fallback session has no `userId` (set to `null`), the frontend displays a `UserIdFallback` page where you can manually enter a user ID.
|
|
- Use `POST /dev/jwt` to generate a JWT token with custom session overrides. See [docs/USER-GUIDE.md](docs/USER-GUIDE.md) for details.
|