This project was generated using Angular CLI version 21.2.11.
From frontend/ (repository root → cd frontend):
npm install
npm startnpm start runs ng serve. Open http://localhost:4200/; the app reloads when you change source files.
Design tokens: UI colors, typography (Inter), spacing, and component cues align with design/DESIGN.md; global CSS variables live in src/styles/_design-tokens.scss. The Stitch UI reference mocks live in design/stitch_chateando_ui_redesign/ (applied to the Angular templates via SCSS + Material Symbols, without Tailwind).
If the Angular CLI is on your PATH, you can use ng serve instead of npm start. The backend API is expected at the URLs configured in your Angular environment files; for local full-stack work, run the .NET API (for example https://localhost:7118) alongside this app.
The header includes an EN | ES control. The default locale is English; your choice is stored in localStorage under hc_locale (en or es) and applied on the next visit without rebuilding. DevExtreme widgets and formatted times follow the active locale. User-written chat text and API error bodies are not translated.
When running via Docker, rebuild images after i18n or UI changes so the container serves the latest assets:
docker compose up --buildThe admin app on :4201 uses the same mechanism (see admin/README.md).
- Notifications tab (
/notifications) lists server-backed notification history (messages, buzz, @mentions, announcements) with read/unread state and a nav badge. - Notify when available (client sync): the API persists inbox rows in the database; live delivery uses SignalR once.
ConnectivitySyncService(started fromauthGuardafterensureSession, not inside it) pulls missed notifications on login, hub reconnect, and browseronlineviaNotificationsInboxService.syncFromServer()(GET /api/notifications+ unread count). Scenario A (logged in but offline): badge andliveItemsrefresh when connectivity returns. Scenario B (logged out then login): full fetch on first guarded route without catch-up toasts for backlog. Open chat threads can append missed messages after reconnect (ChatState.catchUpOpenConversation). - Desktop toasts (Windows Action Center via Edge/Chrome): use the bell icon in the header to enable push. Requires browser permission; persisted as
hc_push_enabledinlocalStorage. - Web Push (offline): when you are not connected to SignalR, the API can send VAPID push via
public/sw.js. Configure backendWebPush:PublicKey,WebPush:PrivateKey, andWebPush:Subject(see root.env.example). Generate keys:npx web-push generate-vapid-keys. HTTPS orlocalhostis required for push subscription. - Sidebar DM/group unread badges (
LocalReadStateService) are separate from the notifications inbox and from server read receipts (checkmarks on your outgoing bubbles). - Read receipts: grey/blue
done_allon your sent messages (DM + groups, including BUZZ); click for readers + times (GET /api/chat/messages/{id}/readers). Server cursor sync is debounced inChatThreadReadSyncServiceviaChatState(POST /api/chat/mark-read+ inbox mark-read) — not injected intoLocalReadStateService(avoids circular DI). Live updates: SignalRConversationReadUpdated(ignores events for your ownuserIdin groups). Loading older pages does not advance the server cursor. Tooltip/README: read time is cursorreadAtUtc, not per-message delivery time.
After changing sw.js or notification APIs: docker compose up --build.
src/app/shared/auth-session/— Cross-cutting pieces used by multiple features: access token storage, the HTTPAuthorizationinterceptor, and route guards (auth,guest).authGuardcallsAuthenticatedSessionBootstrapService.ensureSession()thenConnectivitySyncService.ensureStarted(userId)(non-blocking).src/app/shared/connectivity/—ConnectivitySyncService: debounced inbox sync on reconnect/online; coordinates withNotificationsInboxServiceand optional chat tail catch-up.src/app/shared/session/—ChatSessionSyncService(providedIn: 'root') keeps groups and people directory in sync for the whole login session via SignalR:GroupMembershipChanged,GroupUpdated, andDirectoryChanged(admin user/department changes and public register). Started fromChatUnreadRealtimeService; survives leaving/chat.ChatStateandAnnouncementsStatemirror its signals; chat-only hub handlers (presence, reactions, buzz) stay inChatStateand are cleared withoffUiHandlers()on leave.src/app/shared/read-state/— Local unread counters (per signed-in user,localStoragekeychateando_read_state_v1:{userId}): DM watermarks (dm:{peerUserId}), group watermarks (group:{conversationId}), and read announcement IDs.ChatUnreadRealtimeService(providedIn: 'root') keeps a single SignalR connection forMessageReceivedso badges update even on/announcements. Sidebar badges on People, Groups, and Announcements (cap99+); app nav shows an announcements total. Opening a DM/group marks that thread read; visiting/announcementsmarks all items in the loaded feed as read; your own messages and announcements never increment counts. Bootstrap on login refetches group history for all groups and DM history only for peers with a prior watermark (max 30 peers).src/app/features/chat/— Chat UI (/chat): fixed profile block at the top of the sidebar (avatar, name,@username; links to/profile). Announcements feed in the sidebar (sharedAnnouncementsFeedService, REST list +AnnouncementPublishedin real time; View all →/announcementsto publish). People (DM bypeerUserId) and Groups (multi-user rooms). Sidebar lists directory and groups (live viaChatSessionSyncService); New group creates a room (optional initial members). Outgoing messages show read checkmarks;MessageReadersPopupComponentlists who read (sender-only API).ChatThreadReadSyncServiceorchestrates server mark-read when viewing a thread. Senders can delete their own messages (not BUZZ);DELETE /api/chat/messages/{id}removes DB row and file; peers receiveMessageDeletedon SignalR. Thread anchors with replies cannot be deleted.src/app/features/profile/— Read-only profile page (/profile,GET /api/auth/me): name, username, email, phone, department, photo URL, optional Admin badge. Same app shell and top nav as Chat and Announcements. Group header opens a Members panel (add/remove only for the creator). REST + SignalR: DM usesSendMessage; groups useSendGroupMessage(conversationId, body); membership and directory updates are pushed session-wide (seeChatSessionSyncService). Same multipart upload/download flow as DM. Buzz in DM: send with Ctrl+G or the header button; persists a redBUZZmessage in the thread and shakes the recipient's chat area for ~2s (SendBuzz→ message +BuzzReceived). Presence (PresenceSnapshot/PresenceChanged, clientHeartbeatevery 60s) applies to the people list.src/app/features/announcements/— Announcements UI (/announcements) and sharedAnnouncementsFeedService(also used in the chat sidebar). Choose audience (all / department / selected people), title, optional message and/or file attachment, then publish via multipartPOST. List shows only announcements you receive; Download uses blob fetch +fileUrlfrom the API (same pattern as chat file downloads). Real time:AnnouncementPublished(recipients only). Top navigation: Chat | Announcements.src/app/shared/ui/app-nav/— Shared header links (announcements link shows unread badge when total > 0) and sign-out (disconnects SignalR viaSessionLogoutService, clears in-memory read state).src/app/features/<name>/— Feature slices. Each feature groups its logic in one place with three layers:services/— HTTP clients and API types (e.g. auth and departments underfeatures/auth/services/).state/— Injectable page/session state (signals, orchestration, validation messaging) scoped to a route where appropriate.ui/— Standalone route components, templates, and styles.
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
ng generate component component-nameFor a complete list of available schematics (such as components, directives, or pipes), run:
ng generate --helpTo build the project run:
ng buildThis will compile your project and store the build artifacts in the dist/ directory. By default, the production build optimizes your application for performance and speed.
To execute unit tests with the Vitest test runner, use the following command:
ng test- Spec files live under
test/app/, mirroringsrc/app/(same subfolders and file names with.spec.ts). tsconfig.spec.jsonmaps@app/*tosrc/app/*and@environments/*tosrc/environments/*so specs import production code without deep relative paths.- Because the Angular project
sourceRootissrc,angular.jsonusesinclude:["../test/**/*.spec.ts"]so the unit-test builder discovers specs next tosrc/.
For end-to-end (e2e) testing, run:
ng e2eAngular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
For more information on using the Angular CLI, including detailed command references, visit the Angular CLI Overview and Command Reference page.