Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
183 changes: 183 additions & 0 deletions .junie/Please_update_the_plan,_the_backend_will.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
### Updated plan: Frontend-first with mock data (backend later)

We will build the complete user-facing experience and admin CRUD flows in Next.js using an API abstraction that currently serves mock data. When the backend is ready, we will switch the API implementation without refactoring UI code.

---

### Guiding principles
- Preserve API contracts: mirror the provided OpenAPI schemas for `Event`, `Subscription`, `User` in TypeScript.
- Single swap point: a thin `apiClient` with interchangeable adapters: `mockAdapter` now, `httpAdapter` later.
- SSR-ready: support server components and server actions, but default to client-side fetching for mutating flows during the mock phase to avoid hydration pitfalls.
- UX first: implement responsive UI with Tailwind and dark mode per `.junie/guidelines.md`.
- Deterministic demos: seed mock data; allow URL flags to vary scenarios (empty states, errors, full capacity, etc.).

---

### Phase 1 — Foundation and project wiring
1. Types and contracts
- Create TS types aligned to OpenAPI: `Event`, `Subscription`, `User`, `Tag`, `Category`.
- Add helper enums: `EventStatus = 'DRAFT' | 'PUBLIC' | 'DISABLED'`, `EventFormat = 'IN_PERSON' | 'HYBRID' | 'ONLINE'`.
2. API abstraction
- Define `apiClient` interface with methods mapping to the future endpoints:
- Events: `createEvent`, `updateEvent`, `getEventById`, `deleteEvent`, `findEventsByStatus`, `findEventsByTags`, `uploadEventImage` (mock no-op returning a URL).
- Subscriptions: `createSubscription`, `getSubscriptionById`, `deleteSubscription`, `findSubscriptionsByEventId`.
- Users (optional for MVP): `login`, `logout`, `getUserByName`.
- Export a single instance `api` that internally uses `mockAdapter` for now.
3. Styling and layout
- Ensure Tailwind, palette, and dark mode patterns per `.junie/guidelines.md`.
- Global layout with theme initialization script to avoid dark-mode FOUC.

---

### Phase 2 — Mock data layer and dev tooling
1. Mock strategy
- Use a local in-memory store seeded at boot; persist to `localStorage` in the browser for continuity. For SSR, keep a deterministic seed so server and client render match; prefer client-side hydration for lists during mock phase.
- Optional: add `msw` (Mock Service Worker) only if we want to test actual `fetch` calls; otherwise, call `mockAdapter` directly.
2. Seed data
- Seed several events across statuses and formats, with tags and capacities; include one "full" event (capacity reached) and one upcoming, one past.
- Provide test users only for admin area if needed (no real auth).
3. Scenario flags
- URL/query flags (dev-only) to trigger states:
- `?empty=1` → empty lists
- `?error=events` → simulate 500 on events endpoints
- `?latency=300` → artificial delay in `mockAdapter`

Example `api` interface and mock adapter sketch:
```ts
// api/types.ts
export type ID = number;
export type EventStatus = 'DRAFT' | 'PUBLIC' | 'DISABLED';
export type EventFormat = 'IN_PERSON' | 'HYBRID' | 'ONLINE';
export interface Tag { id: ID; name: string }
export interface Category { id: ID; name: string }
export interface Event {
id: ID;
name: string;
location?: string;
capacity?: number;
startDate?: string; // ISO
endDate?: string; // ISO
category?: Category;
tags?: Tag[];
status?: EventStatus;
format?: EventFormat;
photoUrl?: string;
}
export interface Subscription { id: ID; eventId: ID; quantity: number; email: string }

// api/client.ts
export interface ApiClient {
// Events
createEvent(e: Omit<Event, 'id'>): Promise<Event>;
updateEvent(e: Event): Promise<Event>;
getEventById(id: ID): Promise<Event>;
deleteEvent(id: ID): Promise<void>;
findEventsByStatus(status?: string): Promise<Event[]>;
findEventsByTags(tags?: string[]): Promise<Event[]>;
uploadEventImage(eventId: ID, file: File): Promise<{ url: string }>;
// Subscriptions
createSubscription(s: Omit<Subscription, 'id'>): Promise<Subscription>;
getSubscriptionById(id: ID): Promise<Subscription>;
deleteSubscription(id: ID): Promise<void>;
findSubscriptionsByEventId(eventId: ID): Promise<Subscription[]>;
}
```

---

### Phase 3 — Public UI (using mocks)
1. Events list `/events`
- Filters: status (PUBLIC default), tags; text search by name/location.
- Card grid with image, title, date range, location, tags, capacity remaining.
- Pagination or "Load more"; ensure mobile-first layout.
- Error/empty/loading states wired to mock flags.
2. Event details `/events/[id]`
- Full description area (placeholder in mock), schedule times, tags, image.
- Show remaining capacity; if 0 → display "Full" and disable subscription.
- SEO basics: metadata with event title/description; structured data later.
3. Subscribe form (public)
- Inputs: `email`, `quantity` (1 default); validate email, min/max by remaining capacity.
- On submit: call `api.createSubscription`; show success toast/page. In mock, also "simulate email sent" message.

---

### Phase 4 — Admin UI (mocked CRUD)
1. Admin access (dev-only)
- Gate routes under `/admin` with a simple dev guard (e.g., `NEXT_PUBLIC_ENABLE_ADMIN=true`). No real auth yet.
2. Admin dashboard `/admin`
- Table of events with status, date, RSVPs count; actions: Edit, Publish/Unpublish, Delete.
3. Event create/edit `/admin/events/[id]?new=1`
- Form fields per schema: name, location, capacity, start/end, format, status, category, tags, image upload.
- Use `api.createEvent` and `api.updateEvent` (mock writes to store).
- Image upload uses `api.uploadEventImage` → mock returns a generated URL and updates `photoUrl`.
4. Subscriptions management
- View list for an event; delete/cancel to free capacity in mock store.

Capacity logic in mock adapter:
- Enforce `sum(subscription.quantity) <= event.capacity`; reject with a typed error when over capacity.
- Unique constraint `(eventId, email)` in mock to mimic real-world idempotency; update quantity on repeat subscribe.

---

### Phase 5 — Data fetching, state, and navigation patterns
- Server vs client
- Lists and detail pages can be server components with mock data fetched in-process when using a pure adapter; if using `msw`+`fetch`, keep them as client components for the mock phase to avoid SSR inconsistencies.
- State management
- Prefer local component state and URL params; only lift state where needed.
- For cross-page state (e.g., filters), use query params to keep shareable links.
- Caching
- Keep a simple in-memory cache inside the mock adapter; later map to HTTP cache headers and Next revalidation.

---

### Phase 6 — Email simulation (mock)
- On `createSubscription`, return a payload that includes a `notification` object for UI display:
- `userEmailSent: true`, `organizerEmailSent: true`, `previewUrl` pointing to a dev-only template preview page.
- Provide a dev-only route `/dev/emails/[id]` to render a sample confirmation email using the theme.

---

### Phase 7 — Testing and quality gates (works with mocks)
- Unit tests (Node’s built-in test runner)
- Test pure utilities: capacity calculation, date formatting, filtering, adapters’ business rules (over-capacity rejection, idempotent RSVP).
- Contract tests (prep for backend)
- Validate our TS types mirror OpenAPI schemas: generate types or assert sample payloads against a Zod schema derived from the spec (optional in mock phase).
- UI verifications
- Add Playwright later for E2E; for now, smoke test that event listing renders and subscribe flow updates mock store.
- CI as per guidelines: `pnpm lint`, `pnpm exec tsc --noEmit`, `node --test`.

---

### Phase 8 — Swapping to the real backend later
1. Introduce `httpAdapter` implementing `ApiClient` using `fetch` to `http://localhost:8080/api` (per OpenAPI `servers`).
2. Feature flag or env switch:
- `NEXT_PUBLIC_API_MODE=mock | http`
- Provider at app root chooses adapter accordingly.
3. Map endpoints 1:1 to the spec paths:
- `POST /event`, `PUT /event`, `GET/DELETE /event/{eventId}`, `GET /event/findByStatus`, `GET /event/findByTags`, `POST /event/{eventId}/uploadImage`.
- `POST /subscription`, `GET/DELETE /subscription/{subscriptionId}`, `GET /subscription/{eventId}`.
4. Error handling and auth
- Translate HTTP errors into typed errors already used in UI (keep messages consistent).
- Wire auth only for admin routes when backend supports it.
5. Incremental rollout
- Start by pointing read-only pages (`/events`, `/events/[id]`) to `httpAdapter` while keeping mutations on mock until endpoints are stable; then flip subscriptions, then admin CRUD.

---

### Deliverables checklist (mock phase)
- [ ] `api` interface and `mockAdapter` with seeded data and delays/errors switches
- [ ] Types for `Event`, `Subscription`, `User`, `Tag`, `Category`
- [ ] Public pages: events list, event detail, subscribe flow with success/error states
- [ ] Admin pages: dashboard, create/edit event, subscriptions management
- [ ] Image upload UI wired to mock upload returning a URL
- [ ] Tailwind + dark mode applied across screens; accessibility passes basic checks
- [ ] Unit tests for core utilities and adapter rules; CI steps green

---

### Notes and reminders
- Do not over-couple UI to the mock store; only call `api` methods from components or server actions.
- Keep URL-driven state and make empty/error/loading states first-class for realistic UX.
- Use semantic Tailwind tokens defined in `.junie/guidelines.md` and provide dark variants for all components.

This plan reframes the project as frontend-first while making the backend integration a low-risk, low-diff switch when the service becomes available.
Loading