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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
This project provides a scalable API backend using FastAPI and PostgreSQL, featuring:

- Automatic full-text search on all text fields (via tsvector)
- Endpoints for health checks, product management, prompt handling (via `/prompt`), resend email, and prospect management
- Endpoints for health checks, product management, prompt handling (via `/prompt`), notify email, and prospect management
- Efficient ingestion and processing of large CSV files

#### Features
Expand Down Expand Up @@ -54,7 +54,7 @@ FastAPI auto-generates interactive docs:
- `GET /health` — Health check
- `GET /prompt` or `GET /prompts` — Prompt table metadata (`record_count`, `columns`)
- `POST /prompt` — LLM prompt completion (formerly `/llm`)
- `GET/POST /resend` — Send email via Resend API (see implementation in `app/utils/notify/resend.py`)
- `GET/POST /notify/email` — Send email via Resend API (see implementation in `app/api/notify/email.py`)
- `GET /prospects` — Paginated prospects
- `POST /prospects/process` — Bulk CSV ingestion

Expand Down
3 changes: 2 additions & 1 deletion app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Python° - FastAPI, Postgres, tsvector"""

# Current Version
__version__ = "3.0.8"
__version__ = "3.1.0"

105 changes: 105 additions & 0 deletions app/api/notify/email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"""Email notification routes."""

import os
import resend
from fastapi import APIRouter, status
from pydantic import BaseModel, EmailStr

from app.utils.make_meta import make_meta
from app.utils.email_templates import goldlabel_email

resend.api_key = os.environ.get("RESEND_API_KEY")
RESEND_API_KEY = resend.api_key

router = APIRouter(prefix="/notify")

class EmailRequest(BaseModel):
to: EmailStr
subject: str
html: str
cta_label: str | None = None
cta_url: str | None = None


def send_email_resend(to: str, subject: str, html: str) -> dict:
if not resend.api_key:
return {"error": "Missing RESEND_API_KEY"}
params: resend.Emails.SendParams = {
"from": "NX° <nx@goldlabel.pro>",
"to": [to],
"subject": subject,
"html": html,
}
try:
email: resend.Emails.SendResponse = resend.Emails.send(params)
return dict(email)
except Exception as e:
return {"error": str(e)}


@router.get("/email")
def root() -> dict:
"""GET /notify/email endpoint."""
if not RESEND_API_KEY:
meta = make_meta("error", "RESEND_API_KEY is missing from environment. Please set it in your .env file.")
return {"meta": meta}
meta = make_meta("success", "GET /notify/email endpoint")
return {
"meta": meta,
"data": {
"hint": "Use POST /notify/email to send an email via Resend API.",
"type": {
"to": {
"type": "string",
"format": "email",
"required": True,
"description": "Recipient email address."
},
"subject": {
"type": "string",
"required": True,
"description": "Subject of the email."
},
"html": {
"type": "string",
"required": True,
"description": "HTML content of the email."
},
"cta_label": {
"type": "string",
"required": False,
"description": "Optional CTA button label. Defaults to 'Call To Action'."
},
"cta_url": {
"type": "string",
"required": False,
"description": "Optional CTA URL. Defaults to the website base URL."
}
}
}
}


@router.post("/email", status_code=status.HTTP_202_ACCEPTED)
def send_email(request: EmailRequest):
"""POST /notify/email endpoint to send email via Resend API."""
if not RESEND_API_KEY:
meta = make_meta("error", "RESEND_API_KEY missing. Please set it in your .env file.")
return {"meta": meta}

result = send_email_resend(
to=request.to,
subject=request.subject,
html=goldlabel_email(
request.subject,
request.html,
cta_label=request.cta_label or "Call To Action",
cta_url=request.cta_url or "https://goldlabel.pro",
),
)
if "error" in result:
meta = make_meta("error", result["error"])
return {"meta": meta}

meta = make_meta("success", "Email sent successfully.")
return {"meta": meta, "data": result}
29 changes: 29 additions & 0 deletions app/api/queue/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Queue Overview

## What is the Queue?

The queue is like a waiting line for tasks that need to be done. Imagine you are at a store, and people are waiting in line to be helped. The queue in our system works the same way, but instead of people, it manages jobs or tasks that the computer needs to process.

## Why Do We Need a Queue?

Sometimes, there are too many tasks for the computer to handle all at once. The queue helps by organizing these tasks in the order they arrive, so each one gets done, one after the other. This makes sure nothing is forgotten and everything is handled fairly.

## How Does the Queue Work?

- **Adding Tasks:** When there is something new to do, it gets added to the end of the queue.
- **Processing Tasks:** The computer takes the first task in the queue and works on it. When it’s done, it moves to the next one.
- **Staying Organized:** The queue keeps everything in order, so tasks are not missed or done out of turn.

## Why Is This Important?

- **Fairness:** Every task gets its turn, just like people in a line.
- **Efficiency:** The computer doesn’t get overwhelmed by trying to do everything at once.
- **Reliability:** Tasks are not lost or forgotten, so the system works smoothly.

## Real-Life Example

Think of the queue as a to-do list. When you write down things you need to do, you do them one by one. The queue helps the computer do the same thing, making sure every job is completed in the right order.

---

This overview is for anyone who wants to understand what the queue does, without needing to know how to code or how computers work inside. If you have questions, just ask!
4 changes: 2 additions & 2 deletions app/api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from app.api.root import router as root_router
from app.utils.health import router as health_router
from app.api.notify.resend import router as resend_router
from app.api.notify.email import router as notify_router
from app.api.prompt.prompt import router as prompt_router
from app.api.prompt.empty import router as prompts_empty_router
from app.api.prompt.delete_id import router as prompt_delete_id_router
Expand All @@ -20,7 +20,7 @@
from app.api.youtube import youtube_router

router.include_router(root_router)
router.include_router(resend_router)
router.include_router(notify_router)
router.include_router(health_router)
router.include_router(prompt_router)
router.include_router(prompts_empty_router)
Expand Down
Loading
Loading