Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions docs/features/41-collaborator-beta-application.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# 41 — Collaborator & Beta Application

**NEW document** — Beta application submission, GitHub profile validation, collaborator intake flow

---

## Feature Summary

The collaborator routes handle beta application submissions from users wanting to join the Zync platform. Applicants provide their GitHub username, profile URL, and email. The backend stores the application and notifies the team.

---

## Architecture Diagram

```
┌─────────────────── FRONTEND ───────────────────────────┐
│ │
│ BetaApplicationPage.tsx │
│ ├─ GitHub username input │
│ ├─ GitHub profile URL input │
│ ├─ Email input │
│ └─ Submit → POST /api/collaborators │
│ │
└──────────────────────┬──────────────────────────────────┘
┌─────────────────── BACKEND ────────────────────────────┐
│ │
│ backend/routes/collaboratorRoutes.js │
│ │
│ POST / → submit beta application │
│ │
│ Logic: │
│ 1. Validate: githubUsername, githubProfileUrl, email │
│ 2. Check for duplicate (email or GitHub username) │
│ 3. Store application in DB │
│ 4. Send notification email to admin │
│ 5. Return success │
│ │
└─────────────────────────────────────────────────────────┘
```

---

## Backend Trace

### File: `backend/routes/collaboratorRoutes.js`

### POST / (line 94)
- **Auth:** not required (public endpoint for beta signups)
- **Input:** `{ githubUsername, githubProfileUrl, email }`
- **Logic:**
1. Validate all fields present
2. Check for duplicate: `Collaborator.findOne({ $or: [{ email }, { githubUsername }] })`
3. If duplicate: 409 "Already applied"
4. Create: `Collaborator.create({ githubUsername, githubProfileUrl, email, status: 'pending' })`
5. Send admin notification email
- **Response:** `{ message: "Application submitted", id }`

---

## Database Layer

### Collaborator Model
| Field | Type | Required | Notes |
|---|---|---|---|
| `githubUsername` | String | yes | GitHub handle |
| `githubProfileUrl` | String | yes | Full GitHub URL |
| `email` | String | yes | Contact email |
| `status` | String | no | `pending`, `approved`, `rejected` |
| `reviewedAt` | Date | no | When admin reviewed |
| `createdAt` | Date | auto | |

---

## Error Paths

| Scenario | HTTP Status | Response |
|---|---|---|
| Missing fields | 400 | `{ error: "All fields required" }` |
| Duplicate application | 409 | `{ error: "Already applied" }` |
| Server error | 500 | `{ error: "Server error" }` |

---

## Cross-References

- [28-email-service-notifications.md](./28-email-service-notifications.md) — Admin notification email
- [05-database-schema-and-models.md](./05-database-schema-and-models.md) — Collaborator model
90 changes: 90 additions & 0 deletions docs/features/42-support-ticket-system.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# 42 — Support Ticket System

**NEW document** — Support request submission, email notification to admin, user contact form

---

## Feature Summary

The support routes handle user support requests. Users submit a message (with optional email and name), and the backend sends an email notification to the Zync support team. No authentication required — accessible to all users.

---

## Architecture Diagram

```
┌─────────────────── FRONTEND ───────────────────────────┐
│ │
│ SupportPage.tsx │
│ ├─ Name input │
│ ├─ Email input │
│ ├─ Subject input │
│ ├─ Message textarea │
│ └─ Submit → POST /api/support │
│ │
│ Footer link → Support page │
│ │
└──────────────────────┬──────────────────────────────────┘
┌─────────────────── BACKEND ────────────────────────────┐
│ │
│ backend/routes/supportRoutes.js │
│ │
│ POST / → submit support request │
│ │
│ Logic: │
│ 1. Validate: name, email, subject, message │
│ 2. Build email HTML template │
│ 3. sendZyncEmail(SUPPORT_EMAIL, subject, html) │
│ 4. Return success │
│ │
└─────────────────────────────────────────────────────────┘
```

---

## Backend Trace

### File: `backend/routes/supportRoutes.js`

### POST / (line 93)
- **Auth:** not required
- **Input:** `{ name, email, subject, message }`
- **Logic:**
1. Validate all fields present
2. Build HTML email:
```html
<h2>New Support Request</h2>
<p><strong>From:</strong> {name} ({email})</p>
<p><strong>Subject:</strong> {subject}</p>
<p><strong>Message:</strong></p>
<p>{message}</p>
```
3. `sendZyncEmail(process.env.SUPPORT_EMAIL, subject, html)`
4. Return `{ message: "Support request sent" }`

---

## Error Paths

