This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
LessonsApi is the Node.js/TypeScript backend for Lessons.church. Express.js with Inversify dependency injection, Kysely over MySQL, deployed to AWS Lambda via the Serverless Framework. Uses Yarn (Berry) — npm/pnpm installs are blocked by a preinstall check.
yarn dev # Start development server with auto-reload (nodemon + tsx, port 8090)
yarn dev:start # Build and start once
yarn start # Start production server from dist/yarn build # Clean, lint, compile TypeScript, fix ESM imports
yarn build-fast # Same without lint
yarn lint # ESLint with auto-fix
yarn lint:check # ESLint check onlyyarn test # Jest unit tests with coverage
yarn test:watch # Jest watch modeTests live in __tests__/ folders next to the code (src/**/__tests__/*.test.ts), mirroring the main Api's conventions: repositories/controllers are tested with a mocked getDb() / hand-built doubles — no real database.
yarn initdb # Create tables (migrations) and load demo data
yarn migrate:status # Migration status (also migrate:up / migrate:down / migrate:create)
yarn reset-demo # Drop + recreate the lessons DB and reload demo data (refuses non-local hosts)yarn deploy-staging # Build and deploy to staging
yarn deploy-prod # Build and deploy to production- Models (
src/models/): interfaces for database entities and feed objects - Controllers (
src/controllers/): Express route handlers extendingLessonsBaseController - Repositories (
src/repositories/): Kysely data access;Repositories.getCurrent()is the singleton registry - Helpers (
src/helpers/): external services (Vimeo, HubSpot, S3/transcoding), permissions, feed/playlist logic - DB (
src/db/):getDb()Kysely instance andDatabaseTypes.tstable typings
- Mutating routes check
au.checkAccess(Permissions.lessons.edit)(orPermissions.schedules.edit) and scope every repository call byau.churchId. - Anonymous read routes live under
/public/...paths and useactionWrapperAnon; they must only servelivecontent or church-scoped display data. - Repository
update/deletealways include achurchIdwhere-clause so one church can't touch another's rows.
- Environment-specific configs in
config/(dev/demo/staging/prod/selfhost.json), loaded bysrc/helpers/Environment.tsbased onAPP_ENV - Local secrets in
.env(CONNECTION_STRING,JWT_SECRET, ...); AWS Parameter Store in deployed environments
- Lambda via Serverless Framework (
serverless.yml); thezipBundlesscheduled function runs every 5 minutes vialambda.zipBundles(not the HTTP route) - S3 for file storage, Elastic Transcoder for webm generation
- Create MySQL database named
lessons - Copy
dotenvsample.txtto.envand configure the connection string yarn installyarn initdbyarn dev