# Monlam registration project instructions

These requirements record the user's decisions through 2026-11-09. Read them
before changing the registration form or its export format. Keep this file
current when the user changes a requirement. New explicit user instructions
take precedence.

## Active scope

`MonlamJsonConverter.bas` is the original historical Access exporter for
nam_0000 / MonId 131. Keep it unchanged. `MonlamJsonConverter_v2.bas` contains
the corrected `exportMonlamIDCardAsForms_v2` and an import-time
`RepairMonlam131Forms(parsedForms)` helper. For the historical 1652 x 2338
data.Form layout, repair empty/missing slots using their own row/column bounds,
preserve occupied slots and timestamps, and count actual Participant records
in dataTotal independently of empty X slots or title-category buckets. Keep
the historical output format/settings. Do not use these fixed coordinates on
current web exports. `node --test pocketbase-local/test/monlam-json-converter.test.cjs`
checks the real repair procedures under Windows Script Host via a mechanical
VBA syntax adapter; this does not compile or execute the Access/DAO exporter.
The v2 Access query now includes Sex. Export Id.sex (lowercase key) and
Participant.Sex (uppercase key) as M/F, accepting case-insensitive M/F or
male/female input. A new export requires a known sex for every participant.
Use stable Titel IDs (10=P Lhopon, 11=G) rather than display positions. Count
L/D/N/P in dataM when Sex=M and dataF when Sex=F; do not force D to M in this
Access export. The web form's separate Monk/Nun input locks remain unchanged.
For older JSON, normalize and synchronize available Participant.Sex/Id.sex;
reject conflicting values. When both historical sex fields are missing/blank,
infer M for L/D/N and F for A. Explicit sex always takes precedence. Other titles,
including P, have no inferred default; unknown sex remains blank and does not
enter L/D/N/P M/F counts, but its participant record still counts in dataTotal.
Empty slots have Id.sex="" and no Participant record. Keep other title buckets.
The Access report prints the query consecutively, ten participants per page,
sorted by database SNo even when those values have gaps. Derive exported PNo,
page-local slots and Participant.SNo from the consecutive export counter, not
database SNo. Finalize pages after ten records or EOF. Validate contiguous page
identities/slots/serials/totals and pass Forms.Count to the PDF attachment routine
for comparison against the PDF page tree before attachment/replacement/copying.
Keep JSON-only PDF attachments; the importer renders each physical PDF page at
data.Form.w/h (1652 x 2338 for this report) and derives any Id/Photo crops from
that rendered page. Missing embedded JPGs are expected in this workflow.
Access OutputTo error 2501 occurs before attachment. Export the report through
ExportMonlamReportPdf: check folder writability, open a hidden Print Preview
only if the report is not already loaded, and output to a unique temporary PDF
with AutoStart=False. Replace only the matching previous PDF after successful
output; remove the old wildcard PDF/JSON deletion. Preserve existing user-open
reports and close only previews opened by the helper. A failure must identify
its stage, report name and destination rather than silently suppressing 2501.
The report/Access cancellation cause still requires a real-database retry or
manual PDF export check; do not claim it was reproduced in WSH tests.
The v2 exporter writes BOM-free UTF-8 JSON and embeds that same named JSON in
the exported PDF before copying either file to CloudStation. Keep the separate
JSON file. Import both MonlamJsonConverter_v2.bas and MonlamPdfAttachment.bas.
The attachment module uses pure VBA and standard Windows ADO streams, with no
PDFtk/pdfattach/Acrobat dependency. It appends an incremental update, preserves
the original PDF bytes/catalog metadata and unrelated Names entries, then uses
temporary/backup files to replace the PDF. It supports traditional xref tables,
/Prev chains and the historical sample's trailing legacy XRefStm marker, and
rejects encrypted/certified PDFs, new xref streams and existing EmbeddedFiles
before replacement. It is scoped to fresh Access report output, not arbitrary
PDF editing. `monlam-native-pdf-attachment.test.cjs` runs the actual native VBA
parser/writer and UTF-8 helper via a WSH syntax adapter, testing exact attachment
bytes, Unicode filenames, original byte/catalog/page preservation, the 115-page
historical PDF, and unsupported-input rejection. Access's VBA rollback handler
and DAO/report export still need verification in the real database. Tests also
cover 1597 records with sparse source SNo producing 160 contiguous JSON pages,
and rejecting a 160-page PDF paired with a claimed 191 JSON pages unchanged.

