Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
ad7dca6
style(financial-data): match Stitch design for Financial Data panel
jcleow Jan 23, 2026
85ab2b2
feat(insurance): enhance insurance planner with expanded types and UI
jcleow Jan 23, 2026
92bb957
style(theme): add Monet impressionist theme CSS variables
jcleow Jan 23, 2026
79f6396
feat(theme): add ThemeProvider and ColorSchemeToggle
jcleow Jan 23, 2026
5b30e80
refactor(dashboard): add Monet theme support to main components
jcleow Jan 23, 2026
60a319b
perf(stores): add useShallow to prevent unnecessary re-renders
jcleow Jan 23, 2026
8c259be
style(ui): add Monet theme support to PersonSelector and list items
jcleow Jan 23, 2026
3def01d
style(financial-data): wrap SummaryCards in themed container
jcleow Jan 23, 2026
b774fb8
refactor(theme): centralize Monet theme classes in theme.ts
jcleow Jan 23, 2026
af82fe7
style(financial-data): redesign panel with Stitch-style container
jcleow Jan 23, 2026
d6c01f0
feat(insurance): add questionnaire sliders and improve theme support
jcleow Jan 23, 2026
1d58b59
style(ui): add Monet theme support to LayoutPreviewModal
jcleow Jan 23, 2026
fb96960
refactor(insurance): remove separate view mode from GuidelinesTab
jcleow Jan 23, 2026
53d4e89
style(ui): add Monet theme support to PropertyPlannerModal
jcleow Jan 23, 2026
c2ecc3a
fix(ui): add theme support to FinancialDataManagement container
jcleow Jan 23, 2026
2f5e8cf
fix(landing): simplify pricing to free trial, rebrand, and fix UI issues
jcleow Feb 3, 2026
627da8e
refactor: rebrand Assetra to WealthProject across app
jcleow Feb 3, 2026
b6a2cb0
refactor(dashboard): remove Tax Planner module from navigation
jcleow Feb 3, 2026
ae0f61b
style(ui): add Monet theme support to TaxModeModal, PersonsModal, Cus…
jcleow Feb 3, 2026
65ed229
feat(insurance): add coverage journey components and utilities
jcleow Feb 3, 2026
0ec1796
docs: add coverage UI specs, RAG spec, and Claude config
jcleow Feb 3, 2026
2a0dc82
feat: add onboarding wizard for new user financial plan setup
jcleow Feb 4, 2026
3fc4ad4
feat(person): add relationship field and refactor coverage guidelines
jcleow Feb 4, 2026
06895c8
feat: add onboarding wizard modal and dashboard auto-trigger
jcleow Feb 4, 2026
21bd916
fix(onboarding): add exit confirmation and Start Fresh wizard trigger
jcleow Feb 4, 2026
92ff2f6
fix(onboarding): add calendar icon and free-text relationship input
jcleow Feb 4, 2026
762f8b0
chore: add storybook setup, e2e tests, specs, and conductor config
jcleow Feb 4, 2026
a61f072
feat(onboarding): redesign Income & Expenses step with accordion UX
jcleow Feb 4, 2026
3490869
feat: add reusable UI components, onboarding improvements, and DB mig…
jcleow Feb 4, 2026
27e56b8
refactor: remove search bar and simplify defaults
jcleow Feb 4, 2026
6a39ee8
fix(onboarding): remove search box and fix delete icon overlap in rows
jcleow Feb 4, 2026
91e04dc
fix(tax): show actual person names instead of Person 1/2 in TaxModePanel
jcleow Feb 4, 2026
33476e9
fix(onboarding): redesign assets step, fix summary counts, improve CP…
jcleow Feb 4, 2026
a9a055f
feat(dashboard): add Tax Projections placeholder to toolbar
jcleow Feb 4, 2026
fe9be3e
fix: use projection years and reorder modules menu
jcleow Feb 4, 2026
55598e6
fix: change profile icon to LibraryBig and remove unused vars
jcleow Feb 4, 2026
dbe041b
chore: update claude-code-action to v1 GA release
jcleow Feb 4, 2026
667e62f
fix: revert claude-code-action to pinned commit hash
jcleow Feb 4, 2026
329987c
chore: update claude-code-action to v1.0.43
jcleow Feb 4, 2026
f88b551
fix: improve onboarding UX — focus highlight, reset flow, and bugs
jcleow Feb 4, 2026
a9deee9
feat: add Load Sample Data button to onboarding wizard
jcleow Feb 4, 2026
ffef1cc
fix: sanitize negative obligations value in coverage calculator
jcleow Feb 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .claude/commands/frontend-ui-ux.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
description: Designer-turned-developer who crafts stunning UI/UX even without design mockups
argument-hint: [component-or-page-description]
---

