Skip to content

Commit 7e08c74

Browse files
authored
chore(release): prepare v0.3.0 — Phase 3: JSON import/export — MVP shipped (T306) (#176)
- CHANGELOG: move Phase 3 entries from [Unreleased] to [0.3.0]. - RELEASE-NOTES: add long-form narrative for v0.3.0; flag that this tag marks the end of MVP (Translately works end-to-end without AI configured) and preview Phase 4 (BYOK AI + MT + TM). - tasks.md: tick T301/T302/T304/T305/T306; re-flag T303 (async SSE) as moved-to-Phase-4 per the earlier milestone reshuffle. Closes #57 (T306 — tag v0.3.0 GPG-signed).
1 parent 5414222 commit 7e08c74

3 files changed

Lines changed: 54 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66

77
## [Unreleased]
88

9-
### Added
9+
## [0.3.0] — 2026-04-19 — Phase 3: JSON import/export → MVP shipped
10+
11+
### Added (Phase 3)
1012
- **i18next JSON import + export — backend and webapp wizard** (T301 + T302 + T304 + T305; closes #52 + #53 + #55 + #56). Two synchronous endpoints under `/api/v1/organizations/{orgSlug}/projects/{projectSlug}`: `POST /imports/json` (i18next flat or nested JSON in, `{total, created, updated, skipped, failed, errors[]}` out) and `GET /exports/json` (shape + language-tag + namespace + tag + min-state filters → JSON file body with `Content-Disposition`). Conflict modes: `KEEP` / `OVERWRITE` / `MERGE`. Per-row ICU validation via the existing `IcuValidator`; invalid cells land in the result's `errors[]` without blocking clean rows. Shared parser — new `JsonTranslationsIO` service — handles flat ↔ nested round-trip and emits `JsonShapeError(path, code, message)` with jq-style addressing for parse failures. Webapp surfaces a four-step import wizard and a single-page export modal mounted on the project detail route, both using RHF-free local state because the wizard's flow is linear and small. Eight new backend integration tests (`ImportResourceIT` 6 + `ExportResourceIT` 4) and 11 parser unit tests (`JsonTranslationsIOTest`). Async + SSE progress streaming remains deferred to T303 (Phase 4). New API ref page [`docs/api/imports-and-exports.md`](docs/api/imports-and-exports.md) and product page [`docs/product/imports-and-exports.md`](docs/product/imports-and-exports.md).
1113

1214
## [0.2.0] — 2026-04-19 — Phase 2: Keys + Translations + ICU

RELEASE-NOTES.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,51 @@ Long-form release narratives. For raw diffs and per-PR detail, see [CHANGELOG.md
44

55
---
66

7+
## v0.3.0 — Phase 3: JSON import/export · **MVP shipped**
8+
9+
**Released:** 2026-04-19
10+
**Status:** prerelease (MVP complete)
11+
**Tag:** `v0.3.0` (GPG-signed) · [Compare with v0.2.0](https://github.com/Pratiyush/translately/compare/v0.2.0...v0.3.0)
12+
13+
### The headline
14+
15+
**Translately is now usable end-to-end as a self-hosted localization platform, with zero AI configured.** That was the MVP bar set in Phase 0: sign up, create an organization and a project, add translation keys, write values for a language, ship them back out as i18next JSON. Every piece is MIT. Every "enterprise" feature stays scheduled for its phase — SSO/SAML/LDAP at Phase 7, Tasks + Branching at Phase 7, CLI at Phase 6 — and shipped-to-date pieces remain free.
16+
17+
### i18next JSON import + export (T301 + T302 + T304 + T305)
18+
19+
Two synchronous endpoints on the project scope and the webapp UI that drives them:
20+
21+
- `POST /api/v1/organizations/{orgSlug}/projects/{projectSlug}/imports/json`
22+
Accepts flat (`{"nav.signIn":"Sign in"}`) or nested (`{"nav":{"signIn":"Sign in"}}`) i18next JSON, auto-detects shape, upserts one language per call. Conflict modes: `KEEP` (existing wins), `OVERWRITE` (replace every row), `MERGE` (fill blanks only). Per-row ICU validation via the v0.2.0 `IcuValidator` — invalid cells land in the response's `errors[]` array so the UI can surface them without rolling back the clean rows. Response: `{total, created, updated, skipped, failed, errors[]}`.
23+
- `GET /api/v1/organizations/{orgSlug}/projects/{projectSlug}/exports/json`
24+
Downloads one language as either flat or nested JSON. Filters: `languageTag`, `namespaceSlug`, `tags` (AND intersection), `minState` (`EMPTY < DRAFT < TRANSLATED < REVIEW < APPROVED` — pick `APPROVED` for production dumps). `Content-Disposition` ships a suggested filename; `X-Translately-Key-Count` lets the UI render a progress hint.
25+
26+
Shared parser (`JsonTranslationsIO`) handles flat ↔ nested round-trip and emits `JsonShapeError(path, code, message)` with jq-style addressing (e.g. `nav.items``UNSUPPORTED_TYPE` for a nested array) so the UI can point at the offending path in the pasted JSON.
27+
28+
Webapp adds **Import** and **Export** buttons to the Keys tab on the project detail route. Import wizard: paste JSON or drop a `.json` file, pick language + namespace + mode, run, review per-row errors inline. Export modal: pick shape + language + optional filters, click Download, browser saves `{projectSlug}-{languageTag}-{shape}.json`.
29+
30+
### What ships deferred to later phases
31+
32+
Four tickets originally scheduled for Phases 2–3 were re-allocated during MVP close-out to keep surgical focus:
33+
34+
- **T204 — bulk ops via Quartz** → Phase 4. Piggybacks on the Quartz infra the AI-batch workflow adds.
35+
- **T205 — activity-log per-field diffs** → Phase 7. Pairs naturally with the audit log (T706).
36+
- **T209 — per-key activity panel UI** → Phase 7 (with T205).
37+
- **T303 — async Quartz + SSE progress streaming** → Phase 4. The sync import/export endpoints in this release cover payloads up to ~10k keys comfortably; the async path becomes necessary when Phase 4 adds bulk AI translation jobs.
38+
39+
### What's next
40+
41+
**v0.4.0 — Phase 4: BYOK AI + MT + Translation Memory.** Per-project encrypted API keys for OpenAI / Anthropic / Google / Azure / custom endpoints; suggest + translate endpoints; MT adapter layer; TM lookup via pgvector + trigram. The entire layer is optional — Translately still works end-to-end without an AI key configured. The bulk-ops and async-job tickets deferred from this phase land alongside the AI batch workflow.
42+
43+
### Operator notes
44+
45+
- Schema migrations on upgrade: V3 (Phase 2 data model) + V4 (FTS + trigram) from v0.2.0 both apply automatically via Flyway. No new migrations in v0.3.0.
46+
- No new env vars. No new compose services.
47+
- The import endpoint runs inside a single transaction. Very large payloads (50k+ keys) should wait for T303's async path in v0.4.0 — the current sync call is fine up to ~10k keys per call on commodity hardware.
48+
- `imports.write` + `exports.read` are the scopes. OWNER / ADMIN have both by default; MEMBER has `imports.write` (translators upload) but not `exports.read` (download gate is an ADMIN concern).
49+
50+
---
51+
752
## v0.2.0 — Phase 2: Keys, translations, and ICU
853

954
**Released:** 2026-04-19

tasks.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,12 @@ The per-phase signed-tag cadence (one minor per phase) stays unchanged; the `mvp
9595

9696
| ID | Status | Scope | Est | Title |
9797
|---|---|---|---|---|
98-
| T301 | [ ] | backend | m | i18next flat + nested JSON import (conflict: keep / overwrite / merge) |
99-
| T302 | [ ] | backend | m | i18next flat + nested JSON export (filtered by namespace, tag, state) |
100-
| T303 | [ ] | backend | s | Async via Quartz; `GET /jobs/{id}` status polling + SSE events |
101-
| T304 | [ ] | webapp | m | Import wizard (upload → preview → conflict resolution → run → status) |
102-
| T305 | [ ] | webapp | s | Export modal with filters |
103-
| T306 | [ ] | infra | xs | Tag `v0.3.0` GPG-signed |
98+
| T301 | [x] | backend | m | i18next flat + nested JSON import (conflict: keep / overwrite / merge) |
99+
| T302 | [x] | backend | m | i18next flat + nested JSON export (filtered by namespace, tag, state) |
100+
| T303 | [] | backend | s | Async via Quartz; `GET /jobs/{id}` status polling + SSE events — moved to Phase 4 (bulk-AI batch workflow) |
101+
| T304 | [x] | webapp | m | Import wizard (upload → preview → conflict resolution → run → status) |
102+
| T305 | [x] | webapp | s | Export modal with filters |
103+
| T306 | [x] | infra | xs | Tag `v0.3.0` GPG-signed**MVP shipped** |
104104

105105
---
106106

0 commit comments

Comments
 (0)