Homepage
Handover: KumoHQ → FLIN
This is the dated transfer snapshot for FLIN's in-house engineering and product team. It covers who owns which account, what to transfer and in what order, what is due soon, what is still open with FLIN, and every known issue with a recommended fix. Everything else lives in the permanent docs (see the reading order), which your team should keep up to date. This file is a snapshot and is not meant to be maintained.
Last verified: 2026-10-12 against main @ a270f1d (live infra/EAS/Trigger.dev checks on the same date).
Markers used: TODO(handover) is a fact or decision only KumoHQ or FLIN can
supply. ⚠️ marks something taken from earlier team notes that could not be
re-verified in code or live.
Contents
- Reading order
- State of the system on 2026-10-12
- After the handover: who does what
- Act now
- Accounts and access
- Transfer checklist
- Deadlines
- Open threads with FLIN
- Known issues and recommended fixes
- Questions only KumoHQ or FLIN can answer
- Material that is not in git
Reading order
| Who | Read |
|---|---|
| Everyone | ../README.md → product.md → architecture.md → this file |
| Product | product.md (status board, features, journeys, pending inputs), ../CONTEXT.md (glossary), data-model.md#gotchas-for-analysts-metabase |
| Engineers, day one | development.md, engineering-rules.md, code-map.md |
| Engineers, before touching prod | deployment.md, operations.md, ../infra/terraform/README.md |
| Releasing the app | mobile-release.md |
| Vendors | integrations.md |
| Countries / Philippines | multi-country.md (§8 is the binding PH spec), deployment.md#philippines-go-live-checklist |
| Data | data-model.md |
| Why things are the way they are | adr/ 0001–0010, specs/, research/ |
State of the system on 2026-10-12
| Indonesia (ID) | Philippines (PH) | |
|---|---|---|
| App | 1.1.0 live on App Store (ID storefront only) and Google Play since 2026-10-07. Built from commit 2ac427939 (PR #135): iOS build 31, Android versionCode 4 |
No shipped binary offers PH: EXPO_PUBLIC_SERVER_URL_PH is not set in any EAS environment |
| Server | https://appapi.flin.co.id, AWS 961341531217 (ap-southeast-3), ECS flin-prod-api on task def flin-prod:282, image a270f1dcfdb2 (= main) |
https://appapi.flin.ph, AWS 611858318585 (ap-southeast-1), ECS flin-ph-prod-api on flin-ph-prod:4, same image. Runs APP_ENV=staging because the PH profile refuses prod until the CIBI and Onfido adapters exist |
| Features on | Free credit score (AFPI), paid CLIK report (Rp 25.000), Debt Discipline Program, consultations, mediation, notifications | All four features off. Prices are placeholders (TODO(FLIN-174)) |
| Jobs | Trigger.dev org "Flin", project proj_fqtihpiyjlwzafgdiukm, prod + staging, worker 20261007.1, every prod run in the last 7 days completed |
No Trigger.dev project. Notifications off |
| Deploys | A merge to main deploys both servers (one CodePipeline per account) and, when apps/jobs/**, packages/**, bun.lock or package.json changed, the Trigger.dev jobs (GitHub Action) |
(same pipeline trigger) |
main |
app.json is already at 1.2.0. Only two internal Android preview builds of it exist; no store build |
— |
| Open work | PR #127 ph-languages (English + Filipino, en-PH overlay) is open. Branch onfido-poc holds the Onfido PH KYC POC and is not meant to merge |
Since 2026-10-06, production in Indonesia holds only Test users plus whoever
signed up after the 1.1.0 release. Every other account was purged that day ⚠️
(from team notes); the manual RDS snapshot flin-prod-pre-user-purge-20261006 is the only copy of
the earlier data (see operations.md).
After the handover: who does what
Decided 2026-10-12:
- FLIN owns and operates everything. That means every account, every vendor contract (CIBI and Onfido included), production, releases and on-call, for both countries.
- KumoHQ stays on as FLIN's contractor for the Philippines. It builds the
PH adapters (CIBI, Onfido), app changes and the
PH go-live checklist through
pull requests to
mainthat FLIN reviews. Splitting ownership by country is not possible: there is one codebase and one app binary, and a merge tomaindeploys both servers. Every PH PR runs the Indonesia regression guard in engineering-rules.md. - KumoHQ access is scoped, MFA-protected and ends at PH launch, not at the end of the handover. It covers the PH AWS account, the Trigger.dev "Flin" org (to create the PH project), Expo and the stores (to ship the PH-capable build), and error tracking. In the ID AWS account, read-level access is enough for the regression-guard plan check. The PH launch date is TODO(handover).
- Vendor credentials for PH work (CIBI and Onfido UAT/sandbox) reach KumoHQ through FLIN's password manager, never by email.
Act now
These are live today. They are listed again under known issues.
- A legacy Trigger.dev project is still sending notifications.
proj_wwkvmnfyahwgpebjuuazin the KumoHQ Trigger.dev org (the jobs project before 2026-07-27) still runsnotification-tickevery 30 minutes anddue-date-remindersdaily against a database that is not ID prod. It sent a notification on 2026-10-11. Someone with access to that org should find which database it uses, disable its schedules, then delete the project (operations.md#88-triggerdev-operations). - The Trigger.dev staging environment of the current project sends real Debt
Discipline due-date notifications. Check which server its
SERVER_URLpoints at. - Metabase is reachable from the whole internet. Its role can read every column, including NIK, phone numbers and KTP fields. Put the allowlist back (operations.md#3-metabase-indonesia-only).
- Finfra AFPI credentials expire 2026-11-25 ⚠️ (date recorded in team notes when the pair was set; SSM shows both parameters rotated on 2026-09-07, which is consistent). Get the next key pair from Finfra before then. The previous expiry went unnoticed for three days ⚠️ and blocked onboarding (operations.md#63-rotation-notes-per-secret).
- The live "upgrade" push series quotes the wrong price. It says Rp29.000
and "Today only"; the real price is Rp 25.000 with no discount
(
packages/notifications/src/series.ts,copy.ts). Fixing it needs only a server deploy. - Download the 1.1.0 store binaries from EAS before 2026-11-05, when EAS
deletes the build artifacts. No git tag marks the release commit; tag
2ac427939asapp-v1.1.0. - Security clean-up. The admin, staging-host and shared-account items under Security. Full detail is in the private report delivered separately (not in this repo).
Accounts and access
Verified facts only. Owner after handover and Transfer action are for KumoHQ and FLIN to fill in during review.
| Account / system | Used for | Verified on 2026-10-12 | Owner after handover | Transfer action |
|---|---|---|---|---|
GitHub KumoHQ/flin (private) |
Code. Source for both CodePipelines. GitHub Action deploys Trigger.dev | KumoHQ org, free plan, 2FA required. Org admins ankitsamarthya, vishal21st. Collaborators: deniprobow (maintain), BhuwanTiwari12 (write). No branch protection (not available on the free plan for private repos). One Actions secret, TRIGGER_ACCESS_TOKEN |
KumoHQ: the repo stays in the KumoHQ org (decided 2026-10-12) | Add FLIN's engineers as collaborators (admin for FLIN's lead). Branch protection stays unavailable while the org is on the free plan, so review discipline is manual. Moving the repo later still means the three rewires in checklist step 4 |
AWS 961341531217 (Indonesia, ap-southeast-3, CLI profile flin) |
ID production: ECS, RDS, S3, CloudFront, Metabase, DB tunnel, SES. Also hosts infrastructure that is not in Terraform: the staging API host behind flinapi.kumohq.in, the ID and PH WordPress sites, an SFTP lead-intake host, backup hosts, a company document-drive mirror |
AWS Organizations management account (single member; management email on a flin.co.id address). Root MFA on. IAM Identity Center in ap-south-1 with one user. KumoHQ works through an IAM admin user |
FLIN (decided 2026-10-12). Account admin: TODO(handover) | FLIN admins get access through IAM Identity Center with MFA first. KumoHQ keeps scoped, MFA'd Identity Center access (read-level is enough for the PH regression-guard plan check) until PH launch; replace KumoHQ's IAM admin user with that now; at PH launch remove KumoHQ and rotate every secret it could read |
AWS 611858318585 (Philippines, ap-southeast-1, CLI profile flinph) |
PH production (flin-ph-*) |
Not in the ID organization. Shared with a third party's UAT stack (resources named *-uat / flphut, peered to that party's own account); see deployment.md#staging-and-uat for what not to touch. Admins: a KumoHQ user and a third-party user |
FLIN, keeping the shared account as-is (decided 2026-10-12). Account admin: TODO(handover); third-party owner/contact: TODO(handover) | Join the account to FLIN's AWS Organization, MFA on every admin, IAM password policy, and bucket policies that limit the FLIN buckets (uploads, Terraform state) to FLIN roles. The third-party UAT stack stays; don't touch it. KumoHQ keeps MFA'd admin access (to build PH) until PH launch |
Expo / EAS account flinmaybright, project @flinmaybright/flin (a9da2bb6-…) |
Builds, EAS env vars, signing and push credentials | The KumoHQ maintainer is Admin, not Owner. Owner unknown | FLIN (decided 2026-10-12). Owner: TODO(handover) | Confirm or make a FLIN person the Owner; record eas credentials for iOS and Android with them present (mobile-release.md). KumoHQ stays Admin until the PH-capable build has shipped to both stores (PH launch), then is removed |
App Store Connect, app 6781172200 ("FLIN - Credit Wellness App") |
iOS distribution | Seller: Maybright Asia Pacific Pte Ltd. Indonesian storefront only | FLIN (decided 2026-10-12). Account Holder: TODO(handover) | FLIN adds its own Admin/App Manager users and an App Store Connect API key for eas submit (ascAppId 6781172200 in apps/native/eas.json). KumoHQ users stay until PH launch (PH storefront and the PH-capable release), then are removed |
Google Play, com.flin.flinapp |
Android distribution | Listing live, 1.1.0 | FLIN (decided 2026-10-12). Developer-account owner: TODO(handover) | FLIN creates a Play service account for eas submit, confirms Play App Signing is on and where the upload keystore is backed up, and removes KumoHQ users at PH launch |
Firebase project behind google-services.json |
Android push (FCM) | EAS file variable ANDROID_GOOGLE_SERVICES_JSON. Project unknown |
FLIN (decided 2026-10-12). Project ID and current owner: TODO(handover) | Keep the existing project (a new one would need a store build and break push on 1.1.0). Add a FLIN Google account as Owner, then remove KumoHQ accounts; record the project ID here |
Trigger.dev org "Flin" (flin-8179) → project "Flin App" proj_fqtihpiyjlwzafgdiukm |
Cron schedules for ID (prod + staging) | Only project in that org. Owner and plan unknown | FLIN (decided 2026-10-12). Org owner: TODO(handover) | Make a FLIN person org owner and move billing to FLIN; mint a new TRIGGER_ACCESS_TOKEN from a FLIN account and replace the GitHub Actions secret; KumoHQ stays a member until PH launch and creates the PH project in this org when PH needs jobs; remove KumoHQ members at PH launch |
Trigger.dev org KumoHQ → project "Flin" proj_wwkvmnfyahwgpebjuuaz |
Legacy, should be dead | Still running; see Act now | KumoHQ (decided 2026-10-12). Person: TODO(handover) | KumoHQ, now: identify which database it points at (and wipe it if it holds a copy of user data), disable its schedules, then delete the project |
Bugsink https://bugsink.aws.kumohq.in |
Error tracking. Server: project 4 (DSN in SSM SENTRY_DSN). App: project 5 (DSN baked into the binary) |
Self-hosted by KumoHQ on an EC2 instance in ap-south-1, in neither FLIN account. PH SENTRY_DSN is still a placeholder |
KumoHQ for now; FLIN from the 1.2.0 release (decided 2026-10-12) | Now: KumoHQ keeps hosting and gives FLIN engineers accounts; fill the real PH SENTRY_DSN; agree retention and backups. With 1.2.0: FLIN moves to its own instance (self-hosted Bugsink or Sentry SaaS): server DSN via SSM + new deployment, app DSN in the 1.2.0 build. KumoHQ's instance stays up until 1.1.0 users have updated; KumoHQ gets an account on FLIN's instance until PH launch |
Staging/UAT server flinapi.kumohq.in |
EAS preview-uat builds; probably the Trigger.dev staging target |
A single hand-built EC2 instance inside the ID prod account; the DNS zone kumohq.in is KumoHQ's |
KumoHQ until retired; FLIN owns the replacement (decided 2026-10-12) | Now: restrict its security group, replace its IAM key with a role, stop it writing to the prod bucket. Then FLIN builds a Terraform staging stack (envs/staging, from envs/ph-prod, in its own account), repoints preview / preview-uat in apps/native/eas.json and the Trigger.dev staging environment, and retires this host. See deployment.md#staging-and-uat |
Cloudflare: zones flin.co.id and flin.ph |
DNS. appapi.* and metabase records are DNS-only; the ACM validation CNAMEs must stay for certificate renewal |
The zones use different nameserver pairs, which suggests two Cloudflare accounts (inference) | FLIN (decided 2026-10-12). Account holder per zone and registrars: TODO(handover) | Add FLIN admins to whichever account(s) hold the zones, remove KumoHQ users, record each domain's registrar and renewal date. Later, optionally consolidate both zones into one FLIN account (re-add records, change nameservers at the registrar). Never delete the ACM validation CNAMEs |
tunnelto (flinapi subdomain) |
Optional dev tunnel (TUNNEL=id bun run dev) |
— | KumoHQ keeps it (decided 2026-10-12) | FLIN sets up its own dev tunnel (any tool, own account) and changes the subdomain in apps/server/scripts/dev.mjs; the KumoHQ key is not shared |
Kumo work tracker (work.kumohq.in/flin, FLIN-nnn tickets) |
Every ticket, decision and sign-off thread | Kumo-hosted | KumoHQ hosts it (decided 2026-10-12) | FLIN's team gets read/write accounts now. When FLIN picks its own tracker, export every ticket keeping the FLIN-nnn id in the title (code and docs cite them, e.g. TODO(FLIN-174)), then Kumo's copy goes read-only |
Figma: igRcVhDVxd0vgiPT7BqKxH (FLIN-x-KUMO) and the copy MB64xySEe6NnE7qtr2MesZ |
Designs; tickets link the original file | — | FLIN (decided 2026-10-12). Current owner of the original: TODO(handover) | The original igRcVhDVxd0vgiPT7BqKxH is the single source of truth, in FLIN's Figma team (KumoHQ moves it if it holds it). Archive the copy MB64xySEe6NnE7qtr2MesZ once FLIN has edit access to the original, and update the Figma note in CLAUDE.md (it tells agents to use the copy) |
| PR review bots: Greptile (on demand since 2026-09-07), earlier CodeRabbit and Macroscope | Code review | Greptile config in .greptile/ |
FLIN brings its own reviewer (decided 2026-10-12). Tool: TODO(handover) | FLIN picks and pays for its reviewer; because the repo stays in the KumoHQ org, a KumoHQ org admin has to approve installing that GitHub App. KumoHQ then uninstalls Greptile, CodeRabbit and Macroscope and cancels any remaining subscriptions; delete .greptile/ in the same change |
| Xendit (ID live; PH wired, placeholder secrets) | Checkout for the paid report and Debt Discipline plans; payment becomes paid only via POST /webhooks/xendit (x-callback-token) |
SSM XENDIT_SECRET_KEY, XENDIT_WEBHOOK_TOKEN (ID, updated 2026-10-06). Registered webhook URL and dashboard admins not visible |
FLIN (decided 2026-10-12). Dashboard admin: TODO(handover) | Confirm admins, remove KumoHQ users; record the registered webhook URL (expected https://appapi.flin.co.id/webhooks/xendit, events payment_session.completed / .expired); after handover rotate the secret key and webhook token together (dashboard + SSM, then force a new deployment); open the PH account and keys before PH payments go live |
| CLIK (ID credit bureau) | SOAP enquiry for the paid report; nightly FTPS upload of consent evidence (regulatory, 5-working-day deadline) | SSM CLIK_USERNAME, CLIK_PASSWORD (2026-08-20), CLIK_FTPS_PASSWORD; FTPS user is a Terraform literal. Pinned FTPS TLS intermediate expires 2027-11-02 |
FLIN (decided 2026-10-12). Contract owner and compliance-mail recipient: TODO(handover) | KumoHQ hands CLIK's naming guide and the FTPS credential sheet to FLIN's password manager, then deletes its local copies; rotate the SOAP and FTPS passwords after handover via CLIK's process; confirm with CLIK that CONSENT/Output lists no missing enquiries; route the consent-upload errors in Bugsink to the FLIN owner (the Trigger.dev run shows success even when the upload fails) |
| Finfra / AFPI (ID) | Alternative-credit report behind the free credit score in onboarding | SSM FINFRA_API_BASE_URL, FINFRA_API_USERNAME, FINFRA_API_PASSWORD (rotated 2026-09-07). ⚠️ Pair expires 2026-11-25 per team notes |
FLIN (decided 2026-10-12). Owner and Finfra contact: TODO(handover) | Request the next pair before 2026-11-25; verify (POST …/api/auth/token/v2 → 200), put both SSM parameters, force a new deployment (operations.md#63-rotation-notes-per-secret). Add a CloudWatch log-metric alarm on Finfra token fetch failed → the alerts topic |
| ASLI RI (ID) | Biometric KTP-vs-selfie verify (REST verify_professional, prod endpoint) and the on-device liveness SDK (vendor binaries in apps/native/modules/asliri) |
SSM ASLIRI_VERIFY_TOKEN, ASLIRI_LIVENESS_TOKEN (server-held, served by kyc.getLivenessToken). A stale liveness token is still a plain-text EAS variable in dev/preview |
FLIN (decided 2026-10-12). Contract owner, quota and price: TODO(handover) | KumoHQ hands the vendor SDK/API PDFs to a FLIN document store; rotate both tokens after handover; delete the stale EAS liveness variable; fix the POC-quota comment in apps/server/.env.example |
| CampaignHQ (ID; PH reuses it) | WhatsApp sign-in OTP and early-onboarding lifecycle templates | SSM CHQ_API_KEY (⚠️ PH uses ID's key, so PH OTPs come from ID's +62 sender). Service and template ids are hardcoded (integrations/campaignhq/index.ts, packages/notifications/src/templates.ts) |
FLIN (decided 2026-10-12). Account owner, sender numbers, Meta template approvals: TODO(handover) | Rotate CHQ_API_KEY after handover. Before PH launch, decide whether PH gets its own +63 sender and templates; if so, move the hardcoded ids into the profile/env |
| GoHighLevel / LeadConnector (ID; PH placeholders) | CRM contact sync, application-status pipeline (POST /webhooks/ghl), appointments (/webhooks/ghl-appointment), coach-booking widget, in-app support chat; reps open KTP images via /f/:token |
SSM LEAD_CONNECTOR_API, GHL_LOCATION_ID, GHL_WEBHOOK_SECRET (x-flin-token). ID field/pipeline/stage ids hardcoded in gohighlevel/field-map.ts, pipeline-map.ts; field list in reference/ghl-custom-fields.md |
FLIN (decided 2026-10-12). CRM admin: TODO(handover) | CRM admin owns fields, pipelines, workflows, calendars and the widget's Allowed Domains, and knows a renamed field or picklist value breaks the sync silently (field-map.ts). Confirm the workflow calls /webhooks/ghl with the agreed token. Rotate the API token and webhook secret after handover (SSM and the GHL workflow together). Before PH launch: create the PH location and decide whether it reuses ID's ids |
| Adjust (all countries) | App SDK funnel events; server-to-server paid_report_purchase |
EXPO_PUBLIC_ADJUST_ENV=production in EAS (preview builds too). SSM ADJUST_S2S_TOKEN exists for ID but is not on the running task, so no S2S events are sent; PH token is a placeholder |
FLIN (decided 2026-10-12). Dashboard owner: TODO(handover) | Wire ADJUST_S2S_TOKEN onto the ID task via the clone procedure (deployment.md#change-an-environment-variable-or-secret) and confirm a purchase event arrives; point preview builds at the Adjust sandbox; finish iOS SKAN verification and FCM uninstall measurement (specs/adjust-integration.md); rotate the S2S token after handover |
CIBI (PH credit bureau, not on main) |
Planned PH bureau; the PH profile's bureau port is unavailable() today |
⚠️ Team notes: UAT REST "myScore" JSON works (no-match = 404, UAT scores random, spec drift). Pending FLIN input per multi-country.md §8.6 | FLIN (decided 2026-10-12). Contract owner: TODO(handover) | FLIN holds the contract; KumoHQ builds the adapter. KumoHQ moves the CIBI documents it holds (API spec, test-data sheet, UAT sign-off form) and UAT credentials into FLIN's document store and password manager and works from there; production credentials go from CIBI straight to FLIN |
Onfido (PH KYC, POC on unmerged onfido-poc) |
Planned PH KYC (ID-document OCR + biometric) for both KYC ports; POC verdict "go" (research/onfido-ph-poc.md) | Trial ended ~2026-08-06 ⚠️. Open before contract: classic POST /checks on a paid plan, PhilID/UMID coverage, pricing vs ASLI RI |
FLIN holds the relationship and contract; KumoHQ builds the integration (decided 2026-10-12). FLIN owner: TODO(handover) | FLIN gets the three answers from Onfido sales and signs; sandbox and production keys go to KumoHQ through FLIN's password manager. Keep the onfido-poc branch as reference (it carries the ML Kit manifest plugin the real build needs). KumoHQ deletes the old trial keys from its local .env |
Alert inbox kumo@flin.co.id |
Only subscriber of both SNS alert topics (flin-prod-alerts, flin-ph-prod-alerts) |
Confirmed in both accounts | FLIN on-call (decided 2026-10-12). Address: TODO(handover), ideally a group address | Subscribe FLIN's on-call address to both topics (aws sns subscribe --protocol email) and confirm it; keep kumo@flin.co.id subscribed during the transition, then unsubscribe it |
Transfer checklist
Order matters. Each step says what breaks if it is skipped or done out of order.
-
Fill in the accounts table together, KumoHQ and FLIN.
-
Give FLIN admins access to every account before removing anyone. That means both AWS accounts (with MFA), Expo (Owner), App Store Connect, Play Console, both Trigger.dev orgs, Cloudflare, GitHub, Firebase, Bugsink, Metabase and the vendor portals. If skipped: you can lose the only person able to sign builds, renew certificates or rotate a key.
-
Rotate every secret KumoHQ set or can read. All prod secrets were put in SSM by KumoHQ, and the Terraform-generated ones have never been rotated (operations.md#6-secrets-and-rotation). Pairs that must change together:
JOBS_API_SECRETin SSM and in the Trigger.dev environment. Otherwise every cron call gets 401.BETTER_AUTH_SECRETalso keys the/reports/:tokenlinks, which are 5-minute HMAC tokens. ⚠️ Rotating it should sign every user out; this has not been tested.- Vendor keys: rotate at the vendor first, then update SSM, then force a new deployment.
-
The repository stays in the KumoHQ org (decided 2026-10-12). If it ever moves out, rewire these in the same change:
- The ID CodePipeline source, a console-owned GitHub OAuth-app connection on
KumoHQ/flin. - The PH CodeConnections connection (
github_repoininfra/terraform/envs/{prod,ph-prod}/main.tf), which an org admin approves in the console. - The
TRIGGER_ACCESS_TOKENActions secret.
If skipped: merges stop deploying, silently, because nothing alerts on pipeline failure.
- The ID CodePipeline source, a console-owned GitHub OAuth-app connection on
-
Trigger.dev: decide whether the "Flin" org stays where it is or moves. If the project changes, update
projectinapps/jobs/trigger.config.ts, mint a newTRIGGER_ACCESS_TOKEN, and setSERVER_URLandJOBS_API_SECRETin the new environments. Kill the legacy KumoHQ project either way. -
Bugsink (decided: KumoHQ hosts until 1.2.0, then FLIN's own instance): The server DSN changes with an SSM update and a new deployment. The app DSN is baked into each store build (
apps/native/lib/sentry.ts, EAS env), so app errors keep going to the old instance until users update. -
Staging (decided: lock down now, replace with a Terraform stack, then retire):
flinapi.kumohq.inruns on a KumoHQ domain inside FLIN's prod account. Keep it up until the new staging exists andpreview/preview-uatinapps/native/eas.jsonand the Trigger.dev staging environment point at it (deployment.md#staging-and-uat). -
Expo: make a FLIN person Owner of
flinmaybright, then record the signing, APNs and FCM credentials and where the Android upload keystore is backed up. -
Kumo tracker: FLIN gets accounts now; export later, keeping the FLIN-nnn ids (decided 2026-10-12). Transfer the Figma files.
-
Remove KumoHQ access at PH launch (KumoHQ is FLIN's PH contractor until then): AWS IAM users and the Identity Center user,
flin-prod-db-readersmembers, GitHub collaborators, Expo members, Trigger.dev members, Metabase users, Bugsink. Then rotate anything they could read. -
Add FLIN's on-call address to both SNS alert topics and confirm the subscription.
Deadlines
| Date | What | Action |
|---|---|---|
| 2026-11-05 | EAS deletes the 1.1.0 build artifacts (30-day retention) | Download the .ipa and .aab now (mobile-release.md) |
| 2026-11-25 ⚠️ | Finfra AFPI key pair expires (date from team notes). Symptom: Finfra token fetch failed: 401 … KEY_NOT_VALID on every pull |
Ask FLIN/Finfra for the next pair ahead of time and rotate (operations.md#63-rotation-notes-per-secret) |
| 2027-02-10 | ACM certificate appapi.flin.co.id |
Auto-renews only while its DNS validation CNAME stays in Cloudflare |
| 2027-02-19 | ACM certificate metabase.flin.co.id |
Same |
| 2027-04-24 | ACM certificate appapi.flin.ph |
Same |
| 2027-11-02 | The TLS intermediate certificate pinned for CLIK FTPS (Thawte TLS RSA CA G1) expires | Check CLIK's chain beforehand and update the pin in packages/countries/src/integrations/clik/consent-ftp.ts |
| Rolling | CloudTrail keeps only 90 days of event history (no trail in either account) | Enable a trail now if you want an audit record of the handover period |
| Rolling | ECR keeps the last 10 images. The emergency rollback window in ID reached back to 2026-09-25 on the check date | See deployment.md#rollback |
Open threads with FLIN
⚠️ These come from the team's notes and ticket threads. Check the latest comments on each ticket in the Kumo tracker before acting.
- FLIN-211 (loan list redesign, shipped in PR #131): four decisions were asked on 2026-09-23: keep "Written off" / "Macet" on closed KOL 5 loans; how manual loans count in "Total Loan Amount"; Home's total outstanding versus the section totals; the year filter. There are also label and copy sign-offs ("Loan Amount" vs "Outstanding", Cash Loan replacing Pinjol/KTA, empty-state copy, Indonesian/Filipino copy review).
- FLIN-241…249 (feedback sheet, shipped in PR #135): six owner decisions that deviate from the tickets, each flagged on its ticket. Examples: "Cash Loan / Pinjaman Tunai" instead of "Pinjol"; "Overdue since" = the last missed due date.
- Bank logos (PR #122): FLIN still owes correct logos for several BPRs, a BSN logo and an unidentified file. Logos are cached as immutable, so a replacement needs a new S3 key.
- Legal copy: the Indonesian and Filipino Terms, Privacy and FAQ text are AI translations that have not had legal review. The FAQ also promises things the app does not do (product.md).
- Philippines inputs that block PH work (multi-country.md
§8, product.md#12-pending-inputs-from-flin):
CIBI sample response and access, AI prompts, eligibility rules, pricing
(
TODO(FLIN-174)), legal text, the KOL/DPD explainer, regulator references, nav-bar tabs. - Onfido (PH KYC): the POC verdict was "go" (research/onfido-ph-poc.md).
Still open before a contract: whether API orchestration (classic
POST /checks) comes with a paid plan, PhilID/UMID coverage, and pricing against ASLI RI. - Xendit checkout cancel: untested with real money ⚠️.
Known issues and recommended fixes
Consolidated from every doc in this set and from the live checks. Severity: High = live risk to users, data or deploys; Med = real gap, not urgent; Low = hygiene. Security items name the issue, the component and the fix only.
Security
| Sev | Issue | Where | Fix |
|---|---|---|---|
| High | Metabase is reachable from the whole internet while its database role can read every column, PII included | WAF IP set flin-prod-metabase-allow, infra/terraform/envs/prod/terraform.tfvars |
Restore metabase_allowed_cidrs, then tofu apply -target=module.flin.aws_wafv2_ip_set.metabase_allow |
| High | Admin IAM principals without MFA in both AWS accounts; no IAM password policy in PH; stale principals remain | IAM, both accounts | MFA or SSO for every human, password policy, remove stale users, rotate KumoHQ-held keys after handover |
| High | In the shared PH account, third-party principals can reach the PH uploads (KYC) bucket and the PH Terraform state bucket, which holds secrets | AWS 611858318585 |
Bucket policies limited to FLIN roles now; move PH prod to its own account |
| High | The staging host sits in the ID prod account with broader network exposure than it needs, and writes to the prod uploads bucket with a long-lived IAM key | Default VPC, ID account | Restrict its security group, give staging its own account/bucket, use a role instead of a key |
| High | Hand-built default-VPC hosts (websites, SFTP intake, backups) have broader network exposure than they need and are not in Terraform | ID account | Restrict their security groups (use SSM Session Manager for admin access), own them in IaC or move them out |
| High | A company document-drive mirror (not app data) is stored in an app-account bucket, written by a hand-built host whose role has S3 full access | ID account | Owner decision; move it out of the app account; scope the role |
| High | No CloudTrail trail in either account, no GuardDuty in PH; ALB, WAF and S3 access logging off | Both accounts | Organization trail, GuardDuty, access logs |
| High | Every production secret was set by KumoHQ; the Terraform-generated ones were never rotated and sit in Terraform state | SSM /flin/prod/*, /flin/ph-prod/* |
Rotate after handover (transfer step 3) |
| Med | Unauthenticated scaffold endpoints in production: public todo.* read/write procedures, and POST /ai (a Gemini proxy; neither task definition sets a Google key, so it fails today) |
packages/api/src/routers/todo.ts, apps/server/src/index.ts |
Remove todoRouter, the /ai route and @ai-sdk/google; drop the todo table later. No app or job calls them |
| Med | Fixed-code Test-user login accepted in prod in both countries; the code and numbers are committed in Terraform | infra/terraform/modules/flin-env/ecs.tf, variables.tf, envs/ph-prod/main.tf |
Move TEST_OTP_CODE to an SSM secret, rotate it, keep the numbers out of git |
| Med | Credentials stored as plain-text EAS variables (SENTRY_AUTH_TOKEN); obsolete EXPO_PUBLIC_ASLIRI_LIVENESS_TOKEN and unused JITPACK_TOKEN still set |
EAS env | Rotate and re-create as Secret; delete the obsolete ones |
| Med | OTPs are stored in plain text (Better-Auth default), and verification, session and account are readable by the read-only and Metabase roles |
infra/scripts/db-user.sh, metabase-bootstrap.sql |
REVOKE SELECT on those tables from the read roles; decide whether plain-text OTPs are acceptable |
| Med | The app connects to Postgres as the RDS master role, with TLS but no CA verification | infra/terraform/modules/flin-env/rds.tf |
Least-privilege app role, sslmode=verify-full with the RDS CA |
| Med | Account-level S3 Block Public Access is off in the ID account; one legacy bucket has its blocks off and CORS *; the uploads bucket's CORS still lists KumoHQ/tunnel origins |
ID S3 | Enable the blocks, tighten CORS, import flin-uploads config into Terraform |
| Med | Identity documents under flin-uploads prefixes the app never writes (ktp/, bank-statement/); staging and dev data in the prod bucket |
flin-uploads |
Find the writer, separate non-prod buckets, set retention |
| Med | Metabase runs with the API's task role (S3 read/write, Bedrock) | infra/terraform/modules/flin-env/metabase.tf |
Give it its own empty role |
| Med | Base image floats on oven/bun:1.2-alpine; the PH latest scan shows 2 critical and 10 high CVEs (openssl, musl) |
apps/server/Dockerfile |
Pin and bump the base image, rebuild, review scans |
| Low | GHL webhook secret compared with !==, not in constant time |
packages/api/src/services/ghl-webhook.ts |
timingSafeEqual, as bearerMatches does |
| Low | /f/:token capability route has no rate limit (ADR-0005 flagged it) |
apps/server/src/index.ts |
WAF rate rule scoped to /f/ |
| Low | ASLIRI_MOCK_VERIFY has no prod guard, unlike the CLIK and Finfra mock flags |
packages/countries/src/profiles/id.ts |
Ignore it when APP_ENV=prod |
| Low | AI features use Bedrock global.* inference profiles, which may process data outside APAC |
packages/env/src/server.ts |
Compliance decision; switch to an apac.* profile if required |
| Low | For Test users, sendOTP logs the generated code to CloudWatch |
packages/auth/src/index.ts |
Drop the code from the log line |
| Low | The emailed report PDF password is the date of birth (DDMMYYYY), a deliberate choice that review tools flag as guessable ⚠️ | packages/api/src/services/report/* |
Product/security decision |
Operations and deploys
| Sev | Issue | Where | Fix |
|---|---|---|---|
| High | Legacy Trigger.dev project still sending notifications; staging environment sending real Debt Discipline notifications | Trigger.dev | See Act now |
| High | Nothing alerts on a failed pipeline or CodeBuild run in either country | CodePipeline / CodeBuild | EventBridge rule on FAILED → the SNS alert topic, in Terraform |
| High | No branch protection on main, no CI tests or type-check, and a merge deploys both production servers plus jobs with no approval stage |
GitHub, CodePipeline | GitHub Action running bun run check-types and the bun test suites; branch protection (needs a paid plan) or a pipeline approval; a required second reviewer |
| High | Finfra key expiry 2026-11-25 with no alert | Finfra | Rotate in advance; alert on KEY_NOT_VALID |
| High | Disaster recovery: uploads buckets unversioned in both countries, no AWS Backup plan, no cross-region copy, single-AZ RDS, restore never rehearsed, no RPO/RTO | RDS, S3 | Versioning, a backup plan (check data residency first), a rehearsed restore (operations.md#72-restore-runbook) |
| Med | Two task-definition lineages: Terraform's env list is only a record, and its own revision points at a :bootstrap image (gone from ECR in ID). The infra README used to tell you to deploy the family-latest revision (fixed in this PR) |
ECS, Terraform | Always clone the service's current revision (deployment.md#change-an-environment-variable-or-secret); tofu apply with -target; later collapse to one lineage |
| Med | metabase-bootstrap.sh runs against the family-latest task definition |
infra/scripts/metabase-bootstrap.sh |
Resolve the service's task definition, as db-user.sh does |
| Med | Payments rely only on the Xendit webhook; nothing reconciles. A lost or rejected webhook leaves a paying user stuck at pending | packages/api/src/services/xendit-webhook.ts |
A sweep that checks stale pending sessions with Xendit, or an alert |
| Med | The CLIK consent-upload job answers 202, so Trigger.dev shows success even when the FTPS upload fails; only Bugsink sees failures, and CLIK's deadline is 5 working days | apps/server/src/index.ts (/jobs/clik-consent-upload) |
Alert on those errors; confirm acceptance on CLIK's side |
| Med | ADJUST_S2S_TOKEN is in SSM and Terraform but not on the running ID task, so no server-side purchase events reach Adjust |
ECS flin-prod |
Add it through the clone procedure (the exec role can already read it) |
| Med | The "server before jobs" deploy-order rule is not enforced: the Action and both pipelines fire on the same merge | .github/workflows/trigger-deploy.yml |
Ship new /jobs/* endpoints in an earlier merge, or behind a dormant flag |
| Med | ECR keeps the last 10 images of any tag, and failed builds also push, so the rollback window is short | ECR lifecycle | Keep more, or keep by tag |
| Med | Internal preview builds talk to the production API, so testers create prod data, CRM contacts and charges |
apps/native/eas.json |
Point preview at staging, or test with Test users only |
| Med | Bugsink is KumoHQ-hosted; PH errors are not captured (placeholder DSN); the app hardcodes environment: "prod" for every build |
Bugsink, apps/native/lib/sentry.ts |
Ownership decision; real PH DSN; derive the environment at build time |
| Med | No human read path or one-off runner for the PH database: the tunnel is blocked by the EC2 vCPU quota, which the third-party UAT stack uses up | AWS 611858318585, quota L-1216C47A |
Request a quota increase, then a targeted apply |
| Low | CodeBuild log groups never expire; ALB deletion protection and access logs are off | Both accounts | Set retention; enable both |
| Low | Stale text: Terraform outputs say "proxied"; a tfvars comment cites Rp20.000 while the price is 25000; .env.example defaults (49000 price, Coolify) |
infra/terraform/*, apps/server/.env.example |
Update the text |
| Low | CLIK_CLASSIFY_MODEL_ID absent on the live ID task (same as the schema default); the Trigger.dev hello-world example task is deployed to prod |
ECS, apps/jobs/src/trigger/example.ts |
Add it on the next clone; delete the example |
App and product
| Sev | Issue | Where | Fix |
|---|---|---|---|
| High | Live "upgrade" push series says Rp29.000 / "Today only"; the price is Rp 25.000 with no discount | packages/notifications/src/series.ts, copy.ts |
Fix the copy (server deploy only) |
| Med | No account deletion: "Delete account" hands off to support chat, while the Privacy Policy promises deletion within 7 business days | apps/native/app/delete-account.tsx |
Define the back-office procedure now (operations.md#84-user-data-deletion-requests); build a backend later |
| Med | Tapping a push notification opens the app without routing | apps/native (no response listener; payload carries only notifId) |
Add a notification-response listener that follows the inbox deeplink (store build) |
| Med | Version gating is unused: MIN_SUPPORTED_APP_VERSION, LATEST_APP_VERSION and IOS_APP_STORE_ID are unset on both servers, so the iOS update button opens the generic App Store |
ECS env | Set IOS_APP_STORE_ID=6781172200 now; set LATEST_APP_VERSION after each full rollout (mobile-release.md) |
| Med | Debt Discipline procedures are not gated on the server by DEBT_DISCIPLINE_ENABLED; a direct call reaches checkout even where the programme is off |
packages/api/src/routers/debt-discipline.ts |
Add a server-side gate |
| Low | /r/verify-id redirects to flin://verify-id, which shows "Page Not Found" |
apps/server/src/index.ts |
Point it at flin://verify-identity (server-only fix, reaches 1.1.0) |
| Low | FAQ promises a monthly refresh for paid-report buyers and a Notifications settings screen; neither exists. Legal/FAQ text hardcodes Rp25,000 | apps/native/locales/*.json |
Correct the FAQ; interpolate the price (store build) |
| Low | Dev screens asliri-test and modal can be opened by deep link in store builds |
apps/native/app/_layout.tsx |
Remove or guard with __DEV__ |
| Low | A vendor outage on face match shows the "NO MATCH" badge beside "temporarily unavailable" | apps/native/app/verify-identity.tsx |
Neutral badge for SERVICE_UNAVAILABLE |
| Low | Email OTP message and the not-found screen are English-only | packages/api/src/services/email-otp.ts, apps/native |
Localise |
| Low | The store binary probably requests the microphone through expo-camera defaults ⚠️ | apps/native/app.json plugins |
microphonePermission: false / recordAudioAndroid: false |
| Low | Store privacy labels and Play Data Safety answers are not recorded anywhere; Purchases must be declared while the paid report is on | App Store Connect, Play Console | Export and check them |
| Low | main still calls the deprecated danaTalangan.* document procedures, which blocks removing that alias |
apps/native/lib/use-document-upload.ts |
Switch to bridgingLoan.*, ship, then raise the minimum version |
| Low | fil.json is maintained in every change but is not loaded on main |
apps/native/lib/locale.ts |
Decide: delete it or re-enable it |
Data and compliance
| Sev | Issue | Where | Fix |
|---|---|---|---|
| High | No retention rules: KYC images, application documents, raw CLIK and AFPI responses, biometric vendor responses and booking payloads are kept forever. Only emailed report PDFs expire (365 days) | DB, S3 | Agree retention with legal (OJK, the CLIK agreement, Indonesia's PDP law, the PH equivalent), then lifecycle rules and a purge job |
| Med | No S3 deletion path: deleted documents are a soft flag only | packages/api/src/routers/{dana-talangan,mediation}.ts |
Delete the object when the document or account is deleted |
| Med | PH data residency (Singapore) has no recorded counsel sign-off | multi-country.md §8.7 | TODO(handover) |
| Low | The upload size cap applies only to the declared size; confirmUpload does not check the stored object's length |
packages/storage/src/presign.ts, packages/api/src/routers/files.ts |
Compare ContentLength on confirm |
| Low | Prices are 32-bit integers (caps a single PH price at about ₱21.47M) | report_payment.amount_idr, debt_discipline_purchase.amount_minor |
Widen to bigint next time those columns change |
| Low | The image defaults to RUN_MIGRATIONS=true, so any ad-hoc container migrates whatever DATABASE_URL it points at |
apps/server/Dockerfile |
Default to false; set true only in the Migrate stage |
| Low | Migration 0070 adds an enum value without IF NOT EXISTS; a later migration that uses it would break a fresh-database replay |
packages/db/src/migrations/0070_odd_mongu.sql |
Use the 0049/0052 pattern; add a replay check to CI |
| Low | Revenue analysis must exclude synthetic paid rows, and the internal/test rows carry the full price | report_payment |
Saved Metabase views (data-model.md#gotchas-for-analysts-metabase) |
| Low | docs/clik-data-storage.md is out of date in four places and may have been shared with CLIK |
docs/clik-data-storage.md |
Banner added in this PR; send CLIK an updated version if it was shared |
Code and tooling
| Sev | Issue | Where | Fix |
|---|---|---|---|
| Med | Multi-country gaps that block PH: money formatting is IDR-only; WIB is hardcoded in jobs, notifications, cron time zones and consent naming; credit-report.tsx pushes /financial-details, a step PH does not have; the app ignores features.freeCreditScore / mediation; support chat uses the ID widget |
apps/native/lib/money.ts, packages/api/src/services/jobs.ts, packages/notifications, apps/native/app/credit-report.tsx |
Fix through the multi-country.md §8 mechanisms; checklist in deployment.md#philippines-go-live-checklist |
| Med | PH KYC: the PH mock biometric still requires ASLIRI_LIVENESS_TOKEN, which the PH task does not have, so kyc.getLivenessToken should throw for every PH user (worked out from code, not exercised) |
packages/countries/src/profiles/ph.ts, integrations/asliri/index.ts |
Return a dummy token from the mock, or land Onfido |
| Med | PH payments: the Xendit adapter sends amountMinor as amount. PHP has two decimals, and Xendit's expected unit for PHP is unverified, so a charge could be 100× off |
packages/countries/src/integrations/xendit/index.ts |
Verify in a PH sandbox before PH payments go live |
| Med | PH reuses ID's hardcoded GHL field/pipeline ids, CampaignHQ service/template ids and the support-chat widget id | gohighlevel/field-map.ts, pipeline-map.ts, campaignhq/index.ts, apps/native/app/support-chat.tsx |
Get the PH accounts; move the ids into the profile or env where they differ |
| Med | Code cites client documents that are not in the repo (Debt Discipline programme docs, the Portfolio Insight prompt PDF, the CLIK classification knowledge base) | e.g. packages/api/src/routers/debt-discipline-helpers.ts, routers/portfolio-insight.ts, services/clik/score.ts |
Collect them into a FLIN-owned store or docs/specs/ |
| Med | No shared dev secrets vault, dev S3 bucket or dev IAM user; KYC flows cannot run locally without AWS credentials | — | TODO(handover); see development.md |
| Low | withUserLock serializes per process only; with up to 4 tasks, two concurrent first AFPI pulls can each be billed by Finfra |
packages/api/src/services/user-lock.ts, services/finfra/store.ts |
A database claim row, like the CLIK pull's |
| Low | createContext (a session lookup) runs on every request, including webhooks, /jobs/* and the health check |
apps/server/src/index.ts |
Mount the plain routes before the oRPC middleware |
| Low | apps/web is the untouched Better-T-Stack scaffold: never deployed, cannot sign in against today's server; packages/ui is used only by it |
apps/web, packages/ui |
Decide: delete or build on it |
| Low | AGENTS.md holds only Trigger.dev vendor rules, so non-Claude agents miss every FLIN rule |
AGENTS.md |
Point it at CLAUDE.md and engineering-rules.md |
| Low | Node and Postgres versions are not pinned; test files are excluded from tsc; several workspaces have no check-types script |
root | .nvmrc/engines, a test tsconfig |
| Low | ADR drift: ADR-0001 says WhatsApp goes through the OTP port (code uses integrations.whatsapp); ADR-0004 says no flow writes both inbox and push (three do); notification-center.tsx cites an "ADR-0003 §B" that does not exist |
docs/adr/ |
Add drift notes / the missing section |
| Low | packages/api still imports some vendor types and errors directly (e.g. AsliRiVerifyError) |
packages/api/src/routers/kyc.ts |
Move behind ports when touched |
| Low | apps/jobs/package.json declares @flin/db, @flin/env and @flin/notifications, which apps/jobs/src does not import |
apps/jobs/package.json |
Remove the dependencies |
Questions only KumoHQ or FLIN can answer
Collected from every doc. Each also sits next to the claim it affects.
Access and ownership
- Names for every owner still marked TODO(handover) in the accounts table (ownership and transfer actions were decided on 2026-10-12), and the PH launch date that ends KumoHQ's access.
- Who holds admin on each AWS account after the handover, how new people get
access, and the break-glass procedure. Who should stay in
flin-prod-db-readers. - Who the third party in the PH AWS account is and how to contact them (decided: PH prod stays in the shared account).
- Who owns the Expo account
flinmaybright, the Firebase project behindgoogle-services.json, App Store Connect and Play Console admin, and the tunneltoflinapisubdomain. - Who owns the Cloudflare account(s) for each zone, and the registrars.
- Who owns the Trigger.dev "Flin" org, its plan and
TRIGGER_ACCESS_TOKEN, and whichSERVER_URLprod and staging use. - Bugsink retention and backups while KumoHQ hosts it, and which tool FLIN moves to with 1.2.0.
- Whether a local
set-prod-secrets.sh(or other record of how secrets were set) exists and should be handed over through a secure channel.
Operations
- The agreed rollback method, and how many ECR images to keep.
- RPO and RTO targets per country.
- Who reads
kumo@flin.co.id, who is on call, the escalation path to KumoHQ during the transition, and vendor support contacts. - How
flinapi.kumohq.inis deployed, from which branch and against which database (decided: lock it down, replace it with a Terraform staging stack, then retire it). - Which vendors have the NAT egress IPs allowlisted, which webhook URLs are registered in the Xendit and GHL consoles, and who manages each vendor console.
- Who has Metabase accounts, who is admin, and which addresses go on the allowlist.
Release
- How 1.0.0 and 1.1.0 were uploaded (EAS has no submission records), and the signing and push credentials (
eas credentials). - Which Test-user numbers and instructions were given to Apple and Google review.
- The current App Store privacy labels and Play Data Safety answers.
- Whether Adjust's iOS SKAN app verification was completed.
- Target date for the first PH-capable store build, and whether it ships the
en-PHoverlay (PR #127).
Data, legal, product
- Retention required for KYC images, documents, raw bureau and biometric responses.
- Who handles deletion requests from support chat, and how the 7-business-day promise is met.
- Whether plain-text OTP storage is acceptable to compliance.
- Counsel sign-off on PH data residency.
- Legal review of the Indonesian Terms, Privacy, FAQ and consent text.
- What writes
flin-uploads/ktp/andbank-statement/. - Who owns the Metabase Test-user exclusion and keeps it in sync with
TEST_PHONE_NUMBERS. - The AsliRI contract (quota/price per call) and where engineers get AsliRI tokens for local testing.
- Where specs and issues live from now on. Recommendation: write new specs to
docs/specs/and keep only scratch tickets local (docs/agents/issue-tracker.mdstill describes the local-only.scratch/tracker). - Whether FLIN's CRM team's GHL workflow creates and moves opportunities in the FLIN App pipeline and calls
POST /webhooks/ghl(ID and PH). - Who at FLIN owns each vendor contract (CLIK, Finfra, ASLI RI, CampaignHQ + WhatsApp sender numbers and Meta templates, GHL locations, Xendit, Adjust, CIBI, Onfido) and who can accept AWS Marketplace / Bedrock model agreements.
- Where CLIK's naming guide and the FTPS credential sheet go (both were only in a developer's Downloads folder).
Material that is not in git
KumoHQ worked with a local-only spec tracker (.scratch/) and design notes
(docs/superpowers/); both are gitignored. This PR promotes into the repo
every local file that committed code cites, scrubbed of personal data:
- specs/: Adjust integration, ASLI RI SDK integration, CLIK consent upload (with the APPL PDF prototype), GHL CRM sync, GHL pipeline status
- research/onfido-ph-poc.md
- reference/ghl-custom-fields.md
- runbooks/liveness-onboarding-smoke.md
Still local-only on the previous maintainer's machine, for KumoHQ to hand over through a secure channel:
- Every other
.scratch/<feature>/spec.mdand its issues: Debt Discipline (FLIN-70…79), notifications and the WhatsApp templates handoff, inbox, consultations, due-day picker, loan dedup (6 AFPI ids still unresolved), CLIK classification, portfolio insight. Their substance shipped and the code is the authority, but the specs record intent and open questions. One example:.scratch/debt-discipline/product-questions.mdholds open product questions marked "Blocking Phase 2". - Client documents that may exist nowhere else: the Portfolio Insight prompt PDF (the Google Doc link on the ticket returns 401), the CLIK loan-classification knowledge base, CLIK's naming guide. Also email drafts to CLIK, which contain contact names, so keep them private.
docs/superpowers/plans|specs(May–July 2026 design history) and.superpowers/sdd/(agent scratch, low value).- Local
.envfiles, the gitignored AFPI/CLIK response fixtures (real PII; do not hand these over in plain form) andgoogle-services.json.
TODO(handover): decide where this archive goes, and check it for personal data first.