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
2 changes: 0 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,3 @@ NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=
NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET=
CLOUDINARY_API_KEY=
CLOUDINARY_API_SECRET=
RESEND_API_KEY=
CONTACT_NOTIFICATION_EMAIL=
437 changes: 217 additions & 220 deletions AGENTS.md

Large diffs are not rendered by default.

56 changes: 19 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,29 @@

Official company website and internal CMS for **CODEDDEVS TECHNOLOGY LTD**.

- **Live:** codeddevs.com (pending)
- **Framework:** Next.js 15, App Router, TypeScript
- **Runtime:** React 19
- **Tech:** Tailwind, Drizzle ORM, Neon PostgreSQL
- **Audience:** Investors, press, and partners
- This site presents CODEDDEVS as a product-driven technology company building AI-first software for African markets. The public site is aimed at investors, press, and partners. The admin dashboard is used to manage products, updates, team members, careers, messages, applications, and uploaded media.

- **Live URL:** https://codeddevs.com
- **Company:** CODEDDEVS TECHNOLOGY LTD
- **RC Number:** 9426867
- **Location:** Lagos, Nigeria
- **Contact:** codeddevs.team@gmail.com
- **Email:** codeddevs.team@gmail.com
- **Framework:** Next.js 15, App Router, TypeScript
- **Runtime:** React 19
- **Tech:** Tailwind, Drizzle ORM, Neon PostgreSQL
- **Audience:** Investors, press, partners, collaborators, and people who want to understand what CodedDevs is building

This site presents CODEDDEVS as a product-driven Nigerian technology company building software, payment, and AI products for African markets. The public site is intentionally lean: home, blog, blog posts, and team. The admin dashboard manages team members, products, blog posts, and uploaded media.

## Tech Stack

- **Framework:** Next.js 14, App Router, TypeScript
- **Framework:** Next.js 15, App Router, TypeScript
- **Styling:** Tailwind CSS
- **Database:** Neon PostgreSQL
- **ORM:** Drizzle ORM
- **Auth:** NextAuth.js v5 credentials auth
- **Editor:** TipTap rich text editor
- **Images:** Cloudinary
- **Image cropping:** react-image-crop, admin only
- **Email:** Resend
- **Icons:** lucide-react
- **Fonts:** JetBrains Mono and IBM Plex Sans via `next/font/google`
- **Package manager:** pnpm only

Expand All @@ -37,7 +36,6 @@ Official company website and internal CMS for **CODEDDEVS TECHNOLOGY LTD**.
- pnpm
- Neon PostgreSQL database
- Cloudinary account
- Resend account

### Install

