Skip to content

Ft/pericope view#205

Merged
Joel-Joseph-George merged 15 commits into
mainfrom
ft/pericope-view
Jul 2, 2026
Merged

Ft/pericope view#205
Joel-Joseph-George merged 15 commits into
mainfrom
ft/pericope-view

Conversation

@Joel-Joseph-George

@Joel-Joseph-George Joel-Joseph-George commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Added support for pericope sets and pericope verse data across the app.
    • Introduced new API access to list pericope sets and view pericope groupings for a chapter.
  • Bug Fixes

    • Projects can now be linked to a pericope set, with invalid selections rejected cleanly.
    • Existing project setup now includes pericope set data during seeding.
    • Expanded ignored paths so generated data directories are excluded from linting.

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Joel-Joseph-George, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 58 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d49339da-c560-473b-a6ad-1a3acc072887

📥 Commits

Reviewing files that changed from the base of the PR and between 8719733 and 5a7ebe8.

📒 Files selected for processing (6)
  • src/db/migrations/0012_add_pericope_sets.sql
  • src/db/schema.ts
  • src/db/seeds/pericope-sets.ts
  • src/domains/pericopes/pericopes.route.ts
  • src/domains/pericopes/pericopes.test.ts
  • src/domains/projects/projects.service.ts
📝 Walkthrough

Walkthrough

Introduces a pericopes domain: new pericope_sets and pericope_verses DB tables (schema + SQL migration), a seeding script that loads FCBH/FIA JSON data, repository/service/route layers for listing pericope sets and querying chapter pericopes, and validation of pericope set references in project create/update.

Changes

Pericope Sets Feature

