pkgs <- c("bit64","svglite","dplyr","tidyr","stringr","forcats","ggplot2","scales","patchwork","ggrepel","gt")
invisible(lapply(pkgs, function(p){ if(!requireNamespace(p,quietly=TRUE))
  install.packages(p,quiet=TRUE,repos="https://cloud.r-project.org")
  suppressPackageStartupMessages(library(p,character.only=TRUE)) }))
BUNDLE <- "aging_ltc_jkn_aggregates.rds"
A <- readRDS(BUNDLE)
fix64 <- function(x){
  if(is.data.frame(x)){ x[] <- lapply(x, function(c) if(inherits(c,"integer64")) as.numeric(c) else c); x }
  else if(is.list(x)) lapply(x, fix64)
  else if(inherits(x,"integer64")) as.numeric(x) else x }
A <- fix64(A)
pt <- A$pt
OUT_DIR <- "outputs"; if(!dir.exists(OUT_DIR)) dir.create(OUT_DIR)
TBL_DIR <- "tables";  if(!dir.exists(TBL_DIR)) dir.create(TBL_DIR)
wcsv <- function(df,name) { write.csv(df, file.path(TBL_DIR, paste0(name,".csv")), row.names=FALSE); df }
## ICD-10 3-char -> disease name (built from data: FKL16A / FKP15A). Used to label dx tables/figures.
ICDLAB <- tryCatch(read.csv("icd3_label.csv", stringsAsFactors=FALSE), error=function(e) data.frame(icd3=character(),disease=character()))
addlab <- function(df) df |> left_join(ICDLAB, by="icd3") |>
  mutate(disease=ifelse(is.na(disease)|disease=="","(name unavailable)",disease),
         lbl=paste0(icd3, " ", ifelse(nchar(disease)>44, paste0(substr(disease,1,44),"…"), disease)))

## ---- house style (palet dongker + abu terang) ----
INK<-"#0b1f3a"; NAVY<-"#0b1f3a"; NAVY2<-"#13315c"; BLUE<-"#3d5a80"; STEEL<-"#3d5a80"
SLATE<-"#5b7aa6"; MIST<-"#9fb3c8"; LMIST<-"#c7d2dd"; LGRAY<-"#e3e8ee"; GREY<-"#64748b"
TEAL<-"#13315c"; AMBER<-"#5b7aa6"; RED<-"#274060"; GREEN<-"#13315c"; PURPLE<-"#13315c"; ORANGE<-"#5b7aa6"
PANEL<-"#f3f5f8"; GRID<-"#dbe2ea"; TXT<-"#1f3350"
COLS6 <- c(INK,STEEL,NAVY2,SLATE,MIST,LMIST)
ABAND_COLS <- c("Pra-lansia (45–59)"=LMIST,"Lansia muda (60–69)"=SLATE,
                "Lansia madya (70–79)"=NAVY2,"Lansia tua (80+)"=INK)
LVL_COLS <- c("FKTP (Primer)"="#2f9e44","FKRTL Rawat Jalan"=STEEL,"FKRTL Rawat Inap"=INK)  # FKTP green for contrast
ISLAND_COLS <- c("Jawa"=INK,"Sumatera"=STEEL,"Sulawesi"=NAVY2,"Kalimantan"=SLATE,"Bali-Nusra"=MIST,"Maluku-Papua"=LMIST,"Tidak diketahui"=LGRAY)
ENTRY_COLS <- c("1 FKTP (Primer)"=INK,
                "2 FKRTL Rawat Jalan (langsung ke RS)"=STEEL,
                "3 FKRTL Rawat Inap (langsung opname)"=LMIST)

th <- function(b=11) theme_minimal(base_size=b) + theme(
  plot.title=element_text(color=INK,face="bold",size=b+2,margin=margin(b=4),family="serif"),
  plot.subtitle=element_text(color=GREY,size=b-1,lineheight=1.3),
  plot.caption=element_text(color=GREY,size=b-3,hjust=1),
  plot.background=element_rect(fill="white",color=NA),
  panel.background=element_rect(fill=PANEL,color=NA),
  panel.border=element_rect(color=GRID,fill=NA,linewidth=0.4),
  panel.grid.major=element_line(color=GRID,linewidth=0.3), panel.grid.minor=element_blank(),
  legend.position="bottom", legend.direction="horizontal", legend.box="horizontal",
  legend.key.size=unit(.55,"lines"), legend.text=element_text(size=b-2),
  strip.background=element_rect(fill=INK,color=NA),
  strip.text=element_text(color="white",face="bold",size=b-1))

gfmt <- function(g) g |>
  gt::tab_options(heading.background.color=INK, heading.title.font.size=gt::px(13),
    column_labels.background.color=STEEL, column_labels.font.weight="bold", column_labels.font.size=gt::px(11),
    row.striping.include_table_body=TRUE, row.striping.background_color="#eef2f7",
    table.border.top.color=INK, table.border.top.width=gt::px(3), table.width=gt::pct(100),
    data_row.padding=gt::px(5), source_notes.font.size=gt::px(10)) |>
  gt::tab_style(style=gt::cell_text(color="white",weight="bold"),
    locations=gt::cells_column_labels(gt::everything()))

CAP <- "Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)"
fmt <- function(x) formatC(round(as.numeric(x)), format="d", big.mark=",")
pc1 <- function(x) paste0(formatC(x, format="f", digits=1),"%")
yrx <- function() scale_x_continuous(breaks=2015:2024, labels=function(x) paste0("'",substr(x,3,4)))
ABAND_LAB <- A$meta$aband_lab

## ---- translate bundle data labels to English ----
.rc <- function(df,col,map){ if(!is.null(df)&&is.data.frame(df)&&col%in%names(df)){ v<-as.character(df[[col]]); m<-unname(map[v]); df[[col]]<-ifelse(is.na(m),v,m) }; df }
.AGE <- c("Pra-lansia (45–59)"="Pre-elderly (45–59)","Lansia muda (60–69)"="Young-old (60–69)","Lansia madya (70–79)"="Middle-old (70–79)","Lansia tua (80+)"="Oldest-old (80+)")
.CHRON <- c("Hipertensi (I10–15)"="Hypertension (I10–15)","Diabetes (E10–14)"="Diabetes (E10–14)","Penyakit Jantung Iskemik (I20–25)"="Ischaemic heart disease (I20–25)","Gagal Jantung (I50)"="Heart failure (I50)","Stroke (I60–69)"="Stroke (I60–69)","Penyakit Paru Kronik (J40–47)"="Chronic lung disease (J40–47)","Penyakit Ginjal Kronik (N17–19)"="Chronic kidney disease (N17–19)","Kanker (C00–C97)"="Cancer (C00–C97)","Osteoartritis (M15–19)"="Osteoarthritis (M15–19)","Demensia (F00–03, G30)"="Dementia (F00–03, G30)","Depresi (F32–33)"="Depression (F32–33)","Penyakit Hati Kronik (K70–76)"="Chronic liver disease (K70–76)","Gangguan Tiroid (E00–07)"="Thyroid disorders (E00–07)","Anemia (D50–64)"="Anaemia (D50–64)")
.GERI <- c("Fraktur panggul/femur (S72)"="Hip/femur fracture (S72)","Fraktur fragilitas (vertebra/pinggul/anggota gerak)"="Fragility fracture (vertebra/hip/limb)","Osteoporosis (M80–81)"="Osteoporosis (M80–81)","Stroke akut (I60–64)"="Acute stroke (I60–64)","Gejala sisa stroke (I69)"="Stroke sequelae (I69)","Demensia (F00–03, G30–31)"="Dementia (F00–03, G30–31)","Parkinsonisme (G20–21)"="Parkinsonism (G20–21)","Delirium (F05)"="Delirium (F05)","Ulkus dekubitus (L89)"="Pressure ulcer (L89)","Inkontinensia urin (R32)"="Urinary incontinence (R32)","Kerentaan/senilitas (R54)"="Frailty/senility (R54)","Sinkop/jatuh (R55, W00–19)"="Syncope/falls (R55, W00–19)","Katarak (H25–26)"="Cataract (H25–26)","Glaukoma (H40)"="Glaucoma (H40)","Gangguan pendengaran (H90–91)"="Hearing loss (H90–91)","Malnutrisi (E40–46)"="Malnutrition (E40–46)","Pneumonia (J12–18)"="Pneumonia (J12–18)","Penyakit saluran kemih (N39)"="Urinary tract disease (N39)")
.ACSC <- c("Gagal jantung (I50)"="Heart failure (I50)","Hipertensi (I10–11)"="Hypertension (I10–11)","Diabetes (E10–14)"="Diabetes (E10–14)","PPOK (J40–44)"="COPD (J40–44)","Asma (J45–46)"="Asthma (J45–46)","Pneumonia bakterial (J13–18)"="Bacterial pneumonia (J13–18)","Infeksi saluran kemih (N39)"="Urinary tract infection (N39)","Dehidrasi (E86)"="Dehydration (E86)","Angina (I20)"="Angina (I20)","Selulitis (L03–04)"="Cellulitis (L03–04)")
.COV <- c("FKTP + FKRTL"="FKTP + Hospital","FKTP saja"="FKTP only","FKRTL saja"="Hospital only","Lainnya"="Other")
.SEV <- c("1 Ringan"="1 Mild","2 Sedang"="2 Moderate","3 Berat"="3 Severe","9 Lainnya"="9 Other")
.LVL <- c("FKTP (Primer)"="FKTP (Primary)","FKRTL Rawat Jalan"="Hospital outpatient","FKRTL Rawat Inap"="Hospital inpatient")
.ENTRY <- c("1 FKTP (Primer)"="1 FKTP (Primary care)","2 FKRTL Rawat Jalan (langsung ke RS)"="2 Hospital outpatient (direct)","3 FKRTL Rawat Inap (langsung opname)"="3 Hospital inpatient (direct admission)")
.PBI <- c("PBI (disubsidi)"="PBI (subsidized)","Non-PBI"="Non-PBI")
.ISL <- c("Jawa"="Java","Sumatera"="Sumatra","Bali-Nusra"="Bali-Nusa Tenggara","Kalimantan"="Kalimantan","Sulawesi"="Sulawesi","Maluku-Papua"="Maluku-Papua","Tidak diketahui"="Unknown")
.CHAR <- c("Jenis Kelamin"="Sex","Kelompok Usia"="Age group","Segmentasi"="Membership segment","Kelas Rawat"="Ward class","Pulau"="Island")
.LEV <- c(.AGE,"Laki-laki"="Male","Perempuan"="Female","Kelas I"="Class I","Kelas II"="Class II","Kelas III"="Class III","Bukan Pekerja"="Non-worker","PBPU (Mandiri)"="PBPU (self-paying)","PPU"="PPU (salaried)")
.REFR <- c("Puskesmas"="Puskesmas (PHC)","Rumah Sakit"="Hospital","Klinik Pratama"="Primary clinic","Dokter Umum"="GP","Klinik Utama"="Specialist clinic","Apotik"="Pharmacy","Pemerintah"="Government","Lainnya"="Other")
.SEG <- c("Bukan Pekerja"="Non-worker","PBI APBN"="PBI APBN","PBI APBD"="PBI APBD","PBPU (Mandiri)"="PBPU (self-paying)","PPU"="PPU (salaried)")
ABAND_LAB <- unname(ifelse(ABAND_LAB %in% names(.AGE), .AGE[ABAND_LAB], ABAND_LAB))
if(exists("ABAND_COLS")) names(ABAND_COLS) <- ifelse(names(ABAND_COLS)%in%names(.AGE), unname(.AGE[names(ABAND_COLS)]), names(ABAND_COLS))
if(exists("ENTRY_COLS")) names(ENTRY_COLS) <- ifelse(names(ENTRY_COLS)%in%names(.ENTRY), unname(.ENTRY[names(ENTRY_COLS)]), names(ENTRY_COLS))
if(exists("LVL_COLS")) names(LVL_COLS) <- ifelse(names(LVL_COLS)%in%names(.LVL), unname(.LVL[names(LVL_COLS)]), names(LVL_COLS))
if(exists("ISLAND_COLS")) names(ISLAND_COLS) <- ifelse(names(ISLAND_COLS)%in%names(.ISL), unname(.ISL[names(ISLAND_COLS)]), names(ISLAND_COLS))
for(nm in c("strata_patient","prev_year","los_band","mm_by_band","cost_percapita_band","geriatric_by_band","entry_band","visit_rate","cost_band")) A[[nm]] <- .rc(A[[nm]],"grp",.AGE)
A$chronic_prev <- .rc(A$chronic_prev,"condition",.CHRON)
A$geriatric_prev <- .rc(A$geriatric_prev,"syndrome",.GERI)
A$geriatric_by_band <- .rc(A$geriatric_by_band,"syndrome",.GERI)
A$acsc_breakdown <- .rc(A$acsc_breakdown,"condition",.ACSC)
A$coverage <- .rc(A$coverage,"grpc",.COV)
A$severity <- .rc(A$severity,"severity",.SEV)
A$util_year <- .rc(A$util_year,"level",.LVL)
for(nm in c("entry_overall","entry_band","entry_year","entry_segment")) A[[nm]] <- .rc(A[[nm]],"entry",.ENTRY)
A$entry_segment <- .rc(A$entry_segment,"pbi",.PBI); A$equity_segment <- .rc(A$equity_segment,"pbi",.PBI); A$equity_segment <- .rc(A$equity_segment,"segmen",.SEG)
for(nm in c("geo_island","geo_prov","equity_island","served_rate_prov")) A[[nm]] <- .rc(A[[nm]],"island",.ISL)
A$referrer_type <- .rc(A$referrer_type,"perujuk",.REFR)
A$table1 <- .rc(.rc(A$table1,"char",.CHAR),"level",.LEV)
A$repr_index <- .rc(.rc(A$repr_index,"char",.CHAR),"level",.LEV)
if(!is.null(A$mm_dyads)&&"pair"%in%names(A$mm_dyads)) for(k in names(.CHRON)) A$mm_dyads$pair <- gsub(k, .CHRON[[k]], A$mm_dyads$pair, fixed=TRUE)

Unit of analysis (shown on every table/figure). This document uses three units, see the badge · Unit: …: (1) Unique patients = persons, counted once (prevalence, demographics, mortality, equity, multimorbidity, geriatric syndromes); (2) Visits/Claims = per service (utilisation volume, cost, INA-CBG, top diagnoses); (3) Inpatient episode = per admission (LOS, readmission, ACSC).

How to read. Every population figure is a national weighted projection (PSTV15) from the BPJS reguler sample; raw sample counts are reported separately. The definition of older people follows Law 13/1998: age ≥60 years, with the pre-elderly 45–59 group as a comparator. Age is computed from date of birth (PSTV03) relative to the year of service, so elderly status is set at the time of the claim. Claims data describe only the JKN-served population, not the entire elderly population.

Pillar map (navigation): Foundation (cohort, definitions, Table 1, sample-design validation) · A Burden & Demography · First Contact (point of entry) · B FKTP (Primary care) · C FKRTL (Referral/Hospital) · D Referral & Connectivity · E Member↔︎Facility Geography · F Geriatric Syndromes, ACSC & End-of-life · G Multimorbidity · H Economics · I Equity.

1 Foundation: cohort, definitions, and sample design

⓪ Foundation · Cohort flow (STROBE) · Definition of older people · Table 1 · Sample-design validation

Aim: Define the analytic population (JKN members aged ≥45 with ≥1 FKTP or FKRTL claim at that age; older people = ≥60), characterise it against the general elderly population, and frame the claims limitations.
Source & design: BPJS Kesehatan Sample Data 2015–2024, reguler schema (~1% household sample of JKN members, ~2.59 million individuals in ~1.07 million families). Patients identified via PSTV01, national weight PSTV15, demographics from the official codebook (PSTV05 sex, PSTV08 segment, PSTV07 ward class, PSTV09 province of residence, PSTV18 year of death).

cf <- A$cohort_flow
flow <- data.frame(
  Stage=c("Reguler-sample members aged ≥45 (latest snapshot)",
          "Analytic cohort aged ≥45 with ≥1 claim (FKTP/FKRTL)",
          "  of whom, patients with an FKTP claim",
          "  of whom, patients with an FKRTL claim",
          "  of whom, patients with ≥1 inpatient admission",
          "OLDER-PEOPLE COHORT (≥60) with ≥1 claim"),
  `Patients (raw sample)`=c(cf$member_45plus_latest_def, cf$analytic_cohort_45plus,
          cf$fktp_pts, cf$fkrtl_pts, cf$inpatient_pts, cf$analytic_cohort_lansia),
  check.names=FALSE) |> wcsv("L0_1_cohort_flow")
gt::gt(flow) |>
  gt::tab_header(title=gt::md("**Table L0.1: Cohort construction (STROBE)** · _Unit: Unique patients (sample)_"),
    subtitle=gt::md("_BPJS reguler sample 2015–2024, age computed at time of service_")) |>
  gt::fmt_number(columns=2, decimals=0, use_seps=TRUE) |>
  gt::data_color(columns=2, colors=scales::col_numeric(c("#e3e8ee","#0b1f3a"),domain=NULL)) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table L0.1: Cohort construction (STROBE) · Unit: Unique patients (sample)
BPJS reguler sample 2015–2024, age computed at time of service
Stage Patients (raw sample)
Reguler-sample members aged ≥45 (latest snapshot) 871,994
Analytic cohort aged ≥45 with ≥1 claim (FKTP/FKRTL) 590,123
of whom, patients with an FKTP claim 552,852
of whom, patients with an FKRTL claim 334,727
of whom, patients with ≥1 inpatient admission 209,887
OLDER-PEOPLE COHORT (≥60) with ≥1 claim 246,075
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)
Definition of older people & age groups

Following Law No. 13/1998 and MoH Regulation 67/2015: older people = residents aged ≥60 years. Analysis groups: Pre-elderly (45–59) as comparator, Young-old (60–69), Middle-old (70–79), Oldest-old (80+). Age is computed from date of birth (PSTV03) relative to the year of service; the database age column (~89% missing) is not used.

Demographic context (population benchmarks, BPS & SKI 2023). Indonesia has been an ageing society since 2021 (≥10% of the population aged ≥60). In 2023 older people reached 11.75% of the population with an old-age dependency ratio of 17.08 per 100 working-age people; age structure: 60–69 years 63.6%, 70–79 years 26.8%, ≥80 years 8.7%; majority female (52.3%). Projections: >14% by 2030 and ~20.3% (≈72 million) by 2045. Functionally, SKI 2023 recorded 95.0% of older people as fully independent in daily activities, 2.1% with mild dependency, and 2.9% with moderate-to-total dependency, the latter being the core of long-term-care need. Measured hypertension in older people rises from 49.5% (60–64) to 64.0% (75+), yet only 8.6% of adults have ever been diagnosed by a doctor, indicating a large detection/management gap.

1.1 Table 1. Characteristics of Older Patients vs General Elderly Population

Characteristics of older patients (FKTP, FKRTL, Overall = older-people cohort ≥60) compared with the general elderly population (all reguler-sample members aged ≥60, regardless of claims). Figures = % per column (weighted).
n1 <- A$table1_n
gt::gt(A$table1, groupname_col="char", rowname_col="level") |>
  gt::tab_header(title=gt::md("**Table 1: Characteristics of older patients vs the JKN elderly population** · _Unit: Unique patients (weighted), % per column_"),
    subtitle=gt::md(sprintf("_FKTP n=%s · FKRTL n=%s · Overall n=%s · Elderly GenPop n=%s (sample members)_",
      fmt(n1$raw[n1$kolom=="FKTP"]), fmt(n1$raw[n1$kolom=="FKRTL"]),
      fmt(n1$raw[n1$kolom=="Overall (Lansia)"]), fmt(n1$raw[n1$kolom=="Elderly GenPop"])))) |>
  gt::cols_label(FKTP="FKTP %", FKRTL="FKRTL %", Overall="Overall %", GeneralPop="Elderly GenPop %") |>
  gt::fmt_number(columns=c(FKTP,FKRTL,Overall,GeneralPop), decimals=1) |>
  gt::sub_missing(columns=everything(), missing_text="-") |>
  gt::data_color(columns=Overall, colors=scales::col_numeric(c("#e3e8ee","#0b1f3a"),domain=NULL)) |>
  gt::data_color(columns=GeneralPop, colors=scales::col_numeric(c("#e3e8ee","#13315c"),domain=NULL)) |>
  gt::tab_source_note(gt::md(paste(CAP,"| Elderly GenPop = all reguler-sample members ≥60"))) |> gfmt()
Table 1: Characteristics of older patients vs the JKN elderly population · Unit: Unique patients (weighted), % per column
FKTP n=227,804 · FKRTL n=161,915 · Overall n=246,075 · Elderly GenPop n=383,356 (sample members)
FKTP % FKRTL % Overall % Elderly GenPop %
Sex
Female 52.4 49.8 52.1 50.6
Male 47.6 50.2 47.9 49.4
Age group
Young-old (60–69) 58.1 58.0 57.3 49.8
Middle-old (70–79) 29.1 30.8 29.6 27.7
Oldest-old (80+) 12.8 11.2 13.1 22.5
Membership segment
PBI APBN 52.8 37.6 51.5 48.3
Non-worker 15.7 22.5 16.3 17.6
PBPU (self-paying) 13.8 21.6 14.5 12.6
PBI APBD 13.9 13.0 13.9 16.6
PPU (salaried) 3.9 5.3 3.8 4.9
Ward class
Class III 76.0 64.1 74.8 73.1
Class I 15.5 23.9 16.2 16.6
Class II 8.5 12.0 9.0 10.3
Island
Jawa 64.9 61.9 64.4 59.5
Sumatera 17.5 19.5 17.7 17.5
Sulawesi 7.5 7.9 7.5 7.1
Bali-Nusra 5.2 5.1 5.2 5.3
Kalimantan 3.8 4.2 3.9 4.2
Maluku-Papua 1.1 1.4 1.2 6.4
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection) | Elderly GenPop = all reguler-sample members ≥60
invisible(wcsv(A$table1,"T1_karakteristik"))
sp <- A$strata_patient |> mutate(grp=as.character(grp)) |> filter(!is.na(grp)) |> wcsv("L0_2_strata_usia")
gt::gt(sp) |>
  gt::cols_label(grp="Age group", weighted="Patients (weighted)", raw="Patients (sample)", pct_w="Proportion (%)") |>
  gt::tab_header(title=gt::md("**Table L0.2: Age-group distribution (≥45 cohort)** · _Unit: Unique patients (weighted)_")) |>
  gt::fmt_number(columns=c(weighted,raw),decimals=0,use_seps=TRUE) |>
  gt::data_color(columns=weighted, colors=scales::col_numeric(c("#e3e8ee","#0b1f3a"),domain=NULL)) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table L0.2: Age-group distribution (≥45 cohort) · Unit: Unique patients (weighted)
Age group Patients (weighted) Patients (sample) Proportion (%)
Pre-elderly (45–59) 35,997,105 344,048 56.6
Young-old (60–69) 15,836,344 148,307 24.9
Middle-old (70–79) 8,179,931 70,965 12.9
Oldest-old (80+) 3,622,770 26,803 5.7
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)

Main limitation (applies throughout the document). The figures below are JKN members who reached a facility and whose claim was recorded, not the entire elderly population. Older people who never accessed care, or were served through non-claim programs (Posyandu/Posbindu Lansia, certain drug programs), are not captured. The cohort is built from the reguler household sample, so annual trends are relatively valid, though early years are slightly under-observed (members who left or died before sampling are not seen). There are no laboratory/vital values (blood pressure, HbA1c) or complete drug-dispensing data, so disease-control and polypharmacy indicators are only proxies.

2 Pillar A. Disease Burden & Demography

① Pillar A · Older people served per year · Age-sex pyramid · Geographic distribution
Question: How many older people are served by JKN, what is the trend, the age-sex profile, and the geographic distribution.

2.1 Older people served per year

py <- A$prev_year |> filter(!is.na(grp)) |> mutate(grp=factor(grp, levels=ABAND_LAB)) |> wcsv("A1_prev_year_band")
ggplot(py, aes(yr, wt_pts, fill=grp)) +
  geom_col(width=.72) +
  annotate("text", x=2020.5, y=max(A$prev_year_total$wt_pts)*1.02, label="COVID-19 dip 2020–21", color=RED, size=2.8, fontface="italic") +
  scale_fill_manual(values=ABAND_COLS, name=NULL) +
  yrx() + scale_y_continuous(labels=label_number(scale_cut=cut_short_scale()), expand=expansion(mult=c(0,.08))) +
  labs(title="Population aged ≥45 served by JKN per year, by age group · Unit: unique patients",
       subtitle="Weighted unique patients (national projection). Service dipped in 2020–2021 (pandemic restrictions).",
       x=NULL, y="Patients (weighted)", caption=CAP) + th()

pyt <- A$prev_year_total |> left_join(A$prev_year_lansia |> rename(lansia_raw=raw_pts, lansia_wt=wt_pts), by="yr") |>
  transmute(Year=yr, `Age ≥45 (sample)`=raw_pts, `Age ≥45 (weighted)`=wt_pts,
            `Older ≥60 (sample)`=lansia_raw, `Older ≥60 (weighted)`=lansia_wt) |> wcsv("A1_prev_year_total")
gt::gt(pyt) |>
  gt::tab_header(title=gt::md("**Table A.1: Population ≥45 & older people ≥60 served by JKN per year** · _Unit: Unique patients (weighted)_")) |>
  gt::fmt_number(columns=2:5, decimals=0, use_seps=TRUE) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table A.1: Population ≥45 & older people ≥60 served by JKN per year · Unit: Unique patients (weighted)
Year Age ≥45 (sample) Age ≥45 (weighted) Older ≥60 (sample) Older ≥60 (weighted)
2015 99,900 8,445,870 37,139 3,378,952
2016 130,838 10,508,558 47,662 4,080,945
2017 183,000 19,025,247 65,988 7,386,420
2018 210,186 22,215,950 77,598 8,747,018
2019 234,588 25,329,517 88,222 10,050,800
2020 217,600 22,844,849 83,822 9,208,301
2021 222,929 23,110,229 84,432 9,118,251
2022 252,625 26,229,325 95,644 10,176,227
2023 281,364 29,593,704 110,101 11,875,655
2024 306,558 32,751,039 121,614 13,331,471
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)

2.2 Age-sex pyramid

pyr <- A$pyramid |> mutate(sex_lab=ifelse(sex==1,"Male","Female"),
  wt_signed=ifelse(sex==1,-wt,wt)) |> wcsv("A2_pyramid")
ord <- pyr |> distinct(ageband) |> arrange(ageband) |> pull(ageband)
pyr <- pyr |> mutate(ageband=factor(ageband, levels=ord))
mx <- max(pyr$wt)
ggplot(pyr, aes(wt_signed, ageband, fill=sex_lab)) +
  geom_col(width=.85) +
  scale_fill_manual(values=c("Male"=INK,"Female"=MIST), name=NULL) +
  scale_x_continuous(labels=function(x) label_number(scale_cut=cut_short_scale())(abs(x)),
                     limits=c(-mx,mx)) +
  labs(title="Age-sex pyramid of population aged ≥45 served by JKN · Unit: unique patients",
       subtitle="Weighted unique patients. Female predominance strengthens in the oldest age groups.",
       x="Patients (weighted)", y="Age group (5-year)", caption=CAP) + th()

2.3 Geographic distribution (older people ≥60)

gi <- A$geo_island |> mutate(island=fct_reorder(island, wt_pts)) |> wcsv("A3_geo_island")
ggplot(gi, aes(wt_pts, island, fill=island)) + geom_col(width=.7) +
  geom_text(aes(label=paste0(fmt(wt_pts)," (",pc1(pct),")")), hjust=-0.04, size=3, color=NAVY, fontface="bold") +
  scale_fill_manual(values=ISLAND_COLS, guide="none") +
  scale_x_continuous(labels=label_number(scale_cut=cut_short_scale()), expand=expansion(mult=c(0,.2))) +
  labs(title="Distribution of older people (≥60) served, by island · Unit: unique patients",
       subtitle="Weighted unique patients", x="Older people (weighted)", y=NULL, caption=CAP) + th()

gp <- A$geo_prov |> select(Province=prov_name, Island=island, `Sample`=raw_pts, `Weighted`=wt_pts, `%`=pct) |>
  head(15) |> wcsv("A3_geo_prov")
gt::gt(gp) |>
  gt::tab_header(title=gt::md("**Table A.3: 15 provinces with the most older people served** · _Unit: Unique patients (weighted)_")) |>
  gt::fmt_number(columns=c(Sample,Weighted),decimals=0,use_seps=TRUE) |>
  gt::data_color(columns=Weighted, colors=scales::col_numeric(c("#e3e8ee","#0b1f3a"),domain=NULL)) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table A.3: 15 provinces with the most older people served · Unit: Unique patients (weighted)
Province Island Sample Weighted %
Jawa Timur Java 36,982 5,240,006 19.0
Jawa Tengah Java 42,528 5,039,944 18.2
Jawa Barat Java 31,959 4,449,205 16.1
DKI Jakarta Java 5,697 1,316,903 4.8
Sumatera Utara Sumatra 13,548 1,247,214 4.5
Sulawesi Selatan Sulawesi 10,385 1,023,546 3.7
Banten Java 5,025 887,440 3.2
DI Yogyakarta Java 5,930 782,127 2.8
Lampung Sumatra 7,514 748,069 2.7
Sumatera Selatan Sumatra 8,393 676,056 2.4
Sumatera Barat Sumatra 5,929 625,246 2.3
Bali Bali-Nusa Tenggara 6,979 520,849 1.9
Nusa Tenggara Barat Bali-Nusa Tenggara 3,227 498,362 1.8
Aceh Sumatra 3,921 491,881 1.8
Nusa Tenggara Timur Bali-Nusa Tenggara 6,106 419,488 1.5
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)

3 First Contact: point of entry

▶ First Contact · How many older people attend · Where the first visit goes · by Age/Segment/Year
Question: How many older people actually access care, and at the first observed contact, through which door do they enter, primary care (FKTP) or directly to hospital (FKRTL outpatient/inpatient). This reflects the gatekeeping function and continuity of care for older people.
Definition of first contact

First contact = the earliest dated claim observed for each older person (≥60) within the 2015–2024 window. When FKTP and FKRTL claims share the same date, the contact is counted via FKTP (entry through primary care). Because the observation window is limited, this is the first observed contact, not necessarily the first contact in a lifetime.

3.1 How many older people attend

lvy <- A$lansia_visiting_year |> wcsv("E0_lansia_visiting_year")
ggplot(lvy, aes(yr, wt_pts)) +
  geom_col(width=.7, fill=TEAL) +
  geom_text(aes(label=label_number(scale_cut=cut_short_scale())(wt_pts)), vjust=-0.5, size=3, color=NAVY, fontface="bold") +
  yrx() + scale_y_continuous(labels=label_number(scale_cut=cut_short_scale()), expand=expansion(mult=c(0,.1))) +
  labs(title="Number of older people (≥60) attending JKN services per year · Unit: unique patients",
       subtitle=sprintf("Total unique older people who ever attended 2015–2024 (sample): %s persons | weighted per year below",
                        fmt(A$lansia_visiting_total$n_lansia_visiting)),
       x=NULL, y="Older people (weighted)", caption=CAP) + th()

3.2 Where the first visit goes

eo <- A$entry_overall |> wcsv("E1_entry_overall")
eo2 <- eo |> mutate(entry=factor(entry, levels=names(ENTRY_COLS)))
ggplot(eo2, aes(x=pct, y="", fill=entry)) + geom_col(width=.5) +
  geom_text(aes(label=paste0(pc1(pct))), position=position_stack(vjust=.5), color="white", fontface="bold", size=3.4) +
  scale_fill_manual(values=ENTRY_COLS, name=NULL) +
  scale_x_continuous(labels=scales::percent_format(scale=1), expand=expansion(mult=c(0,.02))) +
  guides(fill=guide_legend(nrow=1)) +
  labs(title="Point of first contact of older people with the JKN system · Unit: unique patients (older people)",
       subtitle="Share of older people by facility type at the first observed contact",
       x="Share of older people", y=NULL, caption=CAP) + th() + theme(axis.text.y=element_blank())

gt::gt(eo |> mutate(entry=stringr::str_remove(entry,"^[0-9] "))) |>
  gt::cols_label(entry="Point of entry (first contact)", raw="Older people (sample)", wt="Older people (weighted)", pct="%") |>
  gt::tab_header(title=gt::md("**Table FC.1: Point of first contact for older people** · _Unit: Unique patients (older people)_")) |>
  gt::fmt_number(columns=c(raw,wt),decimals=0,use_seps=TRUE) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table FC.1: Point of first contact for older people · Unit: Unique patients (older people)
Point of entry (first contact) Older people (sample) Older people (weighted) %
FKTP (Primary care) 194,992 22,347,989 79.2
Hospital outpatient (direct) 21,173 2,026,888 8.6
Hospital inpatient (direct admission) 29,910 3,264,169 12.2
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)

3.3 By age group

eb <- A$entry_band |> filter(!is.na(grp)) |> mutate(grp=factor(grp,levels=ABAND_LAB),
  entry=factor(entry, levels=names(ENTRY_COLS))) |> wcsv("E2_entry_band")
ggplot(eb, aes(grp, pct, fill=entry)) + geom_col(width=.7, position="fill") +
  geom_text(aes(label=ifelse(pct>=5,pc1(pct),"")), position=position_fill(vjust=.5), color="white", size=3, fontface="bold") +
  scale_fill_manual(values=ENTRY_COLS, name=NULL) +
  scale_y_continuous(labels=scales::percent, expand=expansion(mult=c(0,.02))) +
  guides(fill=guide_legend(nrow=1)) +
  labs(title="Point of first contact by age group · Unit: unique patients",
       subtitle="The older the group, the larger the share entering directly via hospital inpatient admission.",
       x=NULL, y="Proportion", caption=CAP) + th()

3.4 By segment & year

es <- A$entry_segment |> mutate(entry=factor(entry, levels=names(ENTRY_COLS))) |> wcsv("E3_entry_segment")
p1 <- ggplot(es, aes(pbi, pct, fill=entry)) + geom_col(width=.65, position="fill") +
  scale_fill_manual(values=ENTRY_COLS, name=NULL) +
  scale_y_continuous(labels=scales::percent, expand=expansion(mult=c(0,.02))) +
  guides(fill=guide_legend(nrow=1)) +
  labs(title="By segment (PBI vs Non-PBI)", x=NULL, y="Proportion") + th()
ey <- A$entry_year |> mutate(entry=factor(entry, levels=names(ENTRY_COLS))) |> wcsv("E4_entry_year")
p2 <- ggplot(ey, aes(yr, pct, fill=entry)) + geom_area(position="fill", color="white", linewidth=.2) +
  scale_fill_manual(values=ENTRY_COLS, name=NULL) +
  yrx() + scale_y_continuous(labels=scales::percent, expand=expansion(mult=c(0,.02))) +
  guides(fill=guide_legend(nrow=1)) +
  labs(title="By year", x=NULL, y="Proportion") + th()
(p1 | p2) + patchwork::plot_annotation(
  title="Point of first contact of older people by segment and year · Unit: unique patients",
  caption=CAP, theme=theme(plot.title=element_text(color=NAVY,face="bold",family="serif",size=13)))

3.5 Facility & reason when entering hospital directly

ec <- A$entry_fkrtl_class |> wcsv("E5_entry_fkrtl_class")
gt::gt(ec) |>
  gt::cols_label(kelas_rs="Hospital class (when entering FKRTL directly)", raw="Visits (sample)", pct="%") |>
  gt::tab_header(title=gt::md("**Table FC.2: Hospital class at first contact entering FKRTL directly** · _Unit: Unique patients (FKRTL entry)_")) |>
  gt::fmt_number(columns=raw,decimals=0,use_seps=TRUE) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table FC.2: Hospital class at first contact entering FKRTL directly · Unit: Unique patients (FKRTL entry)
Hospital class (when entering FKRTL directly) Visits (sample) %
RS Kelas C 24,923 48.8
RS Kelas B 15,284 29.9
RS Kelas D 7,541 14.8
RS Kelas A 1,784 3.5
RS Khusus/Lain 1,551 3.0
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)
ed <- A$entry_dx_top |> filter(icd3!="" & !is.na(icd3) & nchar(icd3)==3) |> head(12) |> addlab() |> wcsv("E6_entry_dx_top")
gt::gt(ed |> select(icd3, disease, raw)) |>
  gt::cols_label(icd3="ICD-10", disease="Disease (first-contact diagnosis)", raw="Visits (sample)") |>
  gt::tab_header(title=gt::md("**Table FC.3: 12 most common diagnoses at first contact of older people (code + name)** · _Unit: Visits (sample)_")) |>
  gt::fmt_number(columns=raw,decimals=0,use_seps=TRUE) |>
  gt::tab_source_note(gt::md(paste(CAP,"| Z codes (administrative contacts) excluded"))) |> gfmt()
Table FC.3: 12 most common diagnoses at first contact of older people (code + name) · Unit: Visits (sample)
ICD-10 Disease (first-contact diagnosis) Visits (sample)
I10 Essential (primary) hypertension 18,798
M79 Myalgia 10,833
J06 Acute upper respiratory infection, unspecified 8,876
K30 Dyspepsia 7,271
K29 Gastritis, unspecified 6,830
J00 Acute nasopharyngitis [common cold] 6,056
E11 Non-insulin-dependent diabetes mellitus with unspecified complications 5,691
R51 Headache 3,503
H25 Senile cataract 3,462
R50 Fever, unspecified 3,120
A09 Diarrhoea and gastroenteritis of presumed infectious origin 2,858
M54 Low back pain 2,665
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection) | Z codes (administrative contacts) excluded
Key takeaway, first contact: Most older people enter the JKN system through primary care (FKTP), but a share enter directly at hospital, and the direct-to-inpatient share rises in the oldest age groups, consistent with more severe/acute presentation in the oldest-old. The pattern by segment shows whether the point of entry differs between subsidized (PBI) and non-PBI members, an important signal for strengthening gatekeeping and early detection at the primary level.

4 Pillar B. FKTP (Primary care)

② Pillar B · FKTP volume · Top diagnoses · FKTP/Hospital coverage · Chronic disease (Prolanis)
Question: How do older people use primary care, which conditions are managed at FKTP, and how large is FKTP’s role in chronic disease management (hypertension & diabetes, the Prolanis targets).

4.1 FKTP volume & diagnoses

fd <- A$fktp_dx_top |> filter(icd3!="" & !is.na(icd3) & nchar(icd3)==3) |> head(15) |> addlab() |>
  mutate(lbl=fct_reorder(lbl, wt)) |> wcsv("B1_fktp_dx_top")
ggplot(fd, aes(wt, lbl)) + geom_col(width=.7, fill=TEAL) +
  geom_text(aes(label=fmt(wt)), hjust=-0.05, size=2.9, color=NAVY) +
  scale_x_continuous(labels=label_number(scale_cut=cut_short_scale()), expand=expansion(mult=c(0,.32))) +
  labs(title="15 most common FKTP diagnoses in older/pre-elderly people · Unit: visits (weighted)",
       subtitle="3-digit ICD-10 code + disease name, Z codes excluded", x="Visits (weighted)", y=NULL, caption=CAP) + th()

gt::gt(fd |> select(icd3, disease, raw, wt)) |>
  gt::cols_label(icd3="ICD-10", disease="Disease", raw="Visits (sample)", wt="Visits (weighted)") |>
  gt::tab_header(title=gt::md("**Table B.1: 15 most common FKTP diagnoses (code + disease name)** · _Unit: Visits_")) |>
  gt::fmt_number(columns=c(raw,wt),decimals=0,use_seps=TRUE) |>
  gt::data_color(columns=wt, colors=scales::col_numeric(c("#e3e8ee","#0b1f3a"),domain=NULL)) |>
  gt::tab_source_note(gt::md(paste(CAP,"| disease names from FKP15A"))) |> gfmt()
Table B.1: 15 most common FKTP diagnoses (code + disease name) · Unit: Visits
ICD-10 Disease Visits (sample) Visits (weighted)
I10 Essential (primary) hypertension 882,856 71,744,841
E11 Non-insulin-dependent diabetes mellitus with unspecified complications 596,534 46,833,760
M79 Myalgia 404,050 35,144,185
J06 Acute upper respiratory infection, unspecified 393,054 31,226,963
K30 Dyspepsia 280,159 21,390,740
J00 Acute nasopharyngitis [common cold] 274,862 21,672,320
K29 Gastritis, unspecified 232,162 18,779,412
R51 Headache 160,827 13,811,426
I11 Hypertensive heart disease 141,640 10,959,973
K04 Pulpitis 129,696 11,153,512
M54 Low back pain 107,546 8,103,949
R50 Fever, unspecified 103,865 8,504,834
J02 Acute pharyngitis, unspecified 95,420 6,919,873
I50 Congestive heart failure 93,149 7,749,006
I15 Secondary hypertension 86,315 5,969,524
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection) | disease names from FKP15A

4.2 Service coverage

cov <- A$coverage |> wcsv("B2_coverage")
gt::gt(cov) |>
  gt::cols_label(grpc="Service coverage (older people)", wt="Patients (weighted)", raw="Patients (sample)", pct="%") |>
  gt::tab_header(title=gt::md("**Table B.2: FKTP vs FKRTL coverage in older people** · _Unit: Unique patients (weighted)_")) |>
  gt::fmt_number(columns=c(wt,raw),decimals=0,use_seps=TRUE) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table B.2: FKTP vs FKRTL coverage in older people · Unit: Unique patients (weighted)
Service coverage (older people) Patients (weighted) Patients (sample) %
FKTP + Hospital 13,081,710 143,644 47.3
FKTP only 12,562,519 84,160 45.5
Hospital only 1,994,816 18,271 7.2
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)
prol <- A$prolanis_fktp
Chronic disease in primary care (Prolanis relevance): Among FKTP patients there are 157,929 patients with a hypertension diagnosis and 64,759 with diabetes (sample), the two main chronic conditions targeted by the JKN Chronic Disease Management Program (Prolanis). The large volume of hypertension/diabetes contacts at FKTP underscores the central role of primary care in managing chronic disease in older people.

5 Pillar C. FKRTL (Referral/Hospital)

③ Pillar C · Outpatient/Inpatient volume · LOS by age & hospital class · Severity · Top diagnoses
Question: What are the hospital care patterns for older people, length of stay (LOS), severity, hospital type, and the conditions that bring older people to inpatient care.

5.1 Utilisation volume per year

uy <- A$util_year |> wcsv("C1_util_year")
ggplot(uy, aes(yr, wt_visits, color=level)) + geom_line(linewidth=1) + geom_point(size=1.9) +
  geom_text(aes(label=label_number(accuracy=0.1, scale_cut=cut_short_scale())(wt_visits)),
            vjust=-0.9, size=2.5, fontface="bold", show.legend=FALSE) +
  scale_color_manual(values=LVL_COLS, name=NULL) +
  yrx() + scale_y_continuous(labels=label_number(scale_cut=cut_short_scale()), limits=c(0,NA), expand=expansion(mult=c(.02,.13))) +
  guides(color=guide_legend(nrow=1)) +
  labs(title="Visit volume by level of care per year (age ≥45) · Unit: visits",
       subtitle="Weighted visits. The 2020–2021 decline reflects pandemic restrictions.",
       x=NULL, y="Visits (weighted)", caption=CAP) + th()

5.2 LOS by age group

lb <- A$los_band |> filter(!is.na(grp)) |> mutate(grp=factor(grp,levels=ABAND_LAB)) |> wcsv("C2_los_band")
ggplot(lb, aes(grp, median_los, fill=grp)) + geom_col(width=.6) +
  geom_errorbar(aes(ymin=q1, ymax=q3), width=.2, color=NAVY) +
  geom_text(aes(label=median_los), vjust=-0.6, size=3.2, color=NAVY, fontface="bold") +
  scale_fill_manual(values=ABAND_COLS, guide="none") +
  scale_y_continuous(expand=expansion(mult=c(0,.12)), limits=c(0,NA)) +
  labs(title="Median length of stay (LOS) by age group · Unit: inpatient episodes",
       subtitle="Median (bars) with interquartile range (Q1–Q3). Days.",
       x=NULL, y="Median LOS (days)", caption=CAP) + th()

5.3 Severity & inpatient diagnoses

sev <- A$severity |> mutate(pct=round(100*wt/sum(wt),1)) |> wcsv("C3_severity")
gt::gt(sev) |>
  gt::cols_label(severity="Severity (FKL23, older people)", raw="Episodes (sample)", wt="Episodes (weighted)", pct="%") |>
  gt::tab_header(title=gt::md("**Table C.3: Inpatient severity in older people** · _Unit: Inpatient episodes_")) |>
  gt::fmt_number(columns=c(raw,wt),decimals=0,use_seps=TRUE) |>
  gt::tab_source_note(gt::md(paste(CAP,"| FKL23: 1=Mild, 2=Moderate, 3=Severe"))) |> gfmt()
Table C.3: Inpatient severity in older people · Unit: Inpatient episodes
Severity (FKL23, older people) Episodes (sample) Episodes (weighted) %
2 Moderate 142,144 12,729,098 63.7
3 Severe 55,411 5,078,601 25.4
9 Other 22,583 2,164,340 10.8
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection) | FKL23: 1=Mild, 2=Moderate, 3=Severe
idx <- A$fkrtl_inp_dx_top |> filter(icd3!="" & !is.na(icd3) & nchar(icd3)==3) |> head(15) |> addlab() |> wcsv("C4_inp_dx_top")
gt::gt(idx |> select(icd3, disease, raw, wt)) |>
  gt::cols_label(icd3="ICD-10", disease="Disease (inpatient diagnosis)", raw="Episodes (sample)", wt="Episodes (weighted)") |>
  gt::tab_header(title=gt::md("**Table C.4: 15 most common inpatient diagnoses in older people (code + name)** · _Unit: Inpatient episodes_")) |>
  gt::fmt_number(columns=c(raw,wt),decimals=0,use_seps=TRUE) |>
  gt::data_color(columns=wt, colors=scales::col_numeric(c("#e3e8ee","#0b1f3a"),domain=NULL)) |>
  gt::tab_source_note(gt::md(paste(CAP,"| disease names from FKL16A, Z codes excluded"))) |> gfmt()
Table C.4: 15 most common inpatient diagnoses in older people (code + name) · Unit: Inpatient episodes
ICD-10 Disease (inpatient diagnosis) Episodes (sample) Episodes (weighted)
R06 Dyspnoea 8,205 776,381
I50 Congestive heart failure 6,793 635,553
R10 Other and unspecified abdominal pain 6,614 603,008
K30 Dyspepsia 6,389 531,945
R50 Fever, unspecified 5,357 497,984
E11 Non-insulin-dependent diabetes mellitus with unspecified complications 5,251 471,383
I64 Stroke, not specified as haemorrhage or infarction 4,972 512,093
A09 Diarrhoea and gastroenteritis of presumed infectious origin 4,561 421,629
N18 Chronic kidney disease, stage 5 4,497 364,095
I10 Essential (primary) hypertension 4,002 336,761
D64 Anaemia, unspecified 3,838 343,017
J18 Bronchopneumonia, unspecified 3,778 349,262
I63 Cerebral infarction, unspecified 3,283 317,135
J44 Chronic obstructive pulmonary disease, unspecified 3,040 272,683
R11 Nausea and vomiting 2,938 261,637
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection) | disease names from FKL16A, Z codes excluded
odx <- A$fkrtl_out_dx_top |> filter(icd3!="" & !is.na(icd3) & nchar(icd3)==3) |> head(15) |> addlab() |> wcsv("C5_out_dx_top")
gt::gt(odx |> select(icd3, disease, raw, wt)) |>
  gt::cols_label(icd3="ICD-10", disease="Disease (outpatient diagnosis)", raw="Visits (sample)", wt="Visits (weighted)") |>
  gt::tab_header(title=gt::md("**Table C.5: 15 most common FKRTL outpatient diagnoses in older people (code + name)** · _Unit: Outpatient visits_")) |>
  gt::fmt_number(columns=c(raw,wt),decimals=0,use_seps=TRUE) |>
  gt::data_color(columns=wt, colors=scales::col_numeric(c("#e3e8ee","#13315c"),domain=NULL)) |>
  gt::tab_source_note(gt::md(paste(CAP,"| disease names from FKL16A, Z codes excluded"))) |> gfmt()
Table C.5: 15 most common FKRTL outpatient diagnoses in older people (code + name) · Unit: Outpatient visits
ICD-10 Disease (outpatient diagnosis) Visits (sample) Visits (weighted)
N18 Chronic kidney disease, stage 5 128,796 10,607,488
E11 Non-insulin-dependent diabetes mellitus with unspecified complications 114,785 10,690,608
I50 Congestive heart failure 95,677 8,382,589
M54 Low back pain 92,379 7,920,154
I11 Hypertensive heart disease 83,480 7,373,754
H25 Senile cataract 70,310 6,408,179
I25 Chronic ischaemic heart disease 69,007 6,555,977
I64 Stroke, not specified as haemorrhage or infarction 46,493 4,429,230
J44 Chronic obstructive pulmonary disease, unspecified 42,571 3,904,093
H26 Cataract, unspecified 41,582 3,765,020
I63 Cerebral infarction, unspecified 31,649 2,958,375
N40 Hyperplasia of prostate 30,961 3,115,673
M19 Arthrosis, unspecified 26,517 2,436,244
M51 Intervertebral disc disorder, unspecified 24,231 2,211,309
M17 narthrosis [arthrosis of knee] 23,443 2,262,922
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection) | disease names from FKL16A, Z codes excluded

6 Pillar D. Referral & Connectivity

④ Pillar D · Referral via FKTP · Referrer type · Referral geography
Question: Are inpatient admissions of older people preceded by a primary-care referral, who is the main referrer, and how far must older people travel across regions for care.
rr <- A$referral_rate_year |> wcsv("D1_referral_rate_year")
rt <- A$referrer_type |> head(8) |> wcsv("D2_referrer_type")
gt::gt(rt |> select(perujuk, raw, pct)) |>
  gt::cols_label(perujuk="Referrer type (inpatient, older people)", raw="Visits (sample)", pct="%") |>
  gt::tab_header(title=gt::md("**Table D.2: Referrer type for inpatient admissions of older people (FKL28)** · _Unit: Inpatient visits_")) |>
  gt::fmt_number(columns=raw,decimals=0,use_seps=TRUE) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table D.2: Referrer type for inpatient admissions of older people (FKL28) · Unit: Inpatient visits
Referrer type (inpatient, older people) Visits (sample) %
Hospital 176,047 83.4
Puskesmas (PHC) 21,072 10.0
GP 7,124 3.4
Primary clinic 5,162 2.4
Specialist clinic 1,536 0.7
Pharmacy 47 0.0
Other 14 0.0
Other 14 0.0
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)
rg <- A$referral_geo
rgd <- data.frame(Category=c("Within the same district/city","Cross-district (within province)","Cross-province"),
  `Visits (sample)`=c(rg$same_kab, rg$cross_kab, rg$cross_prov),
  `%`=round(100*c(rg$same_kab, rg$cross_kab, rg$cross_prov)/rg$tot,1), check.names=FALSE) |> wcsv("D3_referral_geo")
gt::gt(rgd) |>
  gt::tab_header(title=gt::md("**Table D.3: Referral geography for inpatient admissions of older people** · _Unit: Inpatient visits_")) |>
  gt::fmt_number(columns=2,decimals=0,use_seps=TRUE) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table D.3: Referral geography for inpatient admissions of older people · Unit: Inpatient visits
Category Visits (sample) %
Within the same district/city 199,367 94.5
Cross-district (within province) 9,533 4.5
Cross-province 2,132 1.0
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)
Connectivity note: The FKTP→FKRTL referral link (FKP02) is populated only ~2018–2023, so the referral-via-FKTP percentage is a lower bound. The share of cross-district/province admissions reflects travel burden and uneven distribution of referral hospitals for older people, relevant to regional geriatric-service planning (MoH Regulation 79/2014).

7 Pillar E. Member ↔︎ Facility Geography

⑤ Pillar E · Residence vs registered facility match
Question: Is the primary facility where an older person is registered located in their district of residence (nearby access), or outside the district (a potential access barrier).
mg <- A$mf_geo
mgd <- data.frame(Indicator=c("Registered facility in the same province","Registered facility in the same district/city"),
  `%`=c(mg$same_prov, mg$same_kab), check.names=FALSE) |> wcsv("E1_member_faskes")
gt::gt(mgd) |>
  gt::tab_header(title=gt::md("**Table E.1: Match between residence & registered facility (older people)** · _Unit: Members_")) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table E.1: Match between residence & registered facility (older people) · Unit: Members
Indicator %
Registered facility in the same province 96.1
Registered facility in the same district/city 90.6
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)

8 Pillar F. Geriatric Syndromes, ACSC & End-of-life

⑥ Pillar F (Theme core) · Geriatric syndromes · Avoidable admissions (ACSC) · Readmission · Mortality · End-of-life
Question: How large is the burden of classic geriatric syndromes (falls/fractures, dementia, stroke, incontinence, pressure ulcers, frailty), how many inpatient admissions of older people are avoidable with good primary care (ACSC), and what are the patterns of readmission, mortality, and end-of-life care. Indicators are mapped to the WHO Healthy Ageing/ICOPE and OECD Long-Term Care frameworks.

8.1 Geriatric syndromes (served prevalence)

gpv <- A$geriatric_prev |> filter(n_pts>0) |> mutate(syndrome=fct_reorder(syndrome, pct)) |> wcsv("F1_geriatric_prev")
ggplot(gpv, aes(pct, syndrome)) + geom_col(width=.7, fill=PURPLE) +
  geom_text(aes(label=paste0(pc1(pct)," (",fmt(wt_pts),")")), hjust=-0.04, size=2.8, color=NAVY) +
  scale_x_continuous(expand=expansion(mult=c(0,.22)), limits=c(0,NA)) +
  labs(title="Served prevalence of geriatric syndromes in older people (≥60) · Unit: unique patients",
       subtitle="% of older people served with ≥1 claim for the condition (primary or secondary diagnosis). Figures in parentheses = weighted patients.",
       x="% of older people served", y=NULL, caption=CAP) + th()

8.2 Geriatric syndromes by age

gbb <- A$geriatric_by_band |> filter(!is.na(grp)) |>
  group_by(key) |> filter(max(pct)>=1) |> ungroup() |>
  mutate(grp=factor(grp,levels=ABAND_LAB)) |> wcsv("F2_geriatric_by_band")
ggplot(gbb, aes(grp, pct, group=syndrome, color=syndrome)) +
  geom_line(linewidth=.8) + geom_point(size=1.6) +
  scale_y_continuous(limits=c(0,NA)) +
  labs(title="Gradient of geriatric syndromes by age group · Unit: unique patients",
       subtitle="% served per age group (conditions with ≥1% prevalence shown). Burden rises sharply with age.",
       x=NULL, y="% served", color=NULL, caption=CAP) + th() +
  guides(color=guide_legend(nrow=3))

8.3 Avoidable admissions (ACSC)

Ambulatory Care Sensitive Conditions (ACSC)

ACSC (OECD HCQI framework) = conditions that should be manageable in primary care, so their inpatient admissions are potentially avoidable (heart failure, hypertension, diabetes complications, COPD, asthma, pneumonia, UTI, dehydration, angina, cellulitis). A high ACSC share signals an opportunity to strengthen primary care for older people.

ab <- A$acsc_breakdown |> filter(n_adm>0) |> mutate(condition=fct_reorder(condition, n_adm)) |> wcsv("F3_acsc_breakdown")
ov <- A$acsc_overall
ggplot(ab, aes(n_adm, condition)) + geom_col(width=.7, fill=AMBER) +
  geom_text(aes(label=fmt(n_adm)), hjust=-0.05, size=2.9, color=NAVY) +
  scale_x_continuous(labels=label_number(scale_cut=cut_short_scale()), expand=expansion(mult=c(0,.16))) +
  labs(title="Inpatient admissions of older people for avoidable conditions (ACSC) · Unit: inpatient episodes",
       subtitle=sprintf("A total of %s of %s inpatient admissions of older people (%s) are from ACSC conditions",
                        fmt(ov$n_acsc), fmt(ov$n_adm), pc1(ov$pct_acsc)),
       x="Inpatient episodes (sample)", y=NULL, caption=CAP) + th()

8.4 Readmission, mortality & end-of-life

rd <- A$readmit
po <- A$polypharmacy_proxy
mo <- A$mort_overall
eol <- A$eol
out <- data.frame(
  Indicator=c("30-day readmission (all-cause)","90-day readmission (all-cause)",
              "Older people with ≥2 chronic conditions (medication-burden proxy)","Older people with ≥3 chronic conditions",
              "Crude mortality of older people (PSTV18, undercount)",
              "Mean admissions in year of death","Mean FKRTL cost in year of death (Rp)"),
  Value=c(pc1(rd$readmit30_pct), pc1(rd$readmit90_pct), pc1(po$pct_mm2), pc1(po$pct_mm3),
          pc1(mo$crude_pct), formatC(eol$mean_adm_death_yr,format="f",digits=2),
          fmt(eol$mean_cost_death_yr))) |> wcsv("F4_outcomes")
gt::gt(out) |>
  gt::tab_header(title=gt::md("**Table F.4: Readmission, mortality & end-of-life (older people ≥60)** · _Unit: mixed (see row)_")) |>
  gt::tab_source_note(gt::md(paste(CAP,"| mortality via PSTV18 only for snapshot years, undercount; polypharmacy not directly measurable (no dispensing data), chronic-condition count used as proxy"))) |> gfmt()
Table F.4: Readmission, mortality & end-of-life (older people ≥60) · Unit: mixed (see row)
Indicator Value
30-day readmission (all-cause) 16.1%
90-day readmission (all-cause) 25.8%
Older people with ≥2 chronic conditions (medication-burden proxy) 37.4%
Older people with ≥3 chronic conditions 20.8%
Crude mortality of older people (PSTV18, undercount) 16.5%
Mean admissions in year of death 0.61
Mean FKRTL cost in year of death (Rp) 6,236,232
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection) | mortality via PSTV18 only for snapshot years, undercount; polypharmacy not directly measurable (no dispensing data), chronic-condition count used as proxy
Proxy note (required). True polypharmacy (≥5 concurrent medications) and potentially inappropriate medications (Beers/STOPP criteria) require drug-dispensing data that is incomplete in this sample, so only a chronic-condition-count proxy is presented. Mortality uses year of death (PSTV18), populated only for snapshot years, and in-hospital death (FKL14=3), both undercounts. End-of-life figures describe patterns within JKN, not all end-of-life care.

9 Pillar G. Multimorbidity

⑦ Pillar G · Number of chronic conditions · by Age · Chronic disease prevalence · Top combinations
Question: How many older people carry more than one chronic disease at once (multimorbidity), how does this gradient vary by age, and which disease combinations co-occur most often, the core of integrated long-term-care need.

9.1 Distribution of number of chronic conditions

md <- A$mm_dist |> mutate(mm_cat=factor(mm_cat, levels=c("0","1","2","3","4+"))) |> wcsv("G1_mm_dist")
ggplot(md, aes(mm_cat, pct, fill=mm_cat)) + geom_col(width=.7) +
  geom_text(aes(label=pc1(pct)), vjust=-0.5, size=3.2, color=NAVY, fontface="bold") +
  scale_fill_manual(values=c("0"=LGRAY,"1"=MIST,"2"=SLATE,"3"=NAVY2,"4+"=INK), guide="none") +
  scale_y_continuous(expand=expansion(mult=c(0,.12)), limits=c(0,NA)) +
  labs(title="Distribution of number of chronic diseases in older people (≥60) · Unit: unique patients",
       subtitle="Across 14 chronic-disease categories (see Pillar F/G). Weighted.",
       x="Number of chronic conditions", y="% of older people", caption=CAP) + th()

9.2 Multimorbidity by age

mb <- A$mm_by_band |> filter(!is.na(grp)) |> mutate(grp=factor(grp,levels=ABAND_LAB)) |> arrange(grp) |> wcsv("G2_mm_by_band")
gt::gt(mb) |>
  gt::cols_label(grp="Age group", n="Patients (sample)", mean_ncc="Mean number of conditions",
                 pct_mm2="≥2 conditions (%)", pct_mm3="≥3 conditions (%)") |>
  gt::tab_header(title=gt::md("**Table G.2: Multimorbidity by age group** · _Unit: Unique patients_")) |>
  gt::fmt_number(columns=n,decimals=0,use_seps=TRUE) |>
  gt::data_color(columns=pct_mm2, colors=scales::col_numeric(c("#e3e8ee","#274060"),domain=NULL)) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table G.2: Multimorbidity by age group · Unit: Unique patients
Age group Patients (sample) Mean number of conditions ≥2 conditions (%) ≥3 conditions (%)
Pre-elderly (45–59) 344,048 0.79 19.8 9.3
Young-old (60–69) 148,307 1.41 37.2 20.5
Middle-old (70–79) 70,965 1.52 39.6 22.4
Oldest-old (80+) 26,803 1.28 32.7 17.9
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)

9.3 Chronic disease prevalence & top combinations

cp <- A$chronic_prev |> mutate(condition=fct_reorder(condition, pct)) |> wcsv("G3_chronic_prev")
ggplot(cp, aes(pct, condition)) + geom_col(width=.7, fill=BLUE) +
  geom_text(aes(label=pc1(pct)), hjust=-0.05, size=2.9, color=NAVY) +
  scale_x_continuous(expand=expansion(mult=c(0,.12)), limits=c(0,NA)) +
  labs(title="Served prevalence of chronic disease in older people (≥60) · Unit: unique patients",
       subtitle="% of older people served with ≥1 claim for the condition (primary or secondary diagnosis, FKTP+FKRTL)",
       x="% of older people served", y=NULL, caption=CAP) + th()

ht_served <- A$chronic_prev$pct[A$chronic_prev$key=="ht"]
dm_served <- A$chronic_prev$pct[A$chronic_prev$key=="dm"]
Treatment-gap triangulation (hypertension in older people). The SKI 2023 survey measured measured hypertension prevalence in older people at 49.5% (age 60–64) up to 64.0% (75+), yet only 8.6% of adults had ever been diagnosed by a doctor. In these claims data, served hypertension is recorded in 46.6% of older people (and diabetes 18.6%). The gap between community-measured prevalence and the served/diagnosed figure confirms that claims figures are a served population, not true burden, and that early detection of hypertension/diabetes in older people at primary care remains well below need. Ratio figures are illustrative because denominators and definitions differ (measured vs diagnosed vs cumulative-served).
dy <- A$mm_dyads |> head(12) |> wcsv("G4_mm_dyads")
gt::gt(dy) |>
  gt::cols_label(pair="Pair of chronic diseases (older people)", n_pts="Patients (sample)", wt_pts="Patients (weighted)") |>
  gt::tab_header(title=gt::md("**Table G.4: 12 most common chronic-disease pairs in older people** · _Unit: Unique patients_")) |>
  gt::fmt_number(columns=c(n_pts,wt_pts),decimals=0,use_seps=TRUE) |>
  gt::data_color(columns=wt_pts, colors=scales::col_numeric(c("#e3e8ee","#0b1f3a"),domain=NULL)) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table G.4: 12 most common chronic-disease pairs in older people · Unit: Unique patients
Pair of chronic diseases (older people) Patients (sample) Patients (weighted)
Hypertension (I10–15) + Diabetes (E10–14) 34,153 2,991,684
Hypertension (I10–15) + Osteoarthritis (M15–19) 24,324 2,032,967
Hypertension (I10–15) + Ischaemic heart disease (I20–25) 21,257 1,866,315
Hypertension (I10–15) + Chronic lung disease (J40–47) 20,564 1,728,422
Hypertension (I10–15) + Heart failure (I50) 20,322 1,770,193
Hypertension (I10–15) + Stroke (I60–69) 18,866 1,686,076
Ischaemic heart disease (I20–25) + Heart failure (I50) 14,465 1,289,282
Diabetes (E10–14) + Osteoarthritis (M15–19) 11,591 956,943
Hypertension (I10–15) + Anaemia (D50–64) 10,988 927,286
Diabetes (E10–14) + Ischaemic heart disease (I20–25) 10,631 944,642
Hypertension (I10–15) + Chronic kidney disease (N17–19) 9,783 869,967
Diabetes (E10–14) + Heart failure (I50) 9,675 851,192
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)
Key takeaway, multimorbidity: Most older people served carry more than one chronic disease at once, and the count rises sharply with age. The dominance of cardiometabolic combinations (hypertension, diabetes, heart, kidney) underscores the need for integrated person-centred care (ICOPE) rather than fragmented single-disease services, and the direct link to long-term-care need.

10 Pillar H. Economics

⑧ Pillar H · Cost trend · Cost by age & setting · Per-capita cost · Top INA-CBG · Concentration (Pareto)
Question: How large is JKN spending on care for older people, how is it distributed by age, care setting, and number of chronic conditions, and how concentrated is spending in a small share of high-cost patients.

10.1 Cost trend & composition

cy <- A$cost_year |> wcsv("H1_cost_year")
ggplot(cy, aes(yr, total_bil_idr/1000)) + geom_col(width=.7, fill=NAVY) +
  geom_text(aes(label=formatC(total_bil_idr/1000,format="f",digits=1)), vjust=-0.5, size=2.8, color=NAVY) +
  yrx() + scale_y_continuous(expand=expansion(mult=c(0,.12)), limits=c(0,NA)) +
  labs(title="JKN FKRTL spending on older people (≥60) per year · Unit: claims (weighted cost)",
       subtitle="Trillion Rupiah, national projection (FKL47 × PSTV15 weight)", x=NULL, y="Trillion Rp", caption=CAP) + th()

10.2 Per-capita cost by age

cpb <- A$cost_percapita_band |> filter(!is.na(grp)) |> mutate(grp=factor(grp,levels=ABAND_LAB)) |> arrange(grp) |> wcsv("H2_cost_percapita_band")
gt::gt(cpb) |>
  gt::cols_label(grp="Age group", n="Patients (sample)", wt_pts="Patients (weighted)",
                 tot_cost_bil="Total cost (billion Rp)", mean_cost_pp="Mean cost/patient (Rp)") |>
  gt::tab_header(title=gt::md("**Table H.2: FKRTL per-capita cost by age group** · _Unit: Unique patients_")) |>
  gt::fmt_number(columns=c(n,wt_pts,tot_cost_bil,mean_cost_pp),decimals=0,use_seps=TRUE) |>
  gt::data_color(columns=mean_cost_pp, colors=scales::col_numeric(c("#e3e8ee","#0b1f3a"),domain=NULL)) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table H.2: FKRTL per-capita cost by age group · Unit: Unique patients
Age group Patients (sample) Patients (weighted) Total cost (billion Rp) Mean cost/patient (Rp)
Pre-elderly (45–59) 344,048 35,997,105 168,057 11,239,001
Young-old (60–69) 148,307 15,836,344 130,063 14,875,759
Middle-old (70–79) 70,965 8,179,931 69,669 14,986,629
Oldest-old (80+) 26,803 3,622,770 21,401 12,705,107
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)

10.3 Top INA-CBG & cost concentration

cb <- A$cbg_top |> head(12) |> wcsv("H3_cbg_top")
gt::gt(cb) |>
  gt::cols_label(cbg="INA-CBG (older people)", n_claims="Claims (sample)", total_bil_idr="Total (billion Rp)", mean_cost="Mean/claim (Rp)") |>
  gt::tab_header(title=gt::md("**Table H.3: 12 INA-CBG with the most claims in older people** · _Unit: Claims_")) |>
  gt::fmt_number(columns=c(n_claims,total_bil_idr,mean_cost),decimals=0,use_seps=TRUE) |>
  gt::tab_source_note(gt::md(CAP)) |> gfmt()
Table H.3: 12 INA-CBG with the most claims in older people · Unit: Claims
INA-CBG (older people) Claims (sample) Total (billion Rp) Mean/claim (Rp)
PENYAKIT KRONIS KECIL LAIN-LAIN 1,259,668 22,069 199,751
PROSEDUR THERAPI FISIK DAN PROSEDUR KECIL MUSKULOSKLETAL 200,847 2,182 125,262
PROSEDUR DIALISIS 145,842 10,248 862,705
730 106,164 1,820 182,227
PROSEDUR LAIN-LAIN PADA MATA 68,077 1,339 236,445
KONSULTASI ATAU PEMERIKSAAN LAIN-LAIN 46,775 615 143,550
PENYAKIT KRONIS KECIL LAINLAIN 46,622 851 196,154
PROSEDUR REHABILITASI 44,325 604 159,278
PERAWATAN LUKA 38,720 683 197,655
PENYAKIT AKUT KECIL LAIN-LAIN 24,145 411 197,209
PROSEDUR ULTRASOUND LAIN-LAIN 23,366 1,171 582,906
PROSEDUR OPERASI KATARAK 22,406 13,047 6,555,477
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection)
pareto <- A$pareto |> wcsv("H4_pareto")
gt::gt(pareto) |>
  gt::cols_label(top_pct="Top % of patients (highest cost)", spend_share="Share of total spend (%)") |>
  gt::tab_header(title=gt::md("**Table H.4: Spending concentration (Pareto) in older people** · _Unit: Unique patients (weighted)_")) |>
  gt::tab_source_note(gt::md(paste(CAP,sprintf("| Cumulative FKRTL spending on older people ~Rp %s trillion (weighted)", formatC(A$cost_total_bil_lansia/1000,format="f",digits=1))))) |> gfmt()
Table H.4: Spending concentration (Pareto) in older people · Unit: Unique patients (weighted)
Top % of patients (highest cost) Share of total spend (%)
1 15.5
5 36.9
10 51.2
20 68.1
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection) | Cumulative FKRTL spending on older people ~Rp 221.1 trillion (weighted)
Key takeaway, economics: Hospital care cost per older person rises with age and number of chronic diseases, and spending is highly concentrated (a small share of high-cost patients absorbs a large share). This underscores the value of investing in preventing avoidable admissions (ACSC) and managing multimorbidity in primary care to contain the growth of curative spending on older people.

11 Pillar I. Equity & Utilisation vs Population

⑨ Pillar I · Served rate by province · Segment (SES) gradient · Representation index
Question: Is utilisation of care for older people even across regions and socioeconomic segments, or does it show inequity (the inverse care law), and does the served composition represent the general elderly population.

11.1 Served rate by province

