Delivery plan · against System Design v1.0

One door opens on a date
nobody controls.

CamDX membership is the whole moat — a translated login page is not defensible, and anyone can copy it. So the plan has one organising goal: be holding a finished, tested adapter on the day the credentials arrive. Everything else is what you ship while the door is opening.

Months are relative to start, not calendar dates. The bar that runs off the edge is not a schedule — it is a queue nobody on the team controls. Select a phase to open it.

01 — What is possible

Most of the government integration is already public.

This is the finding that reshapes the schedule. The CamDigiKey protocol, a working Node client library, the Security Server install guides and Ansible playbooks are all published. Only the credentials are gated — which means the integration can be built and tested now, and membership arrives to finished work rather than starting it.

Buildable today

The protocol and the code

  • A CamDigiKey client library in Node — the language the stack is already in
  • The full call surface: login token, access-token exchange, JWT validation, refresh, logout, organisation token, profile lookup, face image
  • Security Server install guides, an HA variant behind a load balancer, and Ansible playbooks
  • A KYC Verification API spec referencing both development and production base URLs
  • Everything at L0–L2: linking, consent, organisations, attestation, provenance, recovery, sandbox

Only CamDX can issue

The credentials and the identity

  • Member Name, Member Class and Member Code, assigned by the Central Authority
  • CLIENT_ID, HMAC_KEY, AES_SECRET_KEY, AES_IV_PARAMS, registered client domain
  • Client and trust .p12 keystores for mutual TLS
  • Signed AuthKey and SignKey certificates, issued against CSRs you submit
  • Approval of the Security Server registration itself

Security Server — the real numbers

Host
Ubuntu 24.04 LTS · 2 cores · 4 GB · 100 GB · 100 Mbps. Modest hardware, and two of them for the HA topology Section 8.4 wants — a second and third machine the current deployment plan does not account for.
Outbound
Central Server 443, 4001 · Management 5500, 5577 · OCSP and timestamping 443 · partner servers 5500, 5577. Confirm your VPS provider's egress rules before choosing a host.
Inbound
Admin UI on 4000, never internet-facing. Bastion or VPN only — this host holds your member signing key.
Keys
AuthKey and SignKey CSRs go to the Central Authority. Losing them is the weeks-long bureaucratic recovery R7 describes. Escrow from day one.
Provisioning
Use the published Ansible playbooks. A hand-built Security Server cannot be rebuilt under pressure.

02 — The plan

Aim at one sentence, not a platform.

Twenty-nine features is a programme, and a small team that starts everywhere finishes nothing. So the first months aim at a single claim you can put in front of a funder, a ministry, or the next integrator:

“Farms Nexus deleted its farmer-status field. It reads a revocable cooperative membership from AttaID instead.”

It is the document's own Section 6.7 example. It is the second migration dimension R10 predicts most integrations never reach. It needs no CamDX, so nothing about it waits in a queue. And it is something the app genuinely cannot do alone — Farms Nexus can verify a phone number itself, but it cannot know a cooperative revoked someone last Tuesday.

Deliberately deferred

F10 bulk pre-link
The most dangerous endpoint in the system (AR-01), and per AR-14 it solves a problem the launch does not have: both initial apps are ours, so their migration is an authenticated server-to-server job under dual control, not a public matching API. Reconsider when an app we do not own commits to migrating.
DG SuperApp
Aspirational and partnership-dependent by the document's own assessment. Membership is the credential that makes the conversation possible at all.
IPIS
Design the seam, do not depend on it. Reconsider when it is authoritative in practice, not only in the 2023 law.
A native mobile app
The PWA has not been shown insufficient, and Stage 3 exists precisely to find out.

03 — The stack

Section 7 is largely right. Three changes.

Next.js and NestJS in one language, PostgreSQL, Redis and BullMQ, Docker Compose, Traefik, Prisma, pgBackRest, Ansible — a sound small-team choice, correctly sized. The rejections of Kubernetes, microservices, blockchain, own crypto and SMS OTP are all correct and worth defending when someone proposes them again.

Change

Keycloak becomes a token service

It was kept partly for brokering it cannot do (AR-13), and partly for a user store you are already building. Narrow it to credentials, sessions and Google brokering. Consent and linking screens live in Next.js where F26 and F29 need them.

Add

An RFC 9497 OPRF library

Makes Pattern C's bulk match a real control instead of a documented oracle. Do not hand-roll the protocol — the failure mode is silent.

Add

jose and your own Security Event Tokens

No Node library for Shared Signals is worth adopting. A SET is a signed JWT with an events claim — small to emit. The hard half is the receiver in each connected app.

Add

Ed25519 signing with overlapping JWKS

64-byte signatures are what make the offline QR payload fit in a scannable code. Overlapping key validity is what makes rotation not an outage.

Add

A SCIM subset, not a SCIM server

In practice “SCIM 2.0” means Users, PATCH, and filtering on externalId. A conformant server is weeks spent on a spec nobody exercises completely.

Constrain

PostgreSQL, shaped for Khmer

Separate name_km and name_latin — never auto-transliterate. pg_trgm and unaccent on the Latin form only. Not tsvector for Khmer: the parser does not segment it, so a whole name becomes one token and search silently returns nothing.

04 — What is not possible to answer yet

Four questions nobody has decided.

These are not engineering problems and they will not be solved by building. Each one can invalidate a part of the plan above, and the first can invalidate all of it.

  1. Can AttaID become a CamDX member at all?

    The risk register frames membership as waiting — “start the application now; it is bureaucratic.” But nothing confirms a private company is eligible. Members are predominantly ministries and banks. A queue you wait out; an eligibility bar you clear through a sponsor, or restructure around. Completely different responses, and this is the one that can invalidate everything else on this page.

    Encouraging signal Security Server registration requires a Member Class assigned by the Central Authority, and X-Road convention has several including non-government. Operating Farms Nexus and CashEW also makes a more substantial application than a standalone identity startup would. Ask directly: which classes exist, and which would we fall into?

  2. Will anyone outside the company integrate?

    Farms Nexus and CashEW are ours, so the first integration proves the mechanism works but not that the market wants it. The long-tail thesis — that commune apps, cooperatives and NGO platforms will adopt a shared identity layer rather than roll their own login — remains an assertion until someone who does not report to us accepts the dependency.

    Decide now, not in month five Name one target external integrator and treat landing them as PH2's real definition of done. If we cannot name one today, that is itself the most useful finding in this document.

  3. What do we owe an app that depends on us?

    The plan asks apps to delete their own identity data — that is the whole value. It also means AttaID going down takes their logins with it. Internally that is concentration risk on our own revenue platforms. Externally it is the first question any serious integrator's lawyer will ask, and we have no answer written down: no data export, no wind-down path, no continuity commitment.

    Cheap to write before the first external integration, expensive to negotiate afterwards. Depending on us is a favour they are doing us.

  4. Is assisted registration real consent?

    Stage 3 has a cooperative verifier registering farmers. If the verifier holds the phone and taps through the consent screen, that is not consent — and it is the exact setting where consent theatre happens.

    Needs a designed answer: what the farmer is shown, in Khmer, read aloud where needed, and a record of how consent was taken rather than only that it was. A legal-basis question as much as a design one.

05 — Start here

This week.

  1. Ask CamDX which member class we would fall into. It is a five-minute question, and the answer decides whether this is a queue or a wall.
  2. Start the membership application. Note the process itself requires a CamDigiKey account, so someone has to create one first. Longest lead time in the plan; week 1 is the cheapest week to begin.
  3. Build a Security Server on a throwaway VM from the published guides and playbooks. You learn the real constraints in a day for almost nothing.
  4. Read the CamDigiKey client library end to end and write the ADR that moves the integration into NestJS. Longest architectural tail of anything here.
  5. Name one target external integrator — a commune app, a fisheries portal, a cooperative. Farms Nexus proves the mechanism; an app we do not own is the only thing that proves the market. If we cannot name one, say so out loud.
  6. Book the legal conversation, and run the PH0 decision session: half a day, nine decisions, nine ADRs.