Files
hihala-dashboard/docs/superpowers/specs/2026-03-31-hijri-seasons-design.md
fahed 1dd216f933 docs: add hijri seasons feature design spec
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 15:54:52 +03:00

119 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Hijri Seasons Feature
## Goal
Add configurable hijri seasons (Ramadan, Hajj, etc.) to the dashboard as a presentation overlay. Seasons are user-defined with Gregorian date ranges (since hijri months shift ~11 days each year). They appear as filter presets, chart bands, and are managed through a settings page.
## Data Storage
New NocoDB `Seasons` table:
| Column | Type | Example |
|--------|------|---------|
| Name | string | `Ramadan` |
| HijriYear | number | `1446` |
| StartDate | string | `2025-02-28` |
| EndDate | string | `2025-03-30` |
| Color | string | `#10b981` |
Read on dashboard load alongside PilgrimStats. Written via server proxy to keep NocoDB credentials server-side.
**Loading lifecycle:** Seasons load independently of the main data fetch. A failure to load seasons degrades gracefully — seasons state defaults to `[]`, the dashboard renders normally without bands or season presets. Seasons are non-blocking and non-critical.
## Server Changes
### New files
| File | Responsibility |
|------|----------------|
| `server/src/routes/seasons.ts` | `GET /api/seasons` (read all), `POST /api/seasons` (create), `PUT /api/seasons/:id` (update), `DELETE /api/seasons/:id` (delete) |
### Modified files
| File | Change |
|------|--------|
| `server/src/index.ts` | Mount seasons routes at `/api/seasons` |
| `server/src/services/nocodbClient.ts` | Add generic CRUD helpers typed as `<T extends Record<string, unknown>>` so both ETL and seasons routes can share them without coupling |
| `vite.config.ts` | Add `/api/seasons` proxy rule **before** the catch-all `/api` rule (same pattern as `/api/erp`). Order: `/api/erp``/api/etl``/api/seasons``/api` |
## Client Changes
### New files
| File | Responsibility |
|------|----------------|
| `src/components/Settings.tsx` | Settings page with seasons CRUD table |
| `src/services/seasonsService.ts` | Fetch/create/update/delete seasons via server proxy |
### Modified files
| File | Change |
|------|--------|
| `src/types/index.ts` | Add `Season` interface |
| `src/App.tsx` | Add `/settings` route, nav link (both desktop and mobile bottom nav), load seasons on mount (non-blocking) |
| `src/components/Dashboard.tsx` | Add season filter dropdown, chart annotation bands |
| `src/components/Comparison.tsx` | Add season filter as period preset |
| `src/config/chartConfig.ts` | Import and register `chartjs-plugin-annotation` in the central `ChartJS.register()` call |
| `src/locales/en.json` | Settings page labels, season filter labels |
| `src/locales/ar.json` | Arabic translations |
| `package.json` | Add `chartjs-plugin-annotation` dependency |
## Season Interface
```typescript
export interface Season {
Id?: number;
Name: string;
HijriYear: number;
StartDate: string;
EndDate: string;
Color: string;
}
```
## Settings Page (`/settings`)
New route accessible from the nav bar (gear icon on desktop, gear in mobile bottom nav). Contains:
- **Seasons table**: lists all defined seasons with columns: Name, Hijri Year, Start Date, End Date, Color, Actions (edit/delete)
- **Add season form**: inline row at the bottom of the table with inputs for each field + color picker + save button
- **Edit**: click a row to edit inline
- **Delete**: delete button per row with confirmation
- **No empty state needed**: just show the empty table with the add form
## Period Filter Integration
### Dashboard
Add a "Season" select in the filters section (after Quarter). Options populated from the loaded seasons list:
- `All Seasons` (default — no date filtering from season)
- `Ramadan 1446 (Feb 28 Mar 30, 2025)`
- `Hajj 1446 (Jun 4 Jun 9, 2025)`
- etc.
Selecting a season sets a date range filter on the data — equivalent to filtering by start/end date. This works alongside existing year/district/channel/event filters.
Implementation: when a season is selected, filter data to `row.date >= season.StartDate && row.date <= season.EndDate`. Store the selected season ID in state (not URL params — seasons are dynamic).
### Comparison
Seasons appear as preset period options alongside months/quarters. Selecting "Ramadan 1446" sets the period dates and auto-compares with the same season name in the previous hijri year if defined (e.g. "Ramadan 1445").
## Chart Bands (Revenue Trend)
Uses `chartjs-plugin-annotation` to draw semi-transparent vertical bands on the revenue trend chart. Must be registered in `chartConfig.ts` via `ChartJS.register(Annotation)`.
For each season whose date range overlaps the chart's visible range:
- Draw a vertical box from `season.StartDate` to `season.EndDate`
- Fill with `season.Color` at 15% opacity
- Label at the top with season name + hijri year
Only the revenue trend chart gets bands (it's the only time-series chart where seasons make visual sense).
## What's NOT Changing
- ETL pipeline unchanged — seasons are a UI/presentation concern
- NocoDB DailySales schema unchanged
- All existing filters (year, district, channel, event, quarter) unchanged
- Seasons don't affect data aggregation or storage