Skip to content
Nicolás Amorosi

Italian Adventist Church Union

HR & admin platform

The Union’s staff and ministers report their work every month, request time off and expenses, and wait for the right people to approve them. I led the team that built the platform for it: first a first-generation app, then the rewrite that replaced it.

The problem

Two kinds of staff with different rules — employees under the national labour contract and ministers — each filing a monthly report, plus absences, medical expenses, travel invitations and treasury exports.

Every request has to climb a hierarchy before it counts, and at the end of the month treasury and the secretariat need exports they can use without retyping anything.

Constraints

  • Italian by default, with Spanish and English for an international staff.
  • Sign-in with the organization’s Microsoft accounts; email through Microsoft Graph.
  • A team of three developers, with two more rotating in.
  • Replace the first-generation app, which I had also started.

What I built

The first generation, Rapportopastori: a NestJS and Next.js monorepo with Microsoft single sign-on, PDF reports rendered with Puppeteer and deploys to AWS EC2 through GitHub Actions. I set up the monorepo and the single sign-on.

Then PDOA, its replacement, on the same architecture as Libretto: Next.js route handlers in front of a NestJS 11 API on Prisma and MySQL, stateless JWT sessions in HttpOnly cookies, Microsoft Entra ID sign-in, files on S3 and email through Graph. I wrote the initial stack, authentication and single sign-on, and led the team through the rest.

The hard parts

  1. Request submitted

    Level 3

  2. Approver, level 2

    Snapshot stored

  3. Approver, level 1

    Snapshot stored

  4. Final approval

    Whoever holds the final-approval permission

  5. Timesheet filled

    Approved absences become entries in the monthly report

Built at submission time by walking up the hierarchy. Each step keeps a snapshot of its approver, so a reorganization never rewrites past approvals.

Approval chains from the hierarchy

Every role has a hierarchy level. When someone submits a request, the chain is built by walking up through their managers — a level-3 requester needs approvers at levels 2 and 1 — with protection against cycles, and a final step for whoever holds the final-approval permission. Each step stores a snapshot of its approver and level, so a later reorganization doesn’t rewrite history.

Absences that fill the timesheet

When an absence is approved, the matching vacation, sick-leave or permit entries appear in that person’s monthly report, linked back to the request that created them. Nobody types the same day twice.

Reports that close themselves

Ministers’ monthly reports close automatically a set number of business days after the end of the month — skipping holidays — with configurable reminders before the deadline.

Auditing every page

We audited all 23 pages one by one with a custom Claude Code skill driving Playwright, signing in with locally minted sessions so the single sign-on flow didn’t have to be automated.

Result

  • In production for the Union; the first generation has been retired.
  • About 520 automated tests, 29 data models and 29 API modules.
  • Every page audited for behaviour and permissions.

The code belongs to the client and stays private. Figures are illustrations with sample data; no real records appear on this page.