The new workflow under development is `RegForm/monlam-form-2026-v06.html`,
copied from the existing `monlam-form-2026-v05.html` (there was no v5 file).
V06 omits account/config/API-prefill scripts and opens as a standalone form
without login. It shares guided assets and the base standalone backup format,
but uses its own `monlam-v06-guided-v1` participant draft storage. Its new landing
section follows `RegForm/.note-landing-page.txt`, section 1: New/MonId, monastery
names in English/Tibetan, mailing address, photos/letters, contact name/position,
email, phone/mobile, WhatsApp and other contact methods. Prefer the Tibetan
name on the participant form, otherwise English; New leaves its ID blank.
The landing keeps fields locally and uploads in its own IndexedDB store, with
continuous editing. Continue validates required information and reveals the
participant section below the still-visible monastery section. Keep Continue,
remove the Edit monastery information button, and use the landing's green/cream
theme for the screen controls and form surroundings. Keep print/PDF styling.
Align the monastery/contact/authorization cards, participant heading, toolbars,
participant pages and covering letter to one width (the existing paper width
on desktop, consistent responsive gutters on smaller screens). Number sections
1. Monastery Information, 2. Contact, 3. Authorization,
4. Participation Information, 5. Covering Letter.
Keep the participant count and status/help text above participant pages. Move
the Finish/download/backup/load/clear buttons, with their existing wording,
into a separate matching panel after the covering letter. Keep Add page next
to the participant pages and exclude all action panels from print/PDF output.
Edits to the monastery/contact fields also update the revealed form headers
and covering letter without replacing participants. Continuing prefills monastery/address/representative
and authorization date without replacing participants. Kab/session is filled
from the current online assembly number when continuing. V06 backups additionally
include `v06MonasteryInformation` with all landing fields and attachment data;
Load Backup restores them and Clear all data also clears them. The backend
JSON/PDF attachment contract remains one backend JSON plus form-page JPEGs;
V06 additionally embeds `registration.json`, a complete editable snapshot of
all headers, participant slots/photos, landing fields, authorization date/seal,
and ordinary uploaded documents. The named backend JSON and page JPEG contract
stays unchanged. V06 uses Download Pdf and Open registration PDF instead of
Download Registration/Download Backup/Load Backup buttons; keep older JSON
backups importable. The PDF opener must be available before completing the
landing form. Restore all fields/uploads and preserve older backend-only PDFs
for viewing, explaining that they cannot fully restore missing editable data.
The viewer's Monastery tab shows all V06 metadata plus seal/document previews
and downloads, including information absent from the printed form. Saved PDF
means not submitted; do not imply account/email verification in this workflow.
V06 uploads/contact metadata are not yet part of a server submission or the
main backend export. V06 shows English and Tibetan monastery names on separate
full-width rows; both are required. New/MonId is required and accepts New
(normalized case-insensitively) or digits, preserving leading zeros. Blank or
mixed/nonnumeric IDs are invalid. Contact position, phone/mobile and WhatsApp
are each independently required; whitespace-only required values are invalid.

V06 Authorization follows Contact, with required editable Gregorian year/month/day
prefilled from the device's local date on a fresh form. Retain saved/edited dates.
It has a separate optional signed/dated monastery seal image upload (JPG/PNG/WebP,
up to 10 MB), preview/download/removal and an explicitly labeled sample layout
using a fictitious SAMPLE seal/signature. The signature and date must be on/across
the seal itself, and the sample must show both over the seal rather than beside
it. Save the seal separately from ordinary
photo/letter attachments in IndexedDB. Include the seal as `authorizationSeal`
and date fields in V06 editable backups, restore them, and keep older V06 backups
without these new fields loadable. Continuing copies the authorization date to
the participant form and covering letter. Show the uploaded seal at the bottom
right of the covering letter, including the rendered PDF; preserve its aspect
ratio. Removing, restoring or replacing the seal must update the letter too.
PDF capture must remove empty image placeholders from its clone before decoding
or rasterizing. In particular, a missing optional seal must not cause iPad/WebKit's
"Missing source URL" failure; valid seal and portrait images must still render.
Wait for successful image loading and real pixel dimensions rather than requiring
decode() success. Inline blob-backed seals as data URLs for PDF capture. The local
html-to-image vendor loader has a reproducible patch in vendor/patch-html-to-image.cjs
to tolerate Safari decode rejection after successful loading, while retaining
real image-load failures. Its decode-rejection fallback allows a short paint
delay for embedded SVG fonts/images before rasterization. Test this fallback with SVG decode rejection and verify
rendered seal pixels, plus exports with and without a seal. Do not claim actual
iPad/WebKit testing when the browser check runs Edge.
Clear all data clears the seal and
resets the date to today. Backend PDF attachment conventions are unchanged.
Keep the V06 covering letter compact and include contact name, position, email,
phone/mobile, WhatsApp and optional other contact information from the landing
form. Update those details when edited/restored and include them in PDF rendering.

