Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
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
58 changes: 58 additions & 0 deletions .github/workflows/lighthouse-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Lighthouse CI

on:
pull_request:
branches: ["main"]
push:
branches: ["main"]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: lighthouse-ci-${{ github.ref }}
cancel-in-progress: true

jobs:
lighthouse:
name: Lighthouse budgets
runs-on: ubuntu-latest
timeout-minutes: 15
env:
ADMIN_TOKEN: lhci-local-admin-token
CHATBOT_ENABLED: "false"
CI: "true"
DATABASE_URL: postgresql://lhci:lhci@localhost:5432/lhci?schema=public
NEXT_TELEMETRY_DISABLED: "1"
REWRITER_ENABLED: "false"

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install dependencies
run: npm ci

- name: Build production app
run: npm run build

- name: Run Lighthouse CI
run: npm run lhci

- name: Upload Lighthouse reports
if: always()
uses: actions/upload-artifact@v4
with:
name: lighthouse-ci-reports
path: |
.lighthouseci
lighthouse/reports
if-no-files-found: ignore
retention-days: 14
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
!.yarn/versions
# testing
/coverage
/test-results
/playwright-report
/blob-report
/.lighthouseci
/lighthouse/reports
# next.js
/.next/
/out/
Expand Down
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public/assets/ Images, icons, use-case visuals
agents/ Custom VS Code Copilot agents
instructions/ Auto-loaded instructions for .ts/.tsx files
skills/ On-demand skills (i18n-checker, portfolio-architecture)
workflows/ GitHub Actions (bump-version, codeql, dependency-review)
workflows/ GitHub Actions (bump-version, codeql, dependency-review, lighthouse-ci)
copilot-instructions.md VS Code Copilot always-on context
CODEOWNERS All files owned by @ColdByDefault
```
Expand Down Expand Up @@ -154,5 +154,6 @@ components/[Feature]/
| `bump-version.yml` | push to `main` | Bumps patch version in `package.json` + `README.md`, tags release |
| `codeql.yml` | push / PR / schedule | CodeQL security analysis |
| `dependency-review.yml` | PR | Dependency vulnerability check |
| `lighthouse-ci.yml` | push / PR / manual | Lighthouse CI performance, accessibility, and resource budgets |

The bump workflow commits with `[skip ci]` to prevent loops.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ Comprehensive API endpoints with security-first design:
| `/api/blog`       | Blog content management and retrieval             | Prisma + Zod                       |
| `/api/github`     | Fetches GitHub profile + repos (filtered)         | Tokenized (env)                   |
| `/api/pagespeed` | Surfaces PageSpeed metrics                         | Enhanced caching + error handling |
| `/api/chatbot`   | Interactive AI chatbot (Reem) for visitor queries | Groq API           |
| `/api/chatbot`   | Interactive AI chatbot (Reem) for visitor queries | OpenAI Responses API |
| `/api/admin`     | Administrative operations for content             | Secured endpoints                 |

Controls:
Expand Down Expand Up @@ -256,6 +256,13 @@ Automated security and quality workflows ensuring code integrity and vulnerabili
* **Features**: Blocks PRs with vulnerable dependencies, provides detailed security reports in PR comments
* **Integration**: Automated comments on pull requests with dependency security analysis

**Lighthouse CI Performance Budgets:**

* **Triggers**: Pushes and pull requests to main branch, plus manual dispatch
* **Purpose**: Fails regressions before deployment when Lighthouse scores, Core Web Vitals lab metrics, or resource budgets cross configured thresholds
* **Budgets**: Performance score >= 0.80, accessibility score >= 0.95, LCP <= 2.5s, CLS <= 0.1, TBT <= 300ms, script <= 375 KiB, image <= 1,250 KiB, total page weight <= 2,000 KiB
* **Reports**: Saved as GitHub Actions artifacts from local filesystem output; no public temporary Lighthouse upload required

**Vercel CRON Jobs & Automation:**

* **PageSpeed Data Refresh**: Automated background refresh every 12 hours (`0 */12 * * *`)
Expand Down
4 changes: 2 additions & 2 deletions app/(legals)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import type { Metadata } from "next";
import { getLocale } from "next-intl/server";
import { generateLegalPageSEO } from "@/lib/configs/seo";
import { Background } from "@/components/visuals";
import { ClientBackground } from "@/components/visuals";

export async function generateMetadata(): Promise<Metadata> {
const locale = await getLocale();
Expand All @@ -23,7 +23,7 @@ export default function LegalsGroupLayout({
return (
<div className="min-h-screen">
{children}
<Background />
<ClientBackground />
</div>
);
}
15 changes: 15 additions & 0 deletions app/(live-tools)/automation-audit/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* @author © ColdByDefault
* @license Copyright (c) 2026 ColdByDefault. All rights reserved.
* @version 6.x.x
*/

import { AuditWizard } from "@/components/live-tools/automation-audit";

export default function AutomationAuditPage() {
return (
<main className="min-h-screen bg-background px-4 py-12">
<AuditWizard />
</main>
);
}
4 changes: 2 additions & 2 deletions app/(live-tools)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import type { Metadata } from "next";
import { getLocale } from "next-intl/server";
import { generateLegalPageSEO } from "@/lib/configs/seo";
import { Background } from "@/components/visuals";
import { ClientBackground } from "@/components/visuals";

export async function generateMetadata(): Promise<Metadata> {
const locale = await getLocale();
Expand All @@ -23,7 +23,7 @@ export default function LegalsGroupLayout({
return (
<div className="min-h-screen">
{children}
<Background />
<ClientBackground />
</div>
);
}
10 changes: 9 additions & 1 deletion app/(media)/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,21 @@

"use client";

import dynamic from "next/dynamic";
import { Badge } from "@/components/ui/badge";
import { Card } from "@/components/ui/card";
import { Background } from "@/components/visuals/motion-background";
import type { AboutTranslations } from "@/types/configs/i18n";
import Image from "next/image";
import { useTranslations } from "next-intl";

const Background = dynamic(
() =>
import("@/components/visuals/motion-background").then((mod) => ({
default: mod.Background,
})),
{ loading: () => null, ssr: false },
);

export default function AboutPage() {
const t = useTranslations("About");
const light = "from-black/90 to-gray-500";
Expand Down
2 changes: 2 additions & 0 deletions app/(media)/blog/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import { BlogPageClient } from "@/components/blog";
import { getBlogs } from "@/lib/hubs/blogs";

export const revalidate = 60;

export default async function BlogsPage() {
let blogs: Awaited<ReturnType<typeof getBlogs>>["blogs"] = [];

Expand Down
4 changes: 2 additions & 2 deletions app/(media)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import type { Metadata } from "next";
import { getLocale } from "next-intl/server";
import { generateMediaSectionSEO } from "@/lib/configs/seo";
import { Background } from "@/components/visuals";
import { ClientBackground } from "@/components/visuals";

export async function generateMetadata(): Promise<Metadata> {
const locale = await getLocale();
Expand All @@ -23,7 +23,7 @@ export default function MediaGroupLayout({
return (
<div className="min-h-screen">
{children}
<Background />
<ClientBackground />
</div>
);
}
1 change: 0 additions & 1 deletion app/(media)/projects/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* @version 6.x.x
*/

"use client";
import { ProjectsShowcase } from "@/components/projects";

export default function LibraryPage() {
Expand Down
Loading
Loading