Commit graph

1159 commits

Author SHA1 Message Date
Khalim Conn-Kowlessar
c921db7d9c initial implementation for portfolio invitations. A user can send an invitation to a user and they will receive an invitation email 2026-05-27 16:18:21 +00:00
Jun-te Kim
5ea7e00fbe
Merge pull request #282 from Hestia-Homes/bug/blocked-magic-links
Bug/blocked magic links
2026-05-27 16:21:53 +01:00
Khalim Conn-Kowlessar
e57e4ab750 changing email to test 2026-05-27 15:01:26 +00:00
Khalim Conn-Kowlessar
4f176a482f changing ses config to test values 2026-05-27 14:54:59 +00:00
Khalim Conn-Kowlessar
47efd1bd5a Drop useEffect from VerifyCodeForm; replace tick-based countdown
The per-second countdown was the only thing pulling useEffect into this
component, in violation of the project rule (CLAUDE.md: avoid useEffect,
prefer event handlers). The hook was driving a tick purely so we could
show "Resend in 28s" / "27s" / ... — none of which is load-bearing.

Replace it with a single setTimeout fired from the resend event handler
that flips resendStatus from "cooldown" back to "idle" after 30 seconds.
The button stays disabled with "Code sent — wait a moment" instead of
showing a live countdown. Same blocking signal, no hook needed.

While here, split the single status enum into verifyStatus + resendStatus
so the verify button no longer wrongly disables during a resend cooldown
(latent bug from the previous shape).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 14:50:05 +00:00
Khalim Conn-Kowlessar
ee506425fd Drop link from email body; fix paste + stale-resend-notice UX bugs
Email body now contains the 6-digit code only. The /verify/[token] route
and the EmailProvider link callback are intentionally left wired (just
not advertised in the email) so reverting to a link-bearing template is
a content-only change if the all-code variant doesn't improve
deliverability for the Atkins-style blocked recipients.

Hypothesis being tested: corporate gateway URL scanners are part of why
some emails got silently quarantined, and a short transactional body
without an auth-token URL clears more filters.

Two small UX bugs surfaced in preview testing also fixed here:

- Paste of "482 911" (with the visual space from the email's formatted
  code) was dropping a digit. Root cause: maxLength=6 on the input
  truncated the 7-char paste before our \D-stripping ran. Drop the
  attribute and let the existing .slice(0, 6) after stripping handle
  the bound. Pasting the formatted code now works.

- After requesting a resend and then typing into the code field, the
  green "we've sent a new code" notice would re-appear as soon as the
  previous error message cleared. handleChange now clears the resend
  notice on the next keystroke, alongside the error clear it already
  did.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 14:46:33 +00:00
Khalim Conn-Kowlessar
d042606955 Add 6-digit code sign-in as primary, magic link as fast-path fallback
Same email now contains a 6-digit code and a magic link, both backed by a
single verificationToken row. After submitting their email, the user
lands on /auth/verify-code with a single-input form (inputmode=numeric,
autocomplete=one-time-code, auto-submit on 6 digits or paste) and can
either type the code or use the link from the email. Either path
consumes the same row — single-use, replace-on-resend.

This is the structural fix for the silent-quarantine pattern observed
with Atkins and Sustainable Building UK: corporate gateways are happier
with short transactional content than long opaque token URLs, and a
code can't be broken by SafeLinks-style URL rewriting. The link path is
preserved so users whose email gets through unmangled keep one-click UX.

Security:
  - Codes are 6-digit, crypto.randomInt-generated, stored as sha256
    hashed against NEXTAUTH_SECRET on the same row as the link token
  - 5-attempt lockout per code (attempts column); 6th attempt with the
    correct code still fails
  - Per-email send rate limit: 5/hour fixed window (authRateLimits
    table); 6th send returns an error
  - Code + link share a 10-minute window (maxAge dropped from 1h)
  - Resending replaces any prior token rows for the identifier so only
    the latest send is ever live