Layer / File(s) Summary
DB schema and migration
src/db/schema.ts, src/db/migrations/0012_add_pericope_sets.sql, src/db/migrations/meta/_journal.json, src/db/migrations/meta/0012_snapshot.json
Adds pericope_sets and pericope_verses Drizzle table definitions and matching SQL migration; extends projects with a nullable pericope_set_id FK; records migration in the journal and full schema snapshot.
Pericope set seeding
src/db/seeds/pericope-sets.ts, src/db/scripts/setup.ts, eslint.config.mjs
Adds seedPericopeSets which loads FCBH and FIA JSON files from data/, upserts pericope sets, batch-replaces verses in chunks of 500, and assigns the FIA set to existing projects. Wired into the 10-step setup script; data/** added to ESLint ignore list.
Pericope types and error code
src/domains/pericopes/pericopes.types.ts, src/lib/types.ts
Defines Zod/OpenAPI schemas and TypeScript types for PericopeSet, PericopeGroup, ChapterPericopesResponse, and route path params. Adds PERICOPE_SET_NOT_FOUND error code mapped to HTTP 404.
Repository and service
src/domains/pericopes/pericopes.repository.ts, src/domains/pericopes/pericopes.service.ts
Repository functions fetch all pericope sets, resolve project pericope-set and book IDs, and query chapter verses. Service wraps these into listPericopeSets and getChapterPericopes, grouping verse rows by pericopeNumber and handling missing-set/missing-book edge cases.
Routes and app wiring
src/domains/pericopes/pericopes.route.ts, src/app.ts
Registers GET /pericope-sets (auth required) and GET /projects/:id/pericopes/:bookCode/:chapter (auth + PROJECT_VIEW permission + project read access) as OpenAPI endpoints. Route module imported in app.ts.
Project service validation
src/domains/projects/projects.query-builder.ts, src/domains/projects/projects.service.ts
Adds pericopeSetId to the project query-builder projection. Validates pericopeSetId existence against pericope_sets in both createProject and updateProject, returning PERICOPE_SET_NOT_FOUND on missing reference.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • kaseywright
🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is related to the feature, but "Ft/pericope view" is too vague to convey the main change clearly. Rename it to something more specific, such as "Add pericope view and pericope set support".
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ft/pericope-view

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Joel-Joseph-George
Joel-Joseph-George marked this pull request as ready for review June 30, 2026 05:29

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/db/schema.ts`:
- Around line 249-255: The pericope verse mapping in schema.ts is currently only
indexed, which allows duplicate (pericopeSetId, bookId, chapterNumber,
verseNumber) rows and can make getPericopeVersesForChapter() return ambiguous
results. Update the idx_pericope_verses_set_book_chapter_verse definition to
enforce uniqueness, and keep the migration in 0012_add_pericope_sets.sql aligned
so the database schema and seed/import path both reject conflicting verse
mappings.

In `@src/db/seeds/pericope-sets.ts`:
- Around line 98-119: In the pericope seed logic, unknown FCBH book names are
only warned about and the seed continues, which leaves `pericope_verses`
partially populated. Update the seeding flow in the records loop and the
`unmappedBooks` handling to fail fast instead of logging a warning, matching the
behavior used by the other seeders; ensure the seed aborts as soon as any
unmapped book is detected and surfaces the offending book names clearly.
- Around line 173-186: The project backfill for legacy projects is currently
happening inside the dev-only seed flow in seedPericopeSets(), which means it
won’t run during a normal production rollout. Move the logic that looks up
fiaSet and updates projects with a null pericopeSetId into the migration/rollout
path used by the database schema change, and keep seedPericopeSets() focused on
seeding data only. Use the existing projects, pericope_sets, and isNull update
logic as the implementation reference, but wire it to the migration path instead
of src/db/scripts/setup.ts.
- Around line 53-59: The `buildBookIdMap` helper currently lets `Map#set`
overwrite earlier `books.eng_display_name` entries, so add a duplicate check
before populating the map and fail fast if the same display name appears more
than once. Use the existing `buildBookIdMap` flow in
`src/db/seeds/pericope-sets.ts` to detect ambiguous `books` rows and throw a
clear error instead of returning a silently corrupted mapping, matching the
strict behavior already used by `seedBibles()` and `seedBibleTexts()`.

In `@src/domains/pericopes/pericopes.route.ts`:
- Around line 27-39: The pericopes route currently documents only 401 and 500,
but authenticateUser can also return 403 for inactive users. Update the
responses in pericopes.route.ts for the route that uses authenticateUser to
include a 403 response with the same message schema style used elsewhere, so the
OpenAPI contract matches the runtime behavior.

In `@src/domains/pericopes/pericopes.service.ts`:
- Around line 26-32: The get-pericopes flow in pericopes.service.ts is returning
the empty verse-by-verse fallback before validating bookCode, which makes
invalid book codes behave differently depending on pericopeSetId. Reorder the
checks in the pericopes lookup so getBookIdByCode runs before the
no-pericope-set ok([]) fallback, and keep the existing ErrorCode.BOOK_NOT_FOUND
path in the same method to ensure bad input is rejected consistently.

In `@src/domains/projects/projects.service.ts`:
- Around line 48-57: Use an explicit nullish check for pericopeSetId in the
project create/update validation paths, since the current truthy check skips
values like 0 and can let invalid references reach the write path. Update the
conditional in the relevant projects.service.ts logic around the pericope_sets
lookup to check only for null/undefined, and apply the same fix in the other
branch noted in the review. Keep the existing PERICOPE_SET_NOT_FOUND return
behavior when a provided ID does not exist.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4e3febc5-be9c-4ca7-a876-b3595a0faf91

📥 Commits

Reviewing files that changed from the base of the PR and between 997cce8 and 8719733.

📒 Files selected for processing (17)
  • data/FCBH-All-Books.json
  • data/FIA-All-Books.json
  • eslint.config.mjs
  • src/app.ts
  • src/db/migrations/0012_add_pericope_sets.sql
  • src/db/migrations/meta/0012_snapshot.json
  • src/db/migrations/meta/_journal.json
  • src/db/schema.ts
  • src/db/scripts/setup.ts
  • src/db/seeds/pericope-sets.ts
  • src/domains/pericopes/pericopes.repository.ts
  • src/domains/pericopes/pericopes.route.ts
  • src/domains/pericopes/pericopes.service.ts
  • src/domains/pericopes/pericopes.types.ts
  • src/domains/projects/projects.query-builder.ts
  • src/domains/projects/projects.service.ts
  • src/lib/types.ts

Comment thread src/db/schema.ts
Comment thread src/db/seeds/pericope-sets.ts
Comment thread src/db/seeds/pericope-sets.ts
Comment thread src/db/seeds/pericope-sets.ts
Comment thread src/domains/pericopes/pericopes.route.ts
Comment thread src/domains/pericopes/pericopes.service.ts
Comment thread src/domains/projects/projects.service.ts Outdated

@kaseywright kaseywright left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty solid implementation. I would suggest adding at least basic unit tests for new features like this to avoid drift in the future.

The large seed data files might end up being stored either in a separate repo or CDN later as more of these become necessary.

Comment thread src/db/seeds/pericope-sets.ts Outdated
@Joel-Joseph-George

Joel-Joseph-George commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

Pretty solid implementation. I would suggest adding at least basic unit tests for new features like this to avoid drift in the future.

The large seed data files might end up being stored either in a separate repo or CDN later as more of these become necessary.

I thought about that. but i felt for now keeping it in repo isn't harming that much. But yeah its bigger in size with limited book collection (2 files : 4.5mb approx)

@Joel-Joseph-George
Joel-Joseph-George merged commit 12c970e into main Jul 2, 2026
2 checks passed
@github-actions
github-actions Bot deleted the ft/pericope-view branch July 2, 2026 11:51
JEdward7777 pushed a commit to JEdward7777/fluent-api that referenced this pull request Jul 3, 2026
Phase 1 of the repeated-word-check persistence backend.

- db/schema.ts: add user_settings table (user_id PK, settings jsonb,
  timestamps, FK to users ON DELETE CASCADE) with select/insert schemas;
  add userSettingsSchema (read, .catch({})) + strict userSettingsWriteSchema
  so malformed PUT bodies 400 instead of being silently coerced; extend
  editorStateResourcesSchema with optional activeLeftTab + checkOccurrenceRules.
- migration 0013_add_user_settings.sql (+meta). Renumbered from 0012 during
  rebase onto jel-feature-flags-proposal to avoid colliding with the pericope
  0012 migration that landed on main via eten-tech-foundation#205.
- domains/self/settings quartet: GET/PUT /self/settings, authenticateUser only,
  full-replace upsert, strict-validate -> 400, read-tolerant.
- register self domain in app.ts.
- tests: self-settings.route.test.ts (8) + schema.editor-state-extension.test.ts (8).

Relates to eten-tech-foundation#172, #277, #278
JEdward7777 pushed a commit to JEdward7777/fluent-api that referenced this pull request Jul 3, 2026
Phase 1 of the repeated-word-check persistence backend.

- db/schema.ts: add user_settings table (user_id PK, settings jsonb,
  timestamps, FK to users ON DELETE CASCADE) with select/insert schemas;
  add userSettingsSchema (read, .catch({})) + strict userSettingsWriteSchema
  so malformed PUT bodies 400 instead of being silently coerced; extend
  editorStateResourcesSchema with optional activeLeftTab + checkOccurrenceRules.
- migration 0013_add_user_settings.sql (+meta). Renumbered from 0012 during
  rebase onto jel-feature-flags-proposal to avoid colliding with the pericope
  0012 migration that landed on main via eten-tech-foundation#205.
- domains/self/settings quartet: GET/PUT /self/settings, authenticateUser only,
  full-replace upsert, strict-validate -> 400, read-tolerant.
- register self domain in app.ts.
- tests: self-settings.route.test.ts (8) + schema.editor-state-extension.test.ts (8).

Relates to eten-tech-foundation#172, #277, #278
JEdward7777 pushed a commit to JEdward7777/fluent-api that referenced this pull request Jul 7, 2026
Phase 1 of the repeated-word-check persistence backend.

- db/schema.ts: add user_settings table (user_id PK, settings jsonb,
  timestamps, FK to users ON DELETE CASCADE) with select/insert schemas;
  add userSettingsSchema (read, .catch({})) + strict userSettingsWriteSchema
  so malformed PUT bodies 400 instead of being silently coerced; extend
  editorStateResourcesSchema with optional activeLeftTab + checkOccurrenceRules.
- migration 0013_add_user_settings.sql (+meta). Renumbered from 0012 during
  rebase onto jel-feature-flags-proposal to avoid colliding with the pericope
  0012 migration that landed on main via eten-tech-foundation#205.
- domains/self/settings quartet: GET/PUT /self/settings, authenticateUser only,
  full-replace upsert, strict-validate -> 400, read-tolerant.
- register self domain in app.ts.
- tests: self-settings.route.test.ts (8) + schema.editor-state-extension.test.ts (8).

Relates to eten-tech-foundation#172, #277, #278
JEdward7777 added a commit that referenced this pull request Jul 7, 2026
…res (+ Repeated Word Check backend) (#213)

* docs(proposals): add feature-flags proposal (config/features endpoint)

Add a docs-only proposal for a lightweight, env-sourced feature-flag
mechanism to gate AI-dependent front-end features (starting with the
Repeated Word Check) so their PRs can merge and ship hidden while
fluent-ai is unhosted.

- EN_FEATURE_* env vars, declared in the Zod schema, swept into a map
- new unauthenticated meta route GET /config/features (sibling of /health)
- fluent-web consumes via a useFeatureFlags hook + FeatureGate (fail-closed)
- unlinked, login-gated diagnostics page for the flag view
- publishing only; no server-side enforcement (D5)

Includes -suggestion.md (design, D1-D8, Q1-Q4) and -summary.md.

* docs(proposals): address CodeRabbit on feature-flags (stringbool + fence lang)

* fix(db): correct 0012 pericope snapshot to match schema

The 0012_add_pericope_sets migration snapshot was out of sync with its
own schema/SQL:

- Removed a phantom `public.recordings` table that was never part of the
  migration (an accidental leak from experimental mobile DB work; absent
  from Dev/PROD and from schema.ts).
- Fixed `idx_pericope_verses_set_book_chapter_verse` to `isUnique: true`
  to match the CREATE UNIQUE INDEX in 0012_add_pericope_sets.sql.

No SQL or schema changes; snapshot-only correction so drizzle-kit
generate diffs cleanly against the actual schema.

* feat(self): add /self/settings domain + user_settings table

Phase 1 of the repeated-word-check persistence backend.

- db/schema.ts: add user_settings table (user_id PK, settings jsonb,
  timestamps, FK to users ON DELETE CASCADE) with select/insert schemas;
  add userSettingsSchema (read, .catch({})) + strict userSettingsWriteSchema
  so malformed PUT bodies 400 instead of being silently coerced; extend
  editorStateResourcesSchema with optional activeLeftTab + checkOccurrenceRules.
- migration 0013_add_user_settings.sql (+meta). Renumbered from 0012 during
  rebase onto jel-feature-flags-proposal to avoid colliding with the pericope
  0012 migration that landed on main via #205.
- domains/self/settings quartet: GET/PUT /self/settings, authenticateUser only,
  full-replace upsert, strict-validate -> 400, read-tolerant.
- register self domain in app.ts.
- tests: self-settings.route.test.ts (8) + schema.editor-state-extension.test.ts (8).

Relates to #172, #277, #278

* Prettifier changes.

* feat(checks): surface target ISO 639-3 lang code on chapter assignments (phase-04 BUG #2)

The repeated-words check sends the target language's ISO 639-3 code to
greek-room as lang_code (greek-room keys its legitimate-duplicate
whitelist on the code, not the display name). The user chapter-assignment
response previously exposed only the human display name (targetLanguage),
so the web client had no code to send.

Plumb targetLangCode (targetLang.langCodeIso6393) through
findAssignmentsProgress -> ChapterAssignmentProgressInfo -> toResponse as
targetLanguageCode on UserChapterAssignmentResponse (schema + types).
Add a toResponse regression test. Found during the Phase 4 manual smoke.

* feat(db): add second dev translator and English to dev seed

Enables exercising the full project assign -> draft flow out-of-the-box:
- dev-users seeder now provisions a second translator (translator2,
  t2@fluent.local), so a project meets the >=2-translator requirement for
  chapter assignment (distinct Drafter + Peer Checker). Idempotent; honours
  SEED_TRANSLATOR2_EMAIL/SEED_TRANSLATOR2_PASSWORD overrides.
- languages seed now includes English (eng), so a draftable English target
  language is available without manual DB insertion.

Both seeders remain idempotent (existing rows skipped on re-run).

* fix(checks): surface targetLanguageCode on project progress endpoint

The repeated-words check sends greek-room a `lang_code` keyed on the ISO
639-3 target language code. greek-room's legitimate-duplicate whitelist
(e.g. "truly truly" for "eng") only matches when the code is correct.

The PM "open chapter" path builds its ProjectItem from
GET /projects/{id}/chapter-assignments/progress, but that endpoint never
serialized the target language code: the repository fetched targetLangCode
yet both service mappers (getChapterAssignmentProgressByProject and
assignSelectedChapters) dropped it, and the response schema didn't declare
it. As a result the PM-path check sent lang_code "<unknown>" and legitimate
duplicates were flagged.

Add `targetLanguageCode` to chapterAssignmentProgressResponseSchema and
populate it in both mappers (falling back to '' when the FK doesn't resolve,
matching the existing sourceLangCode handling).

Includes TEMP [RW-DIAG] logging used to pin down the bug; removed in the
following commit.

* chore(checks): remove temporary [RW-DIAG] logging

Removes the diagnostic logging added in the previous commit (inbound
repeated-words request log, fluent-ai response/error log, and the
toResponse targetLangCode log) now that the root cause is fixed and
verified.

* refactor(self-settings): address review on /self/settings contracts

- normalize stored settings JSONB through the tolerant read schema in
  toResponse (null-guarded) so a malformed/legacy blob degrades to {}
  instead of leaking through GET; add two read-path tests
- declare 403 FORBIDDEN on both GET and PUT route contracts (reachable
  via authenticateUser's inactive-account branch); add a 403 test to each
- tighten the OpenAPI response schema settings field to userSettingsSchema
  so the spec advertises the real keys/enums (response provably conforms
  after the read-path normalization); request schema left generic by design

* docs(self-settings): note full-replace is single-key-only; merge before adding a key

* feat(config): publish env-sourced feature flags via GET /config/features

Implements the fluent-api half of the feature-flags proposal (docs in
docs/proposals/feature-flags): an unauthenticated, DB-less meta route that
publishes which optional, AI-dependent features are enabled per environment,
so fluent-web can ship AI UI hidden while fluent-ai is unhosted.

- env.ts: declare EN_FEATURE_REPEATED_WORD_CHECK in the Zod EnvSchema via a
  local envBool() parser (not z.coerce.boolean(), which would read the string
  "false" as true and invert the safe-off default). Optional so an unset flag
  can derive its default.
- lib/features.ts: typed FLAGS registry tying each env var to its camelCase
  wire key + unset default (repeatedWordCheck defaults to whether FLUENT_AI_URL
  + FLUENT_AI_KEY are wired); buildFeatures() derives the published map; named
  OpenAPI featuresSchema guarded by a compile-time `satisfies`.
- routes/config.route.ts: GET /config/features -> { features: { ... } },
  sibling of /health; publishes state, does not enforce it (no gating of the
  AI request path).
- app.ts: register the route. .env.example: document the flag.
- Tests: buildFeatures behavior + a three-way drift guard (env schema / FLAGS /
  OpenAPI schema kept in sync, both directions) + route behavior.

Relates to the feature-flags proposal (fluent-api #211).

* fix(db): seed pericope sets in docker-entrypoint

The container seeds the DB via docker-entrypoint.sh, which inlined its own
seed list and stopped after bible-texts, never running the pericope-sets
seed that setup.ts includes as its final step. As a result every
container-based DB (re)generation left pericope_sets empty, so the Create
Project page's Pericope Set dropdown had nothing to select.

Add the pericope-sets seed after bible-texts (it depends on books, already
seeded earlier). The seed is idempotent (upsert set by name + replace
verses) and its data files are baked into the image, matching the other
entrypoint seeds.

* fix(flags): address CodeRabbit review on #213

- rename wire field targetLanguageCode -> targetLangCode (match sourceLangCode)
- env: treat blank EN_FEATURE_* as unset so empty .env.example lines don't fail boot
- self-settings: return VALIDATION_ERROR (422) on write-schema violation
- docs: update feature-flags snippet from z.stringbool() to shipped envBool()
- tests: assert userSettingsWriteSchema rejects malformed writes
- refactor: extract shared toChapterAssignmentProgressResponse() mapper

* test(doc): add regression test asserting GET /doc renders the OpenAPI spec

The OpenAPI document walk over every registered schema currently 500s
('Unknown zod object type') and nothing at the unit/type level catches it,
so it only surfaced at runtime. This test renders the real assembled
document via GET /doc and asserts a 200, so that class of break fails CI.

Currently RED (reproduces the live 500); the fix follows in the next commit.

* fix(self-settings): keep the .catch({}) read schema off the OpenAPI surface

GET /doc 500'd with 'Unknown zod object type' because the /self/settings
response schema embedded userSettingsSchema (= userSettingsObjectSchema.catch({})).
The .catch wrapper is a ZodCatch node that @asteasolutions/zod-to-openapi
(under @hono/zod-openapi) has no renderer for, so building the OpenAPI
document threw and took the whole /doc endpoint down.

Export the plain userSettingsObjectSchema and embed THAT in
userSettingsResponseSchema. The .catch only affects behaviour on invalid
input, so it adds/removes no fields: the documented shape and the response
bytes are unchanged. The fail-soft W8 read tolerance stays where it belongs
(the service read path, toResponse -> userSettingsSchema.parse), and the
strict write schema is untouched. No request/response contract change.

Turns the doc.route regression test green.

* fix(flags): gate /config/features behind auth (review #211 Q1)

Per kaseywright's review on proposal #211 (Q1), GET /config/features is now
login-gated via authenticateUser (no role required), matching the pattern used
by self-settings and pericopes-list. The endpoint still only publishes flags
(does not enforce them, D5 unchanged); only the read now requires a session.
Reversible later if we decide it should be public.

- config.route.ts: add authenticateUser middleware + UNAUTHORIZED (401) response,
  reword description (no longer 'unauthenticated like /health').
- config.route.test.ts: rewrite against the mocked-auth pattern — null session
  => 401; valid session => 200 with the features map.

* fix(flags): address CodeRabbit re-review on #213 + harden db bootstrap

CodeRabbit re-review (auth-gate follow-up):
- self-settings.route: add 422 UNPROCESSABLE_ENTITY to PUT OpenAPI responses so
  the published contract matches upsertSettings validation behavior (R5)
- self-settings.route: GET error branch derives status via getHttpStatus(result.error)
  instead of hardcoding 500, consistent with PUT (R4)
- schema.ts: correct stale userSettingsWriteSchema comment (400 -> 422) (R3)
- lib/features: tighten FlagDefinition.env to boolean-valued EN_FEATURE_* keys and
  drop the boolean cast in buildFeatures (R7)
- docs/proposals/feature-flags: fold suggestion + summary to the shipped
  authenticated contract and Q1-Q4 resolutions (R1/R2)

Stack durability (unblocks local smoke testing):
- db bootstrap: poll for real query readiness before issuing DDL. The compose
  healthcheck (pg_isready) reports ready as soon as Postgres accepts connections,
  but during startup/WAL-recovery it rejects queries with 57P03; the entrypoint's
  set -e then killed the container (and its dependents) on restart. Retry transient
  startup/connection errors with bounded backoff (~60s ceiling); real errors still
  fail fast.

---------

Co-authored-by: Joshua Lansford <Joshua@Lansfords.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants