Commit Graph

24 Commits

Author SHA1 Message Date
Chandler Copeland
f82364d2c7 feat(04-01): create seed-forms script and npm run seed:forms command
- Create scripts/seed-forms.ts: reads seeds/forms/, upserts PDFs into form_templates via onConflictDoUpdate on filename
- Add seed:forms script to package.json with DOTENV_CONFIG_PATH=.env.local prefix
- Empty seeds/forms/ prints guidance message and exits 0 (monthly-sync workflow ready)
2026-03-19 21:33:02 -06:00
Chandler Copeland
bbbbdbed5e feat(04-01): add formTemplates table and extend documents schema
- Add formTemplates table (id text PK, name, filename unique, createdAt, updatedAt)
- Add formTemplateId (nullable FK) and filePath (nullable text) to documents table
- Generate and apply migration 0002_wealthy_zzzax.sql
- Create seeds/forms/.gitkeep to track seed directory in git
2026-03-19 21:32:30 -06:00
Chandler Copeland
b186ac5f38 feat(03-04): add client profile page with edit/delete and documents table
- Create ConfirmDialog component with overlay, title, message, cancel/confirm buttons
- Create ClientProfilePage server component (awaits params Promise — Next.js 16)
- Create ClientProfileClient client component with edit modal and delete confirmation
- Documents section uses DocumentsTable with showClientColumn={false}
- deleteClient called directly from async event handler in client component
2026-03-19 16:58:21 -06:00
Chandler Copeland
3fa2e1c424 feat(03-03): extend seed.ts with client and placeholder document rows
- Added import of clients, documents, inArray from drizzle-orm
- Seeds 2 clients: Sarah Johnson and Mike Torres (onConflictDoNothing)
- Queries back seeded client IDs, then seeds 4 placeholder documents
- Documents cover Signed/Sent/Draft statuses across both clients
- Seed is idempotent via onConflictDoNothing guard
2026-03-19 16:49:29 -06:00
Chandler Copeland
df1924acc4 feat(03-03): add Clients page with card grid and create modal
- ClientCard.tsx: server component with name, email, doc count, last activity; wrapped in Link to /portal/clients/[id]
- ClientModal.tsx: use client component with useActionState from react; supports create/edit modes via bind pattern; closes on success
- ClientsPageClient.tsx: use client wrapper holding isOpen modal state, renders card grid or empty state CTA
- clients/page.tsx: async server component fetching clients with docCount + lastActivity via Drizzle LEFT JOIN + GROUP BY
2026-03-19 16:47:28 -06:00
Chandler Copeland
e55d7a1de5 feat(03-03): add Dashboard page with filterable documents table
- Async server component queries all documents with LEFT JOIN to clients
- Filter state lives in URL (?status=Draft|Sent|Viewed|Signed) via DashboardFilters client component
- Rows filtered in JavaScript after fetch (tiny dataset in Phase 3)
- DashboardFilters extracted to _components/DashboardFilters.tsx (use client + useRouter)
- Displays agent first name extracted from session email
2026-03-19 16:46:26 -06:00
Chandler Copeland
5b87201b28 feat(03-02): add createClient, updateClient, deleteClient server actions
- 'use server' file with Zod validation (name min 1 char, valid email)
- createClient: validate, insert, revalidatePath /portal/clients
- updateClient: bind pattern (id, prevState, formData), revalidates client list + profile
- deleteClient: auth check, delete by id, revalidatePath /portal/clients
- Fixed Zod v4 .issues access (not .errors — v4 API change)
2026-03-19 16:38:49 -06:00
Chandler Copeland
28d42f5d9b feat(03-02): add StatusBadge and DocumentsTable shared portal components
- StatusBadge: color-coded pill for Draft=gray, Sent=blue, Viewed=amber, Signed=green
- DocumentsTable: reusable table with optional Client column, StatusBadge integration
- Date format: toLocaleDateString en-US short month; null sentAt renders as em-dash
2026-03-19 16:37:30 -06:00
Chandler Copeland
9c4caeedba feat(03-02): add portal authenticated layout and PortalNav
- Create portal/(protected)/layout.tsx with auth() check and redirect to /agent/login
- Create PortalNav.tsx as client component with Dashboard/Clients links and active state
- Nav uses usePathname() for active gold underline, LogoutButton for sign-out
- CSS variables --navy/--gold/--cream applied throughout portal shell
2026-03-19 16:37:03 -06:00
Chandler Copeland
00f9c7c9f0 feat(03-01): protect /portal routes and update post-login redirect
- middleware.ts: add /portal/:path* to matcher array
- auth.config.ts: add isPortalRoute check, redirect unauthenticated to /agent/login
- auth.config.ts: change post-login redirect from /agent/dashboard to /portal/dashboard
- agent dashboard page: replace stub with redirect to /portal/dashboard
2026-03-19 16:17:59 -06:00
Chandler Copeland
f8f8b8f4ba feat(03-01): add clients and documents tables to Drizzle schema
- Add pgEnum import and documentStatusEnum (Draft, Sent, Viewed, Signed)
- Add clients table (id, name, email, createdAt, updatedAt)
- Add documents table (id, name, clientId FK, status enum, sentAt, createdAt)
- Generate migration 0001_watery_blindfold.sql and apply to local PostgreSQL
2026-03-19 16:17:26 -06:00
Chandler Copeland
9500f812e0 docs(02-03): complete human verification — phase 2 approved
- All 7 checklist items approved by human reviewer
- Visual fixes applied: hero objectPosition 20%, contact form white inputs, testimonial gold accent bar
- Phase 2 marketing site marked complete (MKTG-01 through MKTG-04 satisfied)
- STATE.md updated: phase 2 complete, 6/6 plans done, progress 40%
2026-03-19 15:19:22 -06:00
Chandler Copeland
a33b4c9520 fix(02-01): restore TestimonialsSection in page.tsx section order
- Add TestimonialsSection import and render between HeroSection and ListingsPlaceholder
- Correct section order: SiteNav → HeroSection → TestimonialsSection → ListingsPlaceholder → ContactSection → SiteFooter
2026-03-19 15:02:19 -06:00
Chandler Copeland
47c6dd9e62 feat(02-02): add ContactSection client component and wire into homepage
- Create src/app/_components/ContactSection.tsx: useActionState form with
  name, email, phone, message fields and gold Send Message button
