177 lines
9.7 KiB
Markdown
177 lines
9.7 KiB
Markdown
# 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
|
|
- **Refresh-cookie sessions** : the server sets an HttpOnly `__Host-sm_rt` refresh cookie; the short-lived access token is kept in localStorage (`sm_session`) and renewed by `src/api/session.ts` (single-flight across tabs, proactive refresh, backoff when offline). A 401 triggers one refresh + replay; only a really ended session logs the user out.
|
|
- Multi-tab sync over `BroadcastChannel('sm-auth')`: logout in one tab signs out the others; a different user signing in reloads the stale tab. An undelivered logout is retried (`sm_logout_pending`).
|
|
- All `/usr/*` auth calls send credentials (`AUTH_CREDENTIALS`) so the cookie travels same-origin.
|
|
- **Platform maintenance notices** (`src/api/notices.ts`): polls `GET /usr/notices` every 30s. `announced` shows a dismissible strip, `draining` keeps the strip and refuses writes (`PLATFORM_MAINTENANCE` 503), `closed` shows a full-screen block that lifts on its own.
|
|
- Other 503s show an "unavailable" strip without blocking writes.
|
|
- Logout now clears per-user data but keeps session-protocol keys instead of `localStorage.clear()`.
|
|
|
|
## 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.
|