# تماسا — Tamasa

دفترچه مخاطبین فارسی، سریع و زیبا با معماری آماده‌ی CRM.
Persian-first contact manager with IndexedDB storage, Jalali calendar,
Excel import/export and full backup/restore. Optimized for Chrome (desktop-first).

![Tamasa](asstes/tamasa.png)

---

## ✨ Features

- **مدیریت کامل مخاطبین** — Create / Read / Update / Delete با فیلدهای کامل (نام، چند شماره تلفن، چند ایمیل، آدرس، یادداشت)
- **برچسب‌گذاری چندگانه** — تخصیص چند برچسب به هر مخاطب برای دسته‌بندی و آماده‌سازی کمپین
- **جستجوی لحظه‌ای** — فیلتر زنده روی نام، تلفن، ایمیل و برچسب (بدون رفرش صفحه)
- **تقویم جلالی** — Date-picker شمسی برای تاریخ تولد + مهر زمان شمسی برای ساخت/ویرایش
- **ورود/خروج Excel** — سازگار با Excel، LibreOffice، Google Sheets (فرمت `.xlsx`)
- **پشتیبان‌گیری / بازیابی** — بکاپ کامل JSON برای انتقال و بازیابی
- **رابط RTL کامل** — با فونت Vazirmatn FD، طراحی دسکتاپ-محور
- **ذخیره‌سازی آفلاین** — IndexedDB، بدون نیاز به سرور؛ روی file:// هم کار می‌کند

---

## 🚀 Run

No build step. Just open in Chrome:

```
# Option A — double-click
index.html

# Option B — local server (recommended for consistent file:// behavior)
python -m http.server 8080
# then visit http://localhost:8080
```

All dependencies are bundled locally — **fully offline**.

---

## 📁 Project Structure

```
tamasa/
├── index.html              # App shell + modals (RTL, lang=fa)
├── styles.css              # Full design system (CSS variables, RTL-first)
├── README.md               # This file (incl. data schema docs)
├── vendor/
│   └── xlsx.full.min.js    # SheetJS — Excel I/O (bundled offline)
├── js/
│   ├── jalali.js           # Jalali ⇄ Gregorian conversion + formatting
│   ├── db.js               # IndexedDB layer (CRM-ready schema)
│   ├── ui.js               # DOM helpers, modal manager, toast
│   └── app.js              # Controller: state, render, events, I/O
└── asstes/
    ├── tamasa.png          # App logo
    └── fonts/
        ├── vazirmatn/      # Vazirmatn FD .ttf (all weights)
        └── vazirmatn_fd/   # alternate font folder
```

> ℹ️ The asset folder is named `asstes/` (existing on disk). All paths in code use this spelling.

---

## 🗄️ Data Schema (CRM-ready)

Database: `tamasa` (IndexedDB, version `1`)

### Object Store: `contacts`

| Field         | Type        | Indexed | Description |
|---------------|-------------|---------|-------------|
| `id`          | string (UUID) | ✅ keyPath | Stable unique ID |
| `firstName`   | string      | —       | نام |
| `lastName`    | string      | ✅       | نام خانوادگی |
| `fullName`    | string (derived) | —  | `firstName + ' ' + lastName` (auto) |
| `company`     | string      | ✅       | شرکت / سازمان |
| `jobTitle`    | string      | —       | سمت |
| `phones`      | `[{type, value}]` | — | Multiple phone numbers |
| `emails`      | `string[]`  | —       | Multiple emails |
| `tags`        | `string[]` (tag IDs) | ✅ multiEntry | Labels for segmentation |
| `address`     | string      | —       | آدرس |
| `birthday`    | string `"1403/03/12"` (Jalali latin) | — | شمسی |
| `notes`       | string      | —       | یادداشت آزاد |
| `starred`     | boolean     | ✅       | علاقه‌مندی |
| `searchKey`   | string (derived) | ✅ | Normalized search blob (auto) |
| `createdAt`   | number (ms) | ✅       | زمان ایجاد |
| `updatedAt`   | number (ms) | ✅       | آخرین ویرایش |

**Derived fields** (`fullName`, `searchKey`) are recomputed on every write inside `db.js → buildDerived()`,
keeping search fast (single index lookup) without runtime normalization.

### Object Store: `tags`

| Field      | Type   | Description |
|------------|--------|-------------|
| `id`       | string (keyPath) | `name.toLowerCase()` |
| `name`     | string | Display name |
| `color`    | string | Hex color (deterministic from name) |
| `createdAt`| number | ms timestamp |

### Object Store: `settings`

Generic key/value store (`{ key, value }`) for app preferences.

---

## 🔭 CRM Expansion Path

The architecture intentionally leaves room to grow into a full CRM without rewrites:

1. **Interactions timeline** — new `interactions` store keyed by `contactId` (calls, emails, meetings, notes).
   Render in the detail modal as a timeline; reuse `Jalali.formatDate` for timestamps.
2. **Email/SMS templates** — new `templates` store (`{ id, name, type, subject, body }`); add a Templates view
   in the sidebar.
3. **Campaigns** — new `campaigns` store (`{ id, name, type, audienceTags[], status, ... }`).
   Audience selection reuses the `tags` multiEntry index for instant filtering.
4. **Analytics** — aggregate from `interactions` + `contacts`; add a charts view
   (the modular `app.js` makes it straightforward to register a new view).
5. **Multi-user / sync** — swap the IndexedDB layer behind `DB.*` for a remote API;
   the controller depends only on the `DB.Contacts.*` / `DB.Tags.*` interface.

Each future store is independent and can be added in a DB version bump (`DB_VERSION++` + `onupgradeneeded`).

---

## 📥 Excel Format

**Export** produces `.xlsx` with Persian headers, RTL sheet view, and these columns:
نام، نام خانوادگی، شرکت، سمت، تلفن‌ها، ایمیل‌ها، برچسب‌ها، آدرس، تاریخ تولد (شمسی)، یادداشت، تاریخ ایجاد، تاریخ ویرایش.

- Multiple phones/emails/tags are joined with ` | `.
- Import accepts the same file back (round-trips losslessly) and is tolerant of common column name variants
  (English/Persian). Required: **last name** + **at least one phone**.

**Backup** = full JSON (`tamasa-backup-YYYY-MM-DD.json`) containing all contacts + tag definitions.
**Restore** replaces the local dataset (with confirmation).

---

## 🛠️ Tech

- Vanilla JS (ES5-compatible for max browser support), no framework.
- IndexedDB with multi-entry + derived-search-key indexes.
- SheetJS (vendored) for Excel.
- Pure-JS Jalali conversion (no external date library).
- CSS custom properties, RTL-first, `prefers-reduced-motion` aware.

---

## 🔒 Privacy

100% local. No network calls. Your contacts never leave the browser.
