feat: flip routing — customer portal at /, admin at /admin (#57)

* feat: flip routing — customer portal at /, admin at /admin

Move all admin dashboard routes under /admin prefix and mount the
customer portal at root (/). This gives customers clean, shareable
URLs while staff bookmark /admin.

- Admin routes: /admin, /admin/clients, /admin/services, etc.
- Customer portal: / (root)
- Admin nav "Customer Portal" link points to / for staff preview
- Updated tests for new route structure and fixed React 19 act compat

Closes #56

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* fix(e2e): update tests for routing flip — admin at /admin, portal at /

All E2E tests now use /admin prefix for admin routes (clients, services,
staff, invoices, reports, book). Adds customer portal smoke test at /.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(e2e): use specific locator for customer portal test

getByText('Paws & Reflect') matched 3 elements causing strict mode
violation. Scope to navigation role for unique match.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Groom Book CTO <cto@groombook.dev>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit was merged in pull request #57.
This commit is contained in:
groombook-paperclip[bot]
2026-03-19 02:47:19 +00:00
committed by GitHub
parent 1136824fe3
commit c901b1135d
5 changed files with 69 additions and 49 deletions
+19 -13
View File
@@ -40,45 +40,51 @@ test.beforeEach(async ({ page }) => {
});
});
test("appointments page loads", async ({ page }) => {
test("customer portal loads at root", async ({ page }) => {
await page.goto("/");
await expect(page.getByRole("navigation").getByText("Paws & Reflect")).toBeVisible();
await expect(page.locator("nav")).toBeVisible();
});
test("admin appointments page loads", async ({ page }) => {
await page.goto("/admin");
await expect(page.getByText("Groom Book")).toBeVisible();
// Calendar/appointments view renders
await expect(page.locator("nav")).toBeVisible();
});
test("clients page loads", async ({ page }) => {
await page.goto("/clients");
test("admin clients page loads", async ({ page }) => {
await page.goto("/admin/clients");
await expect(page.getByText("Groom Book")).toBeVisible();
await expect(page.getByRole("link", { name: "Clients" })).toBeVisible();
});
test("services page loads", async ({ page }) => {
await page.goto("/services");
test("admin services page loads", async ({ page }) => {
await page.goto("/admin/services");
await expect(page.getByText("Groom Book")).toBeVisible();
await expect(page.getByRole("link", { name: "Services" })).toBeVisible();
});
test("staff page loads", async ({ page }) => {
await page.goto("/staff");
test("admin staff page loads", async ({ page }) => {
await page.goto("/admin/staff");
await expect(page.getByText("Groom Book")).toBeVisible();
await expect(page.getByRole("link", { name: "Staff" })).toBeVisible();
});
test("invoices page loads", async ({ page }) => {
await page.goto("/invoices");
test("admin invoices page loads", async ({ page }) => {
await page.goto("/admin/invoices");
await expect(page.getByText("Groom Book")).toBeVisible();
await expect(page.getByRole("link", { name: "Invoices" })).toBeVisible();
});
test("reports page loads", async ({ page }) => {
await page.goto("/reports");
test("admin reports page loads", async ({ page }) => {
await page.goto("/admin/reports");
await expect(page.getByText("Groom Book")).toBeVisible();
await expect(page.getByRole("link", { name: "Reports" })).toBeVisible();
});
test("booking portal loads", async ({ page }) => {
await page.goto("/book");
test("admin booking portal loads", async ({ page }) => {
await page.goto("/admin/book");
await expect(page.getByText("Book an Appointment")).toBeVisible();
await expect(page.getByText("Choose a service")).toBeVisible();
});