Application Build
How was the CareerChive application implemented?
Supabase Backend
The schema applied by running scripts/schema.sql enables row-level security on every public table. createAdminClient() talks to these tables with SUPABASE_SECRET_KEY, which bypasses row-level security.
There are no anon or authenticated policies — grants below are for service_role:
| Table | Server (SUPABASE_SECRET_KEY) |
|---|---|
settings | SELECT, INSERT, UPDATE, DELETE |
login_attempts | SELECT, INSERT, UPDATE, DELETE |
organizations | SELECT, INSERT, UPDATE, DELETE |
days | SELECT, INSERT, UPDATE, DELETE |
work | SELECT, INSERT, UPDATE, DELETE |
citations | SELECT, INSERT, UPDATE, DELETE |
settingsis a singleton (id = 1). Username andpassword_hash(scrypt) are theFLAG_PRIVATElogin, andpassword_encryptedis an AES-256-GCM copy keyed fromSESSION_SECRETso Settings can refill the password field.login_attemptsis one row per failed login. Count by IP and by username independently — a fourth try in that hour is rejected without checking the password.organizationsstores weekday flags Sun–Sat (0= Sunday …6= Saturday) for auto-generation of daily entries.daysis one log per organization andwork_date.workis the Work Completed rows on a day (title,description,link,position).citationsis the Citations / Artifacts rows on a day.attachmentis the filename shown in the UI, andattachment_keyis the Cloudflare R2 object key.
ensure_generated_days() inserts empty weekday shells for each visible organization, from the Autogenerate From date (further gated by Archive Start and organization Date Active) through today defined by the archive Time Zone, and stops the day before Date Inactive:
ensure_generated_days()does nothing until Autogenerate From is set.pg_cronruns it hourly ascareerchive-ensure-days.- Saving an organization, moving Autogenerate From earlier, changing the Time Zone, signing in, and loading the archive call
ensure_generated_days()too.
Next.js Frontend
When CareerChive opens, CareerChiveLayout loads the archive once. loadArchive() reads settings, organizations, days, work, and citations into DemoProvider, and the pages use that copy. Saves go back through the server actions in src/app/actions/archive.ts.
AppChrome is the top navigation:
(/) is ArchiveView, consisting of a calendar and DayPanel daily organization logs:
- Notes and comments are markdown from rich text
NotesEditorwhich uses Lexical. - Work Completed and Citations / Artifacts are drag-and-drop lists, with order captured in
position. - Citations / Artifacts files are uploaded to Cloudflare R2.
src/lib/r2.tssigns upload and download URLs, andsrc/app/api/attachments/route.tsaccepts the upload and redirects a download.
(/overview) is OverviewView, which shows the counts of how many days were logged, along with attendance and ratings, as well as exportable lists of work competed and citations / artifacts grouped by day for a selected time period.
(/search) is SearchShell, which ranks keyword search results by work titles above other field text, which ranks above the organization name and day title. ChiveBot is a separate panel — refer to ChiveBot Build.
(/organizations) is SettingsForm, which requires Name and Date Active when creating or editing an organization. Deletion of organizations is blocked while any day rows exist.
Modal that can be opened from any page with in the top navigation.
User Login
FLAG_PRIVATE gates the archive with the username and password on settings. The cookie is careerchive_session (httpOnly, path /, 7 days), and signSession() stores the username and an expiry and signs them with HMAC-SHA256 from SESSION_SECRET:
loginAction()checks the username and verifies the password with scrypt (verifyPassword()). Failed tries are written tologin_attemptsbefore the error is returned./loginrendersLoginForm. A signed-in visit redirects to the CareerChive home page (/, Archive).- With
FLAG_PRIVATEoff,getSession()returns a local session,/loginredirects home, and Logout is hidden.SESSION_SECRETis still what encrypts the Settings password copy when a password is saved.
Deleting an organization, clearing or deleting a range of days, and Factory Reset ask for that password again and check it against password_hash.
Feature Flags
Flags are built on compile:
src/lib/flags.tsreadsprocess.env.FLAG_*withenvFlag(true/1vsfalse/0— unset uses the default).withCareerChiveConfig()listsFLAG_PRIVATEandFLAG_CHIVEBOTunderenvso Next can inline them into client components.
When set to true, requires the username and password from Settings before the archive loads. Default is false.
When set to true, shows Ask ChiveBot on Search and writes field embeddings when a day is saved. Refer to ChiveBot Build.
Accessibility
Along with checking pages with Chrome's Lighthouse accessibility audit, as part of pull request checks, a11y lint runs a spot check on all CareerChive application pages to ensure they are somewhat accessible and any errors discovered are patched before deployment.