# Krishna Sales Mobile App This is a Progressive Web App (Pwa) built for the Krishna Sales team. ## Version **1.0.4** ## Changelog ### 1.0.4 **Auth** - Refresh-token sessions: the 15-minute access token now renews itself from the server's HttpOnly `__Host-sm_rt` cookie (`POST /usr/session/refresh`), so users are no longer signed out every 15 minutes. A 401 refreshes once and replays the request; only a refused refresh signs the user out, a network failure never does. Refresh also runs ahead of expiry while the tab is visible, is single-flight across tabs, and sends the idle signal. - Logout now calls `POST /usr/logout` to revoke the session and cookie on the server (retried if the call fails). Sign-out and sign-in in one tab are reflected in the others; a different user signing in elsewhere reloads the tab. - One shared session for all four workflow clients (`src/api/session.ts`) replaces the per-client token copies. Existing sign-ins are cleared once, so everyone logs in again after this update. - Password policy: live rules checklist, forced change on login when the password is expired, temporary or predates the policy, forgot / reset password, and change password. - Password expiry warning & enforcement: Evaluates `user.password_status` (`warn`, `days_left`, `must_change`). Shows a top banner in `ConsoleLayout` with "Change Password" and "Later" skip options during the warning window; automatically launches the mandatory password change dialog when the password has expired. - Note: the refresh cookie is only set when the app and the API share one origin (`VITE_ZINO_API_URL` = `SAME_ORIGIN`, or the app's own host). On a different origin the server returns the token but no cookie, and the session ends when the access token expires. **Maintenance** - Platform notices (`GET /usr/notices`, polled every 30 s): an `announced` strip you can dismiss, a `draining` strip that pauses starting orders / submitting activities, and a full-screen `closed` page that lifts itself when maintenance ends. - A `503 PLATFORM_MAINTENANCE` from any write re-reads the notices and shows the server's reason; any other 503 shows a "service temporarily unavailable" strip. The form keeps its data. ### 1.0.2 - Initial documented version. ## Sitemap ### Public Routes - `/login` - User Authentication ### Authenticated Routes (Console) These routes require the user to be logged in. Roles determine access. #### Daily Logs - `/daily` - My Daily Logs (Sales Officer, Manager, Admin) - `/daily/:instanceId` - View specific daily log - `/all-daily` - All Daily Logs (Manager, Admin) - `/all-daily/:instanceId` - View specific daily log from all #### Orders - `/orders` - View Orders (Sales Officer, Manager, Admin) - `/orders/:instanceId` - View specific order #### Calls - `/calls` - View Calls (Sales Officer, Manager, Admin) - `/calls/:instanceId` - View specific call #### Stores - `/stores` - View Stores (Sales Officer, Manager, Admin) - `/stores/:instanceId` - View specific store #### Reports & Analytics - `/analytics` - Analytics Dashboard (Sales Officer, Manager, Admin) - `/sales-report` - Daily Sales Report (Manager, Admin) #### Admin - `/admin/users` - Manage Users (Manager, Admin) - `/admin/datasets` - Manage Datasets (Admin Only) - `/admin/datasets/:id` - Manage Dataset Items (Admin Only) ## Architecture & Workflows (How Things Work) This app interfaces with a generic backend platform via `ZinoClient` (see `src/api/client.ts`). The business logic is driven by configuring Workflows, Activities, and Views. ### 1. Workflows The app is divided into three primary Workflows, mapped out in `src/api/config.ts`: - **ORDER_BOOKING**: Manages everything from logging a visit, taking an order, to closing an order. - **STORE**: Manages the creation and editing of stores/retailers. - **DAILY_REPORTS**: Manages the Sales Officer's daily punch-in (Day Plan) and punch-out (End of Day report). Each workflow has a unique `workflowUuid` and `versionUuid`. ### 2. How to Add or Start a New Instance When a user submits a form to create something new (e.g., adding a new Store or starting a new Daily Log), the app "starts an instance" of that specific workflow. 1. **Instantiate the Client**: A `ZinoClient` is created for the specific workflow. ```typescript const client = new ZinoClient(BASE_URL, STORE.workflowUuid); ``` 2. **Start the Instance**: The app calls the API to begin the first activity (e.g., `INIT` activity) with the form payload. ```typescript const res = await client.startInstance( STORE.activities.INIT.uid, payload, { version_uuid: STORE.versionUuid } ); ``` 3. **Progressing the Instance**: If the workflow has multiple steps (like Order Booking, which progresses from `LOG_VISIT` to `PLACE_ORDER` to `CLOSE_ORDER`), subsequent updates use `progressInstance` with the existing `instance_id`. ```typescript const res = await client.progressInstance( instanceId, ORDER_BOOKING.activities.PLACE_ORDER.uid, payload ); ``` ### 3. Views (Listing Data) To display lists of data (like the tables on the `/orders` or `/stores` pages), the app queries "Record Views" configured on the backend. ```typescript const data = await client.listInstances(STORE.recordViews.STORE, filters); ``` These views return tabular data containing the latest state of all instances in that workflow. ### 4. Workflows Deep Dive & Activity Chains #### 4.1 Order Booking Workflow Manages the end-to-end process of visiting a store and taking an order. **Activity Chain:** `LOG_VISIT` ➔ `PLACE_ORDER` ➔ `EDIT_ORDER` ➔ `PRODUCTIVITY_OF_VISIT` ➔ `POTENTIAL_MINING` ➔ `CLOSE_ORDER` - **LOG_VISIT (Init)** - Fields: `select_store` (wf_lookup), `date_of_visit` (date), `time_of_visit` (time), `upload_image` (image) - **PLACE_ORDER** - Fields: `date_of_order` (date), `order_details` (grid), `total_bags` (number), `total_kgs` (number) - **EDIT_ORDER** - Fields: Same as Place Order, allowing modifications before closure. - **PRODUCTIVITY_OF_VISIT** - Fields: `is_productive_call` (radio), `store_status` (select), `order_received_channel` (select), `remarks` (longtext), `action` (radio) - **POTENTIAL_MINING** - Fields: `potential` (grid - tracks actual potential vs ordered) - **CLOSE_ORDER** - Fields: `remarks_2` (longtext) #### 4.2 Store Workflow Manages onboarding and updating retailers in the system. **Activity Chain:** `INIT` ➔ `EDIT_STORE` - **INIT (Store Creation)** - Fields: `business_name_2` (text), `area_2` (text), `complete_address_2` (longtext), `pin_code_2` (number), `owner_name_2` (text), `phone_number_2` (phone), `email_2` (email), `store_location_2` (geolocation), `store_image_2` (image), `route_name_2` (select), `route_code_2` (select), `sub_route_2` (select), `distributor_name_2` (select), `distributor_owner_name_2` (text), `distributor_email_2` (email), `distributor_phone_number_2` (phone), `notes_2` (longtext), `potential_2` (grid) - **EDIT_STORE** - Fields: Matches the INIT fields (uses `_3` suffix) to allow updates to store metadata. #### 4.3 Daily Reports Workflow Tracks Sales Officer attendance, daily planning, and end-of-day reports. **Activity Chain:** `INIT` (Day Plan) ➔ `PUNCH_OUT` (EOD) - **INIT (Punch In)** - Fields: `sales_officer_name` (app_user), `date` (date), `time` (time), `route_code` (select), `sub_route` (select), `store_image` (image), `day_plan_notes` (longtext) - **PUNCH_OUT (Punch Out)** - Fields: `total_productive_calls` (number), `total_non_productive_calls` (number), `eod_notes_remarks` (longtext) #### 4.4 User Management Workflow Manages Sales Officers and their credentials. **Activity Chain:** `ADD_USER` ➔ `EDIT_USER` - **ADD_USER** - Fields: `name` (text), `email` (email), `password` (password) - **EDIT_USER** - Fields: `name_3` (text), `email_3` (email) ### 5. Custom Pipelines The app uses backend pipelines (custom API endpoints) to fetch aggregated data that standard Record Views cannot provide. These are defined in `src/api/config.ts`: - `/api/p/krishna-group/v1/nearest-stores`: Fetches stores near the user's geolocation for logging visits. **(Used in: `NearestStoresMap.tsx`)** - `/api/p/krishna-group/v1/daily-sales-report`: Aggregates the daily sales report for managers. **(Used in: `DailySalesReportPage.tsx` via `client.ts`)** - `/api/p/krishna-group/v1/productive-call-summary`: Summarizes productive vs non-productive calls. **(Used in: `DynamicForm.tsx` during order workflows)** - `/api/p/krishna-group/v1/sales-officers`: Retrieves a list of Sales Officers for filtering. **(Used in: `DailySalesReportPage.tsx`)** - `/api/p/krishna-group/v1/auto-close-orders`: Batch process to close pending orders. **(Defined in config, executed via backend CRON or specific admin actions)** - `/api/p/krishna-group/v1/edit-orders`: Pipeline to handle order modifications. **(Configured for future implementation)** - `/api/p/krishna-group/v1/orders`: Fetches order summaries. **(Configured for future implementation)** - `/api/p/krishna-group/v1/potential-mining`: Retrieves potential data for stores to pre-fill the smart grid. **(Used in: `DynamicForm.tsx`, `CallDetail.tsx`, `OrdersPage.tsx`, `CallsPage.tsx`)** ### 6. Admin Pages The application includes two dedicated administrative panels restricted to users with the Admin role (and sometimes Manager). - **Manage Datasets (`/admin/datasets`)**: Connects to Zino's dataset API via `client.getDatasets()`. It dynamically renders a dual-pane UI where admins can select a dataset (either a `List` or a `Table` of objects) from the left sidebar and manage its items on the right via `DatasetItemsPage.tsx`. This allows admins to update core master data (like product lists, route configurations) without deploying new code. - **Manage Users (`/admin/users`)**: Operates on the `USER` workflow (`ADD_USER`, `EDIT_USER` activities) to onboard new Sales Officers and edit their profiles or access roles, using standard workflow instances. ### 7. Daily Sales Report (DSR) The **Daily Sales Report (`/sales-report`)** page provides managers and administrators with a consolidated view of all orders booked on a specific day. #### How it works: - **Filtering**: The user selects a specific Date, Route, Distributor, and Sales Officer. - **Pipeline Aggregation**: Instead of relying on raw workflow lists, it queries a custom pipeline (`/api/p/krishna-group/v1/daily-sales-report`) that heavily aggregates order data from the backend, matching the selected filters. - **PDF Generation**: It uses `jspdf` and `jspdf-autotable` to generate a dynamic, printable PDF in landscape mode. - **SKU Chunking**: Because a store might order many different SKUs across multiple brands, the PDF logic dynamically splits columns (SKUs) into printable chunks (`PDF_MAX_SKUS_PER_CHUNK` defined in config) so that tables never overflow the page horizontally. It generates subsequent pages for overflowed SKUs automatically.