sr <- A$served_rate_prov |> filter(!is.na(rate_per1000)) |> arrange(desc(rate_per1000)) |> head(20) |>
  mutate(prov_name=fct_reorder(prov_name, rate_per1000)) |> wcsv("I1_served_rate_prov")
ggplot(sr, aes(rate_per1000, prov_name, fill=island)) + geom_col(width=.72) +
  geom_text(aes(label=fmt(rate_per1000)), hjust=-0.06, size=2.7, color=NAVY) +
  scale_fill_manual(values=ISLAND_COLS, name=NULL) +
  scale_x_continuous(expand=expansion(mult=c(0,.14)), limits=c(0,NA)) +
  labs(title="Older people served per 1,000 older members, by province · Unit: unique patients",
       subtitle="Older people served (≥1 claim) ÷ registered older members (reguler sample) × 1,000",
       x="Older people served per 1,000 older members", y=NULL, caption=CAP) + th()

11.2 Socioeconomic gradient (segment)

eq <- A$equity_segment |> select(segmen, pbi, n_pts, served_rate_per1000, mean_visits, pct_inp, mean_cost_pp, mean_ncc) |> wcsv("I2_equity_segment")
gt::gt(eq) |>
  gt::cols_label(segmen="Membership segment", pbi="Group", n_pts="Patients (sample)",
                 served_rate_per1000="Served /1,000", mean_visits="Mean visits",
                 pct_inp="% ever admitted", mean_cost_pp="Mean cost/patient (Rp)", mean_ncc="Mean chronic conditions") |>
  gt::tab_header(title=gt::md("**Table I.2: Utilisation & served rate of older people by segment (SES)** · _Unit: Unique patients_")) |>
  gt::fmt_number(columns=c(n_pts,served_rate_per1000,mean_cost_pp),decimals=0,use_seps=TRUE) |>
  gt::data_color(columns=served_rate_per1000, colors=scales::col_numeric(c("#e3e8ee","#13315c"),domain=NULL)) |>
  gt::tab_source_note(gt::md(paste(CAP,"| PBI = subsidized-premium members; Non-PBI = self-paying/salaried"))) |> gfmt()
Table I.2: Utilisation & served rate of older people by segment (SES) · Unit: Unique patients
Membership segment Group Patients (sample) Served /1,000 Mean visits % ever admitted Mean cost/patient (Rp) Mean chronic conditions
PBPU (self-paying) Non-PBI 66,267 630 36.9 53.0 19,432,831 1.73
PBI APBN PBI (subsidized) 93,324 585 23.0 34.8 9,000,417 0.97
Non-worker Non-PBI 47,147 508 49.6 55.8 20,254,878 1.93
PBI APBD PBI (subsidized) 25,632 458 25.5 42.2 11,582,548 1.23
PPU (salaried) Non-PBI 13,705 428 43.8 51.0 19,393,674 1.74
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection) | PBI = subsidized-premium members; Non-PBI = self-paying/salaried

11.3 Representation index vs general elderly population

ri <- A$repr_index |> filter(!is.na(repr)) |> arrange(desc(abs(repr-1))) |> head(14) |> wcsv("I3_repr_index")
gt::gt(ri) |>
  gt::cols_label(char="Characteristic", level="Category", Overall="Served %", GeneralPop="Elderly GenPop %", repr="Representation index") |>
  gt::tab_header(title=gt::md("**Table I.3: Representation index, older people served vs general elderly population** · _Unit: Unique patients_")) |>
  gt::fmt_number(columns=c(Overall,GeneralPop),decimals=1) |>
  gt::fmt_number(columns=repr,decimals=2) |>
  gt::data_color(columns=repr, colors=scales::col_numeric(c("#c7d2dd","#f3f5f8","#0b1f3a"),domain=c(0,2))) |>
  gt::tab_source_note(gt::md(paste(CAP,"| Index >1 = over-representation among those served, <1 = under-representation"))) |> gfmt()
Table I.3: Representation index, older people served vs general elderly population · Unit: Unique patients
Characteristic Category Served % Elderly GenPop % Representation index
Island Maluku-Papua 1.2 6.4 0.19
Age group Oldest-old (80+) 13.1 22.5 0.58
Membership segment PPU (salaried) 3.8 4.9 0.78
Membership segment PBI APBD 13.9 16.6 0.84
Age group Young-old (60–69) 57.3 49.8 1.15
Membership segment PBPU (self-paying) 14.5 12.6 1.15
Ward class Class II 9.0 10.3 0.87
Island Jawa 64.4 59.5 1.08
Age group Middle-old (70–79) 29.6 27.7 1.07
Membership segment PBI APBN 51.5 48.3 1.07
Membership segment Non-worker 16.3 17.6 0.93
Island Kalimantan 3.9 4.2 0.93
Island Sulawesi 7.5 7.1 1.06
Sex Female 52.1 50.6 1.03
Source: BPJS Kesehatan Sample Data 2015–2024 | reguler (~1% household) sample | age ≥60 (45–59 comparator) | PSTV15-weighted (national JKN-member projection) | Index >1 = over-representation among those served, <1 = under-representation
Key takeaway, equity: The served rate per 1,000 older members varies across provinces, and utilisation and per-patient spending differ across membership segments. Regions with low served rates and segments with low utilisation relative to need flag potential uneven access for older people, a priority target for strengthening geriatric services and community-based long-term care.

12 Limitations & next steps

Main limitations. 1. JKN claims capture only older people who reach a facility and whose claim is recorded, not the entire elderly population, so all figures are a served population, not true prevalence.
2. Non-claim program-based services (Posyandu/Posbindu Lansia, some drug programs) are not recorded, so community chronic-disease management is under-captured.
3. There are no laboratory/vital values, so blood-pressure and blood-glucose control cannot be computed. Drug-dispensing data are incomplete, so polypharmacy and inappropriate medications are only a chronic-condition-count proxy.
4. Mortality (PSTV18, FKL14=3) is under-captured, only snapshot years and in-hospital deaths, so end-of-life indicators are indicative.
5. The FKTP→FKRTL referral link (FKP02) is populated only ~2018–2023, so the referral-via-FKTP proportion is a lower bound.
6. Geriatric syndromes and chronic diseases depend on diagnostic coding (primary + secondary); uncoded conditions (e.g. frailty, malnutrition, mild sensory impairment) will be undercounted.

Next steps. 1. Cross-validate with community benchmarks (SKI 2023/Riskesdas 2018, BPS Elderly Population Statistics) for an elderly treatment-gap framework.
2. Integrate dispensing data (Non-Capitation/pharmacy) to compute polypharmacy and potentially inappropriate medications (Beers/STOPP).
3. Deeper long-term-care analysis (dependent older people, continuity of care) linked to functional/disability data (see ARC12.2 Disability).
4. District-level mapping of served rate and geriatric-service availability (hospitals with geriatric clinics, MoH Regulation 79/2014).

13 Indicator framework & references

International indicator frameworks used

Indicators in this report are mapped to internationally recognised ageing and long-term-care frameworks, with feasibility from claims data: WHO Decade of Healthy Ageing 2021–2030 and WHO ICOPE (intrinsic capacity: locomotor, vitality, cognition, psychological, sensory, approximated via downstream diagnoses); OECD Health Care Quality Outcomes (avoidable admissions/ACSC, 30-day readmission, timeliness of hip-fracture surgery); OECD Long-Term Care (structural LTC recipient/workforce/spending indicators are external, not in claims); the concepts of geriatric giants and multimorbidity (Barnett 2012; Quan 2005 comorbidity algorithms); and Indonesian policy (Law 13/1998, MoH Regulation 67/2015, MoH Regulation 79/2014, Prolanis). Coding note: BPJS uses WHO ICD-10 (unspecified diabetes E14; dementia F00–F03 with G30), and sarcopenia has no WHO ICD-10 code so it cannot be computed. Polypharmacy and potentially inappropriate medications (Beers/STOPP-START) require incomplete drug-dispensing data, so only a proxy is presented.

Key references

WHO. UN Decade of Healthy Ageing: Plan of Action 2021–2030 (2020). · WHO. Integrated Care for Older People (ICOPE) Guidelines (2017). · OECD. Health at a Glance 2023 & 2025; HCQO Indicator Definitions (2023). · Barnett K et al. Epidemiology of multimorbidity. Lancet 2012;380:37–43. · Quan H et al. Coding algorithms for comorbidities in ICD-10 administrative data. Med Care 2005;43:1130–9. · Law No. 13 of 1998 on the Welfare of Older Persons. · MoH Regulation No. 67 of 2015 (health services for older people at puskesmas); MoH Regulation No. 79 of 2014 (geriatric services in hospitals). · BPS. Older Population Statistics 2023. · Ministry of Health RI. Key Results of the Indonesia Health Survey (SKI) 2023.

## consolidated multi-sheet workbook
if (requireNamespace("writexl", quietly=TRUE)) {
  sheets <- list(
    INDEX=data.frame(Sheet=c("cohort_flow","table1","strata_usia","prev_year","entry","geriatric","acsc",
      "multimorbidity","chronic_prev","cost","equity"),
      Keterangan=c("STROBE cohort flow","Characteristics vs elderly population","Age distribution",
      "Older people served per year","Point of first contact","Geriatric syndromes",
      "Avoidable admissions","Multimorbidity distribution","Chronic disease prevalence",
      "Per-capita cost & INA-CBG","Equity by segment & province")),
    cohort_flow=A$cohort_flow, table1=A$table1, strata_usia=A$strata_patient,
    prev_year=A$prev_year_total, entry=A$entry_overall, geriatric=A$geriatric_prev,
    acsc=A$acsc_breakdown, multimorbidity=A$mm_dist, chronic_prev=A$chronic_prev,
    cost=A$cost_percapita_band, equity=A$equity_segment)
  sheets <- lapply(sheets, as.data.frame)
  names(sheets) <- substr(names(sheets),1,31)
  writexl::write_xlsx(sheets, file.path(OUT_DIR,"tables_aging_ltc_jkn.xlsx"))
}
cat("Artifacts exported to:", normalizePath(OUT_DIR), "\n")
## Artifacts exported to: /opt/project_center_mirror/ARC12. Aging and Chronic Disease Institute/12.3 Aging & LTC JKN Claims/analysis/outputs

Health-system analysis based on aggregate administrative data (BPJS Kesehatan Sample Data). All population figures are weighted projections from the sample and represent the JKN-served population.