Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 36 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
# Clean Data Export API

Clean Data Export API is a planned local workflow for turning imperfect job
records into review-ready CSV and JSON exports, with duplicate handling,
rejected rows, run history, and handoff notes.
Clean Data Export API is a local workflow for turning imperfect job records into
review-ready CSV and JSON exports, with duplicate handling, rejected rows, run
history, and handoff notes.

The workflow is intentionally local and uses fictional data. It models an
operations tool called **FieldOps Desk** and focuses on exporting `jobs` and
related `job_updates` records. It does not connect to a real customer system or
use real credentials.

## What the workflow will deliver
## Current Status

This is not a broad backend platform. The planned workflow focuses on one
handoff-ready export package:
The first local MVP is implemented. The repository includes deterministic
FieldOps Desk fixture data, a reusable export service, FastAPI and CLI entry
points, clean CSV/JSON outputs, rejected rows, SQLite run history, and tests.

The demo export for `2026-06-01` through `2026-06-05` returns:

```text
source_count=9
clean_count=3
duplicate_count=1
rejected_count=6
```

## What the workflow delivers

This is not a broad backend platform. The workflow focuses on one handoff-ready
export package:

- pull a limited set of source records.
- map source fields into a buyer-friendly output shape.
Expand All @@ -35,7 +50,7 @@ They need a repeatable local workflow that produces:
- a rejected-row file explaining records that were not accepted.
- a short run summary with counts and file paths.

## Planned workflow
## Workflow

```text
source fixture
Expand All @@ -49,10 +64,10 @@ source fixture
-> API/CLI response
```

The same export service will be used by both the FastAPI endpoint and the CLI,
so both entry points produce the same results.
The FastAPI endpoint and CLI use the same export service, so both entry points
produce the same results.

## Planned outputs
## Outputs

```text
outputs/
Expand All @@ -67,7 +82,7 @@ the same accepted records in JSON form. `rejected_jobs.csv` keeps invalid or
duplicate records visible with reason codes. `run_summary.md` gives a
human-readable handoff summary.

## Planned project structure
## Project Structure

```text
clean-data-export-api/
Expand Down Expand Up @@ -101,16 +116,16 @@ clean-data-export-api/
tests/
```

## Planned usage
## Usage

The intended future CLI flow is:
Run the CLI export:

```bash
uv sync
uv run clean-data-export-api export jobs --from-date 2026-06-01 --to-date 2026-06-05
```

The intended future API flow is:
Serve the local API:

```bash
uv run clean-data-export-api serve
Expand All @@ -126,6 +141,10 @@ Content-Type: application/json
}
```

The API uses the configured local output directory. The CLI also supports
explicit `--output-dir`, `--database-path`, and `--sample-data-dir` options for
local runs.

## Documentation

- [Product requirements](docs/PRD.md)
Expand All @@ -139,6 +158,6 @@ This project does not use real third-party credentials, scraping, login bypass,
paid APIs, or real customer data. All sample data should be fictional and safe
to share.

This project should not claim production readiness, guaranteed business
outcomes, enterprise security, or support for a real vendor API before that API
has been reviewed.
This project should not claim readiness for live operations, guaranteed business
outcomes, advanced security guarantees, or support for a real vendor API before
that API has been reviewed.
46 changes: 26 additions & 20 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

## Purpose

This document describes the planned technical design for Clean Data Export API.
The design keeps the workflow small, local, deterministic, and reusable from
both FastAPI and the CLI.
This document describes the technical design for Clean Data Export API. The
design keeps the workflow small, local, deterministic, and reusable from both
FastAPI and the CLI.

## System overview

Expand All @@ -31,7 +31,7 @@ inputs, call the service, and return the summary.
- Keep output files easy to inspect in a spreadsheet.
- Avoid abstractions that are not needed for the first export type.

## Planned package layout
## Package Layout

```text
src/clean_data_export_api/
Expand Down Expand Up @@ -90,13 +90,15 @@ Expected settings:

Defines typed data models for the workflow.

Expected models:
Models include:

- source job.
- source job update.
- clean job.
- rejected row.
- API job export request.
- export request.
- export run record.
- export summary.
- output paths.

Expand Down Expand Up @@ -153,9 +155,11 @@ Workflow:
4. Map source records into clean candidates.
5. Validate candidates.
6. Remove duplicates from accepted records.
7. Write output files.
8. Persist run history.
9. Return summary.
7. Build the output paths and run record.
8. Insert run history to get a run id.
9. Write output files.
10. Remove the run history row if report writing fails.
11. Return summary.

