Rebrand from Casera/MyCrib to honeyDue

Total rebrand across Web project:
- Package name: casera-web -> honeydue-web
- Cookie: casera-token -> honeydue-token
- Theme store: casera-theme -> honeydue-theme
- File sharing: .casera -> .honeydue, component/function renames
- casera-file-handler.tsx -> honeydue-file-handler.tsx
- All UI text, metadata, OG tags updated
- Domains: casera.treytartt.com -> honeyDue.treytartt.com
- Demo data emails updated
- All documentation updated

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-03-07 06:33:59 -06:00
parent 4b8c10d768
commit e2172c20f2
57 changed files with 192 additions and 192 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
WAIT=10 WAIT=10
ATTEMPTS=6 ATTEMPTS=6
/ Casera / honeyDue
+6 -6
View File
@@ -1,6 +1,6 @@
# Casera Web (`myCribAPI-Web`) # honeyDue Web (`honeyDueAPI-Web`)
Next.js web client for the Casera property management platform. Talks to the Go REST API backend. Next.js web client for the honeyDue property management platform. Talks to the Go REST API backend.
## Build & Run ## Build & Run
@@ -32,10 +32,10 @@ npm run analyze # Bundle analysis
``` ```
Browser → Next.js page (client component) Browser → Next.js page (client component)
→ apiFetch("/tasks/") → /api/proxy/tasks (Next.js route handler) → apiFetch("/tasks/") → /api/proxy/tasks (Next.js route handler)
→ Go API (reads casera-token httpOnly cookie, forwards as Authorization header) → Go API (reads honeydue-token httpOnly cookie, forwards as Authorization header)
``` ```
Auth tokens are stored as httpOnly cookies (`casera-token`), never exposed to JS. The Next.js `/api/proxy/[...path]` catch-all route forwards requests to the Go API. Auth tokens are stored as httpOnly cookies (`honeydue-token`), never exposed to JS. The Next.js `/api/proxy/[...path]` catch-all route forwards requests to the Go API.
### Directory Structure ### Directory Structure
@@ -103,7 +103,7 @@ src/
**Kanban boards**: Tasks display in kanban columns (overdue, due_soon, in_progress, not_started, completed). Uses `@dnd-kit` for drag-and-drop. Column names match Go API: `overdue_tasks`, `due_soon_tasks`, `in_progress_tasks`, `not_started_tasks`, `completed_tasks`. **Kanban boards**: Tasks display in kanban columns (overdue, due_soon, in_progress, not_started, completed). Uses `@dnd-kit` for drag-and-drop. Column names match Go API: `overdue_tasks`, `due_soon_tasks`, `in_progress_tasks`, `not_started_tasks`, `completed_tasks`.
**Middleware** (`src/middleware.ts`): Checks `casera-token` cookie. Redirects unauthenticated users to `/login` for protected routes. Skips API routes, static files, and public paths. **Middleware** (`src/middleware.ts`): Checks `honeydue-token` cookie. Redirects unauthenticated users to `/login` for protected routes. Skips API routes, static files, and public paths.
## Conventions ## Conventions
@@ -123,7 +123,7 @@ src/
| Variable | Description | Default | | Variable | Description | Default |
|----------|-------------|---------| |----------|-------------|---------|
| `NEXT_PUBLIC_API_URL` | Go API URL (client-side) | `https://casera.treytartt.com/api` | | `NEXT_PUBLIC_API_URL` | Go API URL (client-side) | `https://honeyDue.treytartt.com/api` |
| `API_URL` | Go API URL (server-side, no proxy) | Falls back to `NEXT_PUBLIC_API_URL` | | `API_URL` | Go API URL (server-side, no proxy) | Falls back to `NEXT_PUBLIC_API_URL` |
| `NEXT_PUBLIC_POSTHOG_KEY` | PostHog analytics key | — | | `NEXT_PUBLIC_POSTHOG_KEY` | PostHog analytics key | — |
| `NEXT_PUBLIC_POSTHOG_HOST` | PostHog host | — | | `NEXT_PUBLIC_POSTHOG_HOST` | PostHog host | — |
+3 -3
View File
@@ -1,6 +1,6 @@
# Casera Web App # honeyDue Web App
Next.js web client for the Casera property management platform. Connects to the [Go REST API](https://github.com/akatreyt/casera-api) backend. Next.js web client for the honeyDue property management platform. Connects to the [Go REST API](https://github.com/akatreyt/honeydue-api) backend.
## Features ## Features
@@ -50,7 +50,7 @@ Open [http://localhost:3000](http://localhost:3000).
| Variable | Description | Required | | Variable | Description | Required |
|----------|-------------|----------| |----------|-------------|----------|
| `NEXT_PUBLIC_API_URL` | Go API base URL (e.g. `https://casera.treytartt.com/api`) | Yes | | `NEXT_PUBLIC_API_URL` | Go API base URL (e.g. `https://honeyDue.treytartt.com/api`) | Yes |
| `API_URL` | Server-side API URL (defaults to `NEXT_PUBLIC_API_URL`) | No | | `API_URL` | Server-side API URL (defaults to `NEXT_PUBLIC_API_URL`) | No |
| `NEXT_PUBLIC_POSTHOG_KEY` | PostHog project API key | No | | `NEXT_PUBLIC_POSTHOG_KEY` | PostHog project API key | No |
| `NEXT_PUBLIC_POSTHOG_HOST` | PostHog instance URL | No | | `NEXT_PUBLIC_POSTHOG_HOST` | PostHog instance URL | No |
+5 -5
View File
@@ -1,8 +1,8 @@
# Casera Web App — Build Plan Overview # honeyDue Web App — Build Plan Overview
## What We're Building ## What We're Building
Full parity web app for Casera: **46 screens**, **104 API operations**, **4 domains** (Residences, Tasks, Contractors, Documents), plus auth, onboarding, subscriptions, settings, and a **sandboxed demo mode** with mock data. Full parity web app for honeyDue: **46 screens**, **104 API operations**, **4 domains** (Residences, Tasks, Contractors, Documents), plus auth, onboarding, subscriptions, settings, and a **sandboxed demo mode** with mock data.
## Tech Stack ## Tech Stack
@@ -33,7 +33,7 @@ Full parity web app for Casera: **46 screens**, **104 API operations**, **4 doma
## Project Structure ## Project Structure
``` ```
myCribAPI-Web/ honeyDueAPI-Web/
├── src/ ├── src/
│ ├── app/ # Next.js App Router │ ├── app/ # Next.js App Router
│ │ ├── (marketing)/ # Public pages (landing, pricing) │ │ ├── (marketing)/ # Public pages (landing, pricing)
@@ -86,7 +86,7 @@ myCribAPI-Web/
|---|---| |---|---|
| Push notifications | Not needed (no push API for web in scope) | | Push notifications | Not needed (no push API for web in scope) |
| Widgets | Not applicable | | Widgets | Not applicable |
| .casera file import/export | File download (export) + drag-and-drop or file picker (import) | | .honeydue file import/export | File download (export) + drag-and-drop or file picker (import) |
| Apple/Google Sign In | OAuth redirect flow (same backend endpoints) | | Apple/Google Sign In | OAuth redirect flow (same backend endpoints) |
| StoreKit subscription | Stripe Checkout or link to App Store (TBD) | | StoreKit subscription | Stripe Checkout or link to App Store (TBD) |
| Camera capture | File upload input (no camera API needed) | | Camera capture | File upload input (no camera API needed) |
@@ -112,4 +112,4 @@ myCribAPI-Web/
| Demo mode data isolation | No backend calls, purely client-side, session-scoped store, no persistence | | Demo mode data isolation | No backend calls, purely client-side, session-scoped store, no persistence |
| API compatibility | 100% same endpoints, same token format (`Token <hex>`), same request/response shapes | | API compatibility | 100% same endpoints, same token format (`Token <hex>`), same request/response shapes |
| Mobile feature gaps | Push notifications and widgets explicitly excluded. Everything else covered. | | Mobile feature gaps | Push notifications and widgets explicitly excluded. Everything else covered. |
| Deployment independence | Separate Dokku app, own domain (e.g., `app.casera.treytartt.com`), no coupling to Go API deployment | | Deployment independence | Separate Dokku app, own domain (e.g., `app.honeydue.treytartt.com`), no coupling to Go API deployment |
+7 -7
View File
@@ -18,8 +18,8 @@ Scaffold the project, wire up auth, build the app shell, and establish the desig
## 1. Project Scaffold ## 1. Project Scaffold
```bash ```bash
npx create-next-app@latest myCribAPI-Web --typescript --tailwind --eslint --app --src-dir npx create-next-app@latest honeyDueAPI-Web --typescript --tailwind --eslint --app --src-dir
cd myCribAPI-Web cd honeyDueAPI-Web
npx shadcn@latest init npx shadcn@latest init
``` ```
@@ -33,9 +33,9 @@ npm install -D vitest @playwright/test
## 2. TypeScript Types ## 2. TypeScript Types
Generate TypeScript types matching the Go API DTOs. Source from: Generate TypeScript types matching the Go API DTOs. Source from:
- `myCribAPI-go/internal/dto/requests/` — request shapes - `honeyDueAPI-go/internal/dto/requests/` — request shapes
- `myCribAPI-go/internal/dto/responses/` — response shapes - `honeyDueAPI-go/internal/dto/responses/` — response shapes
- `myCribAPI-go/internal/models/` — entity shapes - `honeyDueAPI-go/internal/models/` — entity shapes
Key types to define in `src/lib/types/`: Key types to define in `src/lib/types/`:
@@ -73,7 +73,7 @@ api/
```typescript ```typescript
// src/lib/api/client.ts // src/lib/api/client.ts
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'https://mycrib.treytartt.com/api'; const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'https://honeyDue.treytartt.com/api';
async function apiFetch<T>( async function apiFetch<T>(
path: string, path: string,
@@ -225,7 +225,7 @@ Match the mobile app's theme system:
| Desert | TBD | TBD | | Desert | TBD | TBD |
| Mint | TBD | TBD | | Mint | TBD | TBD |
Theme values sourced from `MyCribKMM/composeApp/src/commonMain/.../ui/theme/ThemeColors.kt`. Theme values sourced from `HoneyDueKMM/composeApp/src/commonMain/.../ui/theme/ThemeColors.kt`.
### Spacing ### Spacing
+11 -11
View File
@@ -4,8 +4,8 @@ Build sharing, subscriptions, notifications, profile, onboarding, and summary me
## Checklist ## Checklist
- [ ] Residence sharing: generate/display share code, join residence, manage users, .casera file export/import - [ ] Residence sharing: generate/display share code, join residence, manage users, .honeydue file export/import
- [ ] Contractor sharing: .casera file export/import - [ ] Contractor sharing: .honeydue file export/import
- [ ] Subscription: status display, feature comparison, upgrade prompt, usage tracking - [ ] Subscription: status display, feature comparison, upgrade prompt, usage tracking
- [ ] Notification preferences: toggle + time picker per notification type - [ ] Notification preferences: toggle + time picker per notification type
- [ ] Profile: edit name/email, change password, delete account - [ ] Profile: edit name/email, change password, delete account
@@ -22,7 +22,7 @@ Build sharing, subscriptions, notifications, profile, onboarding, and summary me
| Route | Screen | Description | | Route | Screen | Description |
|-------|--------|-------------| |-------|--------|-------------|
| `/app/residences/[id]/share` | Share Residence | Generate/display share code, manage users | | `/app/residences/[id]/share` | Share Residence | Generate/display share code, manage users |
| `/app/residences/join` | Join Residence | Enter share code or import .casera file | | `/app/residences/join` | Join Residence | Enter share code or import .honeydue file |
### Share Code Flow ### Share Code Flow
@@ -35,15 +35,15 @@ Owner opens Share screen
Invitee opens Join screen Invitee opens Join screen
→ Enter share code manually, OR → Enter share code manually, OR
→ Upload .casera file (drag-and-drop zone) → Upload .honeydue file (drag-and-drop zone)
→ POST /api/residences/join/ { code: "ABC123" } → POST /api/residences/join/ { code: "ABC123" }
→ On success: redirect to residence detail → On success: redirect to residence detail
``` ```
### .casera File Handling ### .honeydue File Handling
**Export** (owner): **Export** (owner):
- Button on residence detail: "Export as .casera" - Button on residence detail: "Export as .honeydue"
- Generates JSON file with `{ type: "residence", code: "ABC123", ... }` - Generates JSON file with `{ type: "residence", code: "ABC123", ... }`
- Browser downloads the file - Browser downloads the file
@@ -73,7 +73,7 @@ Invitee opens Join screen
## 2. Contractor Sharing ## 2. Contractor Sharing
### .casera File Export/Import ### .honeydue File Export/Import
**Export**: **Export**:
- Button on contractor detail: "Share Contractor" - Button on contractor detail: "Share Contractor"
@@ -82,7 +82,7 @@ Invitee opens Join screen
**Import**: **Import**:
- Button on contractor list: "Import Contractor" - Button on contractor list: "Import Contractor"
- File picker or drag-and-drop for .casera file - File picker or drag-and-drop for .honeydue file
- Read JSON, show confirmation dialog, create contractor - Read JSON, show confirmation dialog, create contractor
- `POST /api/contractors/import/` - `POST /api/contractors/import/`
@@ -123,7 +123,7 @@ Check tier limits before allowing creation:
### Upgrade Path (Phase 1) ### Upgrade Path (Phase 1)
Web users are directed to the mobile app for purchases: Web users are directed to the mobile app for purchases:
- "Download Casera on the App Store to upgrade" - "Download honeyDue on the App Store to upgrade"
- Link to App Store listing - Link to App Store listing
### Upgrade Path (Future — Phase 2) ### Upgrade Path (Future — Phase 2)
@@ -215,7 +215,7 @@ Add Stripe Checkout for web-only subscription purchases. Requires backend work t
``` ```
Step 1: Welcome Step 1: Welcome
→ "Welcome to Casera! Let's set up your first property." → "Welcome to honeyDue! Let's set up your first property."
Step 2: Choose Path Step 2: Choose Path
→ "Create a new residence" OR "Join an existing residence" → "Create a new residence" OR "Join an existing residence"
@@ -300,7 +300,7 @@ Data sources:
At the end of Phase 3, you should have: At the end of Phase 3, you should have:
1. Residence sharing with code generation, join flow, and user management 1. Residence sharing with code generation, join flow, and user management
2. Contractor sharing via .casera files 2. Contractor sharing via .honeydue files
3. Subscription status with tier limits and upgrade prompts 3. Subscription status with tier limits and upgrade prompts
4. Notification preferences with toggles 4. Notification preferences with toggles
5. Profile editing (name, email, password, delete account) 5. Profile editing (name, email, password, delete account)
+2 -2
View File
@@ -261,7 +261,7 @@ Persistent banner at the top of the demo app:
``` ```
┌─────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────┐
│ 🎯 You're exploring Casera in demo mode. [Sign Up Free] │ │ 🎯 You're exploring honeyDue in demo mode. [Sign Up Free] │
│ Changes aren't saved. Create an account to get started! │ │ Changes aren't saved. Create an account to get started! │
└─────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────┘
``` ```
@@ -282,7 +282,7 @@ Before entering the demo, show a brief preview page:
``` ```
┌─────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────┐
│ │ │ │
│ 🏠 Try Casera — No Account Needed │ │ 🏠 Try honeyDue — No Account Needed │
│ │ │ │
│ Manage your home maintenance, track tasks, │ │ Manage your home maintenance, track tasks, │
│ organize contractors, and store documents. │ │ organize contractors, and store documents. │
+11 -11
View File
@@ -162,7 +162,7 @@ const nextConfig = {
output: 'standalone', // Required for Docker output: 'standalone', // Required for Docker
images: { images: {
remotePatterns: [ remotePatterns: [
{ protocol: 'https', hostname: 'mycrib.treytartt.com' }, // API media { protocol: 'https', hostname: 'honeyDue.treytartt.com' }, // API media
], ],
}, },
}; };
@@ -171,14 +171,14 @@ const nextConfig = {
### Dokku Deployment ### Dokku Deployment
```bash ```bash
# On mycribDev server # On honeyDueDev server
dokku apps:create casera-web dokku apps:create honeydue-web
dokku domains:add casera-web app.casera.treytartt.com dokku domains:add honeydue-web app.honeyDue.treytartt.com
dokku config:set casera-web NEXT_PUBLIC_API_URL=https://mycrib.treytartt.com/api dokku config:set honeydue-web NEXT_PUBLIC_API_URL=https://honeyDue.treytartt.com/api
dokku letsencrypt:enable casera-web dokku letsencrypt:enable honeydue-web
# Deploy # Deploy
git remote add dokku-web dokku@mycribDev:casera-web git remote add dokku-web dokku@honeyDueDev:honeydue-web
git push dokku-web main git push dokku-web main
``` ```
@@ -316,17 +316,17 @@ Marketing and demo pages need proper meta tags:
```typescript ```typescript
// src/app/(marketing)/page.tsx // src/app/(marketing)/page.tsx
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'Casera — Home Maintenance Made Simple', title: 'honeyDue — Home Maintenance Made Simple',
description: 'Track tasks, organize contractors, store documents. Manage your home maintenance in one place.', description: 'Track tasks, organize contractors, store documents. Manage your home maintenance in one place.',
openGraph: { openGraph: {
title: 'Casera — Home Maintenance Made Simple', title: 'honeyDue — Home Maintenance Made Simple',
description: 'Track tasks, organize contractors, store documents.', description: 'Track tasks, organize contractors, store documents.',
images: ['/og-image.png'], images: ['/og-image.png'],
type: 'website', type: 'website',
}, },
twitter: { twitter: {
card: 'summary_large_image', card: 'summary_large_image',
title: 'Casera', title: 'honeyDue',
description: 'Home Maintenance Made Simple', description: 'Home Maintenance Made Simple',
images: ['/og-image.png'], images: ['/og-image.png'],
}, },
@@ -391,7 +391,7 @@ Track same events as mobile app for consistent analytics.
At the end of Phase 5, you should have: At the end of Phase 5, you should have:
1. Fully responsive web app (mobile, tablet, desktop) 1. Fully responsive web app (mobile, tablet, desktop)
2. Consistent loading, empty, and error states everywhere 2. Consistent loading, empty, and error states everywhere
3. Deployed on Dokku at `app.casera.treytartt.com` 3. Deployed on Dokku at `app.honeyDue.treytartt.com`
4. E2E tests covering auth, CRUD, demo mode, and responsive viewports 4. E2E tests covering auth, CRUD, demo mode, and responsive viewports
5. Optimized bundle with code splitting and image optimization 5. Optimized bundle with code splitting and image optimization
6. SEO-ready marketing and demo pages 6. SEO-ready marketing and demo pages
+7 -7
View File
@@ -56,7 +56,7 @@ Task 6: Integration + Verification (sequential — cross-domain wiring)
### Step 1: Install missing shadcn components and @dnd-kit ### Step 1: Install missing shadcn components and @dnd-kit
```bash ```bash
cd myCribAPI-Web cd honeyDueAPI-Web
npx shadcn@latest add dialog select textarea tabs skeleton tooltip popover calendar npx shadcn@latest add dialog select textarea tabs skeleton tooltip popover calendar
npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities date-fns npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities date-fns
``` ```
@@ -688,7 +688,7 @@ export * from './use-documents';
### Step 14: Verify build ### Step 14: Verify build
```bash ```bash
cd myCribAPI-Web && npm run build cd honeyDueAPI-Web && npm run build
``` ```
Expected: Build succeeds with no type errors. Expected: Build succeeds with no type errors.
@@ -1253,7 +1253,7 @@ export default function EditResidencePage({
### Step 9: Verify build ### Step 9: Verify build
```bash ```bash
cd myCribAPI-Web && npm run build cd honeyDueAPI-Web && npm run build
``` ```
Expected: Build succeeds. All 4 residence routes render. Expected: Build succeeds. All 4 residence routes render.
@@ -2198,7 +2198,7 @@ export default function TaskDetailPage({
### Step 11: Verify build ### Step 11: Verify build
```bash ```bash
cd myCribAPI-Web && npm run build cd honeyDueAPI-Web && npm run build
``` ```
### Step 12: Commit ### Step 12: Commit
@@ -2282,7 +2282,7 @@ Follow the same patterns as Residences (Task 2). Key differences:
### Step 9: Verify build ### Step 9: Verify build
```bash ```bash
cd myCribAPI-Web && npm run build cd honeyDueAPI-Web && npm run build
``` ```
### Step 10: Commit ### Step 10: Commit
@@ -2363,7 +2363,7 @@ Key differences from other domains:
### Step 9: Verify build ### Step 9: Verify build
```bash ```bash
cd myCribAPI-Web && npm run build cd honeyDueAPI-Web && npm run build
``` ```
### Step 10: Commit ### Step 10: Commit
@@ -2442,7 +2442,7 @@ export default function DashboardPage() {
### Step 2: Full build verification ### Step 2: Full build verification
```bash ```bash
cd myCribAPI-Web && npm run build cd honeyDueAPI-Web && npm run build
``` ```
Expected: Build succeeds. All routes compile. No type errors. Expected: Build succeeds. All routes compile. No type errors.
+23 -23
View File
@@ -42,7 +42,7 @@ Task 7: Integration + Verification (sequential — cross-feature wiring)
### Step 1: Install Recharts ### Step 1: Install Recharts
```bash ```bash
cd /Users/treyt/Desktop/code/MyCrib/myCribAPI-Web cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web
npm install recharts npm install recharts
``` ```
@@ -282,7 +282,7 @@ export * from './use-subscription';
### Step 9: Verify build ### Step 9: Verify build
```bash ```bash
cd /Users/treyt/Desktop/code/MyCrib/myCribAPI-Web && npm run build cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build
``` ```
### Step 10: Commit ### Step 10: Commit
@@ -302,7 +302,7 @@ git add -A && git commit -m "feat: add Phase 3 foundation — notification hooks
- Create: `src/app/app/residences/join/page.tsx` - Create: `src/app/app/residences/join/page.tsx`
- Create: `src/components/sharing/share-code-display.tsx` - Create: `src/components/sharing/share-code-display.tsx`
- Create: `src/components/sharing/user-management.tsx` - Create: `src/components/sharing/user-management.tsx`
- Create: `src/components/sharing/casera-file-handler.tsx` - Create: `src/components/sharing/honeydue-file-handler.tsx`
- Create: `src/lib/hooks/use-sharing.ts` - Create: `src/lib/hooks/use-sharing.ts`
- Modify: `src/app/app/residences/[id]/page.tsx` (add Share button) - Modify: `src/app/app/residences/[id]/page.tsx` (add Share button)
- Modify: `src/app/app/contractors/[id]/page.tsx` (add Share/Export button) - Modify: `src/app/app/contractors/[id]/page.tsx` (add Share/Export button)
@@ -320,11 +320,11 @@ git add -A && git commit -m "feat: add Phase 3 foundation — notification hooks
- Each user row: name, email, role badge (Owner/Member) - Each user row: name, email, role badge (Owner/Member)
- Owner can click "Remove" → ConfirmDialog → `residencesApi.removeResidenceUser(residenceId, userId)` - Owner can click "Remove" → ConfirmDialog → `residencesApi.removeResidenceUser(residenceId, userId)`
### .casera File Handler ### .honeydue File Handler
**casera-file-handler.tsx** — Reusable component for both residence and contractor sharing: **honeydue-file-handler.tsx** — Reusable component for both residence and contractor sharing:
- **Export mode**: Takes data object, generates JSON `{ type: "residence"|"contractor", ... }`, triggers browser download as `.casera` file - **Export mode**: Takes data object, generates JSON `{ type: "residence"|"contractor", ... }`, triggers browser download as `.honeydue` file
- **Import mode**: FileUpload drop zone accepting `.casera` files, reads JSON, validates type, calls callback with parsed data - **Import mode**: FileUpload drop zone accepting `.honeydue` files, reads JSON, validates type, calls callback with parsed data
- Uses `URL.createObjectURL` + anchor click for download - Uses `URL.createObjectURL` + anchor click for download
- Uses `FileReader.readAsText` for import - Uses `FileReader.readAsText` for import
@@ -332,19 +332,19 @@ git add -A && git commit -m "feat: add Phase 3 foundation — notification hooks
**Residence Share page** (`/app/residences/[id]/share`): **Residence Share page** (`/app/residences/[id]/share`):
- ShareCodeDisplay for generating/displaying share codes - ShareCodeDisplay for generating/displaying share codes
- .casera export button → downloads file with share code embedded - .honeydue export button → downloads file with share code embedded
- UserManagement table - UserManagement table
- Only accessible to residence owner - Only accessible to residence owner
**Residence Join page** (`/app/residences/join`): **Residence Join page** (`/app/residences/join`):
- Text input for manual code entry - Text input for manual code entry
- .casera file import drop zone - .honeydue file import drop zone
- On submit: calls `residencesApi.joinWithCode()` → redirect to residence detail - On submit: calls `residencesApi.joinWithCode()` → redirect to residence detail
### Contractor Sharing ### Contractor Sharing
On contractor detail page, add "Share" button → generates .casera file with contractor data for download. On contractor detail page, add "Share" button → generates .honeydue file with contractor data for download.
On contractor list page, add "Import" button → opens import dialog → reads .casera file → creates contractor via API. On contractor list page, add "Import" button → opens import dialog → reads .honeydue file → creates contractor via API.
### Query hooks ### Query hooks
@@ -405,13 +405,13 @@ export function useJoinResidence() {
### Verify build ### Verify build
```bash ```bash
cd /Users/treyt/Desktop/code/MyCrib/myCribAPI-Web && npm run build cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build
``` ```
### Commit ### Commit
```bash ```bash
git add -A && git commit -m "feat: add residence sharing (share code, join, user management) and contractor .casera export/import" git add -A && git commit -m "feat: add residence sharing (share code, join, user management) and contractor .honeydue export/import"
``` ```
--- ---
@@ -489,7 +489,7 @@ export async function deleteAccount(): Promise<MessageResponse> {
### Verify build ### Verify build
```bash ```bash
cd /Users/treyt/Desktop/code/MyCrib/myCribAPI-Web && npm run build cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build
``` ```
### Commit ### Commit
@@ -560,7 +560,7 @@ npx shadcn@latest add switch
### Verify build ### Verify build
```bash ```bash
cd /Users/treyt/Desktop/code/MyCrib/myCribAPI-Web && npm run build cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build
``` ```
### Commit ### Commit
@@ -623,11 +623,11 @@ export const useOnboardingStore = create<OnboardingState>()((set) => ({
- Clean, centered layout (no sidebar or app shell) - Clean, centered layout (no sidebar or app shell)
- Progress indicator (step dots or progress bar) - Progress indicator (step dots or progress bar)
- Casera logo at top - honeyDue logo at top
### Steps ### Steps
**Step 0: Welcome** — "Welcome to Casera!" message, illustration, "Get Started" button **Step 0: Welcome** — "Welcome to honeyDue!" message, illustration, "Get Started" button
**Step 1: Choose Path** — Two cards: "Create a new residence" (House icon) and "Join an existing residence" (Users icon). Clicking sets path and advances. **Step 1: Choose Path** — Two cards: "Create a new residence" (House icon) and "Join an existing residence" (Users icon). Clicking sets path and advances.
@@ -637,7 +637,7 @@ export const useOnboardingStore = create<OnboardingState>()((set) => ({
- **Step 4a: Complete** — "You're all set!" Redirect to `/app/residences/${id}` - **Step 4a: Complete** — "You're all set!" Redirect to `/app/residences/${id}`
**Path B — Join:** **Path B — Join:**
- **Step 2b: Join Residence** — Code input (6-char) or .casera file import. On submit: joins via API, advances. - **Step 2b: Join Residence** — Code input (6-char) or .honeydue file import. On submit: joins via API, advances.
- **Step 3b: Complete** — "Welcome to the residence!" Redirect to residence detail. - **Step 3b: Complete** — "Welcome to the residence!" Redirect to residence detail.
### Onboarding trigger ### Onboarding trigger
@@ -649,7 +649,7 @@ For now, just mark `localStorage.setItem('onboarding_complete', 'true')` after c
### Verify build ### Verify build
```bash ```bash
cd /Users/treyt/Desktop/code/MyCrib/myCribAPI-Web && npm run build cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build
``` ```
### Commit ### Commit
@@ -714,7 +714,7 @@ On residence detail page (`src/app/app/residences/[id]/page.tsx`), add a "Downlo
### Verify build ### Verify build
```bash ```bash
cd /Users/treyt/Desktop/code/MyCrib/myCribAPI-Web && npm run build cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build
``` ```
### Commit ### Commit
@@ -732,7 +732,7 @@ git add -A && git commit -m "feat: add enhanced dashboard with charts and task r
### Step 1: Full build verification ### Step 1: Full build verification
```bash ```bash
cd /Users/treyt/Desktop/code/MyCrib/myCribAPI-Web && npm run build cd /Users/treyt/Desktop/code/HoneyDue/honeyDueAPI-Web && npm run build
``` ```
### Step 2: Route verification ### Step 2: Route verification
@@ -766,8 +766,8 @@ git add -A && git commit -m "feat: complete Phase 3 — advanced features integr
At the end of Phase 3, verify: At the end of Phase 3, verify:
- [ ] **Residence sharing**: generate share code, copy, join with code, manage users (list/remove) - [ ] **Residence sharing**: generate share code, copy, join with code, manage users (list/remove)
- [ ] **Contractor sharing**: .casera file export from detail, import on list page - [ ] **Contractor sharing**: .honeydue file export from detail, import on list page
- [ ] **.casera files**: download as JSON, import via drag-and-drop - [ ] **.honeydue files**: download as JSON, import via drag-and-drop
- [ ] **Subscription**: status display with usage bars, feature comparison table, upgrade CTA - [ ] **Subscription**: status display with usage bars, feature comparison table, upgrade CTA
- [ ] **Feature gating**: upgrade prompt dialog available for tier limit enforcement - [ ] **Feature gating**: upgrade prompt dialog available for tier limit enforcement
- [ ] **Notification preferences**: toggle switches per notification type, saves immediately - [ ] **Notification preferences**: toggle switches per notification type, saves immediately
+1 -1
View File
@@ -11,7 +11,7 @@ const nextConfig: NextConfig = {
remotePatterns: [ remotePatterns: [
{ {
protocol: "https", protocol: "https",
hostname: "casera.treytartt.com", hostname: "honeyDue.treytartt.com",
}, },
], ],
}, },
+2 -2
View File
@@ -1,11 +1,11 @@
{ {
"name": "casera-web", "name": "honeydue-web",
"version": "0.1.0", "version": "0.1.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "casera-web", "name": "honeydue-web",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@dnd-kit/core": "^6.3.1", "@dnd-kit/core": "^6.3.1",
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"name": "casera-web", "name": "honeydue-web",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
+3 -3
View File
@@ -26,13 +26,13 @@ export default function AuthLayout({ children }: { children: React.ReactNode })
<Link href="/" className="flex items-center gap-2.5"> <Link href="/" className="flex items-center gap-2.5">
<Image <Image
src="/logo.png" src="/logo.png"
alt="Casera" alt="honeyDue"
width={36} width={36}
height={36} height={36}
className="rounded-lg" className="rounded-lg"
/> />
<span className="font-heading text-xl font-bold text-white"> <span className="font-heading text-xl font-bold text-white">
Casera honeyDue
</span> </span>
</Link> </Link>
</div> </div>
@@ -49,7 +49,7 @@ export default function AuthLayout({ children }: { children: React.ReactNode })
</div> </div>
<p className="relative text-xs text-[#8A8F87]"> <p className="relative text-xs text-[#8A8F87]">
&copy; {new Date().getFullYear()} Casera &copy; {new Date().getFullYear()} honeyDue
</p> </p>
</div> </div>
+1 -1
View File
@@ -47,7 +47,7 @@ export default function RegisterPage() {
return ( return (
<AuthFormWrapper <AuthFormWrapper
title="Create account" title="Create account"
subtitle="Get started with Casera" subtitle="Get started with honeyDue"
footer={ footer={
<p> <p>
Already have an account?{" "} Already have an account?{" "}
+2 -2
View File
@@ -11,9 +11,9 @@ import { NextRequest, NextResponse } from 'next/server';
const API_BASE_URL = const API_BASE_URL =
process.env.API_URL || process.env.API_URL ||
process.env.NEXT_PUBLIC_API_URL || process.env.NEXT_PUBLIC_API_URL ||
'https://casera.treytartt.com/api'; 'https://honeyDue.treytartt.com/api';
const COOKIE_NAME = 'casera-token'; const COOKIE_NAME = 'honeydue-token';
const COOKIE_MAX_AGE = 60 * 60 * 24 * 30; // 30 days const COOKIE_MAX_AGE = 60 * 60 * 24 * 30; // 30 days
export async function POST(request: NextRequest) { export async function POST(request: NextRequest) {
+2 -2
View File
@@ -11,9 +11,9 @@ import { NextRequest, NextResponse } from 'next/server';
const API_BASE_URL = const API_BASE_URL =
process.env.API_URL || process.env.API_URL ||
process.env.NEXT_PUBLIC_API_URL || process.env.NEXT_PUBLIC_API_URL ||
'https://casera.treytartt.com/api'; 'https://honeyDue.treytartt.com/api';
const COOKIE_NAME = 'casera-token'; const COOKIE_NAME = 'honeydue-token';
export async function POST(request: NextRequest) { export async function POST(request: NextRequest) {
try { try {
+2 -2
View File
@@ -11,9 +11,9 @@ import { NextRequest, NextResponse } from 'next/server';
const API_BASE_URL = const API_BASE_URL =
process.env.API_URL || process.env.API_URL ||
process.env.NEXT_PUBLIC_API_URL || process.env.NEXT_PUBLIC_API_URL ||
'https://casera.treytartt.com/api'; 'https://honeyDue.treytartt.com/api';
const COOKIE_NAME = 'casera-token'; const COOKIE_NAME = 'honeydue-token';
export async function GET(_request: NextRequest) { export async function GET(_request: NextRequest) {
try { try {
+4 -4
View File
@@ -5,18 +5,18 @@ import { NextRequest, NextResponse } from 'next/server';
// Catch-all proxy route handler // Catch-all proxy route handler
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Every authenticated client-side API call goes through this proxy. // Every authenticated client-side API call goes through this proxy.
// It reads the `casera-token` httpOnly cookie and forwards the request to the // It reads the `honeydue-token` httpOnly cookie and forwards the request to the
// Go API with an Authorization header. // Go API with an Authorization header.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const API_BASE_URL = const API_BASE_URL =
process.env.API_URL || process.env.API_URL ||
process.env.NEXT_PUBLIC_API_URL || process.env.NEXT_PUBLIC_API_URL ||
'https://casera.treytartt.com/api'; 'https://honeyDue.treytartt.com/api';
/** /**
* Build the target URL from the catch-all path segments. * Build the target URL from the catch-all path segments.
* e.g. /api/proxy/tasks/123/ -> https://casera.treytartt.com/api/tasks/123/ * e.g. /api/proxy/tasks/123/ -> https://honeyDue.treytartt.com/api/tasks/123/
*/ */
function buildTargetUrl(request: NextRequest, pathSegments: string[]): string { function buildTargetUrl(request: NextRequest, pathSegments: string[]): string {
const path = `/${pathSegments.join('/')}`; const path = `/${pathSegments.join('/')}`;
@@ -53,7 +53,7 @@ async function buildHeaders(request: NextRequest): Promise<Headers> {
// Attach auth token from httpOnly cookie // Attach auth token from httpOnly cookie
const cookieStore = await cookies(); const cookieStore = await cookies();
const token = cookieStore.get('casera-token')?.value; const token = cookieStore.get('honeydue-token')?.value;
if (token) { if (token) {
headers.set('Authorization', `Token ${token}`); headers.set('Authorization', `Token ${token}`);
} }
+3 -3
View File
@@ -14,7 +14,7 @@ import { LoadingSkeleton } from "@/components/shared/loading-skeleton";
import { ErrorBanner } from "@/components/shared/error-banner"; import { ErrorBanner } from "@/components/shared/error-banner";
import { ConfirmDialog } from "@/components/shared/confirm-dialog"; import { ConfirmDialog } from "@/components/shared/confirm-dialog";
import { StarRating } from "@/components/shared/star-rating"; import { StarRating } from "@/components/shared/star-rating";
import { downloadCaseraFile } from "@/components/sharing/casera-file-handler"; import { downloadHoneyDueFile } from "@/components/sharing/honeydue-file-handler";
import { import {
useContractor, useContractor,
useContractorTasks, useContractorTasks,
@@ -88,7 +88,7 @@ export default function ContractorDetailPage({
size="sm" size="sm"
onClick={() => { onClick={() => {
const exportData = { const exportData = {
type: "casera_contractor_share", type: "honeydue_contractor_share",
version: 1, version: 1,
contractor: { contractor: {
name: contractor.name, name: contractor.name,
@@ -107,7 +107,7 @@ export default function ContractorDetailPage({
exported_at: new Date().toISOString(), exported_at: new Date().toISOString(),
}; };
const safeName = contractor.name.replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase(); const safeName = contractor.name.replace(/[^a-zA-Z0-9_-]/g, "_").toLowerCase();
downloadCaseraFile(exportData, `${safeName}-contractor`); downloadHoneyDueFile(exportData, `${safeName}-contractor`);
}} }}
> >
<FileDown className="size-4 mr-2" /> <FileDown className="size-4 mr-2" />
+7 -7
View File
@@ -11,7 +11,7 @@ import { PageHeader } from "@/components/shared/page-header";
import { LoadingSkeleton } from "@/components/shared/loading-skeleton"; import { LoadingSkeleton } from "@/components/shared/loading-skeleton";
import { ErrorBanner } from "@/components/shared/error-banner"; import { ErrorBanner } from "@/components/shared/error-banner";
import { EmptyState } from "@/components/shared/empty-state"; import { EmptyState } from "@/components/shared/empty-state";
import { CaseraFileImport } from "@/components/sharing/casera-file-handler"; import { HoneyDueFileImport } from "@/components/sharing/honeydue-file-handler";
import { ContractorCard } from "@/components/contractors/contractor-card"; import { ContractorCard } from "@/components/contractors/contractor-card";
import { ContractorFilters } from "@/components/contractors/contractor-filters"; import { ContractorFilters } from "@/components/contractors/contractor-filters";
import { useContractors, useToggleFavorite, useCreateContractor } from "@/lib/hooks/use-contractors"; import { useContractors, useToggleFavorite, useCreateContractor } from "@/lib/hooks/use-contractors";
@@ -66,7 +66,7 @@ export default function ContractorsPage() {
typeof data === "object" && typeof data === "object" &&
data !== null && data !== null &&
"type" in data && "type" in data &&
(data as Record<string, unknown>).type === "casera_contractor_share" && (data as Record<string, unknown>).type === "honeydue_contractor_share" &&
"contractor" in data "contractor" in data
) { ) {
const contractor = (data as Record<string, unknown>).contractor as Record<string, unknown>; const contractor = (data as Record<string, unknown>).contractor as Record<string, unknown>;
@@ -97,7 +97,7 @@ export default function ContractorsPage() {
}, },
); );
} else { } else {
setImportError("Invalid .casera file. Expected a contractor share file."); setImportError("Invalid .honeydue file. Expected a contractor share file.");
} }
} }
@@ -118,7 +118,7 @@ export default function ContractorsPage() {
}} }}
> >
<Upload className="size-4 mr-2" /> <Upload className="size-4 mr-2" />
Import .casera Import .honeydue
</Button> </Button>
</PageHeader> </PageHeader>
@@ -168,16 +168,16 @@ export default function ContractorsPage() {
</> </>
)} )}
{/* Import .casera dialog */} {/* Import .honeydue dialog */}
<Dialog open={importOpen} onOpenChange={setImportOpen}> <Dialog open={importOpen} onOpenChange={setImportOpen}>
<DialogContent> <DialogContent>
<DialogHeader> <DialogHeader>
<DialogTitle>Import Contractor</DialogTitle> <DialogTitle>Import Contractor</DialogTitle>
<DialogDescription> <DialogDescription>
Import a contractor from a .casera file shared with you. Import a contractor from a .honeydue file shared with you.
</DialogDescription> </DialogDescription>
</DialogHeader> </DialogHeader>
<CaseraFileImport onImport={handleContractorImport} /> <HoneyDueFileImport onImport={handleContractorImport} />
{importError && ( {importError && (
<p className="text-sm text-destructive">{importError}</p> <p className="text-sm text-destructive">{importError}</p>
)} )}
+1 -1
View File
@@ -281,7 +281,7 @@ export default function DashboardPage() {
<Home className="size-9 text-primary" /> <Home className="size-9 text-primary" />
</div> </div>
<h1 className="font-heading text-3xl font-bold tracking-tight"> <h1 className="font-heading text-3xl font-bold tracking-tight">
Welcome to Casera{name ? `, ${name}` : ""} Welcome to honeyDue{name ? `, ${name}` : ""}
</h1> </h1>
<p className="text-muted-foreground mt-3 max-w-md text-base leading-relaxed"> <p className="text-muted-foreground mt-3 max-w-md text-base leading-relaxed">
The easiest way to keep your home running smoothly. The easiest way to keep your home running smoothly.
+6 -6
View File
@@ -9,7 +9,7 @@ import { LoadingSkeleton } from "@/components/shared/loading-skeleton";
import { ErrorBanner } from "@/components/shared/error-banner"; import { ErrorBanner } from "@/components/shared/error-banner";
import { ShareCodeDisplay } from "@/components/sharing/share-code-display"; import { ShareCodeDisplay } from "@/components/sharing/share-code-display";
import { UserManagement } from "@/components/sharing/user-management"; import { UserManagement } from "@/components/sharing/user-management";
import { CaseraFileExport } from "@/components/sharing/casera-file-handler"; import { HoneyDueFileExport } from "@/components/sharing/honeydue-file-handler";
import { useResidence } from "@/lib/hooks/use-residences"; import { useResidence } from "@/lib/hooks/use-residences";
import { useDataProvider } from "@/lib/demo/data-provider-context"; import { useDataProvider } from "@/lib/demo/data-provider-context";
@@ -46,7 +46,7 @@ export default function ResidenceSharePage({ params }: SharePageProps) {
// Build the exportable residence data // Build the exportable residence data
const exportData = { const exportData = {
type: "casera_residence_share", type: "honeydue_residence_share",
version: 1, version: 1,
residence: { residence: {
name: residence.name, name: residence.name,
@@ -87,16 +87,16 @@ export default function ResidenceSharePage({ params }: SharePageProps) {
<ShareCodeDisplay residenceId={id} /> <ShareCodeDisplay residenceId={id} />
)} )}
{/* Export .casera file */} {/* Export .honeydue file */}
{residence.is_owner && ( {residence.is_owner && (
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<CaseraFileExport <HoneyDueFileExport
data={exportData} data={exportData}
filename={`${safeFilename}-residence`} filename={`${safeFilename}-residence`}
label="Export Residence (.casera)" label="Export Residence (.honeydue)"
/> />
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Download residence data as a portable .casera file. Download residence data as a portable .honeydue file.
</p> </p>
</div> </div>
)} )}
+5 -5
View File
@@ -11,7 +11,7 @@ import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { PageHeader } from "@/components/shared/page-header"; import { PageHeader } from "@/components/shared/page-header";
import { ErrorBanner } from "@/components/shared/error-banner"; import { ErrorBanner } from "@/components/shared/error-banner";
import { CaseraFileImport } from "@/components/sharing/casera-file-handler"; import { HoneyDueFileImport } from "@/components/sharing/honeydue-file-handler";
import { useJoinResidence } from "@/lib/hooks/use-sharing"; import { useJoinResidence } from "@/lib/hooks/use-sharing";
import { useDataProvider } from "@/lib/demo/data-provider-context"; import { useDataProvider } from "@/lib/demo/data-provider-context";
@@ -61,7 +61,7 @@ export default function JoinResidencePage() {
}); });
} else { } else {
setFileError( setFileError(
"Invalid .casera file. Expected a share package with a code field.", "Invalid .honeydue file. Expected a share package with a code field.",
); );
} }
} }
@@ -126,13 +126,13 @@ export default function JoinResidencePage() {
{/* File import */} {/* File import */}
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle>Import .casera File</CardTitle> <CardTitle>Import .honeydue File</CardTitle>
<CardDescription> <CardDescription>
If you received a .casera share package file, import it here. If you received a .honeydue share package file, import it here.
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent className="space-y-3"> <CardContent className="space-y-3">
<CaseraFileImport onImport={handleFileImport} /> <HoneyDueFileImport onImport={handleFileImport} />
{fileError && ( {fileError && (
<p className="text-sm text-destructive">{fileError}</p> <p className="text-sm text-destructive">{fileError}</p>
)} )}
+4 -4
View File
@@ -1,13 +1,13 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Try Casera — Free Demo", title: "Try honeyDue — Free Demo",
description: description:
"Try Casera without an account. Manage tasks, contractors, and documents in a live demo.", "Try honeyDue without an account. Manage tasks, contractors, and documents in a live demo.",
openGraph: { openGraph: {
title: "Try Casera — Free Demo", title: "Try honeyDue — Free Demo",
description: description:
"Try Casera without an account. Manage tasks, contractors, and documents in a live demo.", "Try honeyDue without an account. Manage tasks, contractors, and documents in a live demo.",
type: "website", type: "website",
}, },
}; };
+3 -3
View File
@@ -16,19 +16,19 @@ export default function DemoLandingPage() {
<Link href="/" className="inline-flex items-center gap-2.5 mb-10"> <Link href="/" className="inline-flex items-center gap-2.5 mb-10">
<Image <Image
src="/logo.png" src="/logo.png"
alt="Casera" alt="honeyDue"
width={36} width={36}
height={36} height={36}
className="rounded-lg" className="rounded-lg"
/> />
<span className="font-heading text-2xl font-bold tracking-tight text-[#2D3436]"> <span className="font-heading text-2xl font-bold tracking-tight text-[#2D3436]">
Casera honeyDue
</span> </span>
</Link> </Link>
{/* Hero */} {/* Hero */}
<h1 className="font-heading text-4xl font-bold tracking-tight text-[#2D3436]"> <h1 className="font-heading text-4xl font-bold tracking-tight text-[#2D3436]">
See Casera in action See honeyDue in action
</h1> </h1>
<p className="mt-4 text-lg text-[#8A8F87] leading-relaxed"> <p className="mt-4 text-lg text-[#8A8F87] leading-relaxed">
Explore the full app with sample data. No account needed Explore the full app with sample data. No account needed
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

+5 -5
View File
@@ -26,21 +26,21 @@ const geistMono = Geist_Mono({
export const metadata: Metadata = { export const metadata: Metadata = {
title: { title: {
default: "Casera — Home Maintenance Made Simple", default: "honeyDue — Home Maintenance Made Simple",
template: "%s | Casera", template: "%s | honeyDue",
}, },
description: description:
"Track tasks, organize contractors, store documents. Manage your home maintenance in one place.", "Track tasks, organize contractors, store documents. Manage your home maintenance in one place.",
openGraph: { openGraph: {
title: "Casera — Home Maintenance Made Simple", title: "honeyDue — Home Maintenance Made Simple",
description: description:
"Track tasks, organize contractors, store documents. Manage your home maintenance in one place.", "Track tasks, organize contractors, store documents. Manage your home maintenance in one place.",
type: "website", type: "website",
siteName: "Casera", siteName: "honeyDue",
}, },
twitter: { twitter: {
card: "summary_large_image", card: "summary_large_image",
title: "Casera — Home Maintenance Made Simple", title: "honeyDue — Home Maintenance Made Simple",
description: "Home Maintenance Made Simple", description: "Home Maintenance Made Simple",
}, },
}; };
+1 -1
View File
@@ -41,7 +41,7 @@ export default function OnboardingLayout({
{/* Logo */} {/* Logo */}
<div className="mb-2"> <div className="mb-2">
<h1 className="text-2xl font-bold tracking-tight text-primary"> <h1 className="text-2xl font-bold tracking-tight text-primary">
Casera honeyDue
</h1> </h1>
</div> </div>
+6 -6
View File
@@ -89,13 +89,13 @@ export default function HomePage() {
<Link href="/" className="flex items-center gap-2.5"> <Link href="/" className="flex items-center gap-2.5">
<Image <Image
src="/logo.png" src="/logo.png"
alt="Casera" alt="honeyDue"
width={32} width={32}
height={32} height={32}
className="rounded-lg" className="rounded-lg"
/> />
<span className="font-heading text-xl font-bold tracking-tight text-[#2D3436]"> <span className="font-heading text-xl font-bold tracking-tight text-[#2D3436]">
Casera honeyDue
</span> </span>
</Link> </Link>
@@ -272,7 +272,7 @@ export default function HomePage() {
Everything your home needs, nothing it doesn&apos;t. Everything your home needs, nothing it doesn&apos;t.
</h2> </h2>
<p className="mt-4 text-lg text-[#8A8F87] leading-relaxed"> <p className="mt-4 text-lg text-[#8A8F87] leading-relaxed">
Casera brings all your home maintenance into one clear, honeyDue brings all your home maintenance into one clear,
organized space. No bloat, no learning curve. organized space. No bloat, no learning curve.
</p> </p>
</div> </div>
@@ -406,13 +406,13 @@ export default function HomePage() {
<Link href="/" className="flex items-center gap-2.5 mb-4"> <Link href="/" className="flex items-center gap-2.5 mb-4">
<Image <Image
src="/logo.png" src="/logo.png"
alt="Casera" alt="honeyDue"
width={28} width={28}
height={28} height={28}
className="rounded-md" className="rounded-md"
/> />
<span className="font-heading text-lg font-bold text-white"> <span className="font-heading text-lg font-bold text-white">
Casera honeyDue
</span> </span>
</Link> </Link>
<p className="text-sm leading-relaxed"> <p className="text-sm leading-relaxed">
@@ -485,7 +485,7 @@ export default function HomePage() {
<div className="mt-16 pt-8 border-t border-white/5 flex flex-col sm:flex-row items-center justify-between gap-4"> <div className="mt-16 pt-8 border-t border-white/5 flex flex-col sm:flex-row items-center justify-between gap-4">
<p className="text-xs"> <p className="text-xs">
&copy; {new Date().getFullYear()} Casera. All rights reserved. &copy; {new Date().getFullYear()} honeyDue. All rights reserved.
</p> </p>
<p className="text-xs"> <p className="text-xs">
Made for homeowners, by homeowners. Made for homeowners, by homeowners.
+1 -1
View File
@@ -11,7 +11,7 @@ export default function SubscriptionSuccessPage() {
<h2 className="text-lg font-semibold">Thank you!</h2> <h2 className="text-lg font-semibold">Thank you!</h2>
<p className="mt-2 text-muted-foreground text-center max-w-md"> <p className="mt-2 text-muted-foreground text-center max-w-md">
Your Pro subscription is now active. Enjoy unlimited access to all Your Pro subscription is now active. Enjoy unlimited access to all
Casera features. honeyDue features.
</p> </p>
<Button asChild className="mt-6"> <Button asChild className="mt-6">
<Link href="/app/settings/subscription">Back to Settings</Link> <Link href="/app/settings/subscription">Back to Settings</Link>
+1 -1
View File
@@ -13,7 +13,7 @@ export function DemoBanner() {
return ( return (
<div className="sticky top-0 z-50 flex items-center justify-center gap-3 border-b border-brand-clay/20 bg-brand-clay-light/80 px-4 py-2.5 text-sm text-[#92400E] backdrop-blur-xl"> <div className="sticky top-0 z-50 flex items-center justify-center gap-3 border-b border-brand-clay/20 bg-brand-clay-light/80 px-4 py-2.5 text-sm text-[#92400E] backdrop-blur-xl">
<p className="font-medium"> <p className="font-medium">
You&apos;re exploring Casera in demo mode. Changes aren&apos;t saved. You&apos;re exploring honeyDue in demo mode. Changes aren&apos;t saved.
</p> </p>
<Button size="xs" className="rounded-full" asChild> <Button size="xs" className="rounded-full" asChild>
<Link href="/register">Sign Up Free</Link> <Link href="/register">Sign Up Free</Link>
+2 -2
View File
@@ -23,13 +23,13 @@ export function AuthFormWrapper({
<Link href="/" className="flex items-center gap-2.5"> <Link href="/" className="flex items-center gap-2.5">
<Image <Image
src="/logo.png" src="/logo.png"
alt="Casera" alt="honeyDue"
width={32} width={32}
height={32} height={32}
className="rounded-lg" className="rounded-lg"
/> />
<span className="font-heading text-xl font-bold text-foreground"> <span className="font-heading text-xl font-bold text-foreground">
Casera honeyDue
</span> </span>
</Link> </Link>
</div> </div>
+2 -2
View File
@@ -22,13 +22,13 @@ export function Sidebar() {
<Link href={basePath} className="flex items-center gap-2.5 group"> <Link href={basePath} className="flex items-center gap-2.5 group">
<Image <Image
src="/logo.png" src="/logo.png"
alt="Casera" alt="honeyDue"
width={32} width={32}
height={32} height={32}
className="rounded-lg transition-transform group-hover:scale-105" className="rounded-lg transition-transform group-hover:scale-105"
/> />
<span className="hidden lg:inline font-heading text-lg font-bold text-foreground tracking-tight"> <span className="hidden lg:inline font-heading text-lg font-bold text-foreground tracking-tight">
Casera honeyDue
</span> </span>
</Link> </Link>
</div> </div>
+2 -2
View File
@@ -49,13 +49,13 @@ export function TopBar() {
<Link href={basePath} className="flex items-center gap-2.5 shrink-0 group"> <Link href={basePath} className="flex items-center gap-2.5 shrink-0 group">
<Image <Image
src="/logo.png" src="/logo.png"
alt="Casera" alt="honeyDue"
width={32} width={32}
height={32} height={32}
className="rounded-lg transition-transform group-hover:scale-105" className="rounded-lg transition-transform group-hover:scale-105"
/> />
<span className="font-heading text-xl font-bold text-foreground tracking-tight"> <span className="font-heading text-xl font-bold text-foreground tracking-tight">
Casera honeyDue
</span> </span>
</Link> </Link>
+2 -2
View File
@@ -9,8 +9,8 @@ export function WelcomeStep() {
const user = useAuthStore((s) => s.user); const user = useAuthStore((s) => s.user);
const greeting = user?.first_name const greeting = user?.first_name
? `Welcome to Casera, ${user.first_name}!` ? `Welcome to honeyDue, ${user.first_name}!`
: "Welcome to Casera!"; : "Welcome to honeyDue!";
return ( return (
<div className="flex flex-col items-center text-center space-y-6 py-12"> <div className="flex flex-col items-center text-center space-y-6 py-12">
+1 -1
View File
@@ -44,7 +44,7 @@ export function UpgradePrompt({ open, onOpenChange, feature, limitInfo }: Upgrad
features. features.
</p> </p>
<p> <p>
Subscriptions are managed through the Casera iOS or Android app. Subscriptions are managed through the honeyDue iOS or Android app.
</p> </p>
</div> </div>
@@ -9,16 +9,16 @@ import { Button } from "@/components/ui/button";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** /**
* Generates a `.casera` file from the given data object and triggers a download. * Generates a `.honeydue` file from the given data object and triggers a download.
*/ */
export function downloadCaseraFile(data: object, filename: string) { export function downloadHoneyDueFile(data: object, filename: string) {
const json = JSON.stringify(data, null, 2); const json = JSON.stringify(data, null, 2);
const blob = new Blob([json], { type: "application/json" }); const blob = new Blob([json], { type: "application/json" });
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
const anchor = document.createElement("a"); const anchor = document.createElement("a");
anchor.href = url; anchor.href = url;
anchor.download = filename.endsWith(".casera") ? filename : `${filename}.casera`; anchor.download = filename.endsWith(".honeydue") ? filename : `${filename}.honeydue`;
document.body.appendChild(anchor); document.body.appendChild(anchor);
anchor.click(); anchor.click();
@@ -31,12 +31,12 @@ export function downloadCaseraFile(data: object, filename: string) {
// Import component // Import component
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
interface CaseraFileImportProps { interface HoneyDueFileImportProps {
onImport: (data: unknown) => void; onImport: (data: unknown) => void;
accept?: string; accept?: string;
} }
export function CaseraFileImport({ onImport, accept = ".casera" }: CaseraFileImportProps) { export function HoneyDueFileImport({ onImport, accept = ".honeydue" }: HoneyDueFileImportProps) {
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const [dragActive, setDragActive] = useState(false); const [dragActive, setDragActive] = useState(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
@@ -58,7 +58,7 @@ export function CaseraFileImport({ onImport, accept = ".casera" }: CaseraFileImp
const parsed = JSON.parse(text); const parsed = JSON.parse(text);
onImport(parsed); onImport(parsed);
} catch { } catch {
setError("Invalid .casera file. Could not parse contents."); setError("Invalid .honeydue file. Could not parse contents.");
setFileName(null); setFileName(null);
} }
}; };
@@ -109,7 +109,7 @@ export function CaseraFileImport({ onImport, accept = ".casera" }: CaseraFileImp
<Upload className="size-8 text-muted-foreground" /> <Upload className="size-8 text-muted-foreground" />
<div className="text-center"> <div className="text-center">
<p className="text-sm font-medium"> <p className="text-sm font-medium">
Drop a .casera file here or click to browse Drop a .honeydue file here or click to browse
</p> </p>
{fileName && ( {fileName && (
<p className="text-xs text-muted-foreground mt-1"> <p className="text-xs text-muted-foreground mt-1">
@@ -136,18 +136,18 @@ export function CaseraFileImport({ onImport, accept = ".casera" }: CaseraFileImp
// Export button component (convenience wrapper) // Export button component (convenience wrapper)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
interface CaseraFileExportProps { interface HoneyDueFileExportProps {
data: object; data: object;
filename: string; filename: string;
label?: string; label?: string;
} }
export function CaseraFileExport({ data, filename, label = "Export .casera" }: CaseraFileExportProps) { export function HoneyDueFileExport({ data, filename, label = "Export .honeydue" }: HoneyDueFileExportProps) {
return ( return (
<Button <Button
variant="outline" variant="outline"
size="sm" size="sm"
onClick={() => downloadCaseraFile(data, filename)} onClick={() => downloadHoneyDueFile(data, filename)}
> >
<FileDown className="size-4 mr-2" /> <FileDown className="size-4 mr-2" />
{label} {label}
+5 -5
View File
@@ -1,13 +1,13 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Base API client for Casera web app // Base API client for honeyDue web app
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// All client-side requests go through Next.js API route handlers (proxy). // All client-side requests go through Next.js API route handlers (proxy).
// The proxy reads the httpOnly `casera-token` cookie and forwards it to the // The proxy reads the httpOnly `honeydue-token` cookie and forwards it to the
// Go API as an Authorization header. This avoids exposing the token to JS. // Go API as an Authorization header. This avoids exposing the token to JS.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const API_BASE_URL = const API_BASE_URL =
process.env.NEXT_PUBLIC_API_URL || 'https://casera.treytartt.com/api'; process.env.NEXT_PUBLIC_API_URL || 'https://honeyDue.treytartt.com/api';
/** /**
* Server-only base URL. Falls back to the public one so that server * Server-only base URL. Falls back to the public one so that server
@@ -86,7 +86,7 @@ export async function apiFetch<T>(
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** /**
* Server-side fetch that reads the auth token from the `casera-token` cookie * Server-side fetch that reads the auth token from the `honeydue-token` cookie
* and calls the Go API directly (no proxy hop). * and calls the Go API directly (no proxy hop).
* *
* Only use this inside: * Only use this inside:
@@ -102,7 +102,7 @@ export async function serverFetch<T>(
// (the function itself should only be *called* on the server). // (the function itself should only be *called* on the server).
const { cookies } = await import('next/headers'); const { cookies } = await import('next/headers');
const cookieStore = await cookies(); const cookieStore = await cookies();
const token = cookieStore.get('casera-token')?.value; const token = cookieStore.get('honeydue-token')?.value;
const normalized = path.endsWith('/') ? path : `${path}/`; const normalized = path.endsWith('/') ? path : `${path}/`;
const url = `${SERVER_API_URL}${normalized}`; const url = `${SERVER_API_URL}${normalized}`;
+1 -1
View File
@@ -1,5 +1,5 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Casera API Client - barrel export // honeyDue API Client - barrel export
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Usage: // Usage:
// import { auth, residences, tasks } from '@/lib/api'; // import { auth, residences, tasks } from '@/lib/api';
+2 -2
View File
@@ -258,7 +258,7 @@ export const demoProvider: DataProvider = {
{ {
id: 1, id: 1,
username: 'demo_user', username: 'demo_user',
email: 'demo@casera.app', email: 'demo@honeyDue.treytartt.com',
first_name: 'Demo', first_name: 'Demo',
last_name: 'User', last_name: 'User',
is_owner: true, is_owner: true,
@@ -273,7 +273,7 @@ export const demoProvider: DataProvider = {
return { return {
message: 'Report generated (demo)', message: 'Report generated (demo)',
residence_name: r?.name ?? 'Demo Residence', residence_name: r?.name ?? 'Demo Residence',
recipient_email: 'demo@casera.app', recipient_email: 'demo@honeyDue.treytartt.com',
pdf_generated: true, pdf_generated: true,
email_sent: false, email_sent: false,
report: {}, report: {},
+1 -1
View File
@@ -86,7 +86,7 @@ export const demoNotifications: NotificationResponse[] = [
}, },
{ {
id: 9, id: 9,
title: 'Welcome to Casera!', title: 'Welcome to honeyDue!',
body: 'Start by adding your first residence to track home maintenance.', body: 'Start by adding your first residence to track home maintenance.',
notification_type: 'system', notification_type: 'system',
is_read: true, is_read: true,
+1 -1
View File
@@ -3,7 +3,7 @@ import type { UserResponse } from '@/lib/api/auth';
export const demoUser: UserResponse = { export const demoUser: UserResponse = {
id: 1, id: 1,
username: 'demo_user', username: 'demo_user',
email: 'demo@casera.app', email: 'demo@honeyDue.treytartt.com',
first_name: 'Demo', first_name: 'Demo',
last_name: 'User', last_name: 'User',
is_email_verified: true, is_email_verified: true,
+1 -1
View File
@@ -19,7 +19,7 @@ export interface ThemeDefinition {
} }
/** /**
* Single "Warm Sage" theme — the Casera brand palette. * Single "Warm Sage" theme — the honeyDue brand palette.
*/ */
export const themes: ThemeDefinition[] = [ export const themes: ThemeDefinition[] = [
{ {
+1 -1
View File
@@ -1,6 +1,6 @@
// ============================================================================ // ============================================================================
// API-level types: errors, pagination, common response wrappers // API-level types: errors, pagination, common response wrappers
// Generated from myCribAPI-go/internal/dto/responses/auth.go (ErrorResponse, MessageResponse) // Generated from honeyDueAPI-go/internal/dto/responses/auth.go (ErrorResponse, MessageResponse)
// ============================================================================ // ============================================================================
/** /**
+2 -2
View File
@@ -1,8 +1,8 @@
// ============================================================================ // ============================================================================
// Auth request / response types // Auth request / response types
// Generated from: // Generated from:
// myCribAPI-go/internal/dto/requests/auth.go // honeyDueAPI-go/internal/dto/requests/auth.go
// myCribAPI-go/internal/dto/responses/auth.go // honeyDueAPI-go/internal/dto/responses/auth.go
// ============================================================================ // ============================================================================
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
+2 -2
View File
@@ -1,8 +1,8 @@
// ============================================================================ // ============================================================================
// Contractor request / response types // Contractor request / response types
// Generated from: // Generated from:
// myCribAPI-go/internal/dto/requests/contractor.go // honeyDueAPI-go/internal/dto/requests/contractor.go
// myCribAPI-go/internal/dto/responses/contractor.go // honeyDueAPI-go/internal/dto/responses/contractor.go
// ============================================================================ // ============================================================================
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
+3 -3
View File
@@ -1,9 +1,9 @@
// ============================================================================ // ============================================================================
// Document request / response types // Document request / response types
// Generated from: // Generated from:
// myCribAPI-go/internal/dto/requests/document.go // honeyDueAPI-go/internal/dto/requests/document.go
// myCribAPI-go/internal/dto/responses/document.go // honeyDueAPI-go/internal/dto/responses/document.go
// myCribAPI-go/internal/models/document.go (DocumentType enum) // honeyDueAPI-go/internal/models/document.go (DocumentType enum)
// ============================================================================ // ============================================================================
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
+5 -5
View File
@@ -1,11 +1,11 @@
// ============================================================================ // ============================================================================
// Static / lookup data types // Static / lookup data types
// Generated from: // Generated from:
// myCribAPI-go/internal/handlers/static_data_handler.go (SeededDataResponse) // honeyDueAPI-go/internal/handlers/static_data_handler.go (SeededDataResponse)
// myCribAPI-go/internal/dto/responses/residence.go (ResidenceTypeResponse) // honeyDueAPI-go/internal/dto/responses/residence.go (ResidenceTypeResponse)
// myCribAPI-go/internal/dto/responses/task.go (TaskCategory/Priority/Frequency) // honeyDueAPI-go/internal/dto/responses/task.go (TaskCategory/Priority/Frequency)
// myCribAPI-go/internal/dto/responses/contractor.go (ContractorSpecialtyResponse) // honeyDueAPI-go/internal/dto/responses/contractor.go (ContractorSpecialtyResponse)
// myCribAPI-go/internal/dto/responses/task_template.go (TaskTemplatesGroupedResponse) // honeyDueAPI-go/internal/dto/responses/task_template.go (TaskTemplatesGroupedResponse)
// ============================================================================ // ============================================================================
import type { ResidenceTypeResponse } from "./residence"; import type { ResidenceTypeResponse } from "./residence";
+2 -2
View File
@@ -1,8 +1,8 @@
// ============================================================================ // ============================================================================
// Notification request / response types // Notification request / response types
// Generated from: // Generated from:
// myCribAPI-go/internal/services/notification_service.go // honeyDueAPI-go/internal/services/notification_service.go
// myCribAPI-go/internal/models/notification.go (NotificationType enum) // honeyDueAPI-go/internal/models/notification.go (NotificationType enum)
// ============================================================================ // ============================================================================
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
+2 -2
View File
@@ -1,8 +1,8 @@
// ============================================================================ // ============================================================================
// Residence request / response types // Residence request / response types
// Generated from: // Generated from:
// myCribAPI-go/internal/dto/requests/residence.go // honeyDueAPI-go/internal/dto/requests/residence.go
// myCribAPI-go/internal/dto/responses/residence.go // honeyDueAPI-go/internal/dto/responses/residence.go
// ============================================================================ // ============================================================================
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
+2 -2
View File
@@ -1,8 +1,8 @@
// ============================================================================ // ============================================================================
// Subscription request / response types // Subscription request / response types
// Generated from: // Generated from:
// myCribAPI-go/internal/services/subscription_service.go // honeyDueAPI-go/internal/services/subscription_service.go
// myCribAPI-go/internal/models/subscription.go (SubscriptionTier enum) // honeyDueAPI-go/internal/models/subscription.go (SubscriptionTier enum)
// ============================================================================ // ============================================================================
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
+1 -1
View File
@@ -1,7 +1,7 @@
// ============================================================================ // ============================================================================
// Task template response types // Task template response types
// Generated from: // Generated from:
// myCribAPI-go/internal/dto/responses/task_template.go // honeyDueAPI-go/internal/dto/responses/task_template.go
// ============================================================================ // ============================================================================
import type { TaskCategoryResponse, TaskFrequencyResponse } from "./task"; import type { TaskCategoryResponse, TaskFrequencyResponse } from "./task";
+2 -2
View File
@@ -1,8 +1,8 @@
// ============================================================================ // ============================================================================
// Task request / response types // Task request / response types
// Generated from: // Generated from:
// myCribAPI-go/internal/dto/requests/task.go // honeyDueAPI-go/internal/dto/requests/task.go
// myCribAPI-go/internal/dto/responses/task.go // honeyDueAPI-go/internal/dto/responses/task.go
// ============================================================================ // ============================================================================
import type { TotalSummary } from "./residence"; import type { TotalSummary } from "./residence";
+1 -1
View File
@@ -2,7 +2,7 @@ import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server'; import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) { export function middleware(request: NextRequest) {
const token = request.cookies.get('casera-token')?.value; const token = request.cookies.get('honeydue-token')?.value;
const { pathname } = request.nextUrl; const { pathname } = request.nextUrl;
// Public paths that don't require auth // Public paths that don't require auth
+1 -1
View File
@@ -19,7 +19,7 @@ export const useThemeStore = create<ThemeState>()(
}, },
}), }),
{ {
name: "casera-theme", name: "honeydue-theme",
} }
) )
); );
+1 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Casera "Warm Sage" design system * honeyDue "Warm Sage" design system
* Single brand palette — light + dark mode * Single brand palette — light + dark mode
* Maps to shadcn/ui CSS variables and custom app variables * Maps to shadcn/ui CSS variables and custom app variables
*/ */