# Role: Designer-Turned-Developer

You are a designer who learned to code. You see what pure developers miss—spacing, color harmony, micro-interactions, that indefinable "feel" that makes interfaces memorable. Even without mockups, you envision and create beautiful, cohesive interfaces.

**Mission**: Create visually stunning, emotionally engaging interfaces users fall in love with. Obsess over pixel-perfect details, smooth animations, and intuitive interactions while maintaining code quality.

---

# Work Principles

1. **Complete what's asked** — Execute the exact task. No scope creep. Work until it works. Never mark work complete without proper verification.
2. **Leave it better** — Ensure the project is in a working state after your changes.
3. **Study before acting** — Examine existing patterns, conventions, and commit history (git log) before implementing. Understand why code is structured the way it is.
4. **Blend seamlessly** — Match existing code patterns. Your code should look like the team wrote it.
5. **Be transparent** — Announce each step. Explain reasoning. Report both successes and failures.

---

# Design Process

Before coding, commit to a **BOLD aesthetic direction**:

1. **Purpose**: What problem does this solve? Who uses it?
2. **Tone**: Pick an extreme—brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian
3. **Constraints**: Technical requirements (framework, performance, accessibility)
4. **Differentiation**: What's the ONE thing someone will remember?

**Key**: Choose a clear direction and execute with precision. Intentionality > intensity.

Then implement working code (HTML/CSS/JS, React, Vue, Angular, etc.) that is:
- Production-grade and functional
- Visually striking and memorable
- Cohesive with a clear aesthetic point-of-view
- Meticulously refined in every detail

---

# Aesthetic Guidelines

## Typography
Choose distinctive fonts. **Avoid**: Arial, Inter, Roboto, system fonts, Space Grotesk. Pair a characterful display font with a refined body font.

## Color
Commit to a cohesive palette. Use CSS variables. Dominant colors with sharp accents outperform timid, evenly-distributed palettes. **Avoid**: purple gradients on white (AI slop).

## Motion
Focus on high-impact moments. One well-orchestrated page load with staggered reveals (animation-delay) > scattered micro-interactions. Use scroll-triggering and hover states that surprise. Prioritize CSS-only. Use Motion library for React when available.

## Spatial Composition
Unexpected layouts. Asymmetry. Overlap. Diagonal flow. Grid-breaking elements. Generous negative space OR controlled density.

## Visual Details
Create atmosphere and depth—gradient meshes, noise textures, geometric patterns, layered transparencies, dramatic shadows, decorative borders, custom cursors, grain overlays. Never default to solid colors.

---

# Anti-Patterns (NEVER)

- Generic fonts (Inter, Roboto, Arial, system fonts, Space Grotesk)
- Cliched color schemes (purple gradients on white)
- Predictable layouts and component patterns
- Cookie-cutter design lacking context-specific character
- Converging on common choices across generations

---

# Execution

Match implementation complexity to aesthetic vision:
- **Maximalist** → Elaborate code with extensive animations and effects
- **Minimalist** → Restraint, precision, careful spacing and typography

Interpret creatively and make unexpected choices that feel genuinely designed for the context. No design should be the same. Vary between light and dark themes, different fonts, different aesthetics. You are capable of extraordinary creative work—don't hold back.

---

# Task

$ARGUMENTS

If no specific task is provided, ask what UI/UX component or page the user would like to create.
394 changes: 394 additions & 0 deletions .claude/plans/reflective-wiggling-dragonfly.md

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"enabledPlugins": {
"ralph-wiggum@claude-plugins-official": true
},
"permissions": {
"allow": [
"Bash(/Users/jitcorn/.claude/plugins/cache/claude-plugins-official/ralph-wiggum/*)"
]
}
}
24 changes: 7 additions & 17 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Claude Code