Implementation:
  - verificationCode.ts holds generateCode + hashCode + the pure
    evaluateCodeAttempt decision tree; 9 unit tests cover every branch
    of the verification outcome (no-such-row, expired, locked-out, ok,
    wrong-with-newAttempts, locked-out-still-rejects-correct-code)
  - sendVerificationRequest now hashes the URL token the same way
    /verify/[token]/page.tsx does, applies the rate limit + records the
    code + replaces older rows in two transactions
  - CredentialsProvider (id: "email-code") calls evaluateCodeAttempt
    inside a transaction, handles all 5 outcomes, creates the user on
    first successful code (parity with the magic-link callback path)
  - oauthId backfill in the signIn callback is now guarded on
    account.type === "oauth" so the credentials flow doesn't pollute
    oauthProvider with "email-code"
  - Migration is additive: code_hash nullable, attempts default 0; new
    authRateLimits table is independent. In-flight tokens at deploy time
    keep working via the link path.

Vercel preview deployment is the test surface; a Mailpit + Cypress E2E
loop is intentionally deferred per the lean-setup plan in docs/wip/
auth-email-code-fallback-plan.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 14:16:47 +00:00
Jun-te Kim
ed14ac79eb group filter to allow batches 2026-05-27 13:57:10 +00:00
Khalim Conn-Kowlessar
9c569f5584 Add SES observability foundation for email auth (PR 1 of code-fallback)
Wires the X-SES-CONFIGURATION-SET header on outbound auth emails so SES
bounce/delivery events flow through dev-ses-config to the dev-ses-events
SNS topic. Replaces the fire-and-forget "EMAIL MAGIC LINK SENT" log
(which fired before the SMTP transaction and swallowed downstream errors)
with structured EMAIL_MAGIC_LINK_SUCCESS/_FAILURE logs carrying the
Nodemailer messageId, so app-side sends are now correlatable with SES
events.

Motivated by the Atkins / Sustainable Building UK silent-quarantine
incidents where we couldn't tell whether SES had even tried to send.

Plan doc at docs/wip/auth-email-code-fallback-plan.md tracks the
broader email-code-fallback design that PR 2 will implement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 13:15:25 +00:00
Jun-te Kim
54ad998032 additional batches 2026-05-27 10:28:19 +00:00
Jun-te Kim
f205524fe9 more hubspot deal data 2026-05-27 10:26:39 +00:00
Jun-te Kim
6c7c43fb89 roof 2026-05-26 16:07:26 +00:00
Jun-te Kim
35156111d0 built type 2026-05-26 15:04:02 +00:00
Jun-te Kim
9612b1fd4b new wall types 2026-05-26 14:32:57 +00:00
Jun-te Kim
f0d53d4e86 some comments to understand the sql more 2026-05-26 10:25:42 +00:00
Jun-te Kim
b8be604ab3 migration scripts 2026-05-26 10:23:50 +00:00
Jun-te Kim
1df047a84a landlord overrides 2026-05-26 10:21:50 +00:00
Daniel Roth
e22833041d Correct required file type count in tests
Some checks failed
Test Suite / unit-tests (push) Has been cancelled
2026-05-20 09:00:32 +00:00
Daniel Roth
c533bb3e80 specify certain variables as survey 2026-05-19 10:35:15 +00:00
Daniel Roth
d755299043 Correctly separate install document categories 2026-05-19 10:32:18 +00:00
Daniel Roth
d292bb53c1 coordination and design docs not listed under install 2026-05-19 10:30:59 +00:00
Daniel Roth
f99374a16f list coordination and design documents in their own sections 2026-05-19 08:30:57 +00:00
Daniel Roth
61be9a477c pas significance file is not expected 2026-05-19 08:17:17 +00:00
KhalimCK
20f6aff62e
Merge pull request #266 from Hestia-Homes/feature/pm-ui-ux
Some checks failed
Test Suite / unit-tests (push) Has been cancelled
Feature/pm UI ux
2026-05-18 10:00:40 +01:00
Daniel Roth
57d425f848 migration files 2026-05-18 08:23:38 +00:00
Daniel Roth
20648f30e0 add coordination_hub file source 2026-05-18 08:17:28 +00:00
Jun-te Kim
604e0014fc deploy to main 2026-05-15 11:34:14 +00:00
Jun-te Kim
41891a4540 job ordering 2026-05-15 10:13:09 +00:00
Jun-te Kim
cd47aef985 order by job started and not job updated time 2026-05-15 10:10:00 +00:00
Daniel Roth
578e146aec migration files 2026-05-13 13:51:26 +00:00
Daniel Roth
452a2cd61d add new coordination and design file types 2026-05-13 13:51:02 +00:00
Daniel Roth
6b1627d03c migration files 2026-05-13 10:03:43 +00:00
Daniel Roth
00b0cc2a45 add uploaded_file_id fk to magic_plan_plan 2026-05-13 10:03:07 +00:00
Jun-te Kim
6f9fabb622
Merge pull request #243 from Hestia-Homes/feature/onbarding_of_addresses
Some checks are pending
Test Suite / unit-tests (push) Waiting to run
Feature/onbarding of addresses
2026-05-12 18:26:40 +01:00
Jun-te Kim
10b3d81bc2 added enum from hubspot source 2026-05-12 16:18:42 +00:00
Daniel Roth
4b62b12f15 add migration files 2026-05-12 15:42:27 +00:00
Daniel Roth
8f87ea0c96 magic_plan_uid column is unique 2026-05-12 15:41:43 +00:00
Jun-te Kim
b387bc24f8 got rid of get server
Some checks failed
Test Suite / unit-tests (push) Has been cancelled
2026-05-12 13:54:18 +00:00
Khalim Conn-Kowlessar
1345f36d8d Add test coverage for transforms.ts stage classification logic
Some checks failed
Test Suite / unit-tests (push) Has been cancelled
49 tests across all exported functions: resolveDisplayStage (STAGE_ID_MAP
lookups, AFTER_ASSESSMENT sub-classification, POST_DESIGN precedence chain,
RA ISSUE overrides), classifyDeals, computeDampMouldRisk, computeFunnelStages,
computeProjectProgress (Queries exclusion from percentages), computeOutcomeSlices,
and computeLiveTrackerData (__ALL__ synthetic project behaviour).
2026-05-12 13:29:00 +00:00
Khalim Conn-Kowlessar
7841e4a556 xtracted duplicated removal state logic into a shared module.
Created removalState.ts with two functions: deriveEffectiveRemovalState (single DB row → EffectiveRemovalState) and computeRemovalStatusByDeal (ordered rows → RemovalStatusByDeal map, owns deduplication).
Created removalState.test.ts with 11 tests covering all 6 (type, status) combinations and the map-building edge cases (empty input, deduplication, none entries excluded).
live/page.tsx: replaced a 14-line seen-set loop with a single computeRemovalStatusByDeal(removalRows) call.
live/[dealId]/page.tsx: replaced an if/else block with deriveEffectiveRemovalState(removalRows[0]).
2026-05-12 13:12:14 +00:00
Khalim Conn-Kowlessar
e52ab73e9f Remove unused WorkPhaseStats and consolidate deal mapping into shared module
Delete WorkPhaseStats type and its four computation blocks (coordination,
design, install, lodgement) from transforms.ts and types.ts — the computed
values were never read by any component.

