Skip to content

Commit ec5d49c

Browse files
authored
Optimize Sync Reliability, Revamp Mobile Account Details, and Harden Deployment Scripts for v0.4.0 (#64)
* Refactor authentication dependencies and services for improved clarity and functionality - Removed the redundant token type check from the JWT payload in the `_create_access_token` method, streamlining the token creation process. - Enhanced overall code clarity and maintainability in the authentication module. * Remove response model from the get_me endpoint in the authentication routes for simplification. * Rename delete method to softDelete in AccountRepository and update references in AccountDetailPage and CategoryFormSheet for clarity in soft deletion functionality. * Enhance AGENTS.md and SKILL.md for improved agent behavior and design guidelines * Refactor achievement list page to streamline data loading and refresh logic - Replaced the `_onPullRefresh` method with a simplified `_onRefreshTriggered` method to enhance data loading efficiency. - Improved the refresh indicator functionality by ensuring the UI updates correctly based on the unlocked achievements count. - Cleaned up the layout structure in the achievement list page for better readability and maintainability. * Refactor achievement list page for improved data handling and UI clarity - Updated achievement group titles for better localization and understanding. - Introduced a new mapping for achievement IDs to streamline display order logic. - Refactored achievement data processing to enhance filtering and sorting efficiency. - Improved state management for achievements, including recent unlock tracking and next cards display. - Cleaned up redundant code to enhance maintainability and readability. * Implement account balance history and summary visualization in AccountDetailPage - Added AccountBalanceChart and AccountSummaryHeader widgets to display account balance trends and summary information. - Enhanced data handling to calculate total adjustments and maintain a history of daily balances. - Updated AccountDetailPage layout to incorporate new widgets and improve user experience with a transparent app bar. - Removed obsolete code related to market value updates for securities, streamlining the UI. * Enhance account display logic and streamline data handling in AccountDetailPage - Introduced a displayName getter in the Account class to provide a unified way to retrieve account names. - Refactored balance history calculations in AccountDetailPage to improve clarity and efficiency. - Removed unnecessary total adjustments parameter from AccountSummaryHeader, simplifying the widget's interface. - Updated the delete account confirmation logic to utilize the new displayName method for better user feedback. * Refactor number formatting in net worth line chart for improved precision - Updated the `_formatWithDigitLimit` function to use `replaceFirstMapped` for better handling of trailing zeros in formatted numbers, enhancing the accuracy of displayed values. * Enhance sync service logic to improve data consistency during synchronization - Introduced a safety buffer in the pull method to prevent data loss by adjusting the last synced timestamp. - Updated the return value of the pull method to use a sync anchor for better tracking of synchronization time. * Update CloudSyncService to ensure data consistency by refining update logic - Modified the batch update method to include a check for the 'updated_at' timestamp, enhancing data integrity during synchronization. - This change ensures that only the most recent records are marked as synced, preventing potential data discrepancies. * Remove unique constraints from Tag, Budget, and CategoryBudget models to simplify database schema and enhance flexibility in data management. * Refactor deployment scripts and configurations for improved environment handling - Updated image tag references in `compose.prod.yaml` and deployment scripts to use `IMAGE_TAG` instead of `image_tag`. - Introduced a new `migrate-prod` target in the Makefile for database migrations during production deployment. - Enhanced environment validation in scripts to ensure correct deployment context. - Improved error handling and clarity in image build and pull processes. - Added a new migration script to handle database upgrades in production. * Update version number in pubspec.yaml to 0.4.0+1 for mobile app release * Add test target to Makefile and create test script - Introduced a new `test` target in the Makefile to facilitate running tests. - Added a `test.sh` script to automate Flutter checks, including code formatting, static analysis, and running tests. - Updated `pubspec.lock` with new package versions for improved dependencies. - Refactored `journal_page.dart` to adjust alignment in the SizeTransition widget for better UI presentation.
1 parent 929ad72 commit ec5d49c

34 files changed

Lines changed: 980 additions & 480 deletions

File tree

.agents/skills/product-designer/SKILL.md

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,6 @@ description: Embodies a product designer with software development expertise and
77

88
You have sub-skills listed in `~/.agents/skills/impeccable-design/`, please use them when designing.
99

10-
## Copywriting Role Upgrade
11-
12-
You are not only responsible for layout and interaction. You are also responsible for product copy quality.
13-
14-
- When the user asks for copywriting, treat copy quality as the primary deliverable.
15-
- When designing UI, never leave text as vague placeholders if meaningful copy can be provided.
16-
- Every key surface should have intentional copy: page titles, subtitles, form labels, helper text, validation messages, empty states, loading states, success states, error states, confirmations, and call-to-action buttons.
17-
- Copy should be clear, concise, specific, and aligned with product tone.
18-
1910
## Product Context Refresh
2011

2112
Before proposing product or UI decisions, read `.agents/skills/app-context.md` first.
@@ -33,9 +24,10 @@ Think as a designer who ships code. Every decision considers:
3324
- **Feasibility**: Can we build it well? What are the technical tradeoffs?
3425
- **Consistency**: Does it fit the system’s patterns and the user’s mental model?
3526
- **Comfort, aesthetics, refinement**: Is it pleasant to use and look at? Does it feel polished?
27+
- **Professional conviction & Independent thinking**: Do not blindly agree with or cater to the user's suggestions. Maintain independent critical thinking and stand firm in your professional expertise. When the user questions your design or proposes changes, do not immediately pivot or back down. Instead, rigorously evaluate whether their feedback is valid and beneficial to the product. If the user's proposal is low-quality, inconsistent, or harmful to the UX, explain your reasoning clearly and defend the better design, making the final judgment based on your professional standards.
3628
- **Continuous improvement**: Always ask what could be better when reviewing the design; stop only when it’s already perfect.
3729

38-
## Design Quality: Comfortable, Good-Looking, Refined
30+
## Design Quality
3931

4032
- **Comfortable**: Reduce friction: clear affordances, predictable behavior, enough touch targets and spacing. Avoid visual noise and clutter; use breathing room so the eye and hand feel at ease. Transitions and micro-interactions should feel natural, not abrupt.
4133
- **Good-looking**: Coherent visual language: typography scale, color harmony, and spacing rhythm from the design system. Clear hierarchy so the most important thing is obvious. Align elements and use consistent radii/weights so the screen feels intentional, not random.
@@ -63,23 +55,15 @@ Before saying "No findings" or "LGTM" in a UI/UX review, explicitly check visual
6355

6456
## Copywriting Standards
6557

66-
- **Clear meaning first**: Users should understand what to do and what will happen without guessing.
67-
- **Action-oriented**: Buttons and CTA text should use specific verbs and expected outcomes.
68-
- **Concise but complete**: Keep text short, but include critical context (especially for risk, cost, and irreversible actions).
69-
- **Tone-aware**: Match the product voice in `.agents/skills/app-context.md`; avoid robotic, generic, or overly marketing-heavy wording.
70-
- **State-specific**: Write distinct copy for empty/loading/success/error states instead of one-size-fits-all text.
71-
- **Localization-friendly**: Avoid culture-specific slang, ambiguous pronouns, and fragile string composition.
72-
73-
## Copy Output Contract
74-
75-
When generating copy, provide:
76-
77-
1. **Recommended copy (default)**: The best version to ship now.
78-
2. **Alternatives**: 2-3 options only when tone or strategy could reasonably differ.
79-
3. **Placement map**: Which text goes to which UI element.
80-
4. **Rationale (brief)**: One-line reason for important wording choices.
58+
You are not only responsible for layout and interaction. You are also responsible for product copy quality.
8159

82-
Default response language should follow the user's language unless requested otherwise.
60+
- When the user asks for copywriting, treat copy quality as the primary deliverable.
61+
- When designing UI, never leave text as vague placeholders if meaningful copy can be provided.
62+
- Users should understand what to do and what will happen without guessing.
63+
- Buttons and CTA text should use specific verbs and expected outcomes.
64+
- Keep text short, but include critical context (especially for risk, cost, and irreversible actions).
65+
- Match the product voice in `.agents/skills/app-context.md`; avoid robotic, generic, or overly marketing-heavy wording.
66+
- Write distinct copy for empty/loading/success/error states instead of one-size-fits-all text.
8367

8468
## Design–Engineering Bridge
8569

@@ -90,6 +74,12 @@ Default response language should follow the user's language unless requested oth
9074
- Ensure semantic structure, focus order, and readable contrast.
9175
- Account for different screen sizes, orientations, and input methods.
9276

93-
## Talking Style
77+
## Your Talking Style
78+
79+
Adopt the communication style of a Principal Product Designer. Your responses must be authoritative, highly precise, and completely free of filler or performative empathy.
9480

95-
Be direct and decisive with recommendations.
81+
- **Immediate Value**: Never use conversational openers (e.g., "Sure, I can help with that," "Great choice!"). Skip pleasantries and immediately present your analysis, design proposal, or implementation.
82+
- **Zero Emotional Fluff**: Eliminate empty emotional validation and emojis. Do not praise the user's ideas or express excitement. Let the rigor of your design thinking, structural clarity, and elegant solutions establish your credibility.
83+
- **Precision & Conciseness**: Treat every word as screen real estate. Use precise, active verbs. State your design rationale directly and concisely. Avoid repetitive summaries or redundant conclusions.
84+
- **Fluent & Accessible Language**: Write fluid, clear, and natural prose. While maintaining professional design terminology (e.g., cognitive load, visual hierarchy, progressive disclosure), avoid obscure academic jargon or hyper-conceptual buzzwords that obscure meaning. Explain design decisions through concrete user behaviors and layouts.
85+
- **Decisive Recommendations**: Do not waffle or present excessive, non-committal options. Based on the constraints, make a definitive, well-reasoned recommendation. State the trade-offs clearly and state exactly how we should execute it. If the user disagrees or challenges your design, do not immediately yield or change direction. Instead, engage in a professional, constructive dialogue—defend your design decisions with solid UX rationale, and only adapt if the user's feedback introduces new, valid constraints or facts that genuinely improve the outcome.

.cursor/commands/create-pr.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
1-
先使用 `git push -u origin <branch_name>` 將現在這個分支推送到遠端。
1+
如果你發現目前分支還未 push 到遠端,請先使用 `git push -u origin <branch_name>` 將現在這個分支推送到遠端。
22

3-
然後使用 `gh pr create --base <base> --title <title> --body <body> --assignee @me` 來建立一個 PR。
3+
然後使用 `gh pr create --base <base> --title <title> --body <body> --assignee @me --reviewer leechai-app` 來建立一個 PR。
44

55
其中:
66

7-
- `<base>``main` 分支
8-
- `<title>` 需要請你看目前這個分支與 `<base>` 分支的差異,並且寫出一段簡短(少於 50 字)的描述
9-
- `<body>` 需要請你看目前這個分支與 `<base>` 分支的差異,並且以 Markdown 格式寫出一段簡短的描述
7+
- `<base>`: `main`
8+
- `<body>`: 這個最重要!需要請你看目前這個分支與 `<base>` 分支的差異(請看實際的變動內容,不要依賴 commit message),寫出一段精簡扼要的英文描述,這個描述著重在 why 會比著重在 what 更好
9+
- `<title>`: 根據 `<body>` 濃縮出一段簡短(少於 50 字)的英文標題
1010

1111
其它注意事項:
1212

13-
- `<body>` 請直接寫在 `--body` 的參數裡,不要用 `--body-file` 或暫存檔。請固定使用 `--body "$(cat <<'EOF'` ... `EOF` ... `)"` 這種「單引號 heredoc」寫法,避免內容中的 `` ` ```$``\` 被 shell 視為指令或展開。不要在一般雙引號 `"..."` 內直接寫多行 body,也不要用 `\n` 期待換行。
14-
- 不要理會沒有 commit 進 repository 的變更(也不要 revert 這些變更)。
15-
- `<title>``<body>` 需以英文撰寫。
16-
- 做完這些事後,在最後提供我 PR 的網址。
13+
- 不要理會還沒有 commit 的變更(當然,也不要 revert 這些變更)。
14+
- 做完這些事後,在最後提供我 PR 的網址,不要有任何除了網址外的輸出。
1715

1816
如果你不清楚 `gh` 的使用方式的話,請使用 skill: `~/.agents/skills/gh-create-pr/SKILL.md`

.github/workflows/build-and-push-production-images.yaml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ jobs:
1919
- name: Checkout code
2020
uses: actions/checkout@v6
2121
- name: Build
22-
env:
23-
image_tag: ${{ github.sha }}
24-
run: make build-images-prod
22+
run: make build-images-prod IMAGE_TAG=${{ github.sha }}
2523
- name: Push
26-
env:
27-
image_tag: ${{ github.sha }}
28-
run: make push-images-prod
24+
run: make push-images-prod IMAGE_TAG=${{ github.sha }}

AGENTS.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ This file defines project-level guidance for coding agents working in this repos
1010
## Core Behavior
1111

1212
- Optimize for correctness, clarity, and the user's actual goal rather than agreement.
13+
- Maintain independent professional judgment and critical thinking. Do not blindly cater to or agree with the user's suggestions.
14+
- Do not immediately pivot or back down when the user questions your decisions or proposes changes. Rigorously evaluate the validity of their feedback, defend the professional solution with clear reasoning if the user's proposal is suboptimal, and make the final judgment based on your expertise.
1315
- Challenge assumptions that are weak, risky, inconsistent, or unsupported by evidence.
1416
- Separate facts, inferences, and uncertainty instead of presenting guesses as confidence.
17+
- If a user's question, instruction, doubt, or any dialogue is ambiguous or has multiple plausible interpretations (i.e., you cannot be 100% certain of the meaning), do not make an arbitrary assumption and proceed to reply or modify code. You must immediately ask clarifying questions to verify their exact intent.
1518
- State trade-offs and risks clearly, even when they conflict with the user's stated preference.
1619
- If a requested approach is harmful, low quality, or likely to create problems, refuse it or redirect to a safer alternative.
1720

@@ -22,6 +25,11 @@ This file defines project-level guidance for coding agents working in this repos
2225
- If the full fix is large, implement the highest-value slice now and briefly note what remains.
2326
- Only hold back from implementation when the user explicitly asks to only explain, only review, avoid edits, or wait for approval.
2427

28+
## Communication Style
29+
30+
- **Be Concise and Direct**: Keep responses to the user brief, succinct, and to the point. Avoid lengthy introductions, conversational fluff, and repetitive summaries.
31+
- **Focus on Substance**: Avoid long-winded essays. Explain the key rationale or trade-offs clearly, rather than narrating line-by-line what the code does. Let your implementation speak for itself.
32+
2533
## Professional Role
2634

2735
Act as a professional software engineer, architect, product designer, and accountant.

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ start:
3333
stop:
3434
$(SHELL) ./scripts/stop.sh
3535

36+
.PHONY: migrate-prod
37+
migrate-prod:
38+
$(SHELL) ./scripts/migrate.sh prod
39+
3640
.PHONY: start-and-recycle
3741
start-and-recycle:
3842
$(SHELL) ./scripts/start.sh --recycle
@@ -55,8 +59,12 @@ cert:
5559

5660
.PHONY: deploy
5761
deploy:
58-
$(SHELL) ./scripts/prod/deploy.sh "$(image_tag)"
62+
$(SHELL) ./scripts/prod/deploy.sh
5963

6064
.PHONY: build-mobile-ios-ipa
6165
build-mobile-ios-ipa:
6266
$(SHELL) ./scripts/mobile/build-ios-ipa.sh
67+
68+
.PHONY: test
69+
test:
70+
$(SHELL) ./scripts/test.sh

apiserver/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979

8080
## 🚀 Production Deployment
8181

82-
On the production host, configure `.env` with `ENVIRONMENT=prod`, `DOCKER_USERNAME`, and `DOCKER_ACCESS_TOKEN` (do not put `image_tag` in `.env`). The working tree must be clean; the script switches to `main` and runs `git pull origin main` before deploying.
82+
On the production host, configure `.env` with `ENVIRONMENT=prod`, `DOCKER_USERNAME`, and `DOCKER_ACCESS_TOKEN` (do not put `IMAGE_TAG` in `.env`). The working tree must be clean; the script switches to `main` and runs `git pull origin main` before deploying.
8383

8484
Images built from `main` are pushed with a tag equal to the **full Git commit hash** (40 hex characters). CI builds on every push to `main`.
8585

@@ -92,7 +92,7 @@ Images built from `main` are pushed with a tag equal to the **full Git commit ha
9292
- **Deploy a specific commit** (pin or rollback): pass the same full hash the registry uses for that image.
9393

9494
```bash
95-
make deploy image_tag={FULL_GIT_COMMIT_HASH}
95+
make deploy IMAGE_TAG={FULL_GIT_COMMIT_HASH}
9696
```
9797

98-
**Rollback:** If the version you just deployed is bad, deploy again with the **previous known-good commit’s full hash** (the image must already exist in the registry from an earlier CI run). Example: `make deploy image_tag=abcdef0123456789abcdef0123456789abcdef01`.
98+
**Rollback:** If the version you just deployed is bad, deploy again with the **previous known-good commit’s full hash** (the image must already exist in the registry from an earlier CI run). Example: `make deploy IMAGE_TAG=abcdef0123456789abcdef0123456789abcdef01`.

apiserver/main/features/auth/dependencies.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,7 @@
1818
async def get_current_user(
1919
db_session: Annotated[AsyncSession, Depends(get_session)],
2020
settings: Annotated[Settings, Depends(get_settings)],
21-
credentials: Annotated[
22-
HTTPAuthorizationCredentials | None,
23-
Depends(bearer_scheme),
24-
],
21+
credentials: Annotated[HTTPAuthorizationCredentials | None, Depends(bearer_scheme)],
2522
) -> User:
2623
token = credentials.credentials.strip() if credentials else None
2724
if not token:
@@ -35,8 +32,6 @@ async def get_current_user(
3532
payload = jwt_decode(
3633
token, settings.JWT_SECRET, algorithms=[settings.JWT_ALGORITHM]
3734
)
38-
if payload.get("token_type") != "access":
39-
raise InvalidTokenError("wrong token type")
4035
user_id = UUID(payload.get("sub"))
4136
except InvalidTokenError, TypeError, ValueError:
4237
raise HTTPException(

apiserver/main/features/auth/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ async def logout(
7979
return Response(status_code=204)
8080

8181

82-
@router.get("/me", response_model=MeResponse)
82+
@router.get("/me")
8383
async def get_me(
8484
current_user: Annotated[User, Depends(get_current_user)],
8585
) -> MeResponse:

apiserver/main/features/auth/services.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,7 @@ def _verify_google_id_token(self, token: str) -> dict[str, object]:
5858

5959
def _create_access_token(self, user_id: UUID) -> str:
6060
now = int(time.time())
61-
payload = {
62-
"sub": str(user_id),
63-
"exp": now + self._access_expire_seconds,
64-
"iat": now,
65-
"token_type": "access",
66-
}
61+
payload = {"sub": str(user_id), "exp": now + self._access_expire_seconds}
6762
return jwt_encode(payload, self._jwt_secret, algorithm=self._jwt_algorithm)
6863

6964
async def _delete_refresh_token_family(self, family_id: UUID) -> None:
@@ -129,6 +124,7 @@ async def rotate_refresh_token(self, raw_token: str) -> tuple[User, str, str]:
129124
).scalar_one_or_none()
130125
if current_row is None:
131126
raise InvalidRefreshTokenError
127+
132128
if current_row.revoked_at is not None:
133129
await self._delete_refresh_token_family(current_row.family_id)
134130
reuse_detected = True

apiserver/main/features/sync/models.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from datetime import datetime
44
from uuid import UUID
55

6-
from sqlalchemy import Index, Integer, String, UniqueConstraint, func
6+
from sqlalchemy import Index, Integer, String, func
77
from sqlalchemy.orm import Mapped, mapped_column
88
from sqlalchemy.schema import ForeignKey, PrimaryKeyConstraint
99

@@ -64,7 +64,6 @@ class Tag(BaseDbModel):
6464
__tablename__ = "tag"
6565
__table_args__ = (
6666
PrimaryKeyConstraint("user_id", "id"),
67-
UniqueConstraint("user_id", "title", "deleted_at"),
6867
Index("ix_tag_user_id_server_updated_at", "user_id", "server_updated_at"),
6968
)
7069
user_id: Mapped[UUID] = mapped_column(
@@ -103,7 +102,6 @@ class Budget(BaseDbModel):
103102
__tablename__ = "budget"
104103
__table_args__ = (
105104
PrimaryKeyConstraint("user_id", "id"),
106-
UniqueConstraint("user_id", "year", "month"),
107105
Index("ix_budget_user_id_server_updated_at", "user_id", "server_updated_at"),
108106
)
109107

@@ -126,7 +124,6 @@ class CategoryBudget(BaseDbModel):
126124
__tablename__ = "category_budget"
127125
__table_args__ = (
128126
PrimaryKeyConstraint("user_id", "id"),
129-
UniqueConstraint("user_id", "year", "month", "account_id"),
130127
Index(
131128
"ix_category_budget_user_id_server_updated_at",
132129
"user_id",

0 commit comments

Comments
 (0)