|
| 1 | +# Release Plan: v0.1.0 |
| 2 | + |
| 3 | +This plan closes the gap between the current codebase and a first public release. It assumes `IMPLEMENTATION_PLAN.md` Phases 1–7 are complete (they are) and focuses only on the remaining work that blocks a tagged, installable, agent-usable release. |
| 4 | + |
| 5 | +## Release Definition |
| 6 | + |
| 7 | +A release is ready when all of the following hold: |
| 8 | + |
| 9 | +- Every command listed as an "Initial command" in `docs/PRD.md` and `IMPLEMENTATION_PLAN.md` is implemented and covered by contract tests. |
| 10 | +- A new user with no prior `~/.money` can run a single bootstrap command to reach a working encrypted store. |
| 11 | +- `money doctor` returns structured diagnostics for config, store, providers, links, and sync readiness. |
| 12 | +- `money version` obeys the `--json` flag and reports the real build version injected at link time. |
| 13 | +- `go test ./...` and `go vet ./...` run in CI on every push and pull request. |
| 14 | +- A tagged release (`v0.1.0`) exists on GitHub with prebuilt binaries for the supported platforms and a matching Go module proxy entry, so `go install github.com/thedavidweng/money/cmd/money@latest` resolves to that tag. |
| 15 | +- README, `docs/PRD.md`, `docs/CONTRACTS.md`, and `docs/CONFIG.md` describe exactly what ships; no documented command or flag is missing from the binary. |
| 16 | +- No runtime code references donor AI, Ray hosted proxy, subscription billing, or chat concepts (`rg` verification passes). |
| 17 | + |
| 18 | +## Required Reading Before Implementation |
| 19 | + |
| 20 | +1. `AGENTS.md` |
| 21 | +2. `docs/PRD.md` |
| 22 | +3. `docs/CONFIG.md` |
| 23 | +4. `docs/CONTRACTS.md` |
| 24 | +5. `docs/SCHEMA.md` |
| 25 | +6. `IMPLEMENTATION_PLAN.md` |
| 26 | + |
| 27 | +## Principles |
| 28 | + |
| 29 | +- Occam's razor: build the minimum surface that closes each release criterion. Do not add speculative commands, flags, or configuration. |
| 30 | +- No hidden fallbacks: every missing credential, missing file, or unopenable store must produce a stable error code. |
| 31 | +- Small deep modules: keep onboarding helpers inside `internal/config` and `internal/cli`; do not introduce a new top-level package unless two or more callers need it. |
| 32 | +- Dead-code sweep: after each phase, remove code paths that were only used by now-replaced scaffolding. |
| 33 | + |
| 34 | +## Phase R1: Onboarding Commands |
| 35 | + |
| 36 | +Goal: a new user can go from zero to a working encrypted store and diagnose problems without reading source. |
| 37 | + |
| 38 | +### R1.1 `money setup` |
| 39 | + |
| 40 | +Steps: |
| 41 | + |
| 42 | +1. Add `money setup` command. Human mode runs an arrow-key interactive flow using `charm.land/huh/v2`; JSON mode requires all inputs via flags and fails with `VALIDATION` if required flags are missing. |
| 43 | +2. Resolve config path with the same rules as `internal/config` load order; create `~/.money/` when using the default path. |
| 44 | +3. Write a `config.yaml` skeleton with `database.path`, `database.encryption_key: {env: MONEY_DB_ENCRYPTION_KEY}`, and empty `providers:` block. |
| 45 | +4. Generate a 32-byte random `MONEY_DB_ENCRYPTION_KEY`, base64url-encoded without padding, and write it to the resolved `.env` file with `0600` permissions on POSIX platforms. |
| 46 | +5. Open the encrypted store and run migrations so that read commands work immediately after setup. |
| 47 | +6. Never print the encryption key. Setup output reports file paths and boolean `secret_created: true`. |
| 48 | +7. Support `--config <path>` to target an alternate location. Support `--force` in JSON mode to overwrite an existing env var value; human mode asks with the arrow-key selector. |
| 49 | +8. On any write failure after partial writes, stop, report what was written and what failed, return exit code `1` (`INTERNAL` or `CONFIG_WRITE_FAILED`). |
| 50 | +9. On DB open/migration failure after config/env writes, keep the written files, report the DB failure, and suggest running `money doctor`. |
| 51 | +10. After success, run the shared doctor checks (see R1.2) and include their results in setup output. |
| 52 | + |
| 53 | +Acceptance: |
| 54 | + |
| 55 | +- First-time `money setup` on an empty home directory produces a working config, env, and encrypted DB. |
| 56 | +- `money accounts list --json` succeeds with an empty `accounts` array immediately after setup. |
| 57 | +- Re-running `money setup` on an already-configured install is a no-op for files that already exist and does not rotate the encryption key. |
| 58 | +- Setup never prints secret values. JSON output exposes only booleans and paths for secrets. |
| 59 | +- Setup does not attempt DB repair or re-encryption. |
| 60 | + |
| 61 | +### R1.2 `money doctor` |
| 62 | + |
| 63 | +Steps: |
| 64 | + |
| 65 | +1. Add `money doctor` with sections `Config`, `Store`, `Providers`, `Links`, `Sync`, and `Warnings`. Each diagnostic is a `{ code, status, message, category }` record with status `ok`, `warn`, or `error`. |
| 66 | +2. Implement config checks: config file exists, env file exists, required `database.path` and `database.encryption_key` resolvable, optional provider credentials resolvable. |
| 67 | +3. Implement store checks: DB file exists at configured path, opens with the configured key, schema version matches latest migration. |
| 68 | +4. Implement provider checks: for each registered provider, report configured vs available state (credentials present but valid/invalid distinction is `warn`-level only until sync is run). |
| 69 | +5. Implement links check: count linked provider items per provider from the store. |
| 70 | +6. Implement sync check: last `sync_runs` entry status and time; no runs is `warn` only if at least one provider item exists. |
| 71 | +7. Implement warnings check: broad env-file permissions on POSIX, direct secret scalars in YAML, config pointing at non-default path without `--config` or `MONEY_CONFIG`. |
| 72 | +8. Implement `money doctor --json`: return an envelope with `data.diagnostics[]` and `meta.command: "doctor"`. Do not include secret values. |
| 73 | +9. Implement `money doctor --fix` with exactly these repairs: create missing `~/.money/`, create missing config skeleton, create missing env skeleton, generate missing DB encryption key, chmod env file to `0600` on POSIX. |
| 74 | +10. Run the same diagnostic code from `money setup` so setup summary and doctor never diverge. |
| 75 | + |
| 76 | +Acceptance: |
| 77 | + |
| 78 | +- `money doctor` on an unconfigured system reports `Config: error` and exits non-zero. |
| 79 | +- `money doctor --json` returns a parseable envelope even when config is missing. |
| 80 | +- `money doctor --fix` is idempotent, never rotates keys, never edits user-set values, and never migrates donor config paths. |
| 81 | +- `money doctor --fix --dry-run` prints the repair plan without writing. |
| 82 | +- No diagnostic prints secret values or reversible partial previews. |
| 83 | + |
| 84 | +### R1.3 `money providers configure <provider>` |
| 85 | + |
| 86 | +Steps: |
| 87 | + |
| 88 | +1. Add `money providers configure plaid` and `money providers configure bridge` commands. |
| 89 | +2. Human mode uses the arrow-key selector for overwrite confirmation and free-text prompts for scalar credentials, displaying mask characters while typing secrets. |
| 90 | +3. JSON mode requires all credential flags; partial credentials return `VALIDATION` and write nothing. |
| 91 | +4. Write secrets to the resolved env file and corresponding `env:` references to `config.yaml`. Never write raw secret values into `config.yaml`. |
| 92 | +5. Existing env vars are not overwritten unless human user confirms via the arrow-key selector or JSON caller passes `--force`. |
| 93 | +6. After writing, run only that provider's doctor diagnostics plus global blocking diagnostics. |
| 94 | +7. Configuration is atomic per provider. If any required field is missing or any write fails, stop immediately, report what was written, and return `CONFIG_WRITE_FAILED`. |
| 95 | + |
| 96 | +Acceptance: |
| 97 | + |
| 98 | +- `money providers configure plaid --client-id ... --secret ... --environment sandbox --json` writes env entries and YAML `env:` references, then prints Plaid-only diagnostics. |
| 99 | +- Re-running with the same values is a no-op. |
| 100 | +- Missing any required Plaid or Bridge field fails atomically before any file write. |
| 101 | + |
| 102 | +## Phase R2: Version and Output Correctness |
| 103 | + |
| 104 | +Goal: every command obeys the contract for stdout, `--json`, and reports the real build version. |
| 105 | + |
| 106 | +### R2.1 Fix `money version` |
| 107 | + |
| 108 | +Steps: |
| 109 | + |
| 110 | +1. Change the default mode: when `--json` is not set, print a single plain-text line such as `money 0.1.0 (commit abc1234)`. |
| 111 | +2. When `--json` is set, print the existing envelope. |
| 112 | +3. Replace the hardcoded `"0.0.0"` with a package-level variable populated via `-ldflags "-X github.com/thedavidweng/money/internal/cli.Version=... -X github.com/thedavidweng/money/internal/cli.Commit=..."`. |
| 113 | +4. `go build` without ldflags yields `dev` for both fields, never a stale semver. |
| 114 | + |
| 115 | +Acceptance: |
| 116 | + |
| 117 | +- `money version` prints plain text on stdout. |
| 118 | +- `money version --json` prints the JSON envelope on stdout. |
| 119 | +- A binary built with ldflags reports its tag and commit. |
| 120 | +- Contract test covers both modes. |
| 121 | + |
| 122 | +### R2.2 Table rendering for human mode |
| 123 | + |
| 124 | +Steps: |
| 125 | + |
| 126 | +1. Add `github.com/olekukonko/tablewriter` to `go.mod`. |
| 127 | +2. Render `accounts list` human mode with columns `NAME`, `TYPE`, `BALANCE`, `AVAILABLE`, `CURRENCY`, `SOURCE`, `UPDATED`. Add `--verbose` for provider IDs and deeper provenance. |
| 128 | +3. Render `transactions list` / `transactions search` human mode with columns `DATE`, `ACCOUNT`, `MERCHANT`, `AMOUNT`, `CATEGORY`, `STATUS`. Add `--verbose` for local IDs, provider category, tags, note, and source. |
| 129 | +4. Render monetary values with explicit text signs; color is auxiliary only (green for positive, red for negative when stdout is a TTY). |
| 130 | +5. JSON output must remain byte-equivalent to the current contract. Contract tests stay unchanged. |
| 131 | + |
| 132 | +Acceptance: |
| 133 | + |
| 134 | +- Human `accounts list` and `transactions list|search` produce aligned tables. |
| 135 | +- Non-TTY stdout suppresses color escapes. |
| 136 | +- JSON envelopes are unchanged. |
| 137 | + |
| 138 | +### R2.3 Dead code sweep |
| 139 | + |
| 140 | +Steps: |
| 141 | + |
| 142 | +1. Run `go vet ./...` and address any warnings. |
| 143 | +2. Review `internal/cli`, `internal/linking`, and `internal/providers` for helpers that have no callers after R1 lands. |
| 144 | +3. Remove comments, fixtures, and branches that only existed to scaffold Phase 1–3 work. |
| 145 | + |
| 146 | +## Phase R3: Release Infrastructure |
| 147 | + |
| 148 | +Goal: every push is tested, and a tag produces published binaries. |
| 149 | + |
| 150 | +### R3.1 CI workflow |
| 151 | + |
| 152 | +Steps: |
| 153 | + |
| 154 | +1. Create `.github/workflows/ci.yml` that triggers on `push` to `main` and on `pull_request`. |
| 155 | +2. Steps: checkout, setup Go 1.25, `go vet ./...`, `go test ./... -race`, verify `go build ./...`. |
| 156 | +3. Cache Go modules and the Go build cache keyed on `go.sum`. |
| 157 | +4. Run on `ubuntu-latest` and `macos-latest`. |
| 158 | +5. Make the README CI badge resolve to this workflow. |
| 159 | + |
| 160 | +Acceptance: |
| 161 | + |
| 162 | +- CI badge is green on `main`. |
| 163 | +- A pull request that breaks a test fails CI. |
| 164 | + |
| 165 | +### R3.2 Release workflow |
| 166 | + |
| 167 | +Steps: |
| 168 | + |
| 169 | +1. Add a `.goreleaser.yaml` configured for Linux amd64/arm64 and macOS amd64/arm64 binaries, archived as tarballs. |
| 170 | +2. Inject `Version` and `Commit` via `-ldflags`. |
| 171 | +3. Skip Docker images and Homebrew taps for v0.1.0; add them only if there is a real maintainer commitment. |
| 172 | +4. Add `.github/workflows/release.yml` triggered on tags matching `v*`. |
| 173 | +5. Release workflow: checkout with full history, setup Go, run `go test ./...`, run `goreleaser release --clean`. |
| 174 | +6. Generate SHA256 checksums for every archive and include them in the GitHub release. |
| 175 | + |
| 176 | +Acceptance: |
| 177 | + |
| 178 | +- Pushing a tag `v0.1.0-rc.1` produces a draft GitHub release with platform archives and checksums. |
| 179 | +- Downloaded binaries report the tag version via `money version`. |
| 180 | + |
| 181 | +### R3.3 Module and tag |
| 182 | + |
| 183 | +Steps: |
| 184 | + |
| 185 | +1. Confirm the Go module path matches the repository path and that no replace directives leak into the public module. |
| 186 | +2. Tag `v0.1.0` after R1–R3.2 land and CI is green on `main`. |
| 187 | +3. Verify `go install github.com/thedavidweng/money/cmd/money@v0.1.0` succeeds on a clean machine. |
| 188 | +4. Update the README install instructions to reference `@latest` and to mention the release page for prebuilt binaries. |
| 189 | + |
| 190 | +Acceptance: |
| 191 | + |
| 192 | +- `go install github.com/thedavidweng/money/cmd/money@latest` installs a binary that prints `money v0.1.0` on `version`. |
| 193 | +- The release page contains archives for the four target platforms plus checksums. |
| 194 | + |
| 195 | +## Phase R4: Documentation Alignment |
| 196 | + |
| 197 | +Goal: every documented command and flag exists in the binary, and every binary command is documented. |
| 198 | + |
| 199 | +Steps: |
| 200 | + |
| 201 | +1. Walk `docs/PRD.md` "Initial commands" list; mark each as implemented or remove it from the initial list. |
| 202 | +2. Update `docs/CONTRACTS.md` to cover `setup`, `doctor`, `version`, and `providers configure` JSON shapes. |
| 203 | +3. Update `README.md` command list to exactly match the binary. |
| 204 | +4. Remove any deferred capability from user-facing docs that is not behind a flag or subcommand in v0.1.0. |
| 205 | +5. Verify `docs/ROADMAP.md` Phase 1 and Phase 2 descriptions match what shipped. |
| 206 | + |
| 207 | +Acceptance: |
| 208 | + |
| 209 | +- Running `money --help` and comparing against the README command list shows no missing or extra commands. |
| 210 | +- Every `--json` command named in `docs/CONTRACTS.md` returns a valid envelope in a contract test. |
| 211 | + |
| 212 | +## Verification Before Tagging |
| 213 | + |
| 214 | +Run all of the following on a clean workspace. All must pass: |
| 215 | + |
| 216 | +```bash |
| 217 | +go vet ./... |
| 218 | +go test ./... -race |
| 219 | +go run ./cmd/money version --json |
| 220 | +go run ./cmd/money setup --config /tmp/money/config.yaml --json |
| 221 | +go run ./cmd/money --config /tmp/money/config.yaml doctor --json |
| 222 | +go run ./cmd/money --config /tmp/money/config.yaml accounts list --json |
| 223 | +rg -n "RAY_API_KEY|RAY_PROXY_BASE|rayfinance\.app|Anthropic|OpenAI|conversation_history|ai_audit_log|memories" --glob '!donors/**' |
| 224 | +git status --short --ignored |
| 225 | +``` |
| 226 | + |
| 227 | +The `rg` search must return zero matches outside `donors/`. `git status` must be clean. |
| 228 | + |
| 229 | +## Out of Scope for v0.1.0 |
| 230 | + |
| 231 | +These are deferred to v0.2.0 or later and must not block the tag: |
| 232 | + |
| 233 | +- `money accounts update <id> --alias ...` |
| 234 | +- `money transactions cleanup --removed ...` |
| 235 | +- Monarch, CSV, and Apple Card import sources |
| 236 | +- MX and Finicity provider adapters |
| 237 | +- Budgeting, rules, cashflow, net worth primitives |
| 238 | +- Homebrew tap, Docker image, Windows builds |
| 239 | + |
| 240 | +If any of these reappear in implementation work before v0.1.0, move them back to `IMPLEMENTATION_PLAN.md` under a new phase instead of expanding this release plan. |
0 commit comments