Skip to content

Add Region settings tab, remove country-specific defaults - #422

Merged
clstaudt merged 8 commits into
mainfrom
region-settings-no-country-default
Jul 21, 2026
Merged

Add Region settings tab, remove country-specific defaults#422
clstaudt merged 8 commits into
mainfrom
region-settings-no-country-default

Conversation

@clstaudt

@clstaudt clstaudt commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Rename the "Local" settings tab to Region and reorder it after Branding
  • Move operating country, VAT number, and tax number from Profile → Region tab
  • Consolidate Region tab into a single save button
  • Remove all hardcoded "Germany" defaults — frontend forms, backend model field, intent fallbacks, and KPI function parameters all default to empty string
  • Neutralize German-specific UI text: "Income Tax + Soli" → "Income Tax", remove § 16 Abs. 6 UStG citation, replace USt-IdNr / Steuernummer with generic labels
  • Split onboarding wizard "Business" step into granular Profile, Address, and Region steps
  • Expand country dropdown to 59 major countries (previously limited to those with tax models)
  • Graceful tax model degradation: when a country without a tax model is selected, show an info banner with a GitHub link to request it; gray out tax-dependent UI (income tax waterfall bars, tax estimates, spendable income KPI) instead of showing zeros

Test plan

  • Onboarding wizard: country dropdown shows all 59 countries, not just tax-model ones
  • Region tab: selecting a country without a tax model shows the info banner below the fieldset
  • Region tab: banner does not disrupt the 2-column field layout
  • Tax Reserves view: "Est. Income Tax" bar and income tax section render grayed out for unsupported countries
  • Salary view: "Est. Income Tax" line renders muted with hint for unsupported countries
  • Dashboard: "Spendable Income" KPI card renders grayed out for unsupported countries
  • Dashboard: KPI card layout unchanged for supported countries (no spacing regression)
  • Existing users with operating_country = "Germany" still work normally

clstaudt and others added 7 commits July 18, 2026 22:30
Rename the "Local" settings tab to "Region" and move the operating
country selector there alongside currency settings. Remove all
hardcoded "Germany" defaults from the frontend forms, backend model,
intent fallbacks, and KPI function parameters — the onboarding wizard
collects the operating country explicitly.

Also neutralize German-specific UI text: remove "Soli" from tax labels,
drop § 16 Abs. 6 UStG from the currency description, and replace
USt-IdNr / Steuernummer references with generic terms.

Co-authored-by: Cursor <cursoragent@cursor.com>
Tax identifiers belong with the tax jurisdiction, not personal identity.

Co-authored-by: Cursor <cursoragent@cursor.com>
Merge the separate jurisdiction and currency save buttons into one
"Save Region Settings" that saves both in parallel.

Co-authored-by: Cursor <cursoragent@cursor.com>
Split the "Business" wizard step into "Profile" (identity, address,
bank account) and "Region" (operating country, tax identifiers),
matching the settings tab structure.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep each onboarding step focused: Profile has name/email/phone,
Address has street address and bank account.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
- Add 59 major countries to operating-country dropdown (previously
  limited to ~7 with tax models)
- Add has_tax_model() check and all_operating_countries() RPC
- Show info banner when selected country lacks a tax model, with
  link to request it on GitHub
- Gray out tax-dependent UI (income tax waterfall bars, tax estimates,
  spendable income KPI) when country is unsupported
- Add country_supported flag to salary and KPI responses
- Fix remaining Germany default in salary intent

Co-authored-by: Cursor <cursoragent@cursor.com>
@clstaudt
clstaudt requested a review from aaronspring July 18, 2026 21:14
@aaronspring

Copy link
Copy Markdown
Contributor

Will review today

@aaronspring aaronspring left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the attempt removing the Germany default.

Regarding Settings: Invoicing now contains "Saved Invoice Notes" and Region could also hold invoice notes. I think your choice of keeping invoice notes under Invoicing is good judgement.

Regarding onboarding:

  • Region: current default is Argentina by ordering. Possible to have no default?

LGTM

@clstaudt
clstaudt added this pull request to the merge queue Jul 21, 2026
Merged via the queue into main with commit c3d22e3 Jul 21, 2026
3 checks passed
@clstaudt
clstaudt deleted the region-settings-no-country-default branch July 21, 2026 14:51
aaronspring pushed a commit that referenced this pull request Jul 24, 2026
* feat: add Region settings tab, remove country-specific defaults

Rename the "Local" settings tab to "Region" and move the operating
country selector there alongside currency settings. Remove all
hardcoded "Germany" defaults from the frontend forms, backend model,
intent fallbacks, and KPI function parameters — the onboarding wizard
collects the operating country explicitly.

Also neutralize German-specific UI text: remove "Soli" from tax labels,
drop § 16 Abs. 6 UStG from the currency description, and replace
USt-IdNr / Steuernummer references with generic terms.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: move VAT and tax number from Profile to Region tab

Tax identifiers belong with the tax jurisdiction, not personal identity.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: single save button for Region tab

Merge the separate jurisdiction and currency save buttons into one
"Save Region Settings" that saves both in parallel.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: onboarding wizard mirrors settings tabs (Profile, Region)

Split the "Business" wizard step into "Profile" (identity, address,
bank account) and "Region" (operating country, tax identifiers),
matching the settings tab structure.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: split Profile wizard step into Profile + Address

Keep each onboarding step focused: Profile has name/email/phone,
Address has street address and bank account.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: remove German-specific placeholder text from all form fields

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: expand country list and graceful tax model degradation

- Add 59 major countries to operating-country dropdown (previously
  limited to ~7 with tax models)
- Add has_tax_model() check and all_operating_countries() RPC
- Show info banner when selected country lacks a tax model, with
  link to request it on GitHub
- Gray out tax-dependent UI (income tax waterfall bars, tax estimates,
  spendable income KPI) when country is unsupported
- Add country_supported flag to salary and KPI responses
- Fix remaining Germany default in salary intent

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
aaronspring added a commit that referenced this pull request Jul 24, 2026
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
sreedevi-i pushed a commit to sreedevi-i/tuttle that referenced this pull request Jul 28, 2026
…dev#427)

* refactor: replace black, flake8, isort, pydocstyle with ruff

Consolidate four Python linting/formatting tools into ruff:

- pyproject.toml: swap black/isort/pydocstyle dev deps for ruff,
  replace [tool.flake8] + [tool.isort] with [tool.ruff] config
- .pre-commit-config.yaml: replace psf/black hook with
  astral-sh/ruff-pre-commit (ruff check --fix + ruff format)
- CI: replace flake8 lint step with ruff check + ruff format --check
- Apply ruff format and ruff check --fix across the codebase

Supersedes tuttle-dev#420 — the Python 3.14 event-loop crash in black is
no longer relevant since ruff is written in Rust.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: make the append-only migration guard formatting-immune (tuttle-dev#428)

Ruff reformatted committed revisions in tuttle/migrations/versions,
joining multi-line op.execute(...) calls onto one line. The formatting is
fine and stays; the guard was the problem — it compared raw diff text, so
a cosmetic reflow read as an edit to a shipped schema delta and
test_versions_are_append_only_in_git failed on this branch locally.

Compare the parsed op.* calls in upgrade() instead. Reflows and import
sorting become invisible; a change to what a call actually does still
fails. Scoped to upgrade() because that is the code already-migrated
databases executed, and because downgrade() bodies were legitimately
replaced with `raise NotImplementedError` after the fact.

CI never caught any of this: actions/checkout defaults to fetch-depth: 1,
and the guard skips files whose per-file git log has one commit — under a
shallow clone that is every file, so the assert always passed vacuously.
With full history it also surfaces a real pre-existing violation on main
(c3d70beffa72, backfill changed from "" to "Unknown" in 9cec3e0), which
is grandfathered here with a comment and tracked in tuttle-dev#429.

Verified: ruff check clean, ruff format --check clean, 504 passed /
1 skipped, and the guard still fails on a planted table rename.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* Add Region settings tab, remove country-specific defaults (tuttle-dev#422)

* feat: add Region settings tab, remove country-specific defaults

Rename the "Local" settings tab to "Region" and move the operating
country selector there alongside currency settings. Remove all
hardcoded "Germany" defaults from the frontend forms, backend model,
intent fallbacks, and KPI function parameters — the onboarding wizard
collects the operating country explicitly.

Also neutralize German-specific UI text: remove "Soli" from tax labels,
drop § 16 Abs. 6 UStG from the currency description, and replace
USt-IdNr / Steuernummer references with generic terms.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: move VAT and tax number from Profile to Region tab

Tax identifiers belong with the tax jurisdiction, not personal identity.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: single save button for Region tab

Merge the separate jurisdiction and currency save buttons into one
"Save Region Settings" that saves both in parallel.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: onboarding wizard mirrors settings tabs (Profile, Region)

Split the "Business" wizard step into "Profile" (identity, address,
bank account) and "Region" (operating country, tax identifiers),
matching the settings tab structure.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: split Profile wizard step into Profile + Address

Keep each onboarding step focused: Profile has name/email/phone,
Address has street address and bank account.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: remove German-specific placeholder text from all form fields

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: expand country list and graceful tax model degradation

- Add 59 major countries to operating-country dropdown (previously
  limited to ~7 with tax models)
- Add has_tax_model() check and all_operating_countries() RPC
- Show info banner when selected country lacks a tax model, with
  link to request it on GitHub
- Gray out tax-dependent UI (income tax waterfall bars, tax estimates,
  spendable income KPI) when country is unsupported
- Add country_supported flag to salary and KPI responses
- Fix remaining Germany default in salary intent

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>

* style: ruff format intent.py after merging main

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

* style: ruff format intent.py after merging main (tuttle-dev#422)

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

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Aaron Spring <12237157+aaronspring@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Aaron Spring <draaronspring@proton.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants