Install with npm
Drop CareerChive into your existing Next.js app.
Check Dependencies
Ensure you have your required dependencies, which Next.js and React should already satisfy:
-
next(App Router only — Pages Router is not supported.) -
reactandreact-dom -
@supabase/supabase-js
From your terminal at your application project root run:
npm ls next react react-dom @supabase/supabase-js
Installing
Install CareerChive Package
From your existing Next.js app root, install career-chive from GitHub:
npm install career-chive@github:beck-chan/career-chive @supabase/supabase-js
Set Up Environment Variables
-
Copy the
.env.examplefile to.env.local:cp node_modules/career-chive/.env.example .env.local
-
Fill in values from your Supabase project and Cloudflare R2 bucket:
# Supabase project URL NEXT_PUBLIC_SUPABASE_URL=https://<your-database-url>.supabase.co # Supabase publishable key (browser-safe, RLS still applies) NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_<your-publishable-key> # Server Data API secret. (Never NEXT_PUBLIC_) SUPABASE_SECRET_KEY=sb_secret_<your-secret-key> # Cloudflare Account ID CLOUDFLARE_ACCOUNT_ID=<your-account-id> # Cloudflare R2 Bucket R2_BUCKET=<your-bucket-name> # Cloudflare R2 Access Key ID R2_ACCESS_KEY_ID=<your-access-key-id> # Cloudflare R2 Secret Access Key R2_SECRET_ACCESS_KEY=<your-secret-access-key> # Cloudflare R2 Endpoint R2_ENDPOINT=https://<CLOUDFLARE_ACCOUNT_ID>.r2.cloudflarestorage.com
Set Up Schema & Login
1. Run Installation Schema
-
Copy the contents of
schema.sqlto your clipboard. -
Within Supabase, select SQL Editor from the left sidebar, then paste in the contents of
schema.sql. -
Click Run to execute the schema.
-
If you receive a Potential issue detected popup, click Run query to execute the schema.
2. Set Up Your Login
-
Generate a random 32-byte hex value and copy this generated value to your clipboard by calling the following command in your terminal:
openssl rand -hex 32 -
Enter these values into your
.env.localfile:FLAG_PRIVATE=true SESSION_SECRET=<your-generated-value> -
Generate your login credentials by running the following command in your terminal:
npx career-chive login -
Copy the contents of the generated
scripts/login.sqlfile to your clipboard. -
Within Supabase, select SQL Editor from the left sidebar, then paste in the contents of
login.sql. -
Click Run to execute the schema.
-
If you receive a Potential issue detected popup, click Run query to execute the schema.
Configuring the Application
Define CareerChive Path
Set NEXT_PUBLIC_CAREERCHIVE_PATH in your .env.local to determine the slug where CareerChive is served:
Default configuration is CareerChive as the site at the root of your domain. Omit The easiest way to do this is just to connect your CareerChive GitHub repository to a Vercel project, or set it to /:
NEXT_PUBLIC_CAREERCHIVE_PATH=/
When / (root) is already your site, set NEXT_PUBLIC_CAREERCHIVE_PATH=/careerchive in .env.local with no trailing slash:
NEXT_PUBLIC_CAREERCHIVE_PATH=/careerchive
You'll also need to add NEXT_PUBLIC_CAREERCHIVE_PATH to your Vercel environment variables if you set a path that isn't the root of your domain.
Add CareerChive Pages
Next only serves pages from your app/ directory. Re-export the packaged entrypoints:
-
Create the Archive page at
app/page.tsx:import { Suspense } from "react"; import { CareerChiveArchivePage, careerchiveArchiveMetadata as metadata, } from "career-chive"; export { metadata }; export default function Page({ searchParams, }: { searchParams: Promise<{ org?: string; iso?: string }>; }) { return ( <Suspense fallback={null}> <CareerChiveArchivePage searchParams={searchParams} /> </Suspense> ); } -
Create the Overview page at
app/overview/page.tsx:export { CareerChiveOverviewPage as default, careerchiveOverviewMetadata as metadata, } from "career-chive"; -
Create the Search page at
app/search/page.tsx:export { CareerChiveSearchPage as default, careerchiveSearchMetadata as metadata, } from "career-chive"; -
Create the Organizations page at
app/organizations/page.tsx:import { Suspense } from "react"; import { CareerChiveOrganizationsPage, careerchiveOrganizationsMetadata as metadata, } from "career-chive"; export { metadata }; export default function Page({ searchParams, }: { searchParams: Promise<{ add?: string; org?: string; edit?: string }>; }) { return ( <Suspense fallback={null}> <CareerChiveOrganizationsPage searchParams={searchParams} /> </Suspense> ); } -
Create the Login page at
app/login/page.tsx:import { Suspense } from "react"; import { CareerChiveLoginPage, careerchiveLoginMetadata as metadata, } from "career-chive"; export { metadata }; export default function Page() { return ( <Suspense fallback={null}> <CareerChiveLoginPage /> </Suspense> ); } -
Create the Attachments route at
app/api/attachments/route.ts:export { GET, POST } from "career-chive/attachments"; export const runtime = "nodejs"; -
Create the Not Found page at
app/not-found.tsx:export { CareerChiveNotFound as default, careerchiveNotFoundMetadata as metadata, } from "career-chive";
Put the app in a route group so the URLs stay at the slug defined by NEXT_PUBLIC_CAREERCHIVE_PATH and still share one layout. Use app/careerchive/:
-
Create the Archive page at
app/careerchive/page.tsx:import { Suspense } from "react"; import { CareerChiveArchivePage, careerchiveArchiveMetadata as metadata, } from "career-chive"; export { metadata }; export default function Page({ searchParams, }: { searchParams: Promise<{ org?: string; iso?: string }>; }) { return ( <Suspense fallback={null}> <CareerChiveArchivePage searchParams={searchParams} /> </Suspense> ); } -
Create the Overview page at
app/careerchive/overview/page.tsx:export { CareerChiveOverviewPage as default, careerchiveOverviewMetadata as metadata, } from "career-chive"; -
Create the Search page at
app/careerchive/search/page.tsx:export { CareerChiveSearchPage as default, careerchiveSearchMetadata as metadata, } from "career-chive"; -
Create the Organizations page at
app/careerchive/organizations/page.tsx:import { Suspense } from "react"; import { CareerChiveOrganizationsPage, careerchiveOrganizationsMetadata as metadata, } from "career-chive"; export { metadata }; export default function Page({ searchParams, }: { searchParams: Promise<{ add?: string; org?: string; edit?: string }>; }) { return ( <Suspense fallback={null}> <CareerChiveOrganizationsPage searchParams={searchParams} /> </Suspense> ); } -
Create the Login page at
app/careerchive/login/page.tsx:import { Suspense } from "react"; import { CareerChiveLoginPage, careerchiveLoginMetadata as metadata, } from "career-chive"; export { metadata }; export default function Page() { return ( <Suspense fallback={null}> <CareerChiveLoginPage /> </Suspense> ); } -
Create the Attachments route at
app/careerchive/api/attachments/route.ts:export { GET, POST } from "career-chive/attachments"; export const runtime = "nodejs";(Optional) If you want to use the custom CareerChive 404 page inside of
/careerchivepages:
-
Create the Not Found page at
app/careerchive/not-found.tsx:export { CareerChiveNotFound as default, careerchiveNotFoundMetadata as metadata, } from "career-chive"; -
Create the Unknown URL page at
app/careerchive/[...slug]/page.tsx:export { CareerChiveUnknownPage as default, careerchiveNotFoundMetadata as metadata, } from "career-chive";
Configure Next.js
Wrap Config
withCareerChiveConfig adds transpilePackages so Next can compile the GitHub-installed package. It externalizes the Amazon Web Services (AWS) SDK used for uploads and inlines FLAG_PRIVATE and FLAG_CHIVEBOT for client components.
In your next.config.ts (or next.config.js), wrap your existing config with withCareerChiveConfig:
import type { NextConfig } from "next";
import { withCareerChiveConfig } from "career-chive/config";
const nextConfig: NextConfig = {
// your existing options
};
export default withCareerChiveConfig(nextConfig);
Add Stylesheet and Frame
Import career-chive/styles.css in your root layout (app/layout.tsx) to apply the CareerChive theme:
import type { Metadata } from "next";
import { CareerChiveLayout, careerchiveMetadata } from "career-chive";
import "career-chive/styles.css";
export const metadata: Metadata = {
title: "CareerChive",
description:
"Gain oversight over your professional accomplishments and experiences at work.",
icons: careerchiveMetadata.icons,
};
export default function RootLayout({
children,
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en">
<body>
<CareerChiveLayout>{children}</CareerChiveLayout>
</body>
</html>
);
}
Import career-chive/styles.css in app/careerchive/layout.tsx to apply the CareerChive theme. Set the title and icons from careerchiveMetadata on this layout so this part of the site uses the CareerChive tab title and icon. The rest of your site keeps its own.
import type { Metadata } from "next";
import { CareerChiveLayout, careerchiveMetadata } from "career-chive";
import "career-chive/styles.css";
export const metadata: Metadata = {
title: careerchiveMetadata.title,
icons: careerchiveMetadata.icons,
};
export default CareerChiveLayout;
Run Development Server
To preview your application locally, run:
# Serves by default at `http://localhost:3000`
npm run dev
Serve Your CareerChive
To build the application locally for private use:
# Linter check for errors
npm run lint
# Compile
npm run build
# Serve build
npm run start
The easiest way to do this is just to connect your CareerChive GitHub repository to a Vercel project.
From your Vercel dashboard:
-
If you already have projects with Vercel, click Add New and select Project.
-
Click Import for your CareerChive repository, then set the Project Name.
Your project name will become the URL slug for your application if it's unique and available.
-
Click Environment Variables to enter the following variables:
# Supabase project URL NEXT_PUBLIC_SUPABASE_URL=https://<your-database-url>.supabase.co # Supabase publishable key (browser-safe, RLS still applies) NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_<your-publishable-key> # Server Data API secret. (Never NEXT_PUBLIC_) SUPABASE_SECRET_KEY=sb_secret_<your-secret-key> # Gate CareerChive behind login FLAG_PRIVATE=true # Session secret for login authentication SESSION_SECRET=<your-generated-value> # Cloudflare Account ID CLOUDFLARE_ACCOUNT_ID=<your-account-id> # Cloudflare R2 Bucket R2_BUCKET=<your-bucket-name> # Cloudflare R2 Access Key ID R2_ACCESS_KEY_ID=<your-access-key-id> # Cloudflare R2 Secret Access Key R2_SECRET_ACCESS_KEY=<your-secret-access-key> # Cloudflare R2 Endpoint R2_ENDPOINT=https://<CLOUDFLARE_ACCOUNT_ID>.r2.cloudflarestorage.com
What's Next
Enable your ChiveBot and configure your settings and organizations: