Phase 2
Base app architecture:
Route groups for customer, staff and owner.
* Reusable design system with around 20 UI components.
* Complete Prisma schema.
* Authentication with email/password and Google.
* Role and permission model.
* Protected routes.
* Clean separation between features, services, components and shared utilities.
This commit is contained in:
201 files changed
+31984
No files matched your search
@@ -0,0 +1,653 @@
|
||||
# NextChair — Phase 1 Implementation Plan
|
||||
### Template analysis & planning document
|
||||
|
||||
Status: **Planning only.** No application code, migrations, or dependencies have been created. This document is for review and approval before Phase 2 begins.
|
||||
|
||||
---
|
||||
|
||||
## 1. Executive Summary
|
||||
|
||||
**Product.** NextChair (working/internal name — the templates themselves brand the product **"TrimTime"**, see §15) is a mobile-first booking platform for a barbershop business, with three distinct experiences: guest/registered customers who discover the shop and book appointments, barbers who run their day from a phone, and an owner who administers the business, staff, services, and loyalty programme on top of the barber toolset.
|
||||
|
||||
**Who it's for.** Small–to–mid size barbershops that currently rely on phone bookings, generic scheduling SaaS, or paper loyalty cards, and want a branded, mobile-first booking experience with an integrated staff/owner back office.
|
||||
|
||||
**What exists in `/templates`.** 22 static HTML files, one screen each, built with Tailwind CDN + Font Awesome CDN + inline `<style>`/`<script>` blocks. No shared CSS/JS/asset files, no component reuse — every screen re-declares its own Tailwind color palette. All images are remote placeholder URLs from a UX-generation tool (`uxpilot-auth.appspot.com`). There are no desktop or tablet layouts — every screen is phone-width only.
|
||||
|
||||
**How complete the designs are.** The templates cover roughly **55–60%** of the full product surface described in the brief. The booking flow, staff day-to-day tools, and the loyalty configuration screen are close to production-ready visually. Business-profile management, service/category management, booking-rules configuration, appointment rescheduling/cancellation, "upcoming appointments," and most secondary/empty/error states are **not represented at all**. Several screens exist under a misleading name (see §2), and three incompatible visual design systems are in use simultaneously.
|
||||
|
||||
**Most important findings.**
|
||||
1. **No true business-profile-editing screen exists.** The file named "Owner - Business Details" (`21-...html`) is actually the analytics **Dashboard** — business name, address, hours, policies, and branding have no owner-facing edit screen anywhere in the set.
|
||||
2. **Three different color/token systems compete for "the" design system** — a salon-red/multicolor calendar palette (file 1), a green/`ink`-`stone` system (most files), and a blue/`brandbtn` system (file 16, Appointments) — plus a one-off amber palette on the Loyalty Card (file 11). None can be assumed canonical without a decision.
|
||||
3. **The customer "Home" screen (file 15) is a public business-discovery page, not a personalized logged-in home.** It has no upcoming-appointment card, no loyalty progress, no personalized greeting — the brief's expected customer home content is entirely absent, and the plan must treat "public business page" and "logged-in customer home" as two screens the templates never separated.
|
||||
4. **Appointments screen (file 16) only shows a "Finished/Cancelled" list** — there is no Upcoming section, no cancel/reschedule action, and no appointment-detail drill-in, despite this being core to the customer brief.
|
||||
5. **Business content is inconsistent and must be treated as placeholder, not requirements**: the brand appears as "NextChair" (filenames), "TrimTime" (in-page titles/branding), "Blake Heritage Barbershop" and "The Cut & Shave Co." (different shop names on different screens); prices mix £ and $; file 1's calendar shows nail-salon services (manicures) instead of barbershop services.
|
||||
6. Internal navigation links between templates are largely **broken or inconsistent** (mismatched filenames like `Schedule__mobile.html`, `NextChair - Customer - Home__mobile.html` vs. the actual exported filenames), and there are **at least four distinct bottom-navigation variants** across staff/owner screens that should be one component.
|
||||
7. Owner-configurable **booking rules, service/category management, and most Loyalty Programme rules from the brief (eligible services/staff, expiry, approval, max value) have no screens at all** — only entry points that lead nowhere.
|
||||
|
||||
None of this blocks Phase 2 planning — it mainly means Phase 2 (and the early implementation phases) must budget explicit time for missing-screen design decisions rather than pure "translate this Figma-equivalent" work.
|
||||
|
||||
---
|
||||
|
||||
## 2. Template Inventory
|
||||
|
||||
All files live directly in `/templates` (flat, no subfolders) and are self-contained HTML documents (Tailwind CDN + Font Awesome CDN, no build step, no shared partials).
|
||||
|
||||
| # | File | Proposed Screen Name | Role | Viewport | Purpose | Status | Notes |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| 1 | `1-NextChair - Staff - Calendar.html` | Staff Day Calendar | Barber / Owner | Mobile only | Grid-column day view of appointments per barber, current-time indicator | Mostly complete | Uses **salon services** (Manicure) — placeholder content, not requirement. Distinct red/teal/purple palette not used elsewhere. `md:w-full` hints at an abandoned responsive attempt. |
|
||||
| 2 | `2-NextChair - Staff - Current.html` | Current Appointment | Barber | Mobile only | Active client card, start visit, post-visit actions, mini customer history | Mostly complete | No check-in vs. arrived distinction beyond a label; no no-show/cancel actions; no empty state ("no current appointment"). |
|
||||
| 3 | `3-NextChair - Staff - Customers.html` | Client List | Barber / Owner | Mobile only | Searchable client list with visit/stamp counts | Partial | No alphabetical index, filters, "add customer," or empty/loading states. |
|
||||
| 4 | `4-NextChair - Staff - Settings.html` | Staff Settings | Barber | Mobile only | Profile card; links to Working Hours/Breaks/Time Off/Notifications; logout; "Switch to Admin View" | Partial | Destination screens for Working Hours/Breaks/Time Off/Notifications don't exist. "Switch to Admin View" implies a role-toggle UX that needs real design (see §3). |
|
||||
| 5 | `5-NextChair - Owner - Calendar.html` | All-Staff Schedule (Agenda) | Owner | Mobile only | Vertical timeline/agenda list across staff, week strip navigator | Partial / Duplicate concept | Titled "Staff Schedule" — a **second, incompatible pattern** for the same "view all staff" problem file 1 solves with grid columns. These must be reconciled into one calendar component (see §8, §14). |
|
||||
| 6 | `6-NextChair - SignIn.html` | Sign In | Guest | Mobile only | Email/password, forgot-password link, Google/Apple buttons, link to register | Mostly complete | No phone-number login despite the brief requiring it; no invalid-credential error state. |
|
||||
| 7 | `7-NextChair - Verify.html` | Verification Code | Guest/Customer | Mobile only | 4-digit code entry (email-based), resend | Partial | No countdown/expiry, no wrong-code error state, no SMS/phone variant. |
|
||||
| 8 | `8-NextChair - Forgot Password.html` | Forgot Password | Guest | Mobile only | Email entry → reset link | Partial | No "check your email" confirmation state; no error state. |
|
||||
| 9 | `9-NextChair - Customer - Review.html` | Review Booking | Guest/Customer | Mobile only | Booking summary + optional notes → confirm | Partial | No cancellation-policy acknowledgement, no price/loyalty-discount line, and **no guest contact-details step** anywhere upstream — this is a real gap, not just an omission from this screen (see §6). |
|
||||
| 10 | `10-NextChair - Customer - Setting.html` | Customer Settings | Registered Customer | Mobile only | Profile card; links to Preferred Barber/Loyalty/Notifications/Privacy/Help; logout | Partial | No Delete Account option; linked destination screens mostly don't exist. |
|
||||
| 11 | `11-NextChair - Customer - Loyalty.html` | Loyalty Card | Registered Customer | Mobile only | 3D-flip digital stamp card, progress bar, "how it works" | Mostly complete | Strong visual execution. No reward/transaction history, no distinct "reward available" state, uses a one-off amber accent not used elsewhere. |
|
||||
| 12 | `12-NextChair - Owner - Team Manag.html` | Team Management | Owner | Mobile only | Staff list with status (Active/On Break), add-staff button | Partial | Tapping a staff row has no destination screen (staff edit/profile). Nav here is a **4th distinct bottom-nav variant** (Dashboard/Staff/Calendar/Admin). |
|
||||
| 13 | `13-NextChair - Owner - Settings.html` | Owner Settings Hub | Owner | Mobile only | Profile card, dashboard link, Shop Controls (Team/Services/Loyalty/Booking Windows), Staff Preferences | Partial | "Services & Categories" and "Booking Windows" links have no destination screens. Nav reverts to the staff-style 4-item nav — **inconsistent with file 12**, which is also "Owner." Source comments ("Dashboard relocated here") show this screen was iteratively patched. |
|
||||
| 14 | `14-NextChair - Staff - Customer D.html` | Client Detail | Barber / Owner | Mobile only | Client profile, call/email actions, dated service notes, visit history with prices | Mostly complete | No upcoming appointments for this client, no "book for customer" action, no preferred-barber display, no duplicate-customer handling. |
|
||||
| 15 | `15-NextChair - Customer - Home.html` | **Public Business Profile** (mislabeled "Home") | Guest/Public | Mobile only | Hero, gallery, rating, tabbed Services/Portfolio/Details, map, hours, staff strip, amenities | Mostly complete (as a business page) / **Missing as a customer home** | Contains malformed duplicate `<meta>`/`<title>` tags mid-body (export artifact). "Reviews" and "Packages" tab content exists in the DOM with no tab button to reach it (orphaned). No personalized content at all — see Finding #3 above. |
|
||||
| 16 | `16-NextChair - Customer - Appoint.html` | Appointments List | Registered Customer | Mobile only | List of finished/cancelled appointments with "Book again" | Partial — significant gaps | **No Upcoming section**, no cancel/reschedule, no detail drill-in, no empty state. Uses a **3rd, unrelated color palette** (`brandbtn` blue) not seen anywhere else. |
|
||||
| 17 | `17-NextChair - Customer - Confirm.html` | Booking Confirmation | Guest/Customer | Mobile only | Success state, booking summary, "Add to Calendar" (stub), loyalty teaser | Mostly complete | "Add to Calendar" has no wiring; no guest-account-creation upsell; no explicit "we'll remind you" notification messaging. |
|
||||
| 18 | `18-NextChair - Customer - Booking.html` | Barber, Date & Time Selection (mislabeled "Booking") | Guest/Customer | Mobile only | Barber picker, month calendar, time slots, notes, sticky price/time summary | Mostly complete | Combines 3 conceptual steps into one screen (no separate service-selection screen — that lives inside the business page's service list). Duplicate notes field vs. screen 9. Uses `$` while the rest of the app uses `£`. Nav here is a **3rd variant** of the customer bottom nav with mismatched hrefs. |
|
||||
| 19 | `19-NextChair - Create Account.html` | Create Account | Guest | Mobile only | Name/email/phone/password form → verify | Mostly complete | Terms/Privacy text is a statement, not an actual checkbox; no confirm-password field; no social sign-up (SignIn has Google/Apple, this screen doesn't). |
|
||||
| 20 | `20-NextChair - Welcome.html` | Welcome / Splash | Guest | Mobile only | Hero image, Create Account / Sign In / Continue as Guest | Complete | Clean, matches brief well. Good entry point reference. |
|
||||
| 21 | `21-NextChair - Owner - Business D.html` | **Admin Dashboard** (mislabeled "Business Details") | Owner | Mobile only | Visit stats, occupancy, top services, staff performance, booking-rules quick link | Mostly complete (as a dashboard) / **Business Details screen is missing entirely** | "Update Rules" button has no destination. Filename/content mismatch is the single most important gap to resolve before Phase 2 (see Finding #1). |
|
||||
| 22 | `22-NextChair - Owner - Loyalty Co.html` | Loyalty Programme Configuration | Owner | Mobile only | Card appearance (colors/image/stamp icon/terms), reward rules (stamps required, reward type/value/name), disable toggle | Mostly complete, most sophisticated template in the set | Live JS references a `#terms-preview` element that doesn't exist in the DOM (dead code / minor bug). Missing entirely: eligible services/staff, reward expiry, max reward value, auto-apply vs. staff-approval, stamp expiry, no-show/cancellation stamp eligibility — all explicitly required by the brief. |
|
||||
|
||||
**Statuses used above:** *Complete* (20 only), *Mostly complete*, *Partial*, *Duplicate* (file 5 vs. file 1 concept), *Unclear/mislabeled* (files 15, 18, 21), *Reference only* — none needed, everything is at least a partial design.
|
||||
|
||||
**No files are entirely obsolete or unrelated** — all 22 map to a real screen need — but three (15, 18, 21) are **named for a different screen than they contain** and should not be trusted by filename during implementation.
|
||||
|
||||
---
|
||||
|
||||
## 3. User Role Map
|
||||
|
||||
### Guest Customer
|
||||
Can: browse the public business page, browse services, pick a barber/date/time, add notes, complete a booking, see confirmation. **Cannot yet, per templates:** enter contact details as a distinct step (missing screen), acknowledge a cancellation policy, or access a booking later via a secure link (no such flow designed).
|
||||
|
||||
### Registered Customer
|
||||
Everything a guest can do, plus (per templates): appointments list (finished/cancelled only — **no upcoming view**), settings/profile, preferred barber (link only, no screen), loyalty card (fully designed), notifications (link only, no screen).
|
||||
|
||||
### Barber
|
||||
Day calendar (own + all-staff view via file 5), current appointment management, client list + client detail with notes/history, personal settings (profile, working-hours links with no destination screens).
|
||||
|
||||
### Business Owner
|
||||
Templates model the owner largely as **"barber plus an admin section bolted on,"** which matches the brief's intent ("business owners should be able to access all barber features"). However:
|
||||
- **Role-conflict flag:** File 4 (Staff Settings) has a "Switch to Admin View" button, implying a single account can toggle between staff and owner views. File 13 (Owner Settings) independently exposes the same staff-style nav and staff-only settings (Working Hours) under an "owner" header. This suggests the templates were designed **without a clear model of whether Owner is a separate role or a permission layered onto Staff.** This must be resolved explicitly in Phase 2 (recommendation: Owner is a permission/flag on a Staff record, not a separate account type — see §9, §15).
|
||||
- **Nav inconsistency is itself a role-conflict symptom:** two different 4-item owner bottom-navs (file 12 vs. files 5/13/21/22) suggest two different owners were involved in generating these screens, or the "Owner" IA was never finalized.
|
||||
|
||||
### Future Roles
|
||||
Not present in templates (expected — out of scope per brief). The permission model should be a real `Role`/`Permission` structure from day one (see §9) so Receptionist, Multi-location Admin, and Platform Admin can be added later without restructuring auth.
|
||||
|
||||
---
|
||||
|
||||
## 4. User Journey Map
|
||||
|
||||
### Guest booking
|
||||
- **Entry:** Public business page (file 15) → service "Book" button
|
||||
- **Screens:** Business Page → Barber/Date/Time (18) → Review (9) → Confirmation (17)
|
||||
- **Decisions:** which service, which barber ("Anyone" supported), which slot
|
||||
- **Success:** Confirmation screen shown
|
||||
- **Error/exception paths not designed:** slot becomes unavailable between selection and confirm, booking submission failure, duplicate booking attempt
|
||||
- **Missing design steps:** **guest contact-details entry** (name/email/phone) is never shown anywhere in the flow — Review (9) assumes the customer is already known. This is the single biggest hole in the booking journey.
|
||||
|
||||
### Registered customer booking
|
||||
Same as guest, except contact details would be pre-filled from the account — but since no contact-details screen exists at all, there's nothing to differentiate. Loyalty discount application at Review time is not shown.
|
||||
|
||||
### Rescheduling / Cancelling
|
||||
**No screens exist for either.** Not present in the Appointments list (16), which shows only Finished/Cancelled history, not Upcoming appointments with actionable buttons.
|
||||
|
||||
### Booking again
|
||||
Present: "Book again" button on finished appointment cards (16). Destination/behavior (pre-fills service+barber into flow 18?) is not specified by the design — functional ambiguity to resolve in Phase 2.
|
||||
|
||||
### Creating an account after a guest booking
|
||||
Confirmation screen (17) has no upsell CTA for this. Missing design step.
|
||||
|
||||
### Viewing loyalty progress / redeeming a reward
|
||||
Viewing: fully designed (11, plus a teaser on 17). Redeeming: **not designed** — no screen shows the moment/mechanism of applying a reward to a booking or in-shop.
|
||||
|
||||
### Barber managing an appointment
|
||||
Entry: Current Appointment (2) or a calendar appointment tap (1/5 — tap target exists visually but no detail/modal screen was exported). Actions shown: Start Visit, Add Loyalty Stamp, Mark Completed. **Missing:** Confirm arrival/Check-in as a distinct state from "Arrived" label, Cancel, No-show, Rebook.
|
||||
|
||||
### Barber creating a booking for a customer
|
||||
**No screen exists.** Referenced implicitly by the brief's "make a booking on behalf of a customer" requirement; nothing in the 22 templates supports it (not even a FAB shortcut beyond the generic "+" on the calendar, whose destination isn't shown).
|
||||
|
||||
### Owner creating a service
|
||||
**No screen exists.** "Services & Categories" link in Owner Settings (13) has no destination.
|
||||
|
||||
### Owner managing staff availability
|
||||
Partially implied via Team Management (12) tap-through (no destination) and Staff Settings' Working Hours/Breaks/Time Off links (4) (no destination). No actual editor exists for any of these.
|
||||
|
||||
---
|
||||
|
||||
## 5. Screen Catalogue
|
||||
|
||||
### Public & Authentication
|
||||
| Screen | Purpose | Primary actions | Secondary actions | Required data | Roles | Related screens | Missing states | Notes |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| Welcome/Splash (20) | App entry | Create Account, Sign In | Continue as Guest | none | Guest | 6, 19, 15 | — | Good reference for tone |
|
||||
| Sign In (6) | Authenticate | Submit email+password | Forgot password, Google/Apple, Create account | credentials | Guest | 8, 19, 15 | Invalid login, locked account | No phone login despite brief |
|
||||
| Create Account (19) | Register | Submit form | Sign in link | name, email, phone, password | Guest | 7 | Duplicate email/phone, weak password | No social sign-up option |
|
||||
| Verify (7) | Confirm identity | Enter code | Resend | 4-digit code | Guest | 6, 19 | Expired code, wrong code, resend cooldown | Email-only wording |
|
||||
| Forgot Password (8) | Recover access | Submit email | — | email | Guest | 7 | Email not found, success confirmation | — |
|
||||
| Public Business Page (15) | Discover shop & services | Book a service | View portfolio/details, call, map | business+services+staff data | Guest/Public | 18 | Loading, empty reviews | Mislabeled "Home"; must be split from logged-in home |
|
||||
|
||||
### Customer (Registered)
|
||||
| Screen | Purpose | Primary actions | Secondary actions | Required data | Roles | Related | Missing states | Notes |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| Customer Home *(missing)* | Personalized landing | Book again, view upcoming | Loyalty teaser, browse services | upcoming appt, loyalty, preferred barber | Customer | 15, 11, 16 | all | Not present in templates — must be designed net-new |
|
||||
| Appointments (16) | Track bookings | Book again | (missing) cancel/reschedule/detail | appointment list | Customer | 9, 18 | Upcoming (missing), empty, loading | Only Finished/Cancelled currently shown |
|
||||
| Settings (10) | Manage account | Edit profile, navigate to sub-settings | Logout | user profile | Customer | 11 | Delete account (missing entirely) | Sub-screens mostly missing |
|
||||
| Loyalty Card (11) | View stamp progress | Flip card | — | loyalty account + transactions | Customer | 17 | Reward available (distinct), reward expired, disabled | Best-built screen in the set |
|
||||
|
||||
### Booking Flow
|
||||
| Screen | Purpose | Primary actions | Secondary actions | Required data | Roles | Related | Missing states | Notes |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| Service selection | *(embedded in 15, not standalone)* | Tap "Book" on a service | Search, filter by category | services | Guest/Customer | 18 | No results | Should become its own step/route |
|
||||
| Barber/Date/Time (18) | Pick slot | Select barber, date, time | Add note, add another service | availability | Guest/Customer | 9 | No barbers/dates/times available, slot taken mid-flow | Combines 3 conceptual steps |
|
||||
| Guest contact details *(missing)* | Capture identity for guest booking | Enter name/email/phone | — | contact info | Guest | 9 | Duplicate detection | Not present anywhere — critical gap |
|
||||
| Review (9) | Confirm details | Confirm booking | Add notes | full draft booking | Guest/Customer | 17 | Submission failure, price/loyalty display | Notes duplicated from 18 |
|
||||
| Confirmation (17) | Celebrate + inform | Add to calendar, Done | Create account upsell (missing) | confirmed booking | Guest/Customer | 16, 10 | — | "Add to calendar" unwired |
|
||||
|
||||
### Barber
|
||||
| Screen | Purpose | Primary actions | Secondary actions | Required data | Roles | Related | Missing states | Notes |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| Day Calendar (1) | Run the day | Tap appointment, add booking | Filter by barber, notifications | appointments, availability | Barber/Owner | 5, 2 | No appointments, outside hours, break/blocked visualization present but no editor | Placeholder salon services |
|
||||
| All-Staff Agenda (5) | Owner-wide visibility | Browse by day | Search | appointments across staff | Owner | 1 | — | Conflicting pattern vs. file 1 |
|
||||
| Current Appointment (2) | Manage active client | Start visit, add stamp, complete | Call customer | active appointment | Barber | 14 | No current appointment | Missing cancel/no-show |
|
||||
| Client List (3) | Find a client | Search | — | client summaries | Barber/Owner | 14 | Empty search, no clients | No A–Z index |
|
||||
| Client Detail (14) | Full client context | Call/email, add note | View history | client profile, notes, visits | Barber/Owner | 3 | — | Missing "book for client," upcoming appts |
|
||||
| Staff Settings (4) | Manage own profile/availability | Edit profile | Working hours/breaks/time off (missing screens) | staff profile | Barber | 12 | — | "Switch to Admin View" needs a real permission model |
|
||||
|
||||
### Owner
|
||||
| Screen | Purpose | Primary actions | Secondary actions | Required data | Roles | Related | Missing states | Notes |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| Admin Dashboard (21) | Business health at a glance | View stats | Manage team, update rules | aggregated metrics | Owner | 12, 13 | Loading, no data yet | Mislabeled filename |
|
||||
| Team Management (12) | Manage staff | Add staff | Tap into staff (missing detail/edit screen) | staff list | Owner | 4 | Empty team | Distinct nav pattern |
|
||||
| Owner Settings Hub (13) | Central admin nav | Navigate to sub-areas | Logout | — | Owner | 12, 21, 22 | — | Two of four "Shop Controls" links go nowhere |
|
||||
| Business Details *(missing)* | Edit business profile | Edit name/address/hours/policies/branding | — | Business entity | Owner | 21 | all | Not present anywhere — critical gap |
|
||||
| Services & Categories *(missing)* | Manage catalogue | CRUD service/category | Reorder, toggle active | Service, ServiceCategory | Owner | 15 | all | Linked to but not designed |
|
||||
| Booking Rules *(missing)* | Configure scheduling policy | Set notice/windows/buffers | — | BookingRule config | Owner | 21 | all | Linked to but not designed |
|
||||
| Loyalty Configuration (22) | Configure loyalty programme | Set card look, reward rules | Disable programme | LoyaltyProgramme | Owner | 11 | all secondary config below | Most complete owner screen; missing eligible services/staff, expiry, approval, max value |
|
||||
|
||||
### Shared / System
|
||||
| Screen | Purpose | Notes |
|
||||
|---|---|---|
|
||||
| Bottom navigation (customer) | Home/Bookings/Settings | 3 variants observed across files 10/11/16/18 — must unify into 1 component |
|
||||
| Bottom navigation (staff/owner) | Calendar/Current/Clients/Settings **or** Dashboard/Staff/Calendar/Admin | 2 incompatible variants — must pick one IA |
|
||||
| Loading / Empty / Error / Offline / Session-expired | — | **None designed anywhere in the template set** |
|
||||
|
||||
---
|
||||
|
||||
## 6. Missing Screens and States
|
||||
|
||||
### Required for a first usable release
|
||||
- Guest contact-details step in the booking flow (name, email, phone)
|
||||
- Standalone service-selection screen/step (currently only embedded in the business page)
|
||||
- Business Profile edit screen (name, address, hours, policies, branding) — owner
|
||||
- Services & Categories management (CRUD) — owner
|
||||
- Upcoming appointments view + Cancel + Reschedule flows — customer
|
||||
- Cancellation-policy acknowledgement at Review time
|
||||
- Loading, empty, and error states for every list screen (calendar, appointments, clients, team)
|
||||
- Session-expired / invalid-login / locked-account states
|
||||
- Working Hours / Breaks / Time Off editors (staff and owner-on-behalf-of-staff)
|
||||
- Staff detail/edit screen (from Team Management)
|
||||
- "Book on behalf of a customer" flow (barber/owner)
|
||||
- No barbers/no dates/no time-slots-available states in the booking flow
|
||||
- Booking-submission-failure and slot-taken-mid-flow states
|
||||
|
||||
### Required before production
|
||||
- Booking Rules configuration screen (notice period, advance window, cancellation/reschedule windows, buffers, max/day)
|
||||
- Loyalty configuration additions: eligible services/staff, reward expiry, max reward value, auto-apply vs. approval, stamp expiry, no-show/cancellation stamp eligibility
|
||||
- Notification preferences screen (customer and staff)
|
||||
- Delete account flow (with confirmation)
|
||||
- Privacy & Security detail screen
|
||||
- Account-linking / claim-guest-booking flow
|
||||
- Duplicate-customer handling in Client List/Detail
|
||||
- Reward redemption UI (the actual moment of applying a reward)
|
||||
- Add-to-calendar wiring (or explicit deferral)
|
||||
- Reviews tab real content (currently placeholder) and a Gallery full-view screen
|
||||
- PWA install prompt, offline state, update-available state (see §13)
|
||||
- 401/403 (permission denied), 404 (not found) system pages
|
||||
|
||||
### Suitable for a later phase
|
||||
- Multi-location switcher UI
|
||||
- Receptionist / manager role screens
|
||||
- Deposits / payments UI
|
||||
- Package/bundle booking (tab stub exists, no requirement confirmed)
|
||||
- Advanced analytics beyond the current dashboard
|
||||
|
||||
---
|
||||
|
||||
## 7. Reusable Component Inventory
|
||||
|
||||
### Foundations
|
||||
- **Color tokens** — must be consolidated from 3 competing palettes into 1 (see §8)
|
||||
- **Typography scale** — Inter throughout (consistent), weights 400–900 used inconsistently across files
|
||||
- **Spacing/radius scale** — two competing radius scales in use (`jumbo: 1rem/tile: 0.75rem` vs. `jumbo: 1.5rem/tile: 1rem`) — pick one
|
||||
- **Icon set** — Font Awesome 6.4 used consistently; recommend a proper icon package (e.g., `lucide-react`) instead of a CDN script for a production Next.js app
|
||||
|
||||
### Navigation
|
||||
- `BottomNav` (customer variant: Home/Appointments/Profile — 3 items)
|
||||
- `BottomNav` (staff/owner variant: Calendar/Current/Clients/Settings — 4 items) — reconcile file 12's alternate 4-item set into this or a role-aware variant
|
||||
- `TopHeader` (title + back button + action button — appears with at least 5 slightly different implementations)
|
||||
- `TabBar` (segmented, seen in Business Page services/portfolio/details)
|
||||
|
||||
### Forms
|
||||
- `TextInput` (with icon-left variant, seen in Sign In/Create Account/Client search)
|
||||
- `PasswordInput` (with show/hide toggle)
|
||||
- `OTPInput` (4-digit code boxes)
|
||||
- `Textarea` (notes field — appears twice in the booking flow, should be a single shared component/step)
|
||||
- `Select`/segmented control (reward-type picker in Loyalty Config)
|
||||
- `Stepper` (numeric +/-, stamps-required control)
|
||||
- `Toggle`/switch (implied by "enable loyalty" but not actually built as a switch component — built as buttons instead)
|
||||
- `ColorSwatchPicker`, `IconPicker` (Loyalty Card appearance)
|
||||
|
||||
### Booking
|
||||
- `BarberSelector` (avatar row with "Anyone" option)
|
||||
- `DatePickerGrid` (month calendar)
|
||||
- `TimeSlotPicker` (horizontal chip row)
|
||||
- `ServiceListItem` (name, duration, price, Book button)
|
||||
- `BookingSummaryBar` (sticky bottom price/time + Review CTA)
|
||||
- `BookingReviewCard`
|
||||
|
||||
### Appointments
|
||||
- `AppointmentCard` (list item — 2 visually different implementations exist: file 16's card vs. file 1/5's calendar block; needs one canonical list-item design plus the calendar-block rendering)
|
||||
- `StatusPill` (Finished/Cancelled/Confirmed/etc. — colors not yet standardized)
|
||||
- `CalendarDayGrid` (per-barber columns, current-time line) vs. `CalendarAgendaList` (vertical timeline) — **pick one canonical pattern** (see §14)
|
||||
|
||||
### Profiles
|
||||
- `ProfileCard` (avatar + name + role/meta + edit button — reused near-identically across 4, 10, 13, 14)
|
||||
- `ClientListItem`
|
||||
- `StaffListItem` (with status pill)
|
||||
|
||||
### Loyalty
|
||||
- `LoyaltyCard3D` (flip card, front/back) — high-value component, keep close to file 11's design
|
||||
- `StampGrid`
|
||||
- `ProgressBar`
|
||||
- `RewardTypeSelector`
|
||||
|
||||
### Feedback & Status
|
||||
- `SuccessCheck` (Confirmation screen)
|
||||
- `EmptyState` — **not designed anywhere, must be created net-new**
|
||||
- `ErrorState` — **not designed anywhere, must be created net-new**
|
||||
- `Skeleton`/loading — **not designed anywhere, must be created net-new**
|
||||
- `Toast` — not present in any template
|
||||
|
||||
### Layout
|
||||
- `MobileShell` (max-w-md container, safe-area padding)
|
||||
- `DesktopShell` — **does not exist yet**, needed for §12/§13 responsive work
|
||||
- `SettingsGroup` (grouped card with chevron rows — reused heavily, good candidate for early extraction)
|
||||
- `StatTile` (2-up grid stat cards — dashboard, client detail)
|
||||
|
||||
For each component group above, responsive behavior and accessibility considerations are addressed in §12 and the Accessibility notes embedded in §8.
|
||||
|
||||
---
|
||||
|
||||
## 8. Design System Summary
|
||||
|
||||
### What currently exists
|
||||
Three incompatible token sets are in simultaneous use:
|
||||
|
||||
1. **"Salon" palette** (file 1 only): `ink #111b15`, `surface #fff`, `muted #8b9790`, `line #e1e7e2`, `bgLight #f8f9f8`, `accentRed #ec1c4b`, plus calendar-specific `calTeal/calPurple/calGreen`.
|
||||
2. **"TrimTime" palette** (the majority of files: 2–15, 17, 19–22): `ink #111b15`, `stone #f4f6f4`, `surface #fff`, `muted #6c7870`, `line #e1e7e2`, `accent #10b981` (green). This is the closest thing to a canonical system and should be the base.
|
||||
3. **"Blue" palette** (file 16 only): `appbg #f8f9f8`, `cardbg #fff`, `ink #111b15`, `muted #8a948e`, `line #eaeaeb`, `brandbtn #4887a0`, `pillbg #e4e6e5`.
|
||||
4. A one-off **amber accent** (`#f59e0b`) on the Loyalty Card (file 11), which is thematically justified (gold card) but should become an explicit "loyalty" semantic token, not a stray override.
|
||||
|
||||
**Recommendation:** adopt palette #2 as the design-system base (`ink`/`stone`/`surface`/`muted`/`line`/`accent`), fold the salon-red and blue palettes into semantic status tokens (e.g., a `status-*` scale for appointment types/pills) rather than competing brand palettes, and keep amber as a dedicated `loyalty-accent` token.
|
||||
|
||||
**Radius:** two scales in use — `jumbo: 1rem / tile: 0.75rem` (older files) vs. `jumbo: 1.5rem / tile: 1rem` (files 11, 17, 18, 22, the more recently touched files per timestamps). Recommend standardizing on the larger, more recent scale.
|
||||
|
||||
**Buttons:** at least 3 visual button treatments for "primary action" (solid `ink` pill, solid `accent` pill, solid blue rectangular) — must converge to one primary/secondary/ghost/destructive set.
|
||||
|
||||
**Cards:** consistent `bg-white/surface`, `border-line`, `rounded-jumbo` pattern is the strongest, most reusable element across the set — good canonical candidate.
|
||||
|
||||
**Status colors:** appointment/status pills are ad hoc (teal/purple/green in file 1, blue/purple/emerald left-borders in file 5, gray pill in file 16) — needs one status-color mapping (e.g., confirmed/in-progress/completed/cancelled/no-show) applied everywhere.
|
||||
|
||||
**Bottom navigation:** dark (`#0c0c0c`) for staff/owner vs. white for customer is a deliberate and reasonable role signal — keep it, but unify the *item set* within each role (see §5, §14).
|
||||
|
||||
### Accessibility risks observed
|
||||
- Icon-only buttons throughout (back arrows, bell, ellipsis, edit-pencil) have no visible `aria-label` equivalent in the markup — screen-reader labels must be added during build, not assumed from the design.
|
||||
- Touch targets are mostly ≥40px (good) but some inline chevron/icon buttons (e.g., 10px chevrons) are the *visual* icon only inside a larger tappable parent — must verify real hit-area, not just icon size, during implementation.
|
||||
- Color-only status communication (pill background colors, left-border colors on calendar blocks) has no text/icon backup in several places — a colorblind or low-vision user cannot distinguish "teal" from "purple" appointment types reliably.
|
||||
- No visible focus states are defined beyond default browser/Tailwind `focus:ring` on form inputs; buttons and nav links have no explicit focus style — a real risk for keyboard users.
|
||||
- The 3D-flip Loyalty Card (file 11) will need explicit `aria-live`/`role` handling and a non-hover/non-mouse way to flip it (currently no flip trigger element is wired at all — the flip is presentational-only in the static file).
|
||||
- Dialog/modal focus management can't be assessed — no template includes a modal/bottom-sheet in its markup, despite the brief expecting them (e.g., appointment detail); this must be designed and built with a real focus-trap from the start.
|
||||
- WCAG 2.2 AA contrast should be re-verified once the palette is consolidated (§8) — `muted` grays on `stone` backgrounds are borderline in a few templates.
|
||||
|
||||
---
|
||||
|
||||
## 9. Domain Model
|
||||
|
||||
Conceptual entities only — no schema/SQL yet.
|
||||
|
||||
| Entity | Purpose | Key relationships | Needed for v1? |
|
||||
|---|---|---|---|
|
||||
| **Business** | The tenant / shop | has many Locations, Users(staff), Services, ServiceCategories, BookingRules, LoyaltyProgramme | Yes |
|
||||
| **BusinessLocation** | Physical address/hours (splits from Business for multi-location readiness) | belongs to Business | Yes, as a 1:1 with Business initially — see §11 |
|
||||
| **User** | Auth identity (login credentials) | has one UserIdentity per auth method; has one of CustomerProfile/StaffProfile | Yes |
|
||||
| **UserIdentity** | A specific login method (email/password, phone/OTP, Google) tied to a User | belongs to User | Yes — needed even for v1 to support "sign in with Google or email" cleanly |
|
||||
| **CustomerProfile** | Customer-specific data (preferred barber, notes) | belongs to User (nullable — guests won't have one yet) | Yes |
|
||||
| **StaffProfile** | Barber-specific data (bio, services offered) | belongs to User; belongs to Business | Yes |
|
||||
| **Role** / **Permission** | Barber vs. Owner (vs. future Receptionist etc.) | StaffProfile has a Role; Role has many Permissions | Yes — build as a real join now, even with only 2 roles, given the file 4/13 role-conflict finding |
|
||||
| **ServiceCategory** | Grouping for services (e.g., "Hair & Beard — Senior Barber") | belongs to Business; has many Services | Yes |
|
||||
| **Service** | Bookable offering (name, duration, price, buffer) | belongs to ServiceCategory; has many via StaffService | Yes |
|
||||
| **StaffService** | Which staff can perform which service (+ optional staff-specific price/duration) | join of StaffProfile ↔ Service | Yes — brief explicitly requires barber-specific service availability |
|
||||
| **Appointment** | A booked visit | belongs to Business, StaffProfile, CustomerProfile (nullable for guest), has many AppointmentServices | Yes |
|
||||
| **AppointmentService** | Line item(s) within an appointment (supports multi-service bookings, seen in the "add another service" UI in file 18) | belongs to Appointment, Service | Yes |
|
||||
| **WorkingHours** | Recurring weekly availability per staff (and per business) | belongs to StaffProfile or Business | Yes |
|
||||
| **Break** | Recurring or one-off unavailable block within a working day | belongs to StaffProfile | Yes |
|
||||
| **TimeOff** | Date-range unavailability (holiday, sick day) | belongs to StaffProfile | Yes |
|
||||
| **CustomerNote** | Free-text note staff attach to a client (seen in file 14) | belongs to CustomerProfile, authored by StaffProfile | Yes |
|
||||
| **LoyaltyProgramme** | Business-level config (stamps required, reward type/value, card appearance, eligibility) | belongs to Business | Yes |
|
||||
| **LoyaltyAccount** | A customer's running stamp balance for a programme | belongs to CustomerProfile, LoyaltyProgramme | Yes |
|
||||
| **LoyaltyTransaction** | Individual stamp add/remove/redeem event (ledger, not just a counter — brief explicitly requires history) | belongs to LoyaltyAccount, optionally to Appointment, authored by StaffProfile | Yes |
|
||||
| **Reward** | A completed/redeemed reward instance, recorded before the card resets | belongs to LoyaltyAccount | Yes |
|
||||
| **Notification** | Outbound message record (booking confirmation, reminder, etc.) | belongs to User/CustomerProfile | Yes (at least the data model; delivery integration can be phased, see §10) |
|
||||
| **NotificationPreference** | Per-user opt-in/out per channel/type | belongs to User | Deferrable to Phase 5 UI, but model early |
|
||||
| **Review** | Business rating/review (brief shows Google reviews, not an internal review system) | external (Google) for v1 — see §10 | Deferred — model as a cached read from Google, not a first-party entity |
|
||||
| **BusinessSetting** | Misc business-level config not covered by BookingRule/LoyaltyProgramme (timezone, currency, locale, policies text) | belongs to Business | Yes |
|
||||
| **BookingRule** | Scheduling policy (notice period, advance window, cancellation/reschedule windows, buffers, slot interval, max/day, guest booking allowed, barber choice allowed) | belongs to Business | Yes |
|
||||
| **AuditLog** | Who changed what (staff edits, permission changes) | polymorphic, references User | Deferrable — recommend stubbing the table early but not building UI until Phase 6 |
|
||||
|
||||
**Data requirements the design implies but the brief doesn't state explicitly:**
|
||||
- Multi-service bookings ("add another service" in file 18) — the domain model must support an appointment with >1 service from day one, not bolt it on later.
|
||||
- A `CustomerNote` author + timestamp trail (file 14) — implies notes need attribution and audit-style history, not just a free-text blob on the customer record.
|
||||
- Loyalty needs a **ledger**, not a counter (explicitly stated in the brief too, but the templates' "8/10 stamps" + separate transaction concept in file 2's "Add Loyalty Stamp" action confirms this architecturally).
|
||||
- Staff `status` (Active/On Break, seen in file 12) implies a lightweight staff-presence/availability-state concept distinct from the Working Hours schedule — worth a `StaffProfile.currentStatus` field or derived state, to decide in Phase 2.
|
||||
|
||||
---
|
||||
|
||||
## 10. Feature Breakdown
|
||||
|
||||
| Feature | User value | Main screens | Core rules | Dependencies | v1 priority |
|
||||
|---|---|---|---|---|---|
|
||||
| **Auth: Email/password** | Account access | 6, 19, 7 | password policy, verification | UserIdentity | Must-have |
|
||||
| **Auth: Google login** | Fast sign-in | 6 | OAuth callback linking | external OAuth | Must-have |
|
||||
| **Auth: Guest booking** | Book without friction | 18, 9, 17 + missing contact step | no password, secure link access later | none | Must-have |
|
||||
| **Auth: Phone/OTP** | Alternate sign-in | 6 (not currently built), 7 | SMS delivery | SMS provider | Should-have — brief requires it, templates don't show it |
|
||||
| **Business discovery** | Find & trust the shop | 15 | none | — | Must-have |
|
||||
| **Service browsing** | Understand offerings/pricing | 15 | staff-service eligibility, active flag | ServiceCategory, Service | Must-have |
|
||||
| **Booking: barber/date/time** | Core conversion flow | 18 | availability computation (see §11) | WorkingHours, Break, TimeOff, existing Appointments | Must-have |
|
||||
| **Booking: guest details** | Capture contact for guests | *missing screen* | required fields, dedupe by email/phone | CustomerProfile | Must-have |
|
||||
| **Booking: review & confirm** | Reduce booking errors | 9, 17 | policy acknowledgement | BookingRule | Must-have |
|
||||
| **Appointments: upcoming/history** | Self-service management | 16 (partial) | status transitions | Appointment | Must-have |
|
||||
| **Appointments: cancel/reschedule** | Reduce no-shows, flexibility | *missing screens* | cancellation/reschedule window rules | BookingRule | Must-have |
|
||||
| **Book again** | Reduce repeat-booking friction | 16 → 18 (prefilled) | pull last appointment's service/barber | Appointment | Should-have |
|
||||
| **Customer profile & preferences** | Personalization | 10 | preferred barber selection | CustomerProfile | Must-have |
|
||||
| **Staff: day calendar** | Run daily operations | 1 | render availability + bookings | Appointment, WorkingHours | Must-have |
|
||||
| **Staff: current appointment** | In-chair workflow | 2 | status transitions (arrived→started→completed/no-show) | Appointment | Must-have |
|
||||
| **Staff: client contacts** | Relationship management | 3, 14 | search, notes, history | CustomerProfile, CustomerNote | Must-have |
|
||||
| **Staff: availability management** | Accurate scheduling | *missing editor screens* | recurring hours, breaks, time off | WorkingHours, Break, TimeOff | Must-have |
|
||||
| **Owner: business profile** | Brand & operational config | *missing screen* | — | Business, BusinessLocation, BusinessSetting | Must-have |
|
||||
| **Owner: staff management** | Team administration | 12, *missing detail/edit* | roles/permissions, deactivate | Role, StaffProfile | Must-have |
|
||||
| **Owner: services & categories** | Catalogue control | *missing screen* | pricing, duration, buffers, staff eligibility | Service, ServiceCategory, StaffService | Must-have |
|
||||
| **Owner: booking rules** | Prevent scheduling abuse | *missing screen* | notice/windows/buffers/limits | BookingRule | Must-have |
|
||||
| **Loyalty: customer view** | Retention/engagement | 11 | ledger-driven progress | LoyaltyAccount, LoyaltyTransaction | Must-have |
|
||||
| **Loyalty: staff stamp actions** | Reward in-shop visits | 2 (partial) | add/correct stamp, reward eligibility check | LoyaltyTransaction | Must-have |
|
||||
| **Loyalty: owner configuration** | Programme control | 22 (partial) | full rule set (see §6) | LoyaltyProgramme | Must-have (core), Should-have (advanced rules) |
|
||||
| **Notifications: booking lifecycle** | Trust & reduced no-shows | *no screens, transactional* | confirmation, reminder, changes, cancellation | Notification, external email/SMS | Must-have (email), Should-have (SMS/push) |
|
||||
| **Notifications: preferences** | User control | *missing screen* | per-channel opt-in | NotificationPreference | Should-have |
|
||||
| **Owner: dashboard/analytics** | Business insight | 21 | aggregate queries | Appointment, LoyaltyTransaction | Should-have |
|
||||
| **PWA install/offline** | App-like experience | *no screens* | platform-specific prompts (see §13) | service worker | Should-have, hardened in Phase 6 |
|
||||
| **Integrations: Google reviews/calendar, Apple calendar** | Trust + convenience | 15 (reviews), 17 (add to calendar) | — | external APIs | Should-have (reviews), Nice-to-have (calendar) |
|
||||
|
||||
---
|
||||
|
||||
## 11. Recommended Application Architecture
|
||||
|
||||
### High-level Next.js structure
|
||||
|
||||
```text
|
||||
app/
|
||||
(public)/ # marketing/discovery — no auth required
|
||||
page.tsx # business landing (from template 15, split)
|
||||
services/
|
||||
barbers/
|
||||
(auth)/
|
||||
sign-in/
|
||||
create-account/
|
||||
verify/
|
||||
forgot-password/
|
||||
(customer)/ # authenticated customer area, bottom nav shell
|
||||
home/
|
||||
appointments/
|
||||
appointments/[id]/
|
||||
loyalty/
|
||||
settings/
|
||||
book/ # booking flow — accessible to guest AND customer
|
||||
service/
|
||||
barber-time/
|
||||
details/ # new: guest contact details step
|
||||
review/
|
||||
confirmation/
|
||||
(staff)/ # barber app shell, dark bottom nav
|
||||
calendar/
|
||||
current/
|
||||
clients/
|
||||
clients/[id]/
|
||||
settings/
|
||||
(owner)/ # owner admin shell, nested under staff permissions
|
||||
dashboard/
|
||||
team/
|
||||
team/[id]/
|
||||
business/ # new: business profile
|
||||
services/ # new: service/category management
|
||||
booking-rules/ # new
|
||||
loyalty/
|
||||
api/ # route handlers for anything not a server action
|
||||
components/
|
||||
ui/ # design-system primitives (Button, Card, Input, Chip…)
|
||||
booking/
|
||||
appointments/
|
||||
loyalty/
|
||||
calendar/
|
||||
navigation/
|
||||
features/ # feature-oriented composition (booking flow state, etc.)
|
||||
lib/
|
||||
auth/
|
||||
db/
|
||||
validation/
|
||||
time/ # timezone/DST-safe scheduling helpers
|
||||
services/ # server-side domain services (SchedulingService, LoyaltyService…)
|
||||
types/
|
||||
hooks/
|
||||
styles/
|
||||
public/
|
||||
templates/ # kept as read-only design reference, untouched
|
||||
```
|
||||
|
||||
### Route groups
|
||||
- `(public)`, `(auth)` unauthenticated.
|
||||
- `book/` intentionally **outside** `(customer)` since guests must reach it too — a layout checks for an optional session rather than requiring one.
|
||||
- `(staff)` and `(owner)` share a layout shell; `(owner)` routes are additionally gated by a permission check rather than being a separate account type (per the Role/Permission model in §9), directly resolving the file 4/13 role-conflict finding.
|
||||
|
||||
### Customer vs. staff separation
|
||||
Two distinct root layouts/shells (light bottom nav vs. dark bottom nav), matching the one part of the design system that *is* consistent. Shared primitives (Card, Button, Input, etc.) live in `components/ui` and are shell-agnostic.
|
||||
|
||||
### Server and client boundaries
|
||||
- Default to Server Components for data-heavy read screens (calendar, appointments list, client list, dashboard).
|
||||
- Client Components only where interaction state is needed: booking flow steps, loyalty configuration form, OTP input, calendar drag/tap interactions.
|
||||
- Prefer **Server Actions** for mutations (create booking, add stamp, update settings) over hand-rolled API routes; reserve `app/api` for webhooks (e.g., inbound SMS/email provider callbacks) and anything a third party needs to call.
|
||||
|
||||
### Validation
|
||||
Single schema library (recommend **Zod**) shared between client-side form validation and server action input validation — one source of truth per entity, colocated in `lib/validation`.
|
||||
|
||||
### Authentication boundaries
|
||||
- Middleware checks session presence + role for `(customer)`, `(staff)`, `(owner)` route groups.
|
||||
- `book/` middleware allows both guest and authenticated sessions; guest sessions are a lightweight signed cookie tied to a draft booking, not a full account.
|
||||
- Permission enforcement happens **again** at the server-action/service layer (never trust the route group alone) — critical for the owner-vs-staff boundary given how blurred it is in the templates.
|
||||
|
||||
### Service abstractions
|
||||
`services/` houses domain logic independent of Next.js (e.g., `SchedulingService.getAvailableSlots(...)`, `LoyaltyService.addStamp(...)`) so scheduling/loyalty rules are unit-testable without spinning up the framework, and reusable if a future admin CLI or background job needs them.
|
||||
|
||||
### Testing layers
|
||||
- Unit tests on `services/` and `lib/` (especially scheduling math and loyalty ledger logic — the highest-risk domains, see §14).
|
||||
- Component tests for the design-system primitives and booking-flow steps.
|
||||
- Integration/E2E (Playwright) for the golden paths: guest booking, staff completing an appointment, owner configuring loyalty.
|
||||
- Contract tests around any external integration abstraction (§10) so mock providers and real providers stay interchangeable.
|
||||
|
||||
---
|
||||
|
||||
## 12. Route Map
|
||||
|
||||
| Route | Type | Notes |
|
||||
|---|---|---|
|
||||
| `/` | Page | Public business page (from template 15, stripped of personalized-home assumptions) |
|
||||
| `/services`, `/barbers` | Page | Optional dedicated views if the business page tabs prove too dense on desktop |
|
||||
| `/sign-in`, `/create-account`, `/verify`, `/forgot-password` | Page | Auth screens 6, 19, 7, 8 |
|
||||
| `/book` | Page (guest-or-auth) | Service selection (currently embedded in `/`) |
|
||||
| `/book/barber-time` | Page | Template 18 |
|
||||
| `/book/details` | Page | New — guest contact details |
|
||||
| `/book/review` | Page | Template 9 |
|
||||
| `/book/confirmation` | Page | Template 17 |
|
||||
| `/home` | Page (customer) | New — personalized logged-in home |
|
||||
| `/appointments` | Page (customer) | Template 16, extended with Upcoming |
|
||||
| `/appointments/[id]` | Page or **modal/sheet state** | Detail + cancel/reschedule — recommend a route-backed sheet so it's deep-linkable and shareable, not a client-only modal |
|
||||
| `/loyalty` | Page (customer) | Template 11 |
|
||||
| `/settings`, `/settings/*` | Page (customer) | Template 10 + sub-screens |
|
||||
| `/staff/calendar` | Page (staff) | Template 1 |
|
||||
| `/staff/calendar/agenda` | View toggle, not separate route | Consolidates template 5's pattern as a view mode, not a competing page (see §14) |
|
||||
| `/staff/current` | Page (staff) | Template 2 |
|
||||
| `/staff/clients`, `/staff/clients/[id]` | Page (staff) | Templates 3, 14 |
|
||||
| `/staff/settings`, `/staff/settings/*` | Page (staff) | Template 4 + missing sub-editors |
|
||||
| `/owner/dashboard` | Page (owner) | Template 21 |
|
||||
| `/owner/team`, `/owner/team/[id]` | Page (owner) | Template 12 + missing detail |
|
||||
| `/owner/business` | Page (owner) | New — business profile |
|
||||
| `/owner/services` | Page (owner) | New — service/category CRUD |
|
||||
| `/owner/booking-rules` | Page (owner) | New |
|
||||
| `/owner/loyalty` | Page (owner) | Template 22 |
|
||||
|
||||
**Modal/sheet vs. route distinction:** appointment detail, staff detail, and "add booking for customer" should all be **route-backed sheets** (intercepting routes in Next.js App Router) rather than pure client state, so they're deep-linkable, back-button-friendly, and testable in isolation — this is a deliberate improvement over the templates, which show no modal pattern at all.
|
||||
|
||||
---
|
||||
|
||||
## 13. Implementation Phases
|
||||
|
||||
### Phase 0: Foundation
|
||||
**Scope:** project scaffold, consolidated design-system tokens (§8 decisions), auth foundation (schema + one working login method), database foundation, core layouts (customer/staff/owner shells + bottom navs).
|
||||
**Dependencies:** Phase 2 architecture/schema decisions (this document's sequel) must be finalized first.
|
||||
**Deliverables:** running Next.js app, Storybook or equivalent for `components/ui`, one working end-to-end auth flow, empty-state/loading/error primitives (net-new, per §6).
|
||||
**Risks:** underestimating the design-token consolidation effort (three real palettes to reconcile, not a formality).
|
||||
**Test coverage:** component tests for `ui/` primitives; smoke test for auth.
|
||||
|
||||
### Phase 1: Customer Booking
|
||||
**Scope:** public business page, services, barber selection, availability computation, guest booking (including the new contact-details step), confirmation.
|
||||
**Dependencies:** Phase 0 shells + scheduling service groundwork.
|
||||
**Deliverables:** full guest booking golden path, working availability engine (single-barber correctness first).
|
||||
**Risks:** double-booking / race conditions (see §14) — must be addressed here, not deferred, since it's the core transaction of the product.
|
||||
**Test coverage:** unit tests on availability computation; E2E test for the full guest booking path including a concurrent-booking-attempt scenario.
|
||||
|
||||
### Phase 2: Customer Accounts
|
||||
**Scope:** registration, login (email + Google at minimum), personalized customer home (new), appointments (with real Upcoming + cancel/reschedule), profile/settings.
|
||||
**Dependencies:** Phase 1 booking data model.
|
||||
**Deliverables:** account creation from guest booking, appointment self-service.
|
||||
**Risks:** guest-to-account linking and duplicate-customer detection (see §15) — needs a defined (even if simple) matching strategy before this phase closes.
|
||||
**Test coverage:** E2E for register→book→view-in-appointments; unit tests for guest/account linking logic.
|
||||
|
||||
### Phase 3: Barber Tools
|
||||
**Scope:** barber calendar (one canonical pattern, §14), current appointment, client contacts, availability management (the missing working-hours/breaks/time-off editors).
|
||||
**Dependencies:** Phase 1 scheduling engine must support staff-side writes, not just customer-side reads.
|
||||
**Deliverables:** a barber can run a full day end-to-end without leaving the app.
|
||||
**Risks:** calendar UI complexity (multi-barber rendering approach — resolve the file 1 vs. file 5 conflict here, concretely, not just note it).
|
||||
**Test coverage:** E2E for appointment status transitions; unit tests for availability-editor validation (overlapping hours, etc.).
|
||||
|
||||
### Phase 4: Owner Administration
|
||||
**Scope:** business settings (new), staff management + detail/edit (new), services & categories (new), booking rules (new).
|
||||
**Dependencies:** Phase 3 staff model; Phase 1 service model.
|
||||
**Deliverables:** an owner can fully configure the business without developer intervention.
|
||||
**Risks:** permission-boundary bugs given the templates' own confusion about staff-vs-owner (§3) — this phase is where that ambiguity must be fully resolved in code, with tests.
|
||||
**Test coverage:** permission-enforcement tests (owner-only actions rejected for plain staff, and vice versa where appropriate).
|
||||
|
||||
### Phase 5: Loyalty and Notifications
|
||||
**Scope:** loyalty configuration completion (missing rules from §6), stamp transactions, reward redemption UI (missing from templates), email/SMS/push notifications.
|
||||
**Dependencies:** Phase 2 accounts, Phase 3 staff stamp actions, Phase 4 owner config screens.
|
||||
**Deliverables:** full loyalty ledger with redemption; transactional emails at minimum, SMS/push as stretch.
|
||||
**Risks:** loyalty abuse (staff self-stamping, double-redemption) — needs explicit rules and probably an approval-required setting exposed here (already flagged missing in §6).
|
||||
**Test coverage:** unit tests on the loyalty ledger (stamp/redeem/correct sequences); integration test for a notification provider abstraction with a mock backend.
|
||||
|
||||
### Phase 6: Production Hardening
|
||||
**Scope:** accessibility pass against the risks in §8, security review, full test-suite maturity, monitoring, performance, PWA (install/offline/update states — all missing from templates, built fresh here), deployment.
|
||||
**Dependencies:** all prior phases functionally complete.
|
||||
**Deliverables:** production-ready release candidate.
|
||||
**Risks:** PWA install-prompt behavior differs meaningfully by platform (§13 below) and is easy to get wrong late.
|
||||
**Test coverage:** accessibility audit (automated + manual keyboard pass), load test on the availability-computation path, cross-browser PWA install verification.
|
||||
|
||||
---
|
||||
|
||||
## PWA note (platform differences)
|
||||
No install/offline/update-available screens exist in the templates — these must be designed in Phase 6, with these platform constraints in mind from the start:
|
||||
- **iOS Safari:** no `beforeinstallprompt` event; "Add to Home Screen" is a manual Share-sheet action. The app should show its own instructional UI ("tap Share, then Add to Home Screen") rather than assuming a native prompt.
|
||||
- **Android browsers (Chrome):** supports `beforeinstallprompt` — a custom "Install App" button can trigger the real native prompt.
|
||||
- **Desktop browsers:** install affordance varies (omnibox icon in Chrome/Edge); treat as a bonus, not a primary flow — the desktop experience should stand on its own as a responsive web app regardless of installability.
|
||||
|
||||
---
|
||||
|
||||
## 14. Risks and Technical Considerations
|
||||
|
||||
- **Double booking / concurrent slot claims.** No template shows a "slot became unavailable" state. The availability engine must treat slot reservation as a transactional, race-safe operation (e.g., a DB constraint or short-lived hold) from Phase 1 — this is the highest-priority correctness risk in the whole product.
|
||||
- **Time zone & DST handling.** Business hours, staff hours, and appointments must be stored and computed in a way that survives DST transitions cleanly (store in UTC + business timezone, compute locally at render/query time). No template surfaces timezone at all — single-timezone-business assumption is reasonable for v1 (§15) but the data model should not hard-code it.
|
||||
- **Guest account duplication.** With no guest-details or account-linking screens designed, the matching strategy (by email? phone? both?) is undefined and must be decided explicitly in Phase 2 rather than improvised.
|
||||
- **Calendar UI complexity.** Two incompatible multi-barber patterns exist in the templates (grid columns vs. vertical agenda) — must be resolved to one canonical pattern plus a defined small-screen fallback (single-barber-at-a-time / horizontal scroll / staff selector, per the brief) before Phase 3 starts.
|
||||
- **Notification delivery reliability.** Templates show no delivery-failure or retry states; treat email/SMS as best-effort with a `Notification` record and status field so failures are visible to the owner, not silent.
|
||||
- **Loyalty abuse.** Ledger-based transactions (§9) mitigate this, but the missing "staff approval required" toggle (§6) is likely necessary before production, not just nice-to-have.
|
||||
- **Permission mistakes.** The templates' own confusion about staff-vs-owner boundaries (§3) is a real signal that this needs deliberate, tested enforcement — don't rely on route-group gating alone (§11).
|
||||
- **Mobile browser chrome behavior.** Fixed bottom nav + sticky bottom summary bar (file 18) both compete for the same screen real estate near the OS home-indicator/URL-bar area — needs real-device testing, particularly on iOS Safari where the toolbar show/hide changes viewport height dynamically.
|
||||
- **PWA limitations.** See §13 — iOS install-prompt limitations affect onboarding messaging, not just technical implementation.
|
||||
- **External API availability.** Google Reviews and Google/Apple Calendar integrations should degrade gracefully (cached/stale reviews, "add to calendar" as a downloadable `.ics` fallback rather than a hard API dependency) — see §10 integration recommendations below.
|
||||
- **Database portability (Postgres → MySQL).** Favor the ORM and schema choice in the Phase 2 sequel document; at a planning level, avoid designing around Postgres-only features (e.g., native arrays, `JSONB`-specific querying, `LISTEN/NOTIFY`) for anything on the critical path, per the brief's constraint.
|
||||
- **Uploaded template quality.** Broken internal links, malformed duplicate `<meta>` tags (file 15), and dead JS references (file 22's `#terms-preview`) confirm the templates are visual references only, not code to adapt — reinforces the brief's own instruction not to build inside `/templates`.
|
||||
|
||||
---
|
||||
|
||||
## 15. Questions and Assumptions
|
||||
|
||||
### Assumptions
|
||||
- "NextChair" is the working project/repo name; "TrimTime" (appearing in every template's `<title>` and on-screen branding) is the in-design placeholder brand, not necessarily the final product name. Business names shown on-screen ("Blake Heritage Barbershop," "The Cut & Shave Co.") are placeholder demo content, not the real first customer's business.
|
||||
- Owner is modeled as a **permission layered onto a Staff account**, not a separate account type — this best matches "business owners should access all barber features" from the brief and resolves the file 4/13 nav/role inconsistency.
|
||||
- The first release targets a **single business**, but the schema should be **multi-location-ready** (Business/BusinessLocation split, §9) without building multi-location UI yet — see the trade-off note below.
|
||||
- Currency and locale are single-value per business for v1 (no evidence of multi-currency need beyond the £/$ inconsistency, which is treated as template inconsistency, not a requirement).
|
||||
- "Book again" re-runs the booking flow pre-filled with the prior service/barber rather than instantly re-booking without confirmation (safer default, avoids double-booking surprises).
|
||||
- The Loyalty reward redemption moment happens staff-side (barber applies it during checkout/current-appointment), matching how stamps are added, rather than customer-side self-service redemption.
|
||||
|
||||
### Questions
|
||||
1. **Is "NextChair" the final product/brand name, or will the real business's branding replace "TrimTime" entirely?**
|
||||
*Why it matters:* affects whether the design system should stay generic/white-label (multi-tenant-flavored) or be hard-coded to one brand.
|
||||
*Recommended default:* build the design system as brand-neutral/tokenized regardless of the answer — low cost either way.
|
||||
*Can proceed without an answer:* yes.
|
||||
|
||||
2. **Should Owner and Staff be strictly the same account with a permission flag, or genuinely separate account records that can be linked (e.g., an owner who is also a working barber)?**
|
||||
*Why it matters:* directly determines the `Role`/`Permission` schema shape and route-guarding logic in §11.
|
||||
*Recommended default:* single account + permission flag (assumed above) — matches the brief and the "Switch to Admin View" template affordance.
|
||||
*Can proceed without an answer:* yes, using the recommended default, but should be explicitly confirmed before Phase 2's schema is finalized since it's expensive to change later.
|
||||
|
||||
3. **Is phone/SMS login a must-have for the first release, or can it be deferred behind email + Google?**
|
||||
*Why it matters:* SMS OTP requires a paid delivery provider and adds real implementation cost; the templates don't show it at all despite the brief requiring it.
|
||||
*Recommended default:* defer phone login to Phase 2/3 of implementation (post-MVP), ship email + Google first.
|
||||
*Can proceed without an answer:* yes.
|
||||
|
||||
4. **What is the guest-booking identity strategy — should a returning guest with the same email/phone be recognized as "the same customer" automatically, or only after they create an account?**
|
||||
*Why it matters:* affects CustomerProfile creation timing and duplicate-customer risk (§14).
|
||||
*Recommended default:* soft-match by email+phone for internal (staff-facing) client-list purposes, but never silently merge into an authenticated account without an explicit claim/verification step.
|
||||
*Can proceed without an answer:* yes, using the recommended default, but flag for confirmation before Phase 2 building the CustomerProfile/User relationship.
|
||||
|
||||
5. **Do bookings require owner/staff approval before being confirmed, or are all bookings auto-confirmed (subject to availability)?**
|
||||
*Why it matters:* the brief lists "whether approval is required" as a booking rule, but every template (17, 9) shows an instant "Confirmed" state with no pending step.
|
||||
*Recommended default:* auto-confirm for v1 (matches every template shown), with the BookingRule field modeled but defaulted off, so it can be turned on later without a schema change.
|
||||
*Can proceed without an answer:* yes.
|
||||
|
||||
---
|
||||
|
||||
## 16. Recommended Next Step
|
||||
|
||||
**Phase 2 scope (pending your approval of this document):**
|
||||
|
||||
1. **Finalize technical architecture** — confirm the Next.js App Router structure in §11, the Server Actions vs. API routes split, and settle the Prisma-vs-Drizzle / Postgres-vs-portability trade-off left open per your instruction not to force a decision here.
|
||||
2. **Design the database schema** — turn the conceptual entities in §9 into a real schema (tables, columns, indexes, constraints), explicitly deciding the Owner/Staff/Role/Permission shape (Question 2 above) and the multi-location-readiness split (Business/BusinessLocation).
|
||||
3. **Define authentication and permissions** — pick the auth library/approach, design the UserIdentity linking model for email+Google(+phone later), and specify route-group + service-layer permission enforcement concretely.
|
||||
4. **Establish booking and availability rules** — specify the availability-computation algorithm (working hours ∩ bookings ∩ breaks ∩ time off ∩ buffers ∩ notice/advance windows), and the concurrency-safety mechanism that prevents double-booking (§14's top risk).
|
||||
|
||||
I will not begin scaffolding the project, writing schema/migrations, or implementing authentication until you've reviewed and approved this plan.
|
||||
@@ -0,0 +1,176 @@
|
||||
# NextChair — Phase 2 Summary
|
||||
### Project scaffold, design system, database schema, authentication foundation
|
||||
|
||||
Status: **Complete and verified.** Typecheck, lint, and `next build` are all clean. The full schema was migrated against a real Postgres instance and the entire auth flow (register → sign-in → sign-out → permission-gated routing) was exercised end-to-end in a browser, not just eyeballed. See §7 for exactly what was verified and how.
|
||||
|
||||
Per your instructions, this phase stops here: no booking, appointments, loyalty, or staff/owner functionality has been implemented. Where those areas needed a route to exist for the layout/nav/auth architecture to be provable, the route renders a labeled "Coming in Phase N" placeholder — see §3.
|
||||
|
||||
---
|
||||
|
||||
## 1. What was built
|
||||
|
||||
1. **Project scaffold** — Next.js 16 (App Router, Turbopack), React 19, TypeScript 6 (strict), Tailwind CSS v4, ESLint 9 (flat config), Prettier.
|
||||
2. **Architecture** — `src/` layout, five route groups (`(public)` reserved, `(auth)`, `(customer)`, `(staff)`, `(owner)`), a `proxy.ts` (Next 16's renamed `middleware.ts`) gating protected paths, and a `features/`/`lib/`/`services/`/`components/` separation matching the structure proposed in `docs/implementation-plan.md` §11.
|
||||
3. **Design system** — 20 reusable components under `components/ui`, `components/navigation`, and `components/feedback`, all built from the visual language in `/templates`, plus a `/style-guide` reference page showing every one with placeholder content.
|
||||
4. **Database schema** — a complete `prisma/schema.prisma` covering every entity your brief listed (and a few more identified in the Phase 1 domain model), migrated and seeded successfully against a real Postgres database.
|
||||
5. **Authentication foundation** — email/password (Credentials) and Google OAuth via Auth.js (NextAuth v5), a working register → auto-sign-in flow, sign-out, and real role/permission-based route gating (not just "is logged in").
|
||||
|
||||
---
|
||||
|
||||
## 2. Folder structure
|
||||
|
||||
```text
|
||||
NextChair/
|
||||
docs/
|
||||
implementation-plan.md # Phase 1 output
|
||||
phase-2-summary.md # this file
|
||||
prisma/
|
||||
schema.prisma
|
||||
seed.ts
|
||||
migrations/20260802161213_init/migration.sql
|
||||
templates/ # untouched — 35 UX Pilot exports + prototypes
|
||||
src/
|
||||
app/
|
||||
(auth)/ # sign-in, register — shared centered-card layout
|
||||
(customer)/ # home, appointments, settings — light bottom nav, session-gated
|
||||
(staff)/staff/ # calendar, current, clients, settings — dark bottom nav, StaffProfile-gated
|
||||
(owner)/owner/ # dashboard, team — same shell as (staff), MANAGE_STAFF-gated
|
||||
api/auth/[...nextauth]/route.ts
|
||||
style-guide/ # design-system showcase (reference only)
|
||||
page.tsx # Welcome/splash
|
||||
layout.tsx, globals.css
|
||||
auth.ts # full NextAuth config (adapter + real providers)
|
||||
auth.config.ts # DB-free subset, used by proxy.ts
|
||||
proxy.ts # Next 16's middleware convention — see §6
|
||||
components/
|
||||
ui/ # Button, Card, Input, Textarea, Select, Checkbox, Switch,
|
||||
# Modal, BottomSheet, Tabs, MonthCalendar, AppointmentCard,
|
||||
# ServiceCard, BarberCard, ProfileCard, LoyaltyCard, StatusPill
|
||||
navigation/ # BottomNav, TopNav
|
||||
feedback/ # EmptyState, ErrorState, LoadingState, Skeleton, ComingSoon
|
||||
features/auth/ # schemas, register server action, sign-in/up/out components
|
||||
lib/
|
||||
auth/permissions.ts # StaffProfile → Role → RolePermission lookup
|
||||
db/prisma.ts # the one file that imports the Postgres driver adapter
|
||||
navigation/staff-nav-items.ts
|
||||
utils/cn.ts
|
||||
types/
|
||||
domain.ts # UI-facing types, deliberately independent of the ORM
|
||||
next-auth.d.ts # session.user.id module augmentation
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. What each route actually does right now
|
||||
|
||||
| Route | Renders | Gate |
|
||||
|---|---|---|
|
||||
| `/` | Welcome/splash (matches template 20, minus "Continue as Guest" — see §8) | redirects to `/home` if already signed in |
|
||||
| `/sign-in`, `/register` | Real, working forms | none |
|
||||
| `/home`, `/appointments`, `/settings` | `/home` and `/settings` show real session data + a working sign-out; `/appointments` is a labeled placeholder | any authenticated session |
|
||||
| `/staff`, `/staff/current`, `/staff/clients` | Labeled placeholders | authenticated **and** has a `StaffProfile` |
|
||||
| `/staff/settings` | Real profile card + conditional "Switch to Owner Admin" link (only if the signed-in staff member's Role grants `MANAGE_STAFF`) + sign-out | same as above |
|
||||
| `/owner`, `/owner/team` | Labeled placeholders | authenticated, has a `StaffProfile`, **and** `MANAGE_STAFF` permission |
|
||||
|
||||
Every placeholder exists only to prove the layout/nav/auth architecture around it works — none contain business logic. This was a deliberate choice to satisfy "Create the architecture: Route groups, Shared layouts" (Phase 2 scope §3) without drifting into "Staff functionality, Owner functionality" (explicitly excluded).
|
||||
|
||||
---
|
||||
|
||||
## 4. Design system
|
||||
|
||||
All 20 components are in `components/ui`, `components/navigation`, `components/feedback`. Highlights and the judgment calls behind them:
|
||||
|
||||
- **Tokens** (`globals.css`) — Tailwind v4's CSS-based `@theme`, carrying forward the `ink`/`stone`/`surface`/`muted`/`line`/`accent` palette that dominated the templates (Phase 1 plan §8), *not* the salon-red or blue variants found on two outlier templates. Added a `--color-accent-loyalty` token for the gold loyalty-card accent instead of letting it leak into the base palette.
|
||||
- **Button** — `cva`-based variants (`primary`/`accent`/`secondary`/`ghost`/`destructive`), `asChild` via Radix `Slot` so it can wrap a Next `Link` and still look like a button.
|
||||
- **Switch, Tabs** — Radix primitives. These are the two places a hand-rolled implementation is genuinely easy to get subtly wrong (roving tabindex, `aria-checked`); the templates' own `switchTab()` DOM-manipulation script is exactly the kind of thing this replaces.
|
||||
- **Modal, BottomSheet** — built on the native `<dialog>` element rather than Radix Dialog or a hand-rolled focus trap. `showModal()` gives focus containment, Escape-to-close, and top-layer stacking from the browser for free. No template had a modal/sheet pattern at all (Phase 1 §8 flagged this as a gap); these are new.
|
||||
- **Select, Checkbox** — deliberately *native* `<select>`/`<input type="checkbox">`, not Radix — native select gets the OS picker on mobile for free, which no custom listbox matches.
|
||||
- **MonthCalendar** — real date math (no external date library), matches the templates' booking/reschedule calendar. The staff day/agenda calendar is **not** built — Phase 1 §14 found the templates disagree on its layout (grid-columns vs. vertical agenda) and it depends on the booking engine's availability model, which doesn't exist yet.
|
||||
- **LoyaltyCard** — ports the 3D flip card from template 11 faithfully, but fixes a real gap: the original had no actual flip trigger wired up (presentational only). Here it's a real `<button aria-pressed>`, and the flip transition respects `prefers-reduced-motion`.
|
||||
- **BottomNav** — one component serves both the customer (light) and staff/owner (dark) variants, replacing the four inconsistent nav markups found across the templates. It resolves its own "active" tab from `usePathname()` rather than requiring every layout to compute and pass it — see the RSC lesson in §6 for why its `icon` prop is a string key, not a component reference.
|
||||
- **EmptyState, ErrorState, LoadingState, Skeleton** — none of these existed in any template; every list screen needs one for the zero-items/failure/loading case.
|
||||
|
||||
---
|
||||
|
||||
## 5. Database schema
|
||||
|
||||
Full schema in `prisma/schema.prisma`, migrated cleanly (`prisma/migrations/20260802161213_init/migration.sql`) and seeded (`prisma/seed.ts`) against a real Postgres instance. Covers every entity from your brief:
|
||||
|
||||
Business, BusinessLocation, BusinessHours, BusinessSettings, BookingRule · User, Account, Session, VerificationToken (Auth.js standard shape) · CustomerProfile, StaffProfile, Role, RolePermission · ServiceCategory, Service, StaffService · WorkingHours, Break, BreakDay, TimeOff · Appointment, AppointmentService · LoyaltyProgramme, LoyaltyEligibleService, LoyaltyEligibleStaff, LoyaltyAccount, LoyaltyTransaction, LoyaltyReward · Notification, NotificationPreference · CustomerNote, AuditLog.
|
||||
|
||||
**Key decisions** (each is a comment in the schema itself, not just here):
|
||||
|
||||
- **Multi-service appointments.** `AppointmentService` is a proper join table with `priceAtBooking`/`durationAtBookingMinutes` snapshots — a later price change to a `Service` never rewrites historical bookings. Directly required by your "support multiple services within a single appointment" instruction, and matches the "add another service" step visible in the booking templates.
|
||||
- **Loyalty is a ledger, not a counter.** `LoyaltyAccount.currentStamps` is a cached total; `LoyaltyTransaction` is the append-only source of truth (`STAMP_ADDED`/`STAMP_REMOVED`/`STAMP_EXPIRED`/`REWARD_REDEEMED`), and `LoyaltyReward` records a completed redemption before the account's count resets — per your explicit instruction.
|
||||
- **Roles/Permissions.** `Role` is a real per-business table (seeded with "Owner" and "Barber"); `Permission` is a code-defined enum joined via `RolePermission`. A barber who is also an owner is **one** `User` with **one** `StaffProfile`, whose `Role` happens to grant more permissions — never two accounts. This directly resolves the role-conflict the Phase 1 review found in the templates (a "Switch to Admin View" button with no real permission model behind it).
|
||||
- **Guest-friendly by design.** `CustomerProfile.userId` is nullable and `email`/`phone` are **not** unique-constrained — a hard constraint would force guests to either collide with each other or be blocked from repeat bookings under a shared household email/phone. Guest deduplication stays an explicit open question (Phase 1 plan §15, Question 4), not something silently decided by a DB constraint.
|
||||
- **Portability (Postgres → MySQL).** No scalar-list columns anywhere — `Break`'s applicable days are a `BreakDay` join table, not a `Weekday[]` array, because MySQL has no native array type. Money fields use `Decimal`, long text uses `@db.Text`, dates use `@db.Date`, and `AuditLog.metadata` uses `Json` — all four map to native equivalent types on both providers. Recurring wall-clock times (working hours, breaks, business hours) are stored as `Int` minutes-from-midnight rather than a DB `TIME` type, so scheduling math lives in application code, not provider-specific SQL.
|
||||
- **`AuditLog`** exists in the schema but nothing writes to it yet — added now so Phase 4/6 features that need it don't require a migration to start.
|
||||
|
||||
### A real, current-generation Prisma detail worth flagging
|
||||
|
||||
Prisma 7 (what `npm install prisma` currently resolves to) changed two things that aren't yet reflected in most tutorials/training data, and I hit both empirically rather than assuming:
|
||||
|
||||
1. **The client generates to a custom folder** (`generated/prisma`, via the new `prisma-client` generator), not `node_modules/@prisma/client`. Connection config moved out of `schema.prisma` into `prisma.config.ts`.
|
||||
2. **`PrismaClient` now requires an explicit driver adapter** (`@prisma/adapter-pg` for Postgres, `@prisma/adapter-mariadb` for MySQL) instead of a bare connection string. `src/lib/db/prisma.ts` is the **only** file in the app that imports the adapter — switching providers later means changing that one file, `datasource.provider` in the schema, and re-running `prisma migrate dev`, not touching application code.
|
||||
|
||||
---
|
||||
|
||||
## 6. Architecture decisions worth knowing about (found by actually building and running this, not by inspection)
|
||||
|
||||
- **Next.js 16 renamed `middleware.ts` to `proxy.ts`**, and — significantly — proxy files now run on the **Node.js runtime by default**, not Edge. That alone would have resolved the "Prisma isn't Edge-compatible" warning I initially hit, but I still split a DB-free `auth.config.ts` from the full `auth.ts` (§ below) because spinning up a Postgres connection pool just to check "is there a valid session JWT" on every request is wasteful regardless of which runtime it's allowed to run on.
|
||||
- **RSC serialization boundary bit me twice, in the same way, and I want to flag the pattern rather than bury it in a diff.** A Server Component cannot pass a live function (an inline handler, or a React component reference like a Lucide icon) as a prop to a Client Component — both fail with slightly different error messages ("Event handlers cannot be passed to Client Component props" / "Only plain objects can be passed to Client Components from Server Components"). This hit `ErrorState`/`ProfileCard` demo handlers in the style guide (fixed by moving the interactive-with-real-handlers instances into an already-`"use client"` wrapper) and `BottomNav`'s `icon` prop (fixed by passing a string key, resolved to a component inside the Client Component itself, instead of the component reference). Both fixes are the general-purpose pattern for this class of bug, not one-off patches — worth knowing before Phase 3 adds more Server-Component pages that render interactive children.
|
||||
- **Auth split**: `auth.config.ts` (pages, providers: [], session strategy — no DB) vs. `auth.ts` (the full thing: Prisma adapter, Credentials `authorize()`, Google). `proxy.ts` builds its own lightweight `NextAuth(authConfig)` instance from the former; everything else (route handlers, Server Components, Server Actions) uses the latter.
|
||||
- **Permission enforcement happens in two places on purpose**: `proxy.ts` does a cheap "is there a session at all" check (Edge/Node-safe, no DB), and each protected layout does the real DB-backed check (`StaffProfile` exists? does the `Role` grant `MANAGE_STAFF`?). This matches the Phase 1 plan's explicit instruction not to trust route-group gating alone.
|
||||
- **Icons**: swapped the templates' Font Awesome CDN script for `lucide-react` tree-shaken imports, as recommended in the Phase 1 plan.
|
||||
|
||||
---
|
||||
|
||||
## 7. What was actually verified (not just built)
|
||||
|
||||
I don't consider "it compiles" sufficient proof for an auth system, so:
|
||||
|
||||
1. Ran `prisma migrate dev` against a real, throwaway local Postgres (Docker, torn down afterward — did not touch the two unrelated Postgres containers already running on this machine) — the full schema applies as real SQL, not just Prisma-schema-valid.
|
||||
2. Ran the seed script against that database — business, roles + permissions, services, two staff users (an Owner and a plain Barber), and a customer all created successfully.
|
||||
3. In an actual browser: registered a brand-new customer account end-to-end (form → server action → DB write → auto sign-in → redirect to `/home`).
|
||||
4. Signed in as the seeded Owner (`marcus@blakeheritage.co.uk` / `password123`) and confirmed `/owner` renders for them.
|
||||
5. Signed in as the seeded plain Barber (`leo@blakeheritage.co.uk` / `password123`) and confirmed **`/owner` redirects him to `/staff`** — the negative case, which is the one that actually matters for a permission system.
|
||||
6. Confirmed a customer with no `StaffProfile` is bounced from `/staff` to `/home`.
|
||||
7. Confirmed an unauthenticated request to any protected path (`/settings` while logged out) is redirected to `/sign-in` by `proxy.ts`.
|
||||
8. Confirmed sign-out actually clears the session (not just a UI state change).
|
||||
|
||||
`npm run typecheck`, `npm run lint`, and `npm run build` are all clean with zero warnings.
|
||||
|
||||
---
|
||||
|
||||
## 8. Assumptions made this phase
|
||||
|
||||
- Password reset ("Forgot Password", template 8) was **not** wired up, even as a dead link — it needs the Notifications system (real email delivery) to do anything honest, and that's out of scope. I'd rather have no link than a link that silently does nothing, which is exactly the kind of broken-link issue the Phase 1 review flagged in the original templates.
|
||||
- The Welcome/splash page's "Continue as Guest" button (template 20) isn't shown, for the same reason — it leads into the booking flow, which doesn't exist yet.
|
||||
- Registration auto-signs the user in immediately, with no email-verification gate (`emailVerified` is modeled on `User` but not enforced) — consistent with the "auto-confirm" default recommended in the Phase 1 plan (§15, Question 5) and with every template's own instant-success flow.
|
||||
- Seeded demo accounts (`marcus@blakeheritage.co.uk`, `leo@blakeheritage.co.uk`, `alex.chen@example.com`, all password `password123`) exist only for this verification — delete or change them before any real deployment.
|
||||
- Google OAuth is wired in code but untested end-to-end (needs real `AUTH_GOOGLE_ID`/`AUTH_GOOGLE_SECRET` from a Google Cloud project, which I don't have). The Credentials path is fully verified; the Google path follows the same, standard Auth.js provider pattern and should work once real credentials are supplied — flagging this as the one piece of Phase 2 I couldn't verify firsthand.
|
||||
|
||||
## 9. What should be reviewed before moving on
|
||||
|
||||
- **The Role/Permission seed set** (`prisma/seed.ts`) — I picked a reasonable permission split between "Owner" and "Barber" based on the Phase 1 domain model, but you may want different defaults before this becomes load-bearing.
|
||||
- **Whether email verification should gate anything** before Phase 2's account-creation flow is considered "final" — right now it's purely decorative on the `User` model.
|
||||
- **The route/URL naming** (`/staff`, `/owner`, `/home` — no `/customer` prefix) — chosen to match the Phase 1 route map, worth confirming before more pages accumulate under it.
|
||||
|
||||
## 10. Getting a real database running
|
||||
|
||||
```bash
|
||||
docker run -d --name nextchair-pg -e POSTGRES_USER=nextchair \
|
||||
-e POSTGRES_PASSWORD=nextchair -e POSTGRES_DB=nextchair \
|
||||
-p 5432:5432 postgres:16-alpine
|
||||
|
||||
npm run prisma:migrate # applies prisma/migrations/
|
||||
npm run prisma:seed # creates the demo business/staff/customer
|
||||
npm run dev
|
||||
```
|
||||
|
||||
`.env` already has a matching `DATABASE_URL` and a real `AUTH_SECRET`; only `AUTH_GOOGLE_ID`/`AUTH_GOOGLE_SECRET` need filling in to exercise Google sign-in.
|
||||
|
||||
---
|
||||
|
||||
Ready for direction on the next slice of work — per the phasing in `docs/implementation-plan.md` §13, that would be **Phase 2: Customer Accounts** (the real, data-backed home/appointments/loyalty pages, replacing the placeholders in §3 above). Note this is the implementation plan's own Phase 2, distinct from "Phase 2" as you've been using it in this conversation to mean the whole scaffold-and-foundation stage just completed. I won't start building it until you say so.
|
||||
Reference in new issue
Block a user