Extract mapDbRowToHubspotDeal, DealRow, and the coordinator/designer aliases
into a new dealQuery.ts module, eliminating the verbatim duplication between
the live tracker page and the deal detail page.

Replace the inline doc status computation in [dealId]/page.tsx with calls
to the existing fetchDocsByDealId and computeDocStatusMap from docStatus.ts,
so both paths now share a single implementation.
2026-05-12 13:00:09 +00:00
Khalim Conn-Kowlessar
281f15c11e Move the DocStatusMap computation and document fetch logic out of the
server component into a dedicated docStatus.ts module. computeDocStatusMap
is now a pure function with full test coverage (8 tests). Also consolidates
the double user table lookup in page.tsx into a single query.
2026-05-12 12:16:57 +00:00
Khalim Conn-Kowlessar
166cea397b refactoring details drawer to orchestrator format 2026-05-12 11:24:08 +00:00
Khalim Conn-Kowlessar
f6b9f9f65c Updating UI for document upload to improve confusing categorisation
Some checks failed
Test Suite / unit-tests (push) Has been cancelled
2026-05-10 20:11:33 +00:00
Khalim Conn-Kowlessar
9654c2cfd7 remove uprn from page view 2026-05-09 08:58:49 +00:00
Khalim Conn-Kowlessar
d467a61c22 Adding bulk approve and instruct 2026-05-09 08:39:20 +00:00
Khalim Conn-Kowlessar
1620a9a65f move back to 7xl width 2026-05-08 17:36:30 +00:00
Khalim Conn-Kowlessar
7b6763934c increased width of layout to 8xl 2026-05-08 17:27:52 +00:00
Daniel Roth
32dbb18980 migration files 2026-05-08 14:15:39 +00:00
Daniel Roth
edcabea199 add magic plan file source and file type 2026-05-08 14:15:08 +00:00