Phase 1: @source/ Restructure
- Purpose: Reorganize source files into raw/, clean/, config/ subdirectories and update all YAML config paths
T-001 - Create @source/ subdirectories and move xlsx files
Create @source/raw/, @source/clean/, and verify @source/config/ exists. Move all xlsx files from @source/ root into @source/raw/. Add .gitkeep to @source/clean/.
- Status: completed
- Priority: P0
- Dependencies: none
Acceptance
-
@source/raw/exists and contains all 8 xlsx files (4 LAPORAN + 4 DATABASE SISWA) -
@source/clean/exists with.gitkeep -
@source/config/unchanged - Original xlsx files removed from
@source/root -
@source/Contoh punya TM WLC.pdfmoved to@source/raw/(keep with source data)
Files
- @source/raw/ (new directory)
- @source/clean/.gitkeep (new)
T-002 - Update @source/config YAML paths
Update all four @source/config/ions-YYYY.yaml files: change every path: @source/LAPORAN... and path: @source/DATABASE... to path: @source/raw/LAPORAN... and path: @source/raw/DATABASE....
- Status: completed
- Priority: P0
- Dependencies: T-001
Acceptance
-
ions-2023.yamlallpath:values reference@source/raw/ -
ions-2024.yamlallpath:values reference@source/raw/ -
ions-2025.yamlallpath:values reference@source/raw/ -
ions-2026.yamlallpath:values reference@source/raw/ -
pnpm run sync -- --source xlsx --entity IONS --year 2026still resolves paths correctly (loadConfig finds @source/raw/ files)
Files
- @source/config/ions-2023.yaml
- @source/config/ions-2024.yaml
- @source/config/ions-2025.yaml
- @source/config/ions-2026.yaml
Phase 2: @python/ Workspace
- Purpose: Add @python/ as a new workspace prefix and move @packages/transform into it
T-003 - Add @python/ workspace prefix to pnpm-workspace.yaml
Add @python/** to the packages list in pnpm-workspace.yaml. Create the @python/ directory at monorepo root.
- Status: completed
- Priority: P0
- Dependencies: none
Acceptance
-
pnpm-workspace.yamlpackages list includes- '@python/**' -
@python/directory exists at monorepo root
Files
- pnpm-workspace.yaml
- @python/ (new directory)
T-004 - Move @packages/transform → @python/analytics
Copy the entire @packages/transform/ directory to @python/analytics/. Update pyproject.toml name from atlas-transform to atlas-analytics. Update profiles.yml if path depth changed (verify ../../atlas.db is still correct from @python/analytics/). Remove @packages/transform/ after verifying.
- Status: completed
- Priority: P0
- Dependencies: T-003
Acceptance
-
@python/analytics/exists with all dbt files at root:dbt_project.yml,profiles.yml,pyproject.toml,models/,macros/,tests/ -
pyproject.tomlname = "atlas-analytics" -
profiles.ymlpath:resolves correctly toatlas.dbat monorepo root (two levels up from@python/analytics/) -
cd @python/analytics && uv run dbt debugconnects without error -
cd @python/analytics && uv run dbt runruns all models successfully -
@packages/transform/removed
Notes
.venv/,target/,logs/,dbt_packages/,.user.yml,uv.lockfrom the old directory can be recreated — copy only the tracked files (pyproject.toml, requirements.txt, profiles.yml, dbt_project.yml, models/, macros/, tests/)- The
.gitignorein@packages/transform/should also be copied to@python/analytics/
Files
- @python/analytics/pyproject.toml
- @python/analytics/profiles.yml
- @python/analytics/dbt_project.yml
- @python/analytics/requirements.txt
- @python/analytics/.gitignore
Phase 3: @packages/pipeline
- Purpose: Create new unified TypeScript package merging sync + format sources
T-005 - Scaffold @packages/pipeline package
Create @packages/pipeline/ with package.json, tsconfig.json, eslint.config.mjs. Set up Vitest in this task as the test runner (dependency + config). The package replaces both @packages/sync and @packages/format.
- Status: completed
- Priority: P0
- Dependencies: none
Acceptance
-
@packages/pipeline/package.jsonexists with name@packages/pipeline, scripts:build,dev,lint,lint:fix,test,test:type,start -
testscript usesvitest run(notnode --test) - Dependencies include:
@duckdb/node-api,@libsql/client,@packages/db,yaml,xlsx(all via catalog references) - DevDependencies include:
@core/lint,@core/typescript,@types/node,tsx,typescript,vitest -
tsconfig.jsonextends@core/typescript/lib(same as current sync) -
eslint.config.mjsusesbase()from@core/lint/base - Vitest catalog entry added to
pnpm-workspace.yamlif not already present -
pnpm installresolves without errors
Notes
- Check if
vitestis already in a catalog inpnpm-workspace.yamlbefore adding xlsxcatalog entry already exists ascatalog:utilinpnpm-workspace.yaml
Files
- @packages/pipeline/package.json
- @packages/pipeline/tsconfig.json
- @packages/pipeline/eslint.config.mjs
- pnpm-workspace.yaml (vitest catalog entry if needed)
T-006 - Migrate @packages/sync source into @packages/pipeline
Copy all source files from @packages/sync/@source/ into @packages/pipeline/@source/. Organize into subdirectories: config.ts and duck.ts stay at @source/ root; seed.ts stays at root; adapter moves to load/csv.ts (renamed from adapters/xlsx.ts). Fix all imports.
- Status: completed
- Priority: P0
- Dependencies: T-005
Acceptance
-
@packages/pipeline/@source/config.tsexists (unchanged from sync) -
@packages/pipeline/@source/duck.tsexists — merged from both sync'sduck.tsand format'sduck.ts; uses the richerDuckClientinterface from format's version, extended with the raw-table DDL helpers from sync's version -
@packages/pipeline/@source/seed.tsexists (unchanged from sync) -
@packages/pipeline/@source/load/csv.tsexists (renamed fromadapters/xlsx.ts; logic unchanged for now — still reads xlsx directly; Plan 009 will switch to CSV) - All imports updated to reflect new paths
-
pnpm --filter @packages/pipeline test:typepasses
Notes
- The two
duck.tsfiles have different shapes: sync'sduck.tshas raw DDL helpers (createRawTable,appendRawTable, etc.); format'sduck.tshas theDuckClientquery wrapper. Merge both into one@source/duck.ts— export all helpers from sync plus theDuckClientfactory from format.
Files
- @packages/pipeline/@source/config.ts
- @packages/pipeline/@source/duck.ts
- @packages/pipeline/@source/seed.ts
- @packages/pipeline/@source/load/csv.ts
T-007 - Migrate @packages/format source into @packages/pipeline
Copy all source files from @packages/format/@source/ into @packages/pipeline/@source/format/. Fix imports (duck client now comes from ../duck). Preserve all exports.
- Status: completed
- Priority: P0
- Dependencies: T-006
Acceptance
-
@packages/pipeline/@source/format/report.tsexists -
@packages/pipeline/@source/format/types.tsexists -
@packages/pipeline/@source/format/number.tsexists -
@packages/pipeline/@source/format/sections/revenue.tsexists -
@packages/pipeline/@source/format/sections/orders.tsexists -
@packages/pipeline/@source/format/sections/marketing.tsexists -
@packages/pipeline/@source/format/sections/schools.tsexists - All imports pointing to the old
duck.tsupdated to../duck(or../../duckas appropriate) -
pnpm --filter @packages/pipeline test:typepasses
Files
- @packages/pipeline/@source/format/report.ts
- @packages/pipeline/@source/format/types.ts
- @packages/pipeline/@source/format/number.ts
- @packages/pipeline/@source/format/sections/revenue.ts
- @packages/pipeline/@source/format/sections/orders.ts
- @packages/pipeline/@source/format/sections/marketing.ts
- @packages/pipeline/@source/format/sections/schools.ts
T-008 - Create stub extract/ and validate/ directories
Create placeholder modules for the extract and validate steps that Plan 009 will implement. These stubs make the CLI wiring complete without requiring Plan 009's logic now.
- Status: completed
- Priority: P1
- Dependencies: T-006
Acceptance
-
@packages/pipeline/@source/extract/index.tsexists — exports aextract()stub that logs "extract: not yet implemented" and returns -
@packages/pipeline/@source/validate/index.tsexists — exports avalidate()stub that logs "validate: not yet implemented" and returns - Both files type-check cleanly
Files
- @packages/pipeline/@source/extract/index.ts
- @packages/pipeline/@source/validate/index.ts
T-009 - Create unified CLI index.ts
Create @packages/pipeline/@source/index.ts with sub-command dispatch. Sub-commands: extract, load, validate, format, seed, run. Shared flags: --entity, --year, --month, --period, --mode. The run sub-command sequences: extract → load → validate → (dbt is external) → format.
- Status: completed
- Priority: P0
- Dependencies: T-007, T-008
Acceptance
-
pnpm --filter @packages/pipeline start -- load --entity IONS --year 2026runs the xlsx load (same behavior as old@packages/sync) -
pnpm --filter @packages/pipeline start -- format --entity IONS --period 2026-02runs report assembly (same behavior as old@packages/format) -
pnpm --filter @packages/pipeline start -- seed --entity IONSruns seed (same behavior as old sync seed) -
pnpm --filter @packages/pipeline start -- extract --entity IONS --year 2026logs "extract: not yet implemented" -
pnpm --filter @packages/pipeline start -- validate --entity IONS --year 2026logs "validate: not yet implemented" - Unknown sub-command prints usage and exits non-zero
-
pnpm --filter @packages/pipeline test:typepasses
Files
- @packages/pipeline/@source/index.ts
Phase 4: Vitest Tests
- Purpose: Add Vitest test scaffold with passing tests for pure utility functions
T-010 - Add Vitest scaffold and initial tests
Add a vitest.config.ts and write initial unit tests for the most testable pure functions: config.ts (path normalization), format/number.ts (toNumber, roundTo2), and the CLI arg parser in index.ts.
- Status: completed
- Priority: P1
- Dependencies: T-009
Acceptance
-
@packages/pipeline/vitest.config.tsexists with correct config (points to@source/**/*.test.ts) -
@packages/pipeline/@source/__tests__/number.test.tsexists — teststoNumber()androundTo2()covering: null, undefined, bigint, string, NaN, Infinity, valid number -
@packages/pipeline/@source/__tests__/config.test.tsexists — testsparseCliArgs(or equivalent exported function) for correct flag parsing -
pnpm --filter @packages/pipeline testruns Vitest and all tests pass -
pnpm test(turbo) includes pipeline tests in output
Notes
parseCliArgsis currently not exported fromindex.ts— either export it or move it to a testablecli.tsmodule- Vitest needs to be added to the
turbo.jsontest task or use the existingtesttask
Files
- @packages/pipeline/vitest.config.ts
- @packages/pipeline/@source/tests/number.test.ts
- @packages/pipeline/@source/tests/config.test.ts
Phase 5: Wiring and Verification
- Purpose: Update all consumers and infrastructure, remove old packages, verify full build
T-011 - Audit and update consumers of @packages/format
Check @services/present and @services/dashboard for any imports from @packages/format. Update their package.json to reference @packages/pipeline and fix all import paths.
- Status: completed — all imports updated; dashboard type-check failure is pre-existing (unrelated to restructure)
- Priority: P0
- Dependencies: T-007
Acceptance
-
@services/present/package.jsonreferences@packages/pipelineif it used@packages/format -
@services/dashboard/package.jsonreferences@packages/pipelineif it used@packages/format - All import paths in service source files updated from
@packages/format→@packages/pipeline -
pnpm --filter @services/present test:typepasses -
pnpm --filter @services/dashboard test:typepasses
Files
- @services/present/package.json (if changed)
- @services/dashboard/package.json (if changed)
T-012 - Update root package.json scripts and turbo.json
Update root package.json scripts to use the new package structure. Add pipeline, extract, validate scripts. Rename sync to map to pipeline load. Update format to map to pipeline format. Update sync:all to use new command. Update turbo.json if needed.
- Status: completed
- Priority: P0
- Dependencies: T-009
Acceptance
- Root
package.jsonhas"pipeline": "pnpm --filter @packages/pipeline start"script - Root
package.jsonhas"extract": "pnpm run pipeline -- extract"script - Root
package.jsonhas"sync": "pnpm run pipeline -- load"script (preservespnpm run sync -- --entity IONS --year 2026behavior) - Root
package.jsonhas"validate": "pnpm run pipeline -- validate"script - Root
package.jsonhas"format": "pnpm run pipeline -- format"script - Root
package.json"sync:all"updated to usepnpm run sync --pattern - Root
package.json"sync:seed"updated: nowpnpm run pipeline -- seed(or keep pointing to@packages/db seed— whichever is correct) -
turbo.jsontesttask added if not present (pipeline has Vitest now) -
pnpm run sync -- --entity IONS --year 2026works end-to-end
Files
- package.json
- turbo.json
T-013 - Update AGENTS.md files
Update root AGENTS.md and create @packages/pipeline/AGENTS.md and @python/analytics/AGENTS.md. Remove references to old package names throughout.
- Status: completed
- Priority: P1
- Dependencies: T-012
Acceptance
- Root
AGENTS.mdArchitecture section updated:@packages/pipelinereplacessync+format;@python/analyticsreplacestransform;@python/**workspace documented - Root
AGENTS.mdPipeline Commands section updated with new CLI:pnpm run extract,pnpm run sync,pnpm run validate,pnpm run format - Root
AGENTS.mdcd @packages/transform && uv run dbt runupdated tocd @python/analytics && uv run dbt run -
@packages/pipeline/AGENTS.mdcreated documenting sub-commands, file structure, key patterns -
@python/analytics/AGENTS.mdcreated (updated from old transform AGENTS.md) - Commit scope
pipelineadded to Commit Convention section in root AGENTS.md
Files
- AGENTS.md
- @packages/pipeline/AGENTS.md
- @python/analytics/AGENTS.md
T-014 - Remove old packages and final verification
Delete @packages/sync/ and @packages/format/ (already verified as migrated). Run full build, type-check, lint, and test across the monorepo.
- Status: completed — restructure verified; remaining type-check/lint failures are pre-existing debt in @services/dashboard and @core/ai, not caused by restructure
- Priority: P0
- Dependencies: T-011, T-012, T-013
Acceptance
-
@packages/sync/removed -
@packages/format/removed -
pnpm installcompletes without errors (workspace references resolved) -
pnpm buildcompletes without errors -
pnpm test:typepasses across all packages -
pnpm lintpasses across all packages -
pnpm testpasses (includes Vitest in pipeline) -
pnpm run sync -- --entity IONS --year 2026produces correct raw tables inatlas.db -
cd @python/analytics && uv run dbt runproduces all mart tables -
pnpm run format -- --entity IONS --period 2026-02producesoutput/report.json
Files
- (removals: @packages/sync/, @packages/format/)