Skip to content

jyatesdotdev/jyatesdotdev-api

Repository files navigation

jyatesdotdev-api

Go backend for jyates.dev — four HTTP Lambda functions behind API Gateway plus an S3-triggered content notification function.

Architecture

  • Language: Go 1.26 (CI reads the version from backend/go.mod)
  • Runtime: AWS Lambda (ARM64, provided.al2023)
  • Database: DynamoDB (KMS-encrypted, on-demand)
  • Email: SES v2 (sends from blog@jyates.dev)
  • Router: chi (via aws-lambda-go-api-proxy)
  • Structure: Handlers → Services → Repositories

Functions

Function Purpose
interactions Likes and comments (GET/POST)
contact Contact form → SES email
admin Comment moderation (approve/reject/delete)
authorizer Basic Auth for admin endpoints
notifications New-content manifest → confirmed SES topic subscribers

API Routes (via CloudFront /api/*)

GET  /api/v1/likes?slug=...
POST /api/v1/likes                    {slug}
GET  /api/v1/comments?slug=...
POST /api/v1/comments                 {slug, content, authorName, authorEmail, website}
POST /api/v1/comments/:id/like        {slug}
POST /api/v1/contact                  {name, email, message, website}
POST /api/v1/subscriptions            {email, topics, website}
POST /api/v1/subscriptions/confirm    {token}
GET  /api/v1/geo
GET  /api/v1/visits
POST /api/v1/visits
GET  /api/v1/admin/comments?status=...
PUT  /api/v1/admin/comments/:id       {slug, status}
DELETE /api/v1/admin/comments/:id     {slug}

Spam Protection & Identity

  • Honeypot: website is a hidden form field that must be empty; submissions that fill it are rejected (contact returns a fake 200 so bots aren't tipped off). There is no reCAPTCHA.
  • Likes are deduplicated by the X-Visitor-Id request header (required — requests without it get a 400), not by IP.
  • Comments require a valid email address and are approved unless AUTO_APPROVE=false; the admin dashboard can approve or reject them. The CloudFront-generated viewer address is stored for moderation context, and comment creation is limited per IP/day.
  • Subscriptions use a 48-hour, single-use email confirmation token. Confirmed addresses and blog/projects preferences live in an SES contact list, which also supplies one-click unsubscribe links. Pending token hashes live in DynamoDB.

DynamoDB Schema

Single table jyatesdotdev-state with single-table design:

PK SK Purpose
POST#<slug> METADATA Post metadata (likeCount)
POST#<slug> LIKE#<visitorID> Like record (existence = liked)
POST#<slug> COMMENT#<uuid> Comment (content, author, status, likeCount)
COMMENT#<uuid> LIKE#<visitorID> Comment like tracking
POST#<slug>#USER#<visitorID> LIKE#COMMENT#<uuid> User-comment like cross-reference
SUBSCRIPTION_REQUEST#<tokenHash> METADATA Pending double-opt-in request (TTL; atomically consumed)
NOTIFICATION#<commitSHA> MANIFEST Completed-manifest marker (TTL)
NOTIFICATION#<commitSHA> RECIPIENT#<event>#<emailHash> Resumable per-recipient delivery checkpoint (TTL)

GSI1 (GSI1PK/GSI1SK) indexes comments by status for admin queries (e.g., STATUS#approved, STATUS#pending).

Testing

cd backend
go test -short ./...

Deployment

Pushes to main (under backend/**) or manual workflow_dispatch trigger the pipeline:

  1. Build five Lambda binaries (cross-compiled for linux/arm64)
  2. Zip and upload to the artifacts S3 bucket under lambdas/<git-sha>/
  3. Dispatch deploy_api to jyatesdotdev-infra with the artifact locations, and run_e2e to jyatesdotdev-integration

Manual Trigger

gh workflow run deploy.yml --repo <owner>/jyatesdotdev-api --ref main

This builds, uploads, and dispatches to infra automatically.

Required Secrets & Variables

Type Name Description
Secret AWS_ROLE_ARN GitHub OIDC deploy role ARN
Secret INFRA_REPO_PAT PAT to trigger jyatesdotdev-infra / jyatesdotdev-integration dispatches
Variable ARTIFACTS_BUCKET S3 bucket for Lambda zips
Variable AWS_REGION us-west-2

About

Go Lambda backend for jyates.dev

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors