Commit Graph

133 Commits

Author SHA1 Message Date
0f3b981b0f chore(README): update readme 2026-03-26 20:06:40 +09:00
ecca0182f8 chore(uiScoreStore): logger 2026-03-26 17:54:49 +09:00
da2c947efd feat: logger 2026-03-26 17:53:18 +09:00
276f45c58e feat: log level 2026-03-26 17:43:26 +09:00
bff8cc8624 feature: logger 2026-03-26 17:40:44 +09:00
21ea49f7c7 refactor(global): import alias @ 2026-03-26 15:54:42 +09:00
3a7525ae8d style(ClubSummary): remove button text and container for follow actions
Refactor the title section to use raw icon components instead of Button components.
- Removed the surrounding <Flex> wrapper for the name and action.
- Removed the "取消关注" (Unfollow) and "关注" (Follow) text labels.
- Replaced Button components with direct StarFilled and StarOutlined icons
  to reduce visual clutter and align with the icon-only design.
2026-03-26 14:14:07 +09:00
da4c123015 style(ClubSearchTable): adjust search input container flex width and min-width
- Add minWidth: 180 to the main flex container to prevent excessive shrinking.
- Change the search input container width from fixed minWidth: 400 to dynamic width: '100%' with a new minWidth: 200.

This ensures better responsiveness on smaller screens while maintaining usability.
2026-03-26 14:02:16 +09:00
f16f97b4c8 feat(club-event-list): add refresh button for event list Introduces a new refresh button located in the pagination control section. This button allows users to manually trigger a reload of the club events. It uses the SyncOutlined icon and is linked to the requestEvents API. The button also displays a loading state while the refresh is in progress. 2026-03-26 13:54:34 +09:00
5927861af7 feat(club-management): add club follow/unfollow functionality
Introduce a follow/unfollow feature for clubs in the ClubSummary component.
Users can now toggle their subscription status to a specific club, with
the state persisted locally using zustand.

Changes include:
- Added 'Follow' and 'Unfollow' buttons with corresponding star icons (StarOutlined/StarFilled).
- Updated ClubStore to manage a simplified list of clubs (id and name only).
- Refactored Data type in ClubSearchTable to use Pick<ClubInfo, 'id' | 'name'>.
- Fixed club name in GameSelector clubList to '东华乒乓球俱乐部'.
- Excluded follow buttons for club ID '47' (Donghua).

The implementation ensures a consistent UI state across the application
and persists user preferences.
2026-03-26 13:44:32 +09:00
f1ca5cda75 feat: remove web-push dependency and add event summary links to game table
- Remove web-push and related sub-dependencies (asn1.js, http_ece, etc.) from package.json and bun.lock
- Update AppBar z-index to 8 for proper layering
- Enhance GameTable component:
  - Add Skeleton loading states for event names
  - Introduce EventName component with Link to event detail pages
  - Fix column widths and add row-span logic for event grouping
  - Enable horizontal scrolling for better mobile view
- Add /api/match-summary/:matchId endpoint for frontend event name fetching
- Rename getEventInfo to getMatchSummary in KaiqiuService for consistency
2026-03-26 11:52:25 +09:00
53b7f9928e chore(KaiqiuService): remove debug log statement
Removes the console.debug statement for 'clubId' from the method. This cleanup is performed to eliminate unnecessary debug output in production code and improve log clarity.
2026-03-25 23:26:23 +09:00
4453dd6430 refactor(service, routes, types): extract match summary and link to club
- Extract club information (clubId, clubName) from event page in `getEventInfo`.
- Update `getMatchDetail` to return both `detail` and `summary`.
- Introduce `MatchSummary` interface in `src/types/index.ts`.
- Update `EventPage` to display the club name and link to the club page.
- Adjust `EventSubscribeService` and loaders to handle the new return structure.
- Clean up test files and mock data loading logic.
2026-03-25 23:20:33 +09:00
3cd47a1b4d fix(services): correct log messages and error handling in event services
- Capitalize 'Event' in debug logs for consistency
- Fix syntax error in EventWatchSchedule debug message (removed trailing backtick)
- Upgrade subscription error logging from debug to error level for better visibility
- Standardize event URL format in match detail logs

These changes improve logging accuracy and ensure critical subscription errors are not missed.
2026-03-25 22:35:59 +09:00
77530d4c65 refactor(EventSubscribeService): switch to sequential execution and add debug logs
- Replace Promise.all concurrency with sequential for...of loop when fetching event info and match details
- Add console.debug logs to track event processing status and URL retrieval
- Improves visibility into the event fetching flow for easier debugging
- Ensures events are processed one by one before being categorized
2026-03-25 21:53:20 +09:00
16b2899946 chore(services): add debug logging to getUidScore function
Add console.debug logs at the beginning and end of the getUidScore
function in uidScoreStore to track execution flow and performance.
This aids in debugging when the function is called with large lists
of uids.

- Log start entry with uid count
- Log end entry with uid count
2026-03-25 20:34:58 +09:00
30339596d7 feat(search): support province and city filtering for club search
- Add CascaderProvinceCity component to ClubSearchTable for selecting province/city.
- Update KaiqiuService.findClub to accept and append province/city parameters to the query URL.
- Update server-side API handler to extract province/city from query parameters.
- Improve date parsing logic in event processing to handle invalid start dates gracefully.
- Refactor uidScoreStore to use a loop instead of map for better performance/clarity.
- Add debug logging for profile caching in xcxApi.

The search functionality now supports filtering clubs by administrative division, providing users with more precise search results.
2026-03-25 20:27:51 +09:00
03aa0ead18 feat(components/BindKaiqiuAccount): improve loading state and UI for bound account
- Replace null return with Skeleton.Input when binding status is undefined
- Wrap bound account display in a Button with Space layout
- Import Skeleton and Space components from antd

This enhances the user experience by providing a loading skeleton
and making the bound account view more interactive.
2026-03-25 12:13:44 +09:00
67457b0f8b fix(server): handle token verification errors gracefully
Wrap the verifyLogtoToken promise with a catch block to prevent
unhandled promise rejections. When token verification fails,
return an empty payload instead of throwing an error, ensuring
the application continues to run without crashing.

- Added .catch(() => ({ payload: {} })) to the token verification logic
- Prevents downstream errors when the token is invalid or missing
2026-03-25 12:04:31 +09:00
f7b7216ef1 fix(fav-page): switch from static cacheKey to dynamic refreshDeps
- Replace the static `cacheKey` with `refreshDeps: [headers]` in the
  query configuration.
- This ensures the cached data is automatically refreshed when the
  headers dependency changes, rather than relying on a static cache
  identifier.
2026-03-25 12:02:51 +09:00
191906192b feat(cache): remove redis caching and add force refresh mechanism
- Remove Redis-based caching logic from uidScoreStore and xcxApi.
- Add force refresh support to uidScoreRequest in GroupingPrediction component.
- Update server API /api/user/nowScores to accept force parameter.
- Always show refresh button in GroupingPrediction regardless of data state.
- Change default sort type in FavPlayersPage to SCORE_DOWN.
- Clean up unused imports from server.ts.

This change ensures user scores are always up-to-date by bypassing cache
when needed, preventing issues with stale data during manual sync operations.
2026-03-25 11:19:59 +09:00
8be15d51b1 refactor(KaiqiuService): optimize caching for finished matches
- Move `parseEventInfo` and `fetchEventContentHTML` logic into `KaiqiuService`.
- Implement differentiated caching strategies:
  - For finished matches: Cache indefinitely (no TTL) to stop unnecessary HTTP requests since the result is final.
  - For ongoing matches: Retain the 5-minute TTL to fetch live updates.
- Remove unused utility functions from `server.ts`.
- Update type imports to include `EventDetail` and `Player`.

This change reduces server load by avoiding repeated requests for matches with confirmed results, while ensuring live games remain up-to-date.
2026-03-25 09:59:54 +09:00
6cf2d13a73 chore(docker): switch base image to dhi.io/bun:1-debian13-dev
Replace the previous base image 'oven/bun:latest' with 'dhi.io/bun:1-debian13-dev'.
This updates the underlying OS to Debian 13 and pins the Bun version for better consistency.
2026-03-25 01:17:25 +09:00
e37f82f787 refactor(schedules): use explicit array for hour range in event watch
Replace the nodeSchedule.Range object with a literal array for the
hour parameter in the event watch schedule. This makes the scheduled
hours (7 to 22) more explicit and easier to read at a glance, while
maintaining the exact same execution logic.
2026-03-25 01:10:59 +09:00
0cb7c087fc fix(schedules): correct event watch schedule end time to 22:00
The scheduled job for watching events was previously set to run until
hour 23. This changes the `nodeSchedule.Range` end hour from 23 to 22
to ensure the job stops execution correctly before the end of the day.

This is a bug fix to align the actual execution window with the intended
operating hours.

No breaking changes.
2026-03-25 01:06:36 +09:00
95655068b3 feat(components): add bottom drawer for notification permission guide
Introduce a bottom drawer in the notification permission control
component to provide a step-by-step guide for users (specifically
on iOS/Safari) to enable push notifications when the browser does
not support direct requests.

Key changes:
- Added a 'Drawer' component with 'placement="bottom"' to display
  instructions for adding the site to the home screen.
- Updated the permission control panel to use the same bottom
  placement for consistency.
- Refactored the notification control to toggle the drawer state
  upon interaction.

This improves the user experience by explicitly showing how to
enable features that are restricted in PWA-like environments.
2026-03-25 00:54:10 +09:00
36c72a1a11 refactor(services): add Redis caching for match and club data
Introduce Redis caching logic to `getClubInfo` and `getMatchDetail` methods in `KaiqiuService` to improve performance and reduce network requests.

- Added optional `force` parameter to bypass cache when needed.
- Implemented cache fallback for connection timeouts.
- Updated cache expiration times (e.g., 24h for club info, 5m for match details).
- Propagated the `force` parameter from `EventSubscribeService` to ensure data freshness.
2026-03-25 00:19:26 +09:00
548700319f style(KaiqiuService): merge see and nums into single string
Update the `info` array generation logic to concatenate the `see` and `nums` values into a single string separated by a space, instead of keeping them as separate array elements.

This change standardizes the format of the information display for match events.
2026-03-25 00:09:04 +09:00
53a95bfdf2 feat(kaiqiu): add match nums and view count with Redis caching
- Extract 'nums' (号码) and 'see' (查看次数) from event page content.
- Include extracted data in the `IEventInfo` structure for display.
- Implement Redis caching for event details (key: `my-kaiqiuwang:event-info:${eventId}`).
- Cache strategy: Store result for 60 seconds, or refresh if cached data shows timeout errors or force flag is set.
- Reduces redundant external requests and improves response reliability.
2026-03-25 00:05:06 +09:00
2bcf7eb8d8 chore: add .continue directory to gitignore
Exclude the .continue directory from version control to prevent
unwanted configuration or log files from being committed.
2026-03-24 21:11:49 +09:00
cfa59dfb40 chore(docker): mount local time and timezone to container
Added volume mappings for /etc/localtime and /etc/timezone to ensure
the container uses the host's time and timezone settings.

This prevents time discrepancies in logs and scheduled tasks without
requiring manual timezone configuration inside the image.
2026-03-24 20:26:14 +09:00
04a347c981 feat(api): add cache and force refresh for club events; fix event watch rate limits
- Introduce Redis caching for event lists to reduce redundant fetches and handle timeouts gracefully. Added a `force` query parameter to bypass cache when needed.
- Added a check in `EventWatchSchedule` to skip processing if player list is empty, preventing errors from rate-limited or failed requests.
- Updated the `listClubEvents` signature to accept the new `force` parameter and modified API endpoints to propagate this flag.
2026-03-24 18:12:39 +09:00
8d18796d9b refactor(schedules): use Asia/Tokyo timezone for event logs
- Import and extend 'dayjs' with 'utc' and 'timezone' plugins.
- Update logging in 'watchEvents' and 'start' methods to explicitly format
  dates in 'Asia/Tokyo' timezone instead of default system time.
- This ensures consistent timestamp representation across different deployment
  environments regardless of the local server timezone.
2026-03-24 17:58:23 +09:00
0a1c424798 feat(schedules): add next invocation logging for event-watch job
- Import 'dayjs' to format timestamps for better readability.
- Store the scheduled job instance in a private field to access next execution time.
- Update the 'start' method to log the job name and the precise next run time.
- Update 'watchEvents' method with a debug log for the next invocation.

This improves observability by showing exactly when the scheduled task is expected to run next, rather than just the schedule definition.
2026-03-24 17:55:02 +09:00
8dff4009bf refactor(schedules): use Range object for hour definition in EventWatchSchedule
Replace the string '7-23' with new nodeSchedule.Range(7, 23) for the hour configuration.
This change aligns the schedule definition with the explicit Range object type,
potentially improving type safety or ensuring compatibility with the underlying node-schedule library behavior.
2026-03-24 17:45:09 +09:00
5ab0d9d188 fix(schedules): limit event watch task to 7-23 hours
The event watch schedule was previously running every 5 minutes all day.
Added 'hour: 7-23' configuration to restrict the task execution to
business hours, preventing unnecessary load during off-peak times.
2026-03-24 17:41:58 +09:00
58cf736e82 feat(notification): add click-to-open functionality and cleanup test notification
- Update useFirebaseNotificationProcessor to handle notification clicks by opening the URL from data.url.
- Implement notificationclick event handler in sw.ts to redirect users when a notification is clicked.
- Simplify the registration success notification in index.tsx by removing the unnecessary JSON body argument.
- Ensure seamless navigation when users interact with push notifications by passing the URL through the notification payload.
2026-03-24 17:33:52 +09:00
2774037012 feat(app): add push notification support and event management logic
- Introduce PermissionControlPanel in UserCenter for managing notification permissions.
- Update Service Worker (sw.ts) to handle background push notifications via Firebase Cloud Messaging.
- Implement EventSubscribeService logic to fetch active events, filter expired ones, and clean up subscriptions.
- Refactor KaiqiuService and parsing utilities to include eventId in event details.
- Remove deprecated ScheduleService and inline sendNotification logic.
- Update utility functions to support new types and notification checks.
- Add VAPI public key configuration and update Firebase exports.
2026-03-24 17:21:50 +09:00
94b82ba919 feat: refactor websocket notifications and service caching
Refactor the application to implement native browser push notifications and remove unnecessary Redis caching for performance optimization.

Key changes:
- Introduce a dedicated server topic 'SERVER_PUSH' to handle push notification messages via WebSocket.
- Implement a Service Worker (sw.ts) to capture push events and display system-level notifications, replacing the previous Ant Design toast usage for server messages.
- Add a "Notification Permission" button in the User Center to allow users to request push notification rights.
- Remove Redis caching logic from KaiqiuService (event lists, match details, and member details) to ensure real-time data accuracy, as the cache was causing latency in updates.
- Clean up WebSocket service subscription logic to focus on user-specific events.

This shift from UI-only notifications to system push notifications improves visibility for critical server events (like match updates) even when the user is not on the active tab. Additionally, removing the cache simplifies the codebase and ensures the latest match data is always fetched.
2026-03-23 19:13:39 +09:00
36e280cb9f fix(GroupingPrediction): show refresh button when uidScoreRequest data exists
Previously, the refresh button was hidden whenever the cached uidScore size
was greater than 0, or when the cached data was empty. This logic prevented
the button from appearing even after a data request successfully returned
data in uidScoreRequest.