The New/MonId field selects its existing text on first focus/click. Later clicks
within the already-focused field must position the caret normally; preserve
typing, keyboard selection and mouse drag selection without repeatedly selecting all.
For V06 work, open/test V06 directly with
`node --test pocketbase-local/test/v06-browser.test.cjs`; do not run the login
workflow unless specifically needed/requested. Older phone/browser compatibility
is a development objective, not yet verified. Preserve the existing v05/account
workflow and links unless the user explicitly requests changing them.

V06 displays the current Prayer Assembly below the welcome heading, calculated
as the online Tibetan year minus 2115 (2153 gives 38th). Fetch the published
year from Pathgate's Buddhist Practice Dates through the public no-login
`/api/monlam/public/assembly-year` PocketBase endpoint. Cache successful lookups
for six hours; use an explicitly last-confirmed value during outages or show
an unavailable message without blocking the form. Do not hardcode the current
year or derive it from the Gregorian year as a substitute for the online source.
Use this assembly number to prefill Kab/session on continuing or resuming V06.
If the lookup finishes later, fill a blank/previously autofilled Kab without
overwriting a manual edit. Authorization date remains independently editable.

Work on `RegForm/monlam-form-2026-native03_c.html` and its linked
`monlam-guided.js`, `monlam-guided-model.js`, `monlam-guided-pdf.js`,
`monlam-guided.css`, and relevant tests. Leave native04 alone unless requested.
`RegForm/nam_0000_0131_.json` and its PDF are historical backend examples;
do not overwrite them. `title.json` is an older lookup, not the current 2026
title mapping. The guided model contains the implemented 2026 mapping.

`RegForm/native04_c.html` is a user-requested comparison copy of native04 with
signup/login and simulated email verification removed. It starts at monastery
information and saves fields/photos in its own native04c browser draft storage.
Keep original native04 unchanged. This comparison retains native04's participant
requirements, scanned-form workflow and older PDF format; it is not connected
to PocketBase account authorization or participant submission. The account
portal now opens `monlam-form-2026-v05.html`, a user-requested copy of native03_c.
It shares guided JS/CSS and the backup format. V05 loads approved application
details through `monlam-form-account.js` and prefills blank monastery name,
MonId, address/country and representative-name fields. New leaves the MonId
blank; do not fabricate an ID, session number, or date. Preserve participant
entries and existing nonblank fields. Account form drafts are scoped to the
backend/account. Reuse a legacy standalone draft only when its monastery name
and ID match; never bring another monastery's participants into the account.
Native03_c retains standalone draft behavior and legacy backups remain loadable.

## Account application backend and portal

The local PocketBase development instance is in `pocketbase-local`, listens
on `0.0.0.0:8090` for the user-requested LAN viewer at
`http://192.168.177.124:8090/monlam-pdf-viewer.html`, while localhost continues
working. It uses `pocketbase-local/pb_data` (not `bin/pb_data`). Scope the Windows
firewall allowance to the private Ethernet LAN, TCP 8090 and this executable.
Use the start/stop scripts and explicit data directory for administrative CLI
commands. Keep data, backups, logs, credentials, and executables out of Git.

The account portal is `RegForm/monlam-account.html`; staff review is
`RegForm/monlam-staff.html`, with shared `monlam-api.js`, `monlam-config.js`,
and `monlam-account.css`. These are separate from the participant form.
Native04 remains unchanged. Approval links to v05; it does not imply
online participant submission or protection of the static participant form.

WhatsApp verification is manual: applicants send the server-generated code
from their declared number to Monlam at **+91 6362309873**. Staff verify the
received sender and code, then separately authorize monastery access. Never
mark WhatsApp confirmed merely because a link was opened. Gmail is the chosen
SMTP provider; credentials must be entered privately in PocketBase settings.
Do not embed superuser credentials in the portal or create public staff signup.

Show only the email-verification step before email is verified. Keep the
application section hidden and its fields disabled until verification completes.
Preserve pre-existing saved/unfinished application details and restore them when
the section becomes visible. Do not offer WhatsApp or form-access steps before
email verification. Account deletion/sign-out remain available.

Staff can unapprove an approved application with a required reason. Return it
to pending review, deactivate its membership, and audit the actor/time/reason
transactionally. Keep application data, contact verification and participant
drafts. Reapproval reactivates the same membership without duplicates. The
applicant's form link disappears on refresh and v05 rechecks approval on load.

The applicant portal provides Delete account, requiring the current password
and typed DELETE confirmation. The backend deletes only the authenticated
applicant and their applications, memberships and application audit records in
one transaction. Never accept a caller-supplied account ID as the target.
Clear that account's cached portal/form draft and login on the current browser;
preserve unrelated accounts, standalone drafts, staff and monastery directory
records. Downloaded files, other-device copies and backups are unaffected.

Applicants provide monastery information directly. Do not show a monastery
directory/search or allow applicants to choose an official monastery record.
The directory API is staff-only. Staff approval must not require a directory
lookup, selection, match, or creation. Show the applied MonId/New and full
monastery name as read-only information in the authorization section. Approve
the account for those application details, with email/WhatsApp prerequisites
and authority confirmation retained. Membership stores the application MonId
and full name; an official monastery relation is optional. Never fabricate a
permanent ID or automatically create/merge directory records during approval.
Applicants may enter an optional `MonId` as text; missing/whitespace-only values
become `New`. Preserve leading zeros. This is an unverified applicant reference,
not an official monastery relation. Staff lists/details and the authorization
section show this MonId (or New) alongside the applied monastery's full name.
Preserve unfinished application fields across refresh and browser restart,
including incomplete entries. Keep cached drafts scoped to the backend and
applicant account; never save passwords. Applicant sessions persist on the
device until sign-out/expiry; staff sessions remain limited to the browser
session. Retain name/email for convenient sign-in.

Use additive migrations and scoped hooks; preserve unrelated collections,
settings and existing registration exports. Backend and browser tests use
isolated temporary instances, not the development database. See
`pocketbase-local/PORTAL.txt` for setup and test commands.

## Titles

Use `Sort` only for display order. Use the stable `TitelID` for storage;
never substitute the display index. Preserve the backend spelling `Titel`.

| Sort | Letter | TitelID | Meaning |
| --- | --- | --- | --- |
| 0 | X | 0 | Empty |
| 1 | V | 1 | H.H. / Kyabje |
| 2 | T | 2 | Tulku |
| 3 | K | 3 | Khenpo |
| 4 | P | 10 | Lhopon |
| 5 | L | 4 | Lama |
| 6 | D | 5 | Monk |
| 7 | A | 6 | Ani / Nun |
| 8 | N | 7 | Ngagpa |
| 9 | G | 11 | Genyen |
| 10 | S | 8 | Special |
| 11 | O | 9 | Others |

P and G were appended to storage IDs as 10 and 11, while their display positions
are 4 and 9. Dropdowns and printed forms show Tibetan labels, not storage IDs.
Restore older drafts containing Tibetan title text by migrating it to IDs.
An empty title is not a completed participant or, by itself, a started entry.

When a title field has focus, its letter selects that title, case-insensitively.
V/v selects Kyabje; X/x selects empty. Preserve browser modifier shortcuts and
IME composition. Shortcut selection must trigger normal sex, count, and save
updates, including on added or restored pages.

Selecting a nonempty title defaults sex to Male except Ani/Nun, which defaults
to Female. Monk is locked to Male; Ani/Nun is locked to Female. Other titles
allow a manual sex change. Empty does not set a default sex.
When the title or sex control has focus, F/f sets Female and M/m sets Male.
D (Monk) remains locked to Male and A (Ani/Nun) remains locked to Female.
Preserve modifier shortcuts, IME composition and ordinary typing in text fields;
sex shortcut changes must update validation, counts and saved drafts normally.

## Source numbers and filenames

Source names include Email, Mysore, nam, Whatsup, and Online. Preserve spelling
and capitalization. The online form always exports `SourceNo: "Online_0000"`.
0000 means the form has NOT been added to the main Registration. Only the main
Registration will assign the valid yearly source page serial, appended across
registrations. Do not allocate a browser-local serial or increment SourceNo
for each page of the current unregistered download.

For monastery ID 131, pad its filename component to 0131:

- PDF: `Online_0000_0131_.pdf`, containing one or multiple form pages.
- Backend JSON: `Online_0000_0131_.json`.
- Page 1 FormNo: `0131_0001`.
- Page 1 SourceNoFormNo: `Online_0000_0131_0001`.
- Page 1 JPEG: `Online_0000_0131_0001.jpg`.
- Page 1 participant 1 identity: `Online_0000_0131_0001_0001`.
- Page 2 participant 1 identity: `Online_0000_0131_0002_0001`.

Participant identity suffixes are page-local slots, padded to four digits.
Participant SNo is the overall serial (page 2 begins at 11).
Monastery ID remains optional in the form; the current unassigned filename
fallback is `NewMonastery`, not a fabricated valid monastery ID.

## Backend JSON and image metadata

Use underscore page keys matching FormNo, such as `"0131_0001"` and
`"0045_0001"`. The user explicitly replaced the earlier plus-sign notation;
do not use `+` in page keys. Keep lowercase `data.form`. The historical sample
uses uppercase `data.Form`; that separate spelling has not been reconfirmed.

The downloaded backend JSON is keyed by page, not by the old registration
wrapper. Each page contains SourceNo, FormNo, SourceNoFormNo, MonId, PNo, and:

```text
"0131_0001"
  data
    form                 page JPEG dimensions and filename
    Ids
      "1" through "10"
        Participant      entered participant metadata
        Id               card bounds and reference to the PAGE JPEG
        Photo            photo bounds and reference to the SAME PAGE JPEG
```

Use readable UTF-8 Tibetan text in JSON, not literal backslash-u Unicode
sequences or double-encoded JSON. JSON syntax escaping is still necessary for
quotes, backslashes, and control characters. Preserve entered Name, Age,
Fname and RemarkNo as text, including leading zeros in remarks. Export backend
`Participant.Sex` and lowercase `Id.sex` as `M` or `F`; empty/unselected Id
slots use an empty string. Keep male/female internally in the editable form
and draft backups. Titel
is the numeric stable title ID, while Id.title is the title letter.

Measure x/y/w/h in top-left pixel coordinates of the actual rendered page
JPEG. Do not copy the historical scan coordinates or use PDF point coordinates
in these metadata fields. Both Id.name and Photo.name refer to the page JPEG,
not a separate participant crop. Retain participant identity in Id.SourceNoFormNo.
Empty slots have Id metadata with title X, and no Participant/Photo record;
participants without photos omit Photo. Keep Ids.dummy to prevent Firebase
from converting the object to an array. The covering letter is not a backend
participant-form page.

Native03_c PDF downloads embed exactly one named backend JSON and matching
participant-form page JPEGs. For MonId 44 these are `Online_0000_0044_.json`,
`Online_0000_0044_0001.jpg`, `Online_0000_0044_0002.jpg`, etc. Do not embed
individual Id/Photo crops, portraits, or `registration.json` in these native03_c
PDFs. V06 is the explicit exception described above: it adds registration.json
for complete editable PDF save/reopen, including uploads/contact metadata.
Id and Photo metadata continue to reference full-page JPEGs with top-left
pixel crop coordinates. Standalone backend JSON references these same JPEGs.
The PDF covering letter remains a visible page, not a form image attachment.
The viewer reads the page-keyed backend JSON and derives portrait previews
from the page JPEG coordinates; keep support for older registration.json PDFs.
Download Backup saves `_backup.json`, including all editable fields and photos;
Load Backup restores that format. Keep legacy draft imports working.

## Input and download behavior

Participant tab order: Name, Age, Father's name, Title, Sex, Remark. Remark is
last even though it is positioned near the top of the printed card.

The native03_c photo dialog hides Use photo until a source image has decoded
successfully. Keep successfully chosen source images in a filename selector
while the page remains open, shared across participant photo dialogs, so one
scan can provide several portraits without repeated uploads. Reopen with the
last selected image ready to crop. Clear all data also clears this source list.
Source originals are held only for the open page; saved cropped participant
photos retain their existing draft/backup behavior.

Year, month, and day must all be entered before ANY PDF, backend JSON, or backup
download. Block missing/whitespace-only components, show an explanatory message,
and focus the first missing date field. This requirement currently checks
presence, not calendar validity. Browser autosaving is independent of downloads.

## Verification and known limits

Run relevant existing checks, typically:

```powershell
node --test RegForm/monlam-guided.test.cjs RegForm/monlam-pdf.test.cjs RegForm/monlam-pdf-reader.test.cjs
```

Guided PDF capture tests use a simulated DOM/canvas; do not describe them as
real browser rendering verification. Real Edge checks now also download a
native03_c PDF and verify exactly one backend JSON plus participant-page JPEGs,
participant parsing, and coordinate-derived portrait previews in the viewer.
These do not establish a full manual printed-layout review. Account portal
checks use isolated PocketBase and local SMTP capture, not actual Gmail delivery.
The historical example has 115 pages, whereas
the current guided form/import limit is still 100. The complete historical
backend counter/timestamp contract has not been implemented; current backend
records include dataTotal. Do not claim exact compatibility with every field
of the historical sample without checking these differences.
