# Authoring a Bundle

How to package справочники как distributable Ordinis bundle.

См. также: [Bundle Format Specification](../integration/bundle-format-spec.md) — formal spec.

---

## Quick start

```bash
# 1. Create bundle structure
mkdir -p my-bundle/src/main/resources/bundles/my-id
cd my-bundle

# 2. Add at least one schema
cat > src/main/resources/bundles/my-id/widget.schema.json <<'JSON'
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "x-id-source": "code",
  "required": ["code", "name"],
  "additionalProperties": false,
  "properties": {
    "code": { "type": "string", "pattern": "^[A-Z][A-Z0-9_]{1,31}$", "x-unique": true },
    "name": {
      "type": "object", "x-localized": true,
      "patternProperties": { "^[a-z]{2}-[A-Z]{2}$": { "type": "string" } },
      "required": ["ru-RU"]
    }
  }
}
JSON

# 3. Write manifest
cat > manifest.yaml <<'YAML'
apiVersion: ordinis.io/v1
kind: Bundle
metadata:
  id: my-org.widgets
  name: My Widgets Bundle
  version: 1.0.0
  scope: PUBLIC
dictionaries:
  - name: widget
    schemaVersion: 1.0.0
    scope: PUBLIC
    schemaRef: src/main/resources/bundles/my-id/widget.schema.json
YAML
```

---

## Versioning

- `metadata.version` — semver. Patch на data fixes, minor на add'инге dict'ов, major на breaking schema changes.
- `dictionaries[].schemaVersion` — per-dict semver, independent от bundle version. Bump когда меняется shape конкретной schema.
- Breaking schema change (remove required field, change type, add `additionalProperties: false`) → MAJOR bump bundle.

---

## Validation locally

```bash
# Через maven (если bundle — Maven artifact):
mvn test -pl ordinis-bundle-spec -Dtest=CuodManifestFixtureTest

# Или programmatically:
import cloud.nstart.terravault.ordinis.bundle.spec.*;

byte[] yaml = Files.readAllBytes(Path.of("manifest.yaml"));
List<String> errors = ManifestParser.parseAndValidate(yaml);
if (!errors.isEmpty()) {
  errors.forEach(System.err::println);
  System.exit(1);
}
```

---

## Signing (production publish)

Ed25519 keypair generation:
```bash
openssl genpkey -algorithm Ed25519 -out signing-priv.pem
openssl pkey -in signing-priv.pem -pubout -outform DER -out signing-pub.der
```

Sign bundle archive (until publisher Maven plugin lands — manual для now):
```java
byte[] archive = Files.readAllBytes(Path.of("bundle.tar.gz"));
byte[] privKey = Files.readAllBytes(Path.of("signing-priv.der")); // convert PEM→DER first
String sig = BundleSignatureVerifier.sign(archive, privKey);
// → patch manifest.yaml: metadata.signature: <sig>
//   OR write sidecar bundle.sig: <sig>
```

Public key распространяется к operators которые verify bundles перед install.

---

## Conventions

### Naming

- `metadata.id` — reverse-DNS (`ru.cuod.dzz-ground-segment`, `com.acme.widgets`).
- `dictionaries[].name` — snake_case (`spacecraft`, `ground_station`, `frequency_band`).

### Locales

Localized fields (`x-localized: true`) — каждое значение это объект `{lang-COUNTRY: "..."}`:
```json
"name": { "ru-RU": "Космический аппарат", "en-US": "Spacecraft" }
```

Bundle сам не объявляет supported locales — это per-dict. Manifest may add optional `metadata.locales` в future v1.x но spec строго ignores unknown сейчас.

### Foreign keys

`x-references: "<target_dict>.<field>"` — backend validates на write. Если target dict в том же bundle — order ensured (см. consumer protocol §6 в spec).

---

## Anti-patterns

- ❌ Не shipпите `additionalProperties: true` в production schemas — типизация теряется
- ❌ Не используйте `$ref` к внешним URLs (security risk + offline build fail)
- ❌ Не делайте 100+ dicts в одном bundle — расщепляйте по domain (e.g. `cuod-spacecraft`, `cuod-radio`)
- ❌ Не bump'айте `schemaVersion` без реального schema change

---

## Handoff checklist (Java team)

Когда передаёте bundle authoring к новой команде:
1. ✅ Прочитать [bundle-format-spec.md](../integration/bundle-format-spec.md)
2. ✅ Изучить `ordinis-cuod-bundle/manifest.yaml` как working example
3. ✅ Прогнать `mvn test -pl ordinis-bundle-spec` локально
4. ✅ Generate signing keypair, distribute pub key к ops
5. ✅ Set up CI publish job (когда `ordinis-bundle-publisher` plugin landed)

Для вопросов: ordinis maintainers (см. CODEOWNERS).