Expand All @@ -64,16 +62,13 @@ NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=
NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET=
CLOUDINARY_API_KEY=
CLOUDINARY_API_SECRET=
RESEND_API_KEY=
CONTACT_NOTIFICATION_EMAIL=
```

Use:

- `DATABASE_URL` for app queries.
- `DATABASE_URL_UNPOOLED` for Drizzle migrations.
- `NEXTAUTH_SECRET` from a secure random value.
- `CONTACT_NOTIFICATION_EMAIL` for contact and application notifications.

### Database

Expand Down Expand Up @@ -122,14 +117,11 @@ pnpm tsc --noEmit
## Public Pages

- `/` - Home
- `/about` - Company mission and approach
- `/products` - Product list
- `/products/[slug]` - Individual product page
- `/blog` - User-facing label is "Updates"
- `/blog/[slug]` - Editorial update page
- `/blog` - Blog list
- `/blog/[slug]` - Editorial blog post page
- `/team` - Team page
- `/careers` - Careers page with application form
- `/contact` - Contact page and form

The public website is intentionally focused around the home page, company stories, and the team. Products are introduced through company blog updates and link to their external product websites. Twizrr is available at [twizrr.com](https://twizrr.com).

## Admin Dashboard

Expand All @@ -140,21 +132,15 @@ Protected routes live under `/admin`.
- `/admin/team`
- `/admin/products`
- `/admin/blog`
- `/admin/careers`
- `/admin/applications`
- `/admin/messages`

Admin API routes live under `/api/admin/*` and require an authenticated admin session.

## Core Features

- Product CMS with featured products for the home page.
- Updates CMS backed by TipTap JSON content.
- Recognition section controlled by `show_in_recognition` and `placement` fields on blog posts.
- Product CMS for internal product records and external product links.
- Blog CMS backed by TipTap JSON content.
- Recognition metadata controlled by `show_in_recognition` and `placement` fields on blog posts.
- Team member CMS.
- Careers CMS with public application form.
- Contact form with Resend notification.
- Career application notification emails.
- Cloudinary uploads with route-based folders:
- `codeddevs-website/team`
- `codeddevs-website/products`
Expand Down Expand Up @@ -182,8 +168,6 @@ src/
components/
admin/
blog/
careers/
contact/
layout/
sections/
ui/
Expand All @@ -195,7 +179,6 @@ src/
lib/
auth.ts
cloudinary.ts
email.ts
utils.ts
types/
index.ts
Expand All @@ -213,11 +196,10 @@ Important rules:
- Use Zod validation on API routes that accept input.
- Check authentication first on every admin API route.
- Use Cloudinary for content images.
- Use shared inline SVG icons from `src/components/ui/icons.tsx`.
- Do not install icon libraries.
- Do not use dark mode, gradients, or animations.
- Use lucide-react as the only icon library.
- Do not use dark mode.
- Do not use "Projects"; the correct term is "Products".
- The `/blog` route must be labeled as "Updates" in user-facing UI.
- The `/blog` route must be labeled as "Blog" in user-facing UI.
- Never commit secrets. `.env.local` must stay untracked.

## CI
Expand Down
25 changes: 25 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "base-nova",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"rtl": false,
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/admin/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"menuColor": "default",
"menuAccent": "subtle",
"registries": {}
}
26 changes: 26 additions & 0 deletions design-qa.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Design QA

## Footer redesign

- Reference: `C:\Users\HP\AppData\Local\Temp\codex-clipboard-17c41149-c52a-43bf-a577-0af846de2616.png`
- Implementation capture: in-app browser at `http://localhost:3000/#footer`
- Desktop viewport: 1515 x 1252
- Responsive check: two-column navigation below the desktop breakpoint, with ownership metadata moved beneath the links

### Comparison

- Layout: passed. The implementation follows the reference's left ownership rail and right navigation matrix while using fewer columns because CodedDevs currently has fewer real destinations.
- Typography: passed. Brand fonts are retained; compact uppercase group labels create the same scanning hierarchy without copying Anthropic's type system.
- Spacing: passed. The wordmark is medium-sized, navigation columns have even gutters, and company metadata remains bottom-aligned on desktop.
- Color: passed. The reference's black footer is intentionally translated to CodedDevs navy `#121F38`, with white headings and muted light-blue secondary text.
- Copy and links: passed. All visible links point to existing pages, homepage anchors, or verified external destinations; no placeholder policy links were introduced.
- Responsive behavior: passed. No horizontal overflow was detected, and the navigation collapses to two columns on smaller screens.
- Accessibility: passed. Navigation groups have headings, icon-only social links have accessible labels, and external links identify their destination through link text or labels.

### Patches after comparison

- Reduced the wordmark from an oversized treatment to a 175-190px responsive width.
- Corrected an invalid fixed-height utility so the logo preserves its intrinsic aspect ratio.
- Forced footer navigation headings to white to prevent the global heading color from reducing contrast.

Final result: passed
29 changes: 24 additions & 5 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { fixupConfigRules } from "@eslint/compat";
import { FlatCompat } from "@eslint/eslintrc";
import nextPlugin from "@next/eslint-plugin-next";
import { defineConfig, globalIgnores } from "eslint/config";

const __filename = fileURLToPath(import.meta.url);
Expand All @@ -12,12 +12,31 @@ const compat = new FlatCompat({
});

const eslintConfig = defineConfig([
...fixupConfigRules(
compat.extends("next/core-web-vitals", "next/typescript"),
...compat.extends(
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:jsx-a11y/recommended",
"plugin:@typescript-eslint/recommended",
),
// Override default ignores of eslint-config-next.
{
files: ["**/*.{js,mjs,cjs,ts,tsx}"],
plugins: {
"@next/next": nextPlugin,
},
rules: {
...nextPlugin.configs["core-web-vitals"].rules,
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
"@typescript-eslint/no-unused-vars": "warn",
"@typescript-eslint/no-unused-expressions": "warn",
},
settings: {
react: {
version: "detect",
},
},
},
globalIgnores([
// Default ignores of eslint-config-next:
".next/**",
"out/**",
"build/**",
Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,34 @@
"lint": "eslint"
},
"dependencies": {
"@base-ui/react": "^1.6.0",
"@neondatabase/serverless": "^1.1.0",
"@react-email/components": "^1.0.12",
"@tiptap/extension-image": "^3.22.5",
"@tiptap/extension-link": "^3.22.5",
"@tiptap/extension-placeholder": "^3.22.5",
"@tiptap/pm": "^3.22.5",
"@tiptap/react": "^3.22.5",
"@tiptap/starter-kit": "^3.22.5",
"bcryptjs": "^3.0.3",
"class-variance-authority": "^0.7.1",
"cloudinary": "^2.10.0",
"clsx": "^2.1.1",
"drizzle-orm": "^0.45.2",
"lucide-react": "^1.21.0",
"next": "^15.5.15",
"next-auth": "5.0.0-beta.31",
"react": "19.2.5",
"react-dom": "19.2.5",
"react-email": "^6.0.5",
"react-image-crop": "^11.0.10",
"resend": "^6.12.2",
"shadcn": "^4.11.0",
"tailwind-merge": "^3.5.0",
"tw-animate-css": "^1.4.0",
"zod": "^4.4.1"
},
"devDependencies": {
"@eslint/compat": "^2.0.5",
"@eslint/eslintrc": "3.3.5",
"@next/eslint-plugin-next": "15.5.15",
"@tailwindcss/postcss": "^4",
"@types/bcryptjs": "^3.0.0",
"@types/node": "^20",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
Expand Down
Loading
Loading