- Honeypot field (name="website") with display:none, tabIndex=-1, autoComplete="off"
- Success state: form replaced by thank-you message on successful submission
- Error state: inline alert for validation failures
- page.tsx: replace <section id="contact" /> stub with <ContactSection />
- useActionState imported from 'react' (not react-dom, React 19 compatible)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 15:01:36 -06:00
Chandler Copeland
6d701b7faa feat(02-01): add testimonials carousel and wire into homepage
- Create TestimonialsSection with 5 placeholder reviews
- Auto-rotates every 5s, pauses on hover, clearInterval cleanup
- ChevronLeft/ChevronRight arrow controls and dot indicators
- Wire TestimonialsSection into page.tsx between hero and listings
2026-03-19 15:01:07 -06:00
Chandler Copeland
c26a0b1b62 feat(02-01): scaffold marketing site nav, hero, listings, footer
- Add scroll-behavior: smooth and scroll-margin-top to globals.css
- Create SiteNav with sticky navy bar, desktop links, mobile hamburger
- Create HeroSection with split-panel layout and next/image
- Create ListingsPlaceholder with brand navy background and gold CTA
- Create SiteFooter with license number and TODO verify comment
- Update page.tsx to compose all section components
- Install lucide-react for icons

[Rule 1 - Bug] Fixed event handlers in server components — used CSS hover classes instead
2026-03-19 14:59:56 -06:00
Chandler Copeland
39f233dbb4 feat(02-02): install nodemailer and create contact mailer + server action
- Add nodemailer@^7.0.7 and @types/nodemailer (v7 required by next-auth peer dep)
- Create src/lib/contact-mailer.ts: Nodemailer SMTP transporter + sendContactEmail()
- Create src/lib/contact-action.ts: Server Action with Zod validation, honeypot check
- SMTP credentials read from CONTACT_EMAIL_USER/PASS/SMTP_HOST/PORT env vars
- Add CONTACT_* placeholder vars to .env.local (gitignored, for local setup docs)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 14:59:23 -06:00
Chandler Copeland
39af0f19ba fix(auth): resolve middleware Edge Runtime + layout redirect loop
Two bugs:
1. auth.ts imported postgres (Node.js TCP) which crashes in Edge Runtime,
   causing Auth.js to silently fall back to redirecting all requests to login.
   Fix: split into auth.config.ts (Edge-safe, no DB) used by middleware,
   and auth.ts (full, with DB) used by server components.

2. /agent/layout.tsx applied to /agent/login, so unauthenticated login page
   visits redirected to themselves in an infinite loop.
   Fix: moved dashboard + layout into (protected) route group so login page
   has no auth layout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 14:08:04 -06:00
Chandler Copeland
0a75442af3 fix(db): swap @neondatabase/serverless for postgres.js (local dev support)
Neon serverless driver requires remote WebSocket — incompatible with local
PostgreSQL. Replaced with postgres.js (drizzle-orm/postgres-js) in db/index.ts,
scripts/seed.ts, and drizzle.config.ts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 14:00:32 -06:00
Chandler Copeland
32dc2d3ee5 feat(01-02): build agent portal layout, dashboard stub, and logout mechanism
- LogoutButton: client component with server action calling signOut to ?signed_out=1
- AgentLayout: defense-in-depth auth() check, header with email and sign-out button
- DashboardPage: belt-and-suspenders auth() check, welcome message with agent email
- HomePage: updated to Teressa Copeland Homes placeholder (Phase 2 marketing site)
- npm run build and npx tsc --noEmit both pass with zero errors
2026-03-19 13:39:25 -06:00
Chandler Copeland
f221597677 feat(01-02): build branded login page with password toggle and error handling
- Split-screen layout: agent photo left (lg+), login card right
- loginAction server action: signIn credentials, redirects on AuthError
- PasswordField client component: show/hide toggle with eye/eye-off SVG
- Signed-out confirmation banner on ?signed_out=1
- Error banner on ?error=invalid with generic message
- Brand colors: gold #C9A84C accent, navy #1B2B4B text, off-white #FAF9F7 bg
- Copied /Users/ccopeland/Downloads/red.jpg to public/red.jpg
2026-03-19 13:38:42 -06:00
Chandler Copeland
e5db79a8f0 feat(01-01): configure Auth.js v5 JWT + Credentials, route protection middleware
- Created src/lib/auth.ts with NextAuth JWT strategy, 7-day rolling session, Credentials provider
- Created src/app/api/auth/[...nextauth]/route.ts with GET/POST handlers and force-dynamic
- Created middleware.ts at project root (not src/) protecting /agent/* routes
- Fixed db/index.ts: lazy Proxy singleton prevents neon() crash during Next.js build
- npm run build passes; /api/auth/[...nextauth] renders as Dynamic route
2026-03-19 13:33:15 -06:00
Chandler Copeland
f46e7027a5 feat(01-01): define DB schema, configure Drizzle Kit, write seed script
- Created src/lib/db/schema.ts with users table (id, email, password_hash, created_at)
- Created src/lib/db/index.ts exporting db singleton via Drizzle + Neon HTTP driver
- Created drizzle.config.ts pointing to schema.ts with postgresql dialect
- Created scripts/seed.ts reading AGENT_EMAIL/AGENT_PASSWORD to create hashed user row
- Generated drizzle/0000_milky_black_cat.sql migration (committed per user decision)
- db:migrate and db:seed pending user Neon database setup
2026-03-19 13:30:52 -06:00
Chandler Copeland
dac1bc817b feat(01-01): scaffold Next.js 16.2.0 project with all Phase 1 dependencies
- Created teressa-copeland-homes with TypeScript, Tailwind, ESLint, App Router, src dir
- Installed next-auth@5.0.0-beta.30 (pinned exact version), drizzle-orm, @neondatabase/serverless
- Installed bcryptjs, @vercel/blob, zod, drizzle-kit, tsx, dotenv
- Added db:generate, db:migrate, db:seed, db:studio npm scripts
- Verified npm run build passes with zero TypeScript errors
2026-03-19 13:29:56 -06:00