| Scenario | HTTP Status | Response |
|---|---|---|
| Missing fields | 400 | `{ error: "All fields required" }` |
| Email send fails (auth) | 200 | Still returns success (fail-open) |
| Email send fails (network) | 500 | `{ error: "Failed to send request" }` |
| Server error | 500 | `{ error: "Server error" }` |

---

## Environment Variables

| Variable | Required | Description |
|---|---|---|
| `SUPPORT_EMAIL` | Yes | Email address to receive support requests |

---

## Cross-References

- [28-email-service-notifications.md](./28-email-service-notifications.md) — Email service used for sending
130 changes: 130 additions & 0 deletions docs/features/43-design-inspiration-system.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# 43 — Design Inspiration System

**NEW document** — Inspiration search, Dribbble scraping, live web scraping, design reference aggregation

---

## Feature Summary

The design inspiration system allows users to search for design references from multiple sources. The backend aggregates results from Dribbble and live web scraping, providing designers with visual inspiration for their projects.

---

## Architecture Diagram

```
┌─────────────────── FRONTEND ───────────────────────────┐
│ │
│ InspirationView.tsx │
│ ├─ Search bar (query input) │
│ ├─ Source tabs: All | Dribbble | Web │
│ ├─ Results grid (image cards) │
│ │ └─ GET /api/inspiration?query=... │
│ ├─ Dribbble tab │
│ │ └─ GET /api/inspiration/dribbble?query=... │
│ └─ Live scrape tab │
│ └─ GET /api/inspiration/scrape?query=... │
│ │
└──────────────────────┬──────────────────────────────────┘
┌─────────────────── BACKEND ────────────────────────────┐
│ │
│ backend/routes/inspirationRoutes.js │
│ ├─ GET / → getInspiration (aggregated) │
│ ├─ GET /dribbble → getDribbbleInspiration │
│ └─ GET /scrape → getLiveScrape │
│ │
│ backend/routes/designRoutes.js │
│ └─ GET /search → getInspiration (alias) │
│ │
│ backend/controllers/inspirationController.js │
│ ├─ getInspiration(req, res) │
│ │ ├─ Parse query param │
│ │ ├─ Aggregate from multiple sources │
│ │ └─ Return unified results │
│ ├─ getDribbbleInspiration(req, res) │
│ │ ├─ Scrape Dribbble search results │
│ │ ├─ Parse HTML for image URLs + titles │
│ │ └─ Return structured results │
│ └─ getLiveScrape(req, res) │
│ ├─ General web search for design images │
│ ├─ Parse search engine results │
│ └─ Return image URLs + metadata │
│ │
└─────────────────────────────────────────────────────────┘
```

---

## Backend Trace

### File: `backend/routes/inspirationRoutes.js`

### GET / (line 86)
- **Auth:** not specified (likely public or auth-required)
- **Query:** `?query=<search term>`
- **Handler:** `getInspiration` from `inspirationController.js`
- **Returns:** Aggregated inspiration results from multiple sources

### GET /dribbble (line 88)
- **Query:** `?query=<search term>`
- **Handler:** `getDribbbleInspiration`
- **Returns:** Dribbble-specific design results

### GET /scrape (line 84)
- **Query:** `?query=<search term>`
- **Handler:** `getLiveScrape`
- **Returns:** Live web-scraped design images

### File: `backend/routes/designRoutes.js`
### GET /search (line 84)
- Alias for `getInspiration` — same handler
- Mounted at `/api/design/search`

---

## Controller Logic

### File: `backend/controllers/inspirationController.js`

### getInspiration
1. Parse `query` from `req.query`
2. If no query: return empty array
3. Aggregate from sources:
- Dribbble results
- Web scrape results
4. Return unified array: `[{ title, imageUrl, source, sourceUrl }]`

### getDribbbleInspiration
1. Build Dribbble search URL: `https://dribbble.com/search/{query}`
2. Fetch HTML with axios
3. Parse with cheerio:
- Extract shot images: `.shot-thumbnail img`
- Extract titles: `.shot-title`
- Extract author: `.shot-by-user`
4. Return structured results

### getLiveScrape
1. Build search engine query for design images
2. Fetch results page HTML
3. Parse for image URLs and metadata
4. Return results

---

## Error Paths

| Scenario | HTTP Status | Response |
|---|---|---|
| No query provided | 200 | Empty array |
| External site down | 200 | Partial results (best-effort) |
| Scraping fails | 200 | Empty array (graceful) |
| Server error | 500 | `{ error: error.message }` |

---

## Cross-References

- [04-service-inventory.md](./04-service-inventory.md) — Inspiration controller listing
- [14-project-crud.md](./14-project-crud.md) — Projects can reference inspiration
Loading
Loading