Commit 97c8509
Replace GitHub App with Firestore as profile source of truth (#71)
* fix: cache profile data in Firestore to eliminate GitHub sync delay
Write profile data to Firestore alongside GitHub on create/update, and
read from Firestore first (instant, consistent) instead of GitHub. This
removes the retry loop, optimistic signal, sync-pending banner, and
timer management from the Angular frontend — a net reduction of ~200
lines. Existing GitHub-only profiles are lazily backfilled on first read.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add unknown type to catch callback variable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: harden profile caching with fallback, cache invalidation, and tests
- Wrap Firestore cache lookup in its own try/catch so GitHub fallback
still works when Firestore is unavailable
- Clear cached profile data on refund and subscription-ended flows
- Add tests for Firestore error fallback, and cache write failures
in create/write profile routes
- Extract shared buildProfileImageUrl utility
- Remove double-logging in saveProfileContent
- Use API response data directly instead of reload() in Angular
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review findings and CI failures
- Use proper Elysia response types in tests instead of Record<string, unknown>
- Add clearProfileCache to ProfileMemberService interface and implementation
- Harden error handling in saveProfileContent and setProfileCreatedAt
- Use ProfileMemberService.clearProfileCache in stripe webhooks
- Upgrade cache lookup logging from warn to error with errorId
- Fix factory JSDoc and add unknown type annotation
- Remove obsolete E2E retry/sync-pending tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Refactor profiles API and migrate to Firestore
- Removed markdown serialization utility as it is no longer needed.
- Updated refund and subscription ended processing to trigger Hugo rebuilds.
- Removed cached profile data from member documents.
- Introduced Firestore-based profiles collection with CRUD operations.
- Implemented profile migration script from Hugo markdown to Firestore.
- Added synchronization script to keep Firestore profiles in sync with Hugo markdown files.
- Updated package dependencies for js-yaml and firebase-admin.
* fix: harden Firestore profile operations and clean up stale GitHub references
- Use atomic create()/update() instead of check-then-write to prevent race conditions
- Add empty-snapshot guard and per-profile error handling in Hugo sync script
- Add dedicated API_HUGO_REBUILD_FAILED error ID for trigger-rebuild
- Make profile field required in write/create response schemas
- Remove dead triggerHugoRebuild re-export from barrel
- Update stale GitHub references in comments, test names, and JSDoc
- Add TODO for localStorage cleanup removal in profile.service.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix unnecessary optional chains in profile test files
The `profile` property on `CreateProfileSuccessResponse` and
`WriteProfileSuccessResponse` is non-optional, so optional chaining
is flagged by @typescript-eslint/no-unnecessary-condition.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: remove committed profile content, sync from Firestore on build
Profiles are now sourced from Firestore at build time instead of being
committed as markdown files. The sync script runs before Hugo in CI
(both merge and PR preview workflows) and on `bun run hugo:dev` locally.
- .gitignore profile directories (hugo/content/doulas/*/)
- Add sync step to PR preview workflow for working preview URLs
- Replace js-yaml with Bun.YAML.parse and custom block-style serializer
- Fix initFirebase to pass explicit projectId for ADC usage
- Run sync script before hugo:dev for fresh local data
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use existing service account secret for Firestore sync in CI
Both Hugo workflows now write the FIREBASE_SERVICE_ACCOUNT_DOULA_COOPERATIVE
secret to a temp file instead of referencing the non-existent
FIREBASE_SERVICE_ACCOUNT_JSON_PATH secret.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use printenv to write service account JSON to avoid shell quoting
The secret JSON was getting mangled by shell single-quote interpolation.
Using printenv writes the exact env var contents without shell parsing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: pass service account JSON as env var instead of temp file
Match the pattern from kingston-church: pass FIREBASE_SERVICE_ACCOUNT
as an env var, JSON.parse() it in the script, pass to cert(). No temp
files needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add admin draft toggle, draft-aware access control, notification link, and GitHub cleanup
- Add POST /admin/members/:memberId/profile/toggle-draft endpoint to
publish/unpublish doula profiles from the admin dashboard
- Restrict GET /api/profiles/:slug to return 404 for draft profiles
unless the requester is an admin or the profile owner (optional auth)
- Add direct admin dashboard link to profile creation notification email
- Remove redundant GitHub secret validation from profiles handler and
14 orphaned GitHub-related error IDs
- Add Publish/Unpublish button with draft status indicator to Angular
admin member detail page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve lint errors in functions and members
- Remove useless `undefined` argument (unicorn/no-useless-undefined)
- Use direct boolean check instead of `=== false` comparison
- Rename `profileRef`/`profileDoc` to full names (unicorn/prevent-abbreviations)
- Suppress unused-vars for destructured ownerUid used to strip field
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review findings from comprehensive code review
- Add missing updatedAt to toggleProfileDraft (was inconsistent with draftProfile)
- Fix falsy guards in createProfile that silently dropped empty arrays/strings
- Fix admin notification email referencing Hugo files instead of Firestore documents
- Fix script JSDoc referencing wrong env var (GOOGLE_APPLICATION_CREDENTIALS → FIREBASE_SERVICE_ACCOUNT)
- Update stale "deleted from GitHub" schema description
- Remove unused IMAGEKIT_BASE_URL from sync script
- Add explanatory comment to .gitignore for generated Hugo profile directories
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve exactOptionalPropertyTypes error in readProfileBySlugLogic
Change userToken parameter from optional property (userToken?) to
explicit union type (userToken: DecodedIdToken | undefined) to match
what Elysia's derive provides. Fixes CI typecheck failure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add parameter types to sendEmail mock to fix test typecheck
The mock function had no parameter types, causing TypeScript to infer
an empty tuple for call arguments, which broke the type assertion on
mock.calls[0][0].
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use correct type assertion pattern for sendEmail mock calls
Use `as unknown as` pattern (consistent with stripe handler tests) to
fix both the TypeScript typecheck error and ESLint no-unused-vars error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>1 parent 38fcdd7 commit 97c8509
129 files changed
Lines changed: 2342 additions & 2842 deletions
File tree
- .github/workflows
- functions/src
- admin-members-api
- plugins
- routes
- schemas
- services
- test-utils
- admin-unclaimed-profiles-api/services
- collections
- constants
- profiles-api
- plugins
- routes
- schemas
- services
- github
- member
- profile-store
- test-utils
- types
- utils
- stripe-webhook-api/services
- hugo/content/doulas
- abbey-staffieri
- adriana-lozada
- allison-kelly
- alyssa-actaea
- alyssa-krokenberger
- amanda-moore
- amy-schlageter
- anna-evevsky
- anneliese-goho
- ashley-wyffels
- bert-kiehle
- bridget-strub
- chelse-inman
- christine-landers
- cris-puccia
- danielle-cisneros
- eileen-steinchen
- ellen-pavlacka
- enuma-okafor
- erin-hegeman
- heather-acomb
- janet-mcadoo
- jenna-roberge-karns
- jennie-kieffer
- joanna-jackson
- jocelyn-semple
- julia-m-sittig
- julie-hobart
- kat-head
- kathryn-franke
- kirsten-elting
- lakeisha-washington
- lauren-dearman
- mabel-primus
- margo-fox
- mariel-rivera-piluso
- mark-goho
- mary-feeney
- megan-stavalone
- melissa-ebner
- melissa-keyes
- melody-osgood
- michelle-grosodonia-maiola
- mindy-class
- molly-deutschbein
- morgan-moy
- natalie-skomski
- phyllis-sharp
- rachel-stacy
- rebecca-dilley
- sara-dempsey
- sarah-connor
- sarah-oconnor
- sarah-ozimek
- shannon-glaser
- shannon-pessin
- tamara-l-albert
- tara-rice
- teagan-white
- members
- e2e/tests
- src/app
- admin
- services
- users/admin-member-detail
- edit-profile
- services
- scripts
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
| 13 | + | |
12 | 14 | | |
13 | 15 | | |
14 | 16 | | |
| |||
21 | 23 | | |
22 | 24 | | |
23 | 25 | | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
24 | 30 | | |
25 | 31 | | |
26 | 32 | | |
| |||
36 | 42 | | |
37 | 43 | | |
38 | 44 | | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
50 | | - | |
51 | | - | |
52 | | - | |
53 | | - | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
69 | | - | |
70 | | - | |
71 | | - | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
32 | 37 | | |
33 | 38 | | |
34 | 39 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
| 39 | + | |
| 40 | + | |
39 | 41 | | |
40 | 42 | | |
41 | 43 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 23 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
| 16 | + | |
16 | 17 | | |
17 | 18 | | |
18 | 19 | | |
| |||
28 | 29 | | |
29 | 30 | | |
30 | 31 | | |
| 32 | + | |
31 | 33 | | |
32 | 34 | | |
33 | 35 | | |
| |||
145 | 147 | | |
146 | 148 | | |
147 | 149 | | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
148 | 171 | | |
149 | 172 | | |
150 | 173 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
Lines changed: 221 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
0 commit comments