The updated logic now checks both the cached uidScore and the request data.
If either contains data, the button is shown, ensuring users can refresh
scores regardless of the caching state.
2026-03-23 14:44:59 +09:00
0c82384fd5 feat(api & services): add error handling for club summary and refresh match details
- Add `.catch(() => null)` in `ClubSummary.tsx` to gracefully handle failed API requests and prevent UI crashes.
- Return `null` from `ClubSummary` when the club data is `null` to skip rendering during errors.
- Extract `getMatchInfo` logic into a new static method `getMatchDetail` within `KaiqiuService` for better separation of concerns.
- Update `getClubLocation` and `getEventInfo` to accept an optional `force` parameter, allowing cache bypass when network errors (like '连接超时') occur.
- Remove the old `getMatchInfo` utility function from `server.ts` and update the `/api/match` route to use `KaiqiuService.getMatchDetail`.
2026-03-23 14:33:12 +09:00
76b68c0ea6 refactor(ws): unify WebSocket topic handling and add event subscription
- Refactor `WebSocketService` and `common.ts` to use a unified topic system instead of custom prefixes.
- Replace manual topic string concatenation with `getEventSubKey` and defined `WsServerSendTopics` types.
- Update client-side components (`EventCard`, `GroupingPrediction`) to support real-time event subscriptions and notifications.
- Move `useAuthSocket` and `WebScoketContext` initialization into `AppBarLayout` to ensure WebSocket state is available globally.
- Add error handling to WebSocket message processing in the Bun server.
- Implement a manual "Refresh Current Scores" button for `GroupingPrediction` to fetch fresh `nowScore` data.
- Update `HydrateFallback` UI to display a loading message instead of a refresh button during long load times.
- Add Service Worker (`sw.js`) build route to the Bun server configuration.
2026-03-22 13:00:50 +09:00
fd8257e194 feat(api): add user location management endpoints and database model
- Added `UserLocation` model to `prisma/schema.prisma` to store user location data including coordinates (point geometry), name, avatar, and bindings to Logto and Kaiqiu users.
- Created new API endpoints under `/api/account/location` to handle location operations:
  - `POST`: Create a new location record for a user.
  - `GET`: Retrieve nearby locations based on latitude and longitude.
  - `PUT`: Update an existing location record, including coordinate updates via spatial index.
  - `DELETE`: Remove a specific location record.
- Integrated the custom spatial operations from `xprisma` DAO to support geospatial queries and updates.
- Updated dependencies to include `@mui/icons-material` (and its peer dependencies like `prop-types` and `react-transition-group` which are implicitly required by the new icon components).
- Implemented `verifyLogtoToken` logic to secure the new endpoints and associate locations with authenticated users.

No breaking changes in API contracts; new endpoints are additive.
2026-03-19 00:29:02 +09:00
5168bdca29 feat(user-center): enhance loading fallback and avatar display
- Update HydrateFallback to show a refresh button after 10 seconds of loading
- Improve UserCenter avatar by using username/name as fallback when image is missing
- Add /dev route pointing to HydrateFallback component
2026-03-18 10:02:45 +09:00
3be476ad13 feat(UserCenter): add background change functionality
This commit introduces a new `ChangeBackground` component into the User Center page.
The component is now rendered before the main content to dynamically update the
background based on the user's picture URL.

- Added import for `ChangeBackground` component.
- Integrated `ChangeBackground` with the user's picture URL (falling back to empty string if unavailable).
- No breaking changes or migration required.
2026-03-18 01:59:21 +09:00
845a50253b chore: refactor dockerfile for prisma migration and build optimization
Refactor the Dockerfile to separate dependency installation and type
generation from the runtime environment.

Changes:
- Moved `bun prisma generate` to the build phase to ensure type definitions
  are created during image build rather than at runtime.
- Updated the ENTRYPOINT to run `bun prisma migrate deploy` before starting
  the application. This ensures database migrations are applied automatically
  upon container startup, supporting production deployments with incremental
  schema changes.
