The Need: A Paper Directory Does Not Remember Anything
Every year my church prints a small booklet with a photo of each family. Under each photo there are the names, a short address, and a mark next to each name: br for brother or si for sister. In my church the mark is not about being male or female. It means the person has been saved and baptized. A husband who has not been baptized has no mark, even when his wife has si next to her name, and in church we call that family by the wife’s name.
The booklet is useful for one thing: putting a face to a name. But I want to do more than that. When someone tells me their mother is in the hospital, or their son is starting a new job, I want to remember it next Sunday. I want to pray for it during the week. A paper booklet cannot hold that, and my memory is not as good as it was.
I also wanted to find a family fast. With a paper booklet, I have to remember the family name and turn pages. On my phone, I wanted to type a name and see the family.
So the need was simple: the directory, on my phone, with a place to write notes about each family and each person, and search over all of it. I started calling it my church member care notebook.
The Proof: A New Tab in My Bible App
I already run a Bible app on my home NAS. It has a reader, search, AI verse notes and my sermon notes. Now it has one more tab at the bottom: 성도 (“church members”).
What it does today:
- 142 families, 382 people, taken from 8 scanned pages of the booklet.
- A list with a small photo, the address and the family members. Each name shows its br or si mark as a colored badge, exactly as printed. People without a mark show only their name.
- Each family is listed under the name of its oldest br. If the family has no br, the oldest si. So a family where only the wife is baptized is listed under her name, the way we say it at church.
- Tap a family to see the big photo, the address, a table of members with birth years, and the notes.
- A family note and a personal note for each person. They save by themselves 0.8 seconds after I stop typing.
- Search by name, by address, and (since the same evening) by the text in my notes. If I type “hospital”, the families I wrote that word about show up, with the matching part of the note highlighted.
From my request to the first commit was about 15 minutes, by the timestamps. I wrote my first real notes about 40 minutes later.
I am not showing a screenshot. Every photo, name and address in this tab belongs to real people in my church. That is also the reason for most of the decisions below.
The Story: The Rule That Mattered Most Was “Copy What Is Printed”
This is the request I typed. I recorded it in my coding history, so I can show it as it was (translated from Korean):
💬 Prompt that worked “The folder C:\Users\SSG\Documents\2026_10_20 is our church’s member directory. Add a tab to bible and list it by family. If a family has a man (br, short for brother), group the family under the oldest man’s name. If there is no man, use the woman’s name (si, short for sister). Show the family photo and the family members with the names and the br or si mark as printed on the photo. If there is no br or si mark, show just the name. The br and si marks are important, so they must match the photo. Show each member’s birth year in a separate column. Also save and show the address under the photo. And let me write notes for each family and for each person.”
One minute later I sent one more line: “And let me search by name.”
Looking back, the most useful sentence was “the br and si marks are important, so they must match the photo.” Some people in the booklet have no mark. Children often have none. A few husbands are written with a note like 夫 (“husband”) instead of br. Without that sentence, an AI might “fix” the data and guess a mark from the name. Names do not tell you that. So the rule became: copy the mark that is printed, and never guess one.
What surprised me was the next step. My prompt said “a man (br)” and “a woman (si)”. It did not explain what the marks mean in my church, and it did not say what to do with a husband who has no mark. Claude read “man” as “a person with a br mark”, not “a male person”. So in families where the husband has no br and the wife has si, it did not make the husband the head of the family. It listed the family under the wife’s name. That is exactly how we call those families at church, and I never told it.
It also built the notes the way I wanted from that same single prompt: one note for the family, and one note for each person in it. I did not have to describe the screens.
It was not perfect, and I want to show where. In two families the mother has si and a grown-up son has br. In one of them the father is in the photo without a mark; in the other he is not in the photo. The rule “oldest br first” put those families under the son’s name. At church we call them by the mother’s name. My prompt did not cover this case, so this is my rule’s gap more than Claude’s mistake. The next morning I asked for those two families to be renamed, and for one family that moved to another church to be removed. That took one short prompt, and it only changed the data file.
I put this into the Bible app instead of making a new app for two reasons. The app already has accounts that save data on the NAS, and it already has a password screen. A directory of real people should not be one more open website.
The How: From Scanned Pages to a Searchable Tab
This is the part to copy if you want to do the same for your own church, club or class. Everything ran on my ThinkPad (Windows 11) and my Synology DS224+ NAS. Claude Code did the coding. I scanned the pages and checked the result.
1. Scan the pages
I scanned the 8 pages of the booklet at 300 dpi. Each page became a JPG of 2480 × 3508 pixels (A4 size). Up to 21 family photos fit on each page, in columns, with the address line under each photo.
2. Straighten each page
A page on a scanner is never perfectly straight, and a tilt of one degree is enough to cut the edge of a photo. The script tried every angle from -2 to +2 degrees, in steps of 0.1, on a small copy of the page. For each angle it measured how sharp the edges of the dark areas were, going across and going down. The angle with the sharpest edges is the straight one.
for a in np.arange(-2, 2.01, 0.1):
r = rotate(small, a)
dark = (r < 225).astype(np.float32)
score = (np.abs(np.diff(dark.mean(axis=0))).sum()
+ np.abs(np.diff(dark.mean(axis=1))).sum())
if best is None or score > best[0]:
best = (score, a)
This uses only OpenCV and NumPy in Python. No AI service.
3. Find the photos, then fill the gaps with a grid
The first idea was simple: a photo is a large dark rectangle on a white page, so find the runs of dark pixels down each column and across each row.
That found most photos, but not all. Some photos have a bright background (a white wall, a sunny day), and their edges disappear into the white page. The fix was to use the photos that were found well to learn the layout. In each column, all photos have the same width, and the distance from one photo to the next (the “pitch”) is the same. The script took the median of those distances and placed a box at every pitch step, from the top of the page to the bottom. Where a detected photo was close to a grid box, it used the detected one, because it is more exact.
After this step every photo had a box. I did not count them by hand. Claude drew the boxes in red on a copy of each page and looked at those images to check.
4. Cut out the photos and make “contact sheets” to read
For each box, the script saved two images: the photo itself, and the photo plus the strip under it, where the address is printed. Then it put 8 of the second kind on one sheet, 2 across and 4 down, with an ID like p3_07 (page 3, photo 7) above each one.
5. Read the names: Claude looked, instead of OCR
I have used Tesseract OCR for Korean books before. It is fine for searching a book, but it often breaks Korean names, and it would not keep small marks like “br” and “si” reliably. Here every single name and mark had to be right.
So Claude opened each contact sheet as an image and typed what it saw, one line per family:
p3_07 | <city> <district> <street> | <name> br 61, <name> si 66
p4_19 | <city> <district> | <name> si 55, <name> - -
p3_09 | <city> <street> | <name> - 87 夫, <name> si 83, <name> - 17
The format is: ID, address, then each person as name, mark (- for no mark), two-digit birth year (- if not printed), and an optional note like 夫 (husband), 母 (mother) or 父 (father). For names that were hard to read, Claude made zoomed-in crops and checked them again.
To be honest about accuracy: I have not compared all 382 names with the booklet line by line yet. If I find a mistake, I fix one line in a JSON file. The server reads the file on every request, so there is no restart. The first fixes (two family names, one family removed) worked exactly like that. The list is now 141 families and 377 people.
6. Build one data file
A short Python script turned those lines into index.json and made the photos:
- Birth year: two digits
00–26become 2000–2026, anything else becomes 19xx. (This works for my church. The oldest member in the booklet was born in the 1930s. It would break for someone born in 1925.) - Family name: the oldest br; if there is none, the oldest si. People with no mark are never treated as a man or a woman. The data stores the head of the family as a position in the member list (
"head": 0), so renaming a family later means changing one number, not moving people around. - Photos: the full crop (JPEG quality 88) and a 360-pixel-wide thumbnail for the list. All together, about 14 MB.
7. Add three small API routes
The Bible app’s server is Node.js with Express, running in Docker on the NAS. The new routes sit behind the same login check as my sermon notes:
| Route | What it does |
|---|---|
GET /api/directory | Sends index.json |
GET /api/directory/photo/:name | Sends one photo. The name must match a strict pattern like p3_07.jpg, so nobody can ask for other files |
GET / PUT /api/directory/memos | Reads or saves my notes |
Notes are saved per user, in one JSON file. The server first writes a temporary file and then renames it, so a half-written file never replaces a good one. Every save is also added as one line to a log file that the app never deletes. If I erase a note by mistake, the old text is still in the log. A week earlier I had asked for the same kind of protection for my sermon notes, because a note that took effort to write can disappear with one tap. The directory notes copy that idea.
8. Keep personal data out of places it should not go
🗂 Claude.md Rule Church directory data (
directory-data/: names, addresses, photos) and the notes (directory-memos/) are personal information. They are in.gitignore, they are not in the code backup zip, and a deploy must never overwrite or delete them. The data lives only on the PC and the NAS.
That rule has a cost, and I want to say it plainly: my daily code backup does not include this data. Right now the directory exists on my PC and on the NAS. The scans are still on my PC, so I could rebuild it. The notes exist only on the NAS. Backing up the NAS itself is the next thing I need to sort out.
Who can see it: only the accounts that save data on the server. The Bible app also has a “phone only” login for guests. With that login, the tab only shows a short message. The live API answers 401 to anyone who is not logged in.
9. Search over notes (the same evening)
In the evening I asked: “Let me search in the notes too.” That was a front-end change only. The search removes spaces from both the query and the text before comparing, so “입원중” finds “입원 중” (Korean is often typed with or without the space). When a family appears because of a note, the card shows which note matched (the family note, or a person’s name) and a short part of the text around the match, highlighted in yellow.
10. Deploy
The deploy was the same as for every change to this app: copy index.html, server.js and the data folder to the NAS share, then restart the API container once over SSH (because server.js changed). The search change needed only a page refresh.
What It Cost
- $0 extra. No AI API was called. The image work was OpenCV on my PC, and reading the names was done inside my existing Claude subscription.
- Hosting: the same NAS and Cloudflare Tunnel that already run the Bible app.
- My time: scanning 8 pages and typing two requests (three, with the search change).
What I Do Not Know Yet
- Whether all 382 names, marks and birth years are correct. I have not checked them all against the booklet.
- How I will update it next year. A new booklet probably means running the same steps again, and then the notes must still match the right families. The IDs like
p3_07come from the page position, so they will change. I have not solved that yet. - How useful it will be after months of use. Today I have written notes for a few families. Ask me again at the end of the year.
What I can say now: the paper booklet only helped me remember faces. This version helps me remember people.