Backend Implementation Plan (Java v0.4.x)¶
Note: This plan replaces the earlier Python-based development plan. It outlines the staged implementation of the new Java backend (v0.4.x), focusing on CLI-first services, provider integration, and sync logic. The JavaFX UI will only be layered on after the backend is fully stable.
Current Status (0.4.1-SNAPSHOT)¶
- Modules in place:
spi,core,cli(all build & run cleanly). - CLI: Provides
--help,--version,providers, andservestubs. - Persona & Credentials: Core model present, lint-clean.
- Javadoc: Per-module + aggregate (
javadocAll) staged todocs/javadoc/. - Docs: MkDocs integrated, Javadocs embedded via iframe pages in
dev/api/. - Sanity-check workflow: Runs clean locally (Gradle build, CLI runs, Javadoc).
Next Steps¶
- Expand Core:
- Implement persona persistence and validation.
-
CredentialStore backends (file/JSON, not only in-memory).
-
SPI:
- Finalize
ProviderClientcontract with fetch/sync semantics. -
Lock API versioning before publishing.
-
Providers:
-
eQSL prototype first, others later.
-
Sync/Server:
-
Add module stubs for scheduling + MCP server HTTP API.
-
CI/CD:
- Publish snapshot artifacts.
- Harden smoke tests with JUnit.
CLI commands available
- `adif-mcp --help` – shows subcommands
- `adif-mcp providers` – lists installed providers (via `ServiceLoader`)
- `adif-mcp ui` – launches JavaFX app (dev: via reflection; packaged: separate launcher)
- `adif-mcp serve` – server stub (prints placeholder)
Provider registration
- eQSL provider **registered and discovered**
- Service file: `META-INF/services/com.ki7mt.adifmcp.providers.ProviderFactory`
- Factory: `com.ki7mt.adifmcp.providers.eqsl.EqslProviderFactory`
- Current capability: **pull-only** (stub)
Documentation integrated
- Aggregated Javadoc built by `./gradlew javadocAll` → output to `docs/javadoc/`
- MkDocs **strict** build succeeds; nav points to `javadoc/index.html`
- `make docs-serve` serves site with Javadoc included
Sanity-check workflow
# Top-level smoke gate (Makefile target: sanity-check)
./gradlew clean build
./gradlew --no-configuration-cache :cli:run --args="--help"
./gradlew --no-configuration-cache :cli:run --args="providers"
./gradlew --no-configuration-cache :ui:run
./gradlew javadocAll
Notes¶
- Gradle toolchain: Java 21; JavaFX via org.openjfx.javafxplugin.
- During development, :cli depends on :providers:provider-eqsl with implementation(...) for discovery.
- Next feature target: Credentials v1 (core API + cli creds), then eQSL fetch implementation.
1. Credentials (OS-native + fallback)¶
- [ ] Define
Credentialsmodel (personaId,providerId,authType, fields) - [ ] Implement
CredentialStoreinterface (put,get,delete,doctor) - [ ] macOS: shell out to
securityCLI for Keychain - [ ] Linux: try
secret-tool(DBus); fallback to portable - [ ] Windows: stub for Credential Manager; fallback to portable
- [ ] Portable fallback: AES-GCM encrypted file in
state/creds/ - [ ] CLI:
creds set|get|delete|list|doctor - [ ] Ensure key format is
adif-mcp/<persona>:<provider>
2. Providers (registry + enable/disable)¶
- [ ] Define provider descriptor JSON (
resources/providers/*.json) - [ ] Implement
ProviderRegistryto load descriptors - [ ] Track enabled/disabled per persona in
state/providers/ - [ ] Implement
ProviderClientinterface (ping,authCheck,fetchActivity,pushQso) - [ ] CLI:
provider list|enable|disable|doctor - [ ] Implement first real clients: QRZ and Clublog
3. Personas (multi-callsign, configs)¶
- [ ] Define
Personamodel (id,callsigns,defaultStation) - [ ] Persist as
config/personas/<persona>.yaml - [ ] Implement
PersonaServicefor CRUD - [ ] CLI:
persona add|list|show|remove|set-active|doctor
4. ADI → JSON¶
- [ ] Implement
AdifReaderto parse.adiinto normalized records - [ ] Define
AdifRecordPOJO (strict but logs unknowns) - [ ] Implement
AdifWriterlater for export - [ ] CLI:
convert --in … --out … - [ ] Validate with sample ADI logs
5. Sync Core (MCP plumbing)¶
- [ ] Define
SyncStateunderstate/sync/<persona>/<provider>.json - [ ] Implement dedupe by hash/time
- [ ] Implement
sync pull(dry-run + real) - [ ] Implement
sync push(dry-run + real) - [ ] CLI:
sync now|pull|push|status - [ ] Use
resources/mapping/usage.jsonfor transforms
6. JavaFX UI (thin shell over backend)¶
- [ ] Status pane: persona, providers, last sync, “Sync Now”
- [ ] Credential management dialogs → reuse
CredentialStore - [ ] Log viewer tailing
logs/ - [ ] No new logic — strictly a frontend to CLI services
Sequencing (2–3 day slices)¶
- CredentialStore (macOS + portable fallback)
- ProviderRegistry + enable/disable + doctor
- PersonaService + CRUD + active persona
- ADI Reader + normalized JSON + CLI converter
- SyncState + pull/push (dry-run first)
- Real provider integration (QRZ, Clublog)
- Wire JavaFX status + creds screen
Testing Strategy¶
- Unit: POJOs and services without network
- Integration: provider stubs for offline tests
- Doctor: every
doctorcommand checks creds, provider reachability, state
Current Task — Credentials v1 (Java backend)¶
First milestone: implement secure credential storage and CLI surfaces. Focus on macOS Keychain + portable encrypted fallback. Windows/Linux native stores will come later.
Scope¶
com.ki7mt.adifmcp.credentials(models, interfaces, adapters)com.ki7mt.adifmcp.cli.creds(picocli subcommands)
Checklist¶
-
[ ] Models
- [ ]
CredentialsPOJO (personaId,providerId,authType, fields map) - [ ]
AuthTypeenum (USERPASS,API_KEY)
- [ ]
-
[ ] Service API
- [ ]
CredentialStoreinterface:put,get,delete,list,doctor - [ ]
DoctorReportandCredentialRefhelper models
- [ ]
-
[ ] Adapters
- [ ] macOS Keychain adapter via
securityCLI - [ ] Portable encrypted file store under
state/creds/(AES-GCM + PBKDF2) - [ ] Stubs for Windows Credential Manager / Linux Secret Service
- [ ] macOS Keychain adapter via
-
[ ] Selection logic
- [ ] Store resolver: explicit
--store, else OS default, else fallback to portable - [ ] Log which backend is used
- [ ] Store resolver: explicit
-
[ ] CLI commands
- [ ]
adif-mcp creds set - [ ]
adif-mcp creds get - [ ]
adif-mcp creds delete - [ ]
adif-mcp creds list - [ ]
adif-mcp creds doctor
- [ ]
-
[ ] Testing
- [ ] Unit: in-memory fake for
CredentialStore - [ ] Integration: portable store round-trip, bad passphrase, tamper detection
- [ ] Integration: macOS Keychain add/get/delete with JSON payload
- [ ] CLI: end-to-end set/get/delete/list/doctor (with redaction verified)
- [ ] Security: grep logs/artifacts for secrets (must be redacted)
- [ ] Unit: in-memory fake for
Acceptance¶
- macOS: Keychain round-trip works with JSON payload
- Portable: encrypt/decrypt works, wrong passphrase rejected
- CLI: list shows refs only (no secrets), doctor prints a clear checklist
- Logs: never contain secrets
- Exit codes: non-zero on failure