- Added missing newline at the end of the file for compliance.

This change ensures that the application handles schema updates safely in
production without requiring a separate migration step outside the container.
2026-03-18 01:39:54 +09:00
1793c10b45 feat(components): add navigation to profile on UID click
- Modified `BindKaiqiuAccount` to wrap the UID text in a clickable `Flex` component.
- Added an `ExportOutlined` icon to indicate the actionable link.
- Implemented navigation to `/profile/{uid}` when the UID section is clicked, utilizing the `useNavigate` hook.
- Imported the new icon and navigation hook to support this interaction.
2026-03-18 01:30:23 +09:00
c70aeda412 feat(auth): add Kaiqiu account binding and update WebSocket architecture
- Add `UserBind` model to Prisma schema for linking Logto and Kaiqiu user IDs.
- Implement `/api/account/bind` endpoint (GET/PUT) to handle Kaiqiu account binding and retrieval.
- Refactor `KaiqiuService` to include a `login` method that performs browser automation-like login on kaiqiuwang.cc using `cheerio` and `fetch`.
- Update `UserCenter` page to include a new `BindKaiqiuAccount` component.
- Restructure `WebSocketService`:
  - Change from a simple global connection map to a per-user client tracking system (`#userClients`).
  - Update topic naming conventions (e.g., `ONLINE_MEMBER_CHANGE` -> `MEMBER_CHANGE`).
  - Add client-side broadcast capabilities for user-specific events like `MY_CLIENT_ONLINE`.
  - Add support for dynamic subscription handling (SUB/UNSUB) via WebSocket messages.
- Update `verifyLogtoToken` to accept either `Headers` or a raw token string for flexibility in WebSocket auth.
- Minor fixes: typo corrections in `WSTopic` enum and commented out debug logs.

BREAKING CHANGE: WebSocket payload structure has changed.
The `ws.data` property now contains a `WsPaylaod` object with a `user` field (previously it was a JSON string of the JWT payload).
The `WSTopic` names have been updated (e.g., `ONLINE_MEMBER_CHANGE` is now `MEMBER_CHANGE`), requiring updates to any client code subscribing to these topics.
2026-03-18 01:18:34 +09:00
09f3ecaca6 feat(WebSocket & Event System): Add real-time updates and event subscription
Introduces WebSocket connectivity for live data updates and a new subscription model for events.

Key changes:
- Integrated WebSocketService to handle open, message, and close events via the /ws endpoint.
- Added EventSubscribeService APIs to manage user subscriptions to specific events (matchId) via REST endpoints (`/api/subscribe-event` and `/api/subscribe-event/:matchId`).
- Implemented custom message protocol (JSON format) for WebSocket communication with defined topics (ONLINE_MEMBER_CHANGE, etc.).
- Updated database schema to include the `EventSubs` model for storing subscriptions.
- Refactored Dockerfile to use `bun prisma db push` for database migrations on startup.
- UI Updates:
  - Replaced the Rate component in FavButton with Star icons for better UX.
  - Adjusted layout of FavButton to be absolute positioned.
  - Added debounce to ClubSummary data fetching.
  - Removed unused `isMobile` import from ClubSummary.
- Utilities: Added helper functions `toCustomMessage` and `fromCustomMessage` for parsing WebSocket messages.
2026-03-17 17:26:52 +09:00
c7faeb1b65 feat(api-versioning): remove git-based versioning and serve via HTML script tag
- Remove `getGitHash` function from `src/utils/server.ts` as it relied on `.git` directory presence which is not available in production builds.
- Remove the `/api/app-version` endpoint from `src/index.tsx` since fetching version via API is no longer needed.
- Update `src/hooks/useAppVersion.ts` to derive the version directly from the `src` attribute of a script tag in the HTML head.
- This change improves performance by avoiding an extra API request and ensures version accuracy across all deployment environments without requiring Git metadata.
2026-03-17 11:23:25 +09:00