This module coordinates the workflow but should delegate specialized logic to
mapping, validation, reports, and repository modules.
Expand Down Expand Up @@ -189,7 +193,7 @@ SQLite is not used as the source of truth for job data.

### Source job

Planned source fields:
Source fields:

- `source_row_id`
- `job_id`
Expand All @@ -201,7 +205,7 @@ Planned source fields:

### Source job update

Planned source fields:
Source fields:

- `update_id`
- `job_id`
Expand Down Expand Up @@ -263,22 +267,24 @@ Request:
```json
{
"from_date": "2026-06-01",
"to_date": "2026-06-05",
"output_dir": "outputs"
"to_date": "2026-06-05"
}
```

The API uses the configured local output directory. Caller-controlled output
paths are rejected by the request model.

Response:

```json
{
"run_id": 1,
"from_date": "2026-06-01",
"to_date": "2026-06-05",
"source_count": 12,
"clean_count": 8,
"duplicate_count": 2,
"rejected_count": 2,
"source_count": 9,
"clean_count": 3,
"duplicate_count": 1,
"rejected_count": 6,
"output_paths": {
"clean_csv": "outputs/clean_jobs.csv",
"clean_json": "outputs/clean_jobs.json",
Expand All @@ -288,9 +294,6 @@ Response:
}
```

Counts above are examples. Implementation and tests should define deterministic
fixture counts.

## CLI contract

Command:
Expand All @@ -309,9 +312,12 @@ The CLI should print:
- rejected count.
- output file paths.

The CLI supports local path overrides such as `--output-dir`,
`--database-path`, and `--sample-data-dir`.

## SQLite run history

Planned table: `export_runs`
Table: `export_runs`

Fields:

Expand Down
18 changes: 9 additions & 9 deletions docs/DELIVERY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

## Purpose

This document defines the expected handoff package for the finished delivery.
This document defines the handoff package for the finished delivery.

The delivery should show more than working code. It should show how a buyer
would receive a clean export workflow: output files, rejected rows, a run
summary, and enough notes to rerun or extend the work.
The delivery shows more than working code. It shows how a buyer would receive a
clean export workflow: output files, rejected rows, a run summary, and enough
notes to rerun or extend the work.

## Delivery package

The finished repository should include:
The repository includes:

```text
README.md
Expand Down Expand Up @@ -94,7 +94,7 @@ Required sections:

## Buyer-facing handoff standard

The finished delivery should answer these questions without requiring a meeting:
The delivery should answer these questions without requiring a meeting:

- What does this workflow do?
- What source data does it read?
Expand Down Expand Up @@ -146,9 +146,9 @@ Realistic follow-up work may include:

Avoid promising:

- guaranteed revenue or ROI.
- production readiness.
- enterprise security.
- revenue or ROI guarantees.
- readiness for live operations.
- advanced security guarantees.
- support for a real vendor before reviewing its API docs and credentials.
- full platform ownership.

Expand Down
10 changes: 7 additions & 3 deletions docs/PRD.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,9 @@ The CLI must support:
clean-data-export-api export jobs --from-date 2026-06-01 --to-date 2026-06-05
```

The CLI response must include the same summary fields as the API response.
The CLI response must include the same summary fields as the API response. It
may accept local path overrides such as `--output-dir`, `--database-path`, and
`--sample-data-dir`.

### API

Expand All @@ -176,7 +178,9 @@ Request fields:

- `from_date`
- `to_date`
- optional `output_dir`

The API uses the configured local output directory. It does not accept caller
controlled output paths.

Response fields:

Expand All @@ -199,7 +203,7 @@ Response fields:
- No hosted production deployment.
- No background scheduler in the first version.
- No broad dashboard application.
- No claim that this project is production-ready.
- No claim that this project is ready for live operations.

## Acceptance criteria

Expand Down
4 changes: 4 additions & 0 deletions outputs/clean_jobs.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
job_id,customer_name,job_status,work_type,scheduled_date,last_updated_at,source_updated_at
JOB-1001,Avery Plumbing,scheduled,repair,2026-06-02,2026-06-02T08:45:00Z,2026-06-01T09:15:00Z
JOB-1002,Northstar Dental,in_progress,installation,2026-06-03,2026-06-03T10:15:00Z,2026-06-02T10:30:00Z
JOB-1003,Harbor Cafe,completed,inspection,2026-06-04,2026-06-04T16:30:00Z,2026-06-03T11:45:00Z
29 changes: 29 additions & 0 deletions outputs/clean_jobs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[
{
"job_id": "JOB-1001",
"customer_name": "Avery Plumbing",
"job_status": "scheduled",
"work_type": "repair",
"scheduled_date": "2026-06-02",
"last_updated_at": "2026-06-02T08:45:00Z",
"source_updated_at": "2026-06-01T09:15:00Z"
},
{
"job_id": "JOB-1002",
"customer_name": "Northstar Dental",
"job_status": "in_progress",
"work_type": "installation",
"scheduled_date": "2026-06-03",
"last_updated_at": "2026-06-03T10:15:00Z",
"source_updated_at": "2026-06-02T10:30:00Z"
},
{
"job_id": "JOB-1003",
"customer_name": "Harbor Cafe",
"job_status": "completed",
"work_type": "inspection",
"scheduled_date": "2026-06-04",
"last_updated_at": "2026-06-04T16:30:00Z",
"source_updated_at": "2026-06-03T11:45:00Z"
}
]
7 changes: 7 additions & 0 deletions outputs/rejected_jobs.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
source_row_id,source_job_id,reason_code,reason_detail,raw_record
row-004,,missing_job_id,job_id is required,"{""customer_name"": ""Brightline Salon"", ""job_id"": null, ""scheduled_date"": ""2026-06-04"", ""source_row_id"": ""row-004"", ""status"": ""scheduled"", ""updated_at"": ""2026-06-03T13:00:00Z"", ""work_type"": ""repair""}"
row-005,JOB-1005,missing_customer_name,customer_name is required,"{""customer_name"": """", ""job_id"": ""JOB-1005"", ""scheduled_date"": ""2026-06-05"", ""source_row_id"": ""row-005"", ""status"": ""scheduled"", ""updated_at"": ""2026-06-04T08:20:00Z"", ""work_type"": ""maintenance""}"
row-006,JOB-1006,invalid_status,job_status must be an allowed value,"{""customer_name"": ""Cedar Books"", ""job_id"": ""JOB-1006"", ""scheduled_date"": ""2026-06-05"", ""source_row_id"": ""row-006"", ""status"": ""waiting"", ""updated_at"": ""2026-06-04T09:10:00Z"", ""work_type"": ""repair""}"
row-007,JOB-1007,invalid_date,scheduled_date must be a valid ISO date,"{""customer_name"": ""Pioneer Fitness"", ""job_id"": ""JOB-1007"", ""scheduled_date"": ""2026-15-01"", ""source_row_id"": ""row-007"", ""status"": ""scheduled"", ""updated_at"": ""2026-06-04T14:30:00Z"", ""work_type"": ""inspection""}"
row-008,JOB-1008,missing_work_type,work_type is required,"{""customer_name"": ""Metro Florist"", ""job_id"": ""JOB-1008"", ""scheduled_date"": ""2026-06-05"", ""source_row_id"": ""row-008"", ""status"": ""scheduled"", ""updated_at"": ""2026-06-05T08:00:00Z"", ""work_type"": null}"
row-009,JOB-1002,duplicate_record,duplicate job_id JOB-1002 was skipped,"{""customer_name"": ""Northstar Dental"", ""job_id"": ""JOB-1002"", ""scheduled_date"": ""2026-06-03"", ""source_row_id"": ""row-009"", ""status"": ""in_progress"", ""updated_at"": ""2026-06-05T12:00:00Z"", ""work_type"": ""installation""}"
27 changes: 27 additions & 0 deletions outputs/run_summary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Export Run Summary

Run ID: 1
Requested date range: 2026-06-01 to 2026-06-05
Source records fetched: 9
Clean records written: 3
Duplicates removed: 1
Rejected records written: 6

## Output File Paths

- Clean CSV: `outputs/clean_jobs.csv`
- Clean JSON: `outputs/clean_jobs.json`
- Rejected CSV: `outputs/rejected_jobs.csv`
- Run summary: `outputs/run_summary.md`

## Known Limits

- Uses fictional local fixture data only.
- Covers jobs and job_updates only.
- Does not connect to a real vendor API.

## Suggested Next Steps

- Review rejected rows before using the clean export.
- Add buyer-specific validation rules before a real integration.
- Review vendor API docs before replacing the fixture source.
Loading