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
11 changes: 11 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false
10 changes: 8 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Resend API key for contact form
# Get your key from https://resend.com/api-keys
# Public site URL used for canonical metadata, sitemap, and robots.
NEXT_PUBLIC_SITE_URL=https://anusbutt.com

# Resend API key. Keep this server-only and configure it in Vercel/local .env.local.
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxx

# Verified sender and destination addresses for the fixed portfolio contact workflow.
CONTACT_FROM_EMAIL=portfolio@anusbutt.com
CONTACT_TO_EMAIL=your-email@example.com
3 changes: 0 additions & 3 deletions .eslintrc.json

This file was deleted.

27 changes: 27 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: CI

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

jobs:
quality:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run lint
- run: npm run typecheck
- run: npm run build
- run: npx playwright install --with-deps chromium
- run: npm run test:e2e
7 changes: 7 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Contributing

1. Read the feature specification and plan under specs/portfolio-architecture-refactor/ before making architectural changes.
2. Keep portfolio content in src/content and avoid duplicating identity values in components.
3. Run npm run check and npm run test:e2e before opening a pull request.
4. Preserve accessible keyboard navigation, reduced-motion behavior, responsive layout, and the existing visual identity.
5. Keep secrets in environment variables and update .env.example when configuration changes.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Anus Butt

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
73 changes: 53 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,69 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
# Anus Butt Portfolio

## Getting Started
Personal portfolio for Anus Butt, an AI engineer and full-stack engineer building auditable agent systems, developer tools, and production web applications.

First, run the development server:
Live site: https://anusbutt.com

## Architecture

This is a server-first Next.js App Router application.

- `src/app` contains the page, layout, metadata routes, and contact route.
- `src/components` contains server-rendered sections plus small client islands for navigation, the form, and the custom cursor.
- `src/content` is the canonical typed source for profile, projects, skills, socials, and education.
- `src/server` contains the contact validation, in-memory abuse limiter, application function, and Resend adapter.
- `tests` contains Playwright browser and API acceptance checks.

The refactor preserves the existing dark editorial visual identity and project hierarchy. Unused React Three Fiber/Three packages were removed because the current portfolio does not render a 3D scene.

## Stack

Next.js 16, React 19, TypeScript, Tailwind CSS, Framer Motion, Resend, and Playwright.

## Local setup

Requirements: Node.js 20.9 or newer and npm.

```bash
npm ci
cp .env.example .env.local
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
On PowerShell, copy the environment file with:

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
```powershell
Copy-Item .env.example .env.local
```

The contact form remains safe but unavailable until the Resend variables are configured. The sender must be verified with Resend.

## Environment variables

- `NEXT_PUBLIC_SITE_URL` — canonical public site URL.
- `RESEND_API_KEY` — server-only Resend API key.
- `CONTACT_FROM_EMAIL` — verified Resend sender address.
- `CONTACT_TO_EMAIL` — fixed portfolio inbox destination.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
Never expose `RESEND_API_KEY` to client code or commit `.env.local`.

## Learn More
## Commands

To learn more about Next.js, take a look at the following resources:
```bash
npm run dev
npm run build
npm run lint
npm run typecheck
npm run test:e2e
npm run check
```

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
`npm run check` runs lint, typecheck, and the production build. Playwright starts the local app on port 3100 for browser tests.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deployment

## Deploy on Vercel
Deploy the repository to Vercel with the four environment variables configured in the project settings. Pushes to the main branch can use the included GitHub Actions checks as the merge gate. The contact limiter is intentionally an in-memory, per-instance guard suitable for low-volume portfolio traffic; a managed limiter would be the next step if abuse volume grows.

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
## Contributing and security

Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
Small fixes should preserve the current visual identity, accessibility, strict typing, and server/client boundaries. See `CONTRIBUTING.md` for the lightweight contribution workflow and `SECURITY.md` for reporting vulnerabilities.
5 changes: 5 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Security

Please do not disclose vulnerabilities in a public issue. Report them privately to the repository owner through the contact details on the live site or GitHub profile.

Do not send credentials, API keys, or other secrets in reports. The contact endpoint intentionally accepts only name, email, and message fields, uses a fixed recipient, validates input on the server, and applies a lightweight per-instance request limiter.
72 changes: 0 additions & 72 deletions app/api/contact/route.ts

This file was deleted.

41 changes: 0 additions & 41 deletions app/layout.tsx

This file was deleted.

38 changes: 0 additions & 38 deletions components/education/Education.tsx

This file was deleted.

17 changes: 17 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTypescript from "eslint-config-next/typescript";

export default defineConfig([
...nextVitals,
...nextTypescript,
globalIgnores([
".next/**",
"out/**",
"build/**",
"coverage/**",
"next-env.d.ts",
"playwright-report/**",
"test-results/**",
]),
]);
Loading
Loading