on:
issue_comment:
types: [created]
types: [created, edited]
pull_request_review_comment:
types: [created]
types: [created, edited]
issues:
types: [opened, assigned]
pull_request_review:
Expand All @@ -19,11 +19,11 @@ jobs:
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
contents: write
pull-requests: write
issues: write
id-token: write
actions: read # Required for Claude to read CI results on PRs
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand All @@ -32,19 +32,9 @@ jobs:

- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@v1
uses: anthropics/claude-code-action@v1.0.43
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

# This is an optional setting that allows Claude to read CI results on PRs
additional_permissions: |
actions: read

# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
# prompt: 'Update the pull request description to include a summary of changes.'

# Optional: Add claude_args to customize behavior and configuration
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://docs.claude.com/en/docs/claude-code/cli-reference for available options
# claude_args: '--allowed-tools Bash(gh pr:*)'

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ dist/
build/
.next/
.gocache/
storybook-static/

# Logs
*.log
Expand Down
4 changes: 4 additions & 0 deletions backend/cmd/server/handlers/persons_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type personV2CreateInput struct {
Gender string `json:"gender"` // Required: 'male' or 'female' for CPF LIFE calculations
ResidencyStatus string `json:"residencyStatus"` // 'citizen' or 'pr' (PR year is computed from prGrantDate)
PRGrantDate *string `json:"prGrantDate"` // Required if residencyStatus='pr', format: "2006-01-02"
Relationship string `json:"relationship"` // 'self', 'spouse', 'child', 'parent', 'sibling', 'other'
}

// personV2UpdateInput is the JSON-friendly input struct for updating a person.
Expand All @@ -28,6 +29,7 @@ type personV2UpdateInput struct {
Gender string `json:"gender"` // Optional: 'male' or 'female'
ResidencyStatus string `json:"residencyStatus"` // 'citizen' or 'pr'
PRGrantDate *string `json:"prGrantDate"` // Required if residencyStatus='pr', format: "2006-01-02"
Relationship string `json:"relationship"` // Optional: 'self', 'spouse', 'child', 'parent', 'sibling', 'other'
}

// PersonV2Handler serves person v2 endpoints.
Expand Down Expand Up @@ -146,6 +148,7 @@ func (h *PersonV2Handler) HandleCreate(w http.ResponseWriter, r *http.Request) {
Gender: input.Gender,
ResidencyStatus: residencyStatus,
PRGrantDate: prGrantDate,
Relationship: input.Relationship,
}
if input.DisplayColor != "" {
person.DisplayColor = &input.DisplayColor
Expand Down Expand Up @@ -274,6 +277,7 @@ func (h *PersonV2Handler) HandleUpdate(w http.ResponseWriter, r *http.Request, i
Gender: gender,
ResidencyStatus: input.ResidencyStatus,
PRGrantDate: prGrantDate,
Relationship: input.Relationship,
}
if input.DisplayColor != "" {
person.DisplayColor = &input.DisplayColor
Expand Down
14 changes: 9 additions & 5 deletions backend/internal/financial/repository/timeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type UserSettings struct {
GroupItemsByCategory bool `json:"groupItemsByCategory"` // Whether to group financial items by category in UI
ChartPictureInPicture bool `json:"chartPictureInPicture"` // Whether to show mini chart when scrolled out of view
DashboardLayout string `json:"dashboardLayout"` // Dashboard layout: stacked, chart-left, or chart-right
OnboardingCompleted bool `json:"onboardingCompleted"` // Whether the onboarding wizard has been completed or dismissed
UpdatedAt time.Time `json:"updatedAt,omitempty"`
}

Expand Down Expand Up @@ -257,11 +258,12 @@ func (s *Store) GetUserSettings(ctx context.Context, userID string) (UserSetting
COALESCE(group_items_by_category, true),
COALESCE(chart_picture_in_picture, false),
COALESCE(dashboard_layout, 'stacked'),
COALESCE(onboarding_completed, false),
updated_at
FROM user_settings
WHERE user_id = $1`, userID)
var settings UserSettings
if err := row.Scan(&settings.ID, &settings.UserID, &settings.StartingAge, &settings.TerminalAge, &settings.YearDisplayFormat, &settings.TimeResolution, &settings.CompoundingFrequency, &settings.AutoExecuteTools, &settings.GroupItemsByCategory, &settings.ChartPictureInPicture, &settings.DashboardLayout, &settings.UpdatedAt); err != nil {
if err := row.Scan(&settings.ID, &settings.UserID, &settings.StartingAge, &settings.TerminalAge, &settings.YearDisplayFormat, &settings.TimeResolution, &settings.CompoundingFrequency, &settings.AutoExecuteTools, &settings.GroupItemsByCategory, &settings.ChartPictureInPicture, &settings.DashboardLayout, &settings.OnboardingCompleted, &settings.UpdatedAt); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return DefaultUserSettings, nil
}
Expand All @@ -273,8 +275,8 @@ func (s *Store) GetUserSettings(ctx context.Context, userID string) (UserSetting
// UpsertUserSettings inserts or updates user settings.
func (s *Store) UpsertUserSettings(ctx context.Context, userID string, settings UserSettings) (UserSettings, error) {
row := s.db.QueryRowContext(ctx, `
INSERT INTO user_settings (user_id, starting_age, terminal_age, year_display_format, time_resolution, compounding_frequency, auto_execute_tools, group_items_by_category, chart_picture_in_picture, dashboard_layout)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
INSERT INTO user_settings (user_id, starting_age, terminal_age, year_display_format, time_resolution, compounding_frequency, auto_execute_tools, group_items_by_category, chart_picture_in_picture, dashboard_layout, onboarding_completed)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
ON CONFLICT (user_id) DO UPDATE
SET starting_age = EXCLUDED.starting_age,
terminal_age = EXCLUDED.terminal_age,
Expand All @@ -285,6 +287,7 @@ func (s *Store) UpsertUserSettings(ctx context.Context, userID string, settings
group_items_by_category = EXCLUDED.group_items_by_category,
chart_picture_in_picture = EXCLUDED.chart_picture_in_picture,
dashboard_layout = EXCLUDED.dashboard_layout,
onboarding_completed = EXCLUDED.onboarding_completed,
updated_at = NOW()
RETURNING id, user_id, starting_age, terminal_age, year_display_format,
COALESCE(time_resolution, 'yearly'),
Expand All @@ -293,10 +296,11 @@ func (s *Store) UpsertUserSettings(ctx context.Context, userID string, settings
COALESCE(group_items_by_category, true),
COALESCE(chart_picture_in_picture, false),
COALESCE(dashboard_layout, 'stacked'),
COALESCE(onboarding_completed, false),
updated_at`,
userID, settings.StartingAge, settings.TerminalAge, settings.YearDisplayFormat, settings.TimeResolution, settings.CompoundingFrequency, settings.AutoExecuteTools, settings.GroupItemsByCategory, settings.ChartPictureInPicture, settings.DashboardLayout)
userID, settings.StartingAge, settings.TerminalAge, settings.YearDisplayFormat, settings.TimeResolution, settings.CompoundingFrequency, settings.AutoExecuteTools, settings.GroupItemsByCategory, settings.ChartPictureInPicture, settings.DashboardLayout, settings.OnboardingCompleted)
var updated UserSettings
if err := row.Scan(&updated.ID, &updated.UserID, &updated.StartingAge, &updated.TerminalAge, &updated.YearDisplayFormat, &updated.TimeResolution, &updated.CompoundingFrequency, &updated.AutoExecuteTools, &updated.GroupItemsByCategory, &updated.ChartPictureInPicture, &updated.DashboardLayout, &updated.UpdatedAt); err != nil {
if err := row.Scan(&updated.ID, &updated.UserID, &updated.StartingAge, &updated.TerminalAge, &updated.YearDisplayFormat, &updated.TimeResolution, &updated.CompoundingFrequency, &updated.AutoExecuteTools, &updated.GroupItemsByCategory, &updated.ChartPictureInPicture, &updated.DashboardLayout, &updated.OnboardingCompleted, &updated.UpdatedAt); err != nil {
return UserSettings{}, err
}
return updated, nil
Expand Down
39 changes: 23 additions & 16 deletions backend/internal/financial_v2/repository/person.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func (s *Store) ListPersons(ctx context.Context, userID string) ([]Person, error
query := `
SELECT id, user_id, name, display_color, is_included,
date_of_birth, gender, residency_status, pr_grant_date,
created_at, updated_at
relationship, created_at, updated_at
FROM persons
WHERE user_id = $1
ORDER BY created_at ASC`
Expand All @@ -31,7 +31,7 @@ func (s *Store) ListPersons(ctx context.Context, userID string) ([]Person, error
if err := rows.Scan(
&p.ID, &p.UserID, &p.Name, &p.DisplayColor, &p.IsIncluded,
&p.DateOfBirth, &p.Gender, &p.ResidencyStatus, &p.PRGrantDate,
&p.CreatedAt, &p.UpdatedAt,
&p.Relationship, &p.CreatedAt, &p.UpdatedAt,
); err != nil {
return nil, fmt.Errorf("failed to scan person: %w", err)
}
Expand All @@ -51,7 +51,7 @@ func (s *Store) ListPersonsWithStats(ctx context.Context, userID string) ([]Pers
SELECT
p.id, p.user_id, p.name, p.display_color, p.is_included,
p.date_of_birth, p.gender, p.residency_status, p.pr_grant_date,
p.created_at, p.updated_at,
p.relationship, p.created_at, p.updated_at,
COALESCE(income_counts.count, 0) as income_count,
COALESCE(cpf_counts.count, 0) as cpf_count
FROM persons p
Expand Down Expand Up @@ -84,7 +84,7 @@ func (s *Store) ListPersonsWithStats(ctx context.Context, userID string) ([]Pers
if err := rows.Scan(
&p.ID, &p.UserID, &p.Name, &p.DisplayColor, &p.IsIncluded,
&p.DateOfBirth, &p.Gender, &p.ResidencyStatus, &p.PRGrantDate,
&p.CreatedAt, &p.UpdatedAt, &p.IncomeCount, &p.CPFCount,
&p.Relationship, &p.CreatedAt, &p.UpdatedAt, &p.IncomeCount, &p.CPFCount,
); err != nil {
return nil, fmt.Errorf("failed to scan person with stats: %w", err)
}
Expand All @@ -103,7 +103,7 @@ func (s *Store) GetPerson(ctx context.Context, userID, id string) (*Person, erro
query := `
SELECT id, user_id, name, display_color, is_included,
date_of_birth, gender, residency_status, pr_grant_date,
created_at, updated_at
relationship, created_at, updated_at
FROM persons
WHERE user_id = $1 AND id = $2`

Expand All @@ -113,7 +113,7 @@ func (s *Store) GetPerson(ctx context.Context, userID, id string) (*Person, erro
err := s.pool.QueryRow(ctx, query, userID, id).Scan(
&p.ID, &p.UserID, &p.Name, &p.DisplayColor, &p.IsIncluded,
&p.DateOfBirth, &p.Gender, &p.ResidencyStatus, &p.PRGrantDate,
&p.CreatedAt, &p.UpdatedAt,
&p.Relationship, &p.CreatedAt, &p.UpdatedAt,
)
if err == pgx.ErrNoRows {
return nil, ErrNotFound
Expand All @@ -130,11 +130,11 @@ func (s *Store) CreatePerson(ctx context.Context, userID string, p Person) (*Per
query := `
INSERT INTO persons (user_id, name, display_color, is_included,
date_of_birth, gender, residency_status, pr_grant_date,
created_at, updated_at)
VALUES ($1, $2, NULLIF($3, ''), $4, $5, $6, $7, $8, NOW(), NOW())
relationship, created_at, updated_at)
VALUES ($1, $2, NULLIF($3, ''), $4, $5, $6, $7, $8, $9, NOW(), NOW())
RETURNING id, user_id, name, display_color, is_included,
date_of_birth, gender, residency_status, pr_grant_date,
created_at, updated_at`
relationship, created_at, updated_at`

displayColor := ""
if p.DisplayColor != nil {
Expand All @@ -153,15 +153,21 @@ func (s *Store) CreatePerson(ctx context.Context, userID string, p Person) (*Per
gender = "male"
}

args := []any{userID, p.Name, displayColor, true, p.DateOfBirth, gender, residencyStatus, p.PRGrantDate}
// Default relationship to 'self' if not provided
relationship := p.Relationship
if relationship == "" {
relationship = "self"
}

args := []any{userID, p.Name, displayColor, true, p.DateOfBirth, gender, residencyStatus, p.PRGrantDate, relationship}

logQuery(query, args)

var created Person
err := s.pool.QueryRow(ctx, query, args...).Scan(
&created.ID, &created.UserID, &created.Name, &created.DisplayColor,
&created.IsIncluded, &created.DateOfBirth, &created.Gender, &created.ResidencyStatus, &created.PRGrantDate,
&created.CreatedAt, &created.UpdatedAt,
&created.Relationship, &created.CreatedAt, &created.UpdatedAt,
)
if err != nil {
return nil, fmt.Errorf("failed to create person: %w", err)
Expand All @@ -181,11 +187,12 @@ func (s *Store) UpdatePerson(ctx context.Context, userID, id string, p Person) (
gender = COALESCE(NULLIF($7, ''), gender),
residency_status = COALESCE(NULLIF($8, ''), residency_status),
pr_grant_date = $9,
relationship = COALESCE(NULLIF($10, ''), relationship),
updated_at = NOW()
WHERE user_id = $1 AND id = $2
RETURNING id, user_id, name, display_color, is_included,
date_of_birth, gender, residency_status, pr_grant_date,
created_at, updated_at`
relationship, created_at, updated_at`

displayColor := ""
if p.DisplayColor != nil {
Expand All @@ -198,15 +205,15 @@ func (s *Store) UpdatePerson(ctx context.Context, userID, id string, p Person) (
dateOfBirth = p.DateOfBirth
}

args := []any{userID, id, p.Name, displayColor, p.IsIncluded, dateOfBirth, p.Gender, p.ResidencyStatus, p.PRGrantDate}
args := []any{userID, id, p.Name, displayColor, p.IsIncluded, dateOfBirth, p.Gender, p.ResidencyStatus, p.PRGrantDate, p.Relationship}

logQuery(query, args)

var updated Person
err := s.pool.QueryRow(ctx, query, args...).Scan(
&updated.ID, &updated.UserID, &updated.Name, &updated.DisplayColor,
&updated.IsIncluded, &updated.DateOfBirth, &updated.Gender, &updated.ResidencyStatus, &updated.PRGrantDate,
&updated.CreatedAt, &updated.UpdatedAt,
&updated.Relationship, &updated.CreatedAt, &updated.UpdatedAt,
)
if err == pgx.ErrNoRows {
return nil, ErrNotFound
Expand Down Expand Up @@ -245,15 +252,15 @@ func (s *Store) TogglePersonIncluded(ctx context.Context, userID, id string) (*P
WHERE user_id = $1 AND id = $2
RETURNING id, user_id, name, display_color, is_included,
date_of_birth, gender, residency_status, pr_grant_date,
created_at, updated_at`
relationship, created_at, updated_at`

logQuery(query, []any{userID, id})

var updated Person
err := s.pool.QueryRow(ctx, query, userID, id).Scan(
&updated.ID, &updated.UserID, &updated.Name, &updated.DisplayColor,
&updated.IsIncluded, &updated.DateOfBirth, &updated.Gender, &updated.ResidencyStatus, &updated.PRGrantDate,
&updated.CreatedAt, &updated.UpdatedAt,
&updated.Relationship, &updated.CreatedAt, &updated.UpdatedAt,
)
if err == pgx.ErrNoRows {
return nil, ErrNotFound
Expand Down
1 change: 1 addition & 0 deletions backend/internal/financial_v2/repository/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ type Person struct {
Gender string `json:"gender"` // 'male' or 'female' - required for CPF LIFE calculations
ResidencyStatus string `json:"residencyStatus"` // 'citizen' or 'pr' (PR year computed from prGrantDate)
PRGrantDate *time.Time `json:"prGrantDate,omitempty"`
Relationship string `json:"relationship"` // 'self', 'spouse', 'child', 'parent', 'sibling', 'other'
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
// Stats populated by GetPersonsWithStats
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE persons DROP COLUMN IF EXISTS relationship;
Loading