docs: Epic-001 v1.2 — Implementation plan + Development rules
- Added Vision: 'LandveX Intelligence Lab is the internal factory where
raw reality is refined into verified Control Intelligence'
- Added Architecture Goal: Every artifact traceable backward to source
and forward to decision
- Added Development Rule: No Story starts with UI. Order: Domain model →
API → Storage → Tests → UI
- Added Story 1 implementation plan with 5 PRs:
PR-001: Domain Model (Mission, MissionAsset, Upload, types)
PR-002: Storage (S3/R2 bucket, PostgreSQL metadata, checksums, EXIF, GPS)
PR-003: API (POST /missions, POST /missions/{id}/assets, GET /missions)
PR-004: Events (MissionCreated, AssetUploaded, RawDatasetReady)
PR-005: UI (simple drag-and-drop upload with progress)
- Added Definition of Done for Story 1:
Phone → Video → Upload → Bucket → Metadata → Mission visible in Dataset Explorer
- Added ID Convention: mission_YYYYMMDD_NNNNNN, asset_NNNNNN, obs_NNNNNN,
decision_NNNNNN. Never UUID in UI.
- Added Artifact Viewer: show raw asset metadata, hash, GPS, EXIF,
storage location, version for debugging
Rationale: Clean architecture, testable without UI, traceable artifacts.
This commit is contained in:
@@ -371,6 +371,160 @@ These are important but don't help reach the first verified workflow.
|
||||
|
||||
---
|
||||
|
||||
## STATUS
|
||||
## Vision
|
||||
|
||||
**READY FOR DEVELOPMENT**
|
||||
**LandveX Intelligence Lab is the internal factory where raw reality is refined into verified Control Intelligence.**
|
||||
|
||||
**Architecture Goal:** Every artifact must be traceable backward to its source and forward to its decision.
|
||||
|
||||
## Development Rule
|
||||
|
||||
**No Story may start with UI. Every Story starts with:**
|
||||
1. Domain model
|
||||
2. API
|
||||
3. Storage
|
||||
4. Tests
|
||||
5. UI
|
||||
|
||||
This keeps architecture clean and allows testing each part without frontend.
|
||||
|
||||
## Story 1: Mission Import — Implementation Plan
|
||||
|
||||
### PR-001: Domain Model
|
||||
|
||||
```typescript
|
||||
// Mission
|
||||
interface Mission {
|
||||
id: string; // mission_20260814_000123
|
||||
status: MissionStatus;
|
||||
location: Location;
|
||||
device: Device;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
// MissionAsset
|
||||
interface MissionAsset {
|
||||
id: string; // asset_000456
|
||||
missionId: string;
|
||||
type: AssetType; // image | video
|
||||
storagePath: string;
|
||||
checksum: string;
|
||||
sizeBytes: number;
|
||||
mimeType: string;
|
||||
metadata: AssetMetadata;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
// AssetMetadata
|
||||
interface AssetMetadata {
|
||||
exif: ExifData;
|
||||
gps: GpsCoordinates;
|
||||
device: DeviceInfo;
|
||||
}
|
||||
|
||||
// Upload
|
||||
interface Upload {
|
||||
id: string;
|
||||
missionId: string;
|
||||
status: UploadStatus;
|
||||
progress: number;
|
||||
startedAt: Date;
|
||||
completedAt?: Date;
|
||||
}
|
||||
|
||||
// Enums
|
||||
type MissionStatus = 'created' | 'uploading' | 'processing' | 'completed' | 'failed';
|
||||
type AssetType = 'image' | 'video';
|
||||
type UploadStatus = 'pending' | 'in_progress' | 'completed' | 'failed';
|
||||
```
|
||||
|
||||
### PR-002: Storage
|
||||
|
||||
- Upload to bucket (S3/R2)
|
||||
- Metadata in PostgreSQL
|
||||
- Checksums (SHA-256)
|
||||
- File size
|
||||
- MIME type
|
||||
- EXIF extraction
|
||||
- GPS parsing
|
||||
- **No AI yet**
|
||||
|
||||
### PR-003: API
|
||||
|
||||
```
|
||||
POST /missions
|
||||
POST /missions/{id}/assets
|
||||
GET /missions/{id}
|
||||
GET /missions
|
||||
```
|
||||
|
||||
### PR-004: Events
|
||||
|
||||
```
|
||||
MissionCreated
|
||||
↓
|
||||
AssetUploaded
|
||||
↓
|
||||
RawDatasetReady
|
||||
```
|
||||
|
||||
**No pipeline yet. Just events.**
|
||||
|
||||
### PR-005: UI
|
||||
|
||||
Extremely simple:
|
||||
|
||||
```
|
||||
Mission Import
|
||||
|
||||
[Drag files] or [Choose files]
|
||||
|
||||
[Upload]
|
||||
|
||||
Progress: ████████░░ 80%
|
||||
|
||||
Done! Mission mission_20260814_000123 created.
|
||||
```
|
||||
|
||||
### Definition of Done (Story 1)
|
||||
|
||||
```
|
||||
Phone → Video → Upload → Bucket → Metadata → Mission visible in Dataset Explorer
|
||||
```
|
||||
|
||||
This is the first proof.
|
||||
|
||||
## ID Convention
|
||||
|
||||
**Never UUID in UI. UUID internally.**
|
||||
|
||||
| Entity | ID Format | Example |
|
||||
|--------|-----------|---------|
|
||||
| Mission | `mission_YYYYMMDD_NNNNNN` | `mission_20260814_000123` |
|
||||
| Asset | `asset_NNNNNN` | `asset_000456` |
|
||||
| Observation | `obs_NNNNNN` | `obs_000981` |
|
||||
| Decision | `decision_NNNNNN` | `decision_000044` |
|
||||
|
||||
## Artifact Viewer
|
||||
|
||||
When clicking a file, show:
|
||||
|
||||
```
|
||||
Raw Asset
|
||||
├── Filename: IMG_20260814_143052.jpg
|
||||
├── Size: 4.2 MB
|
||||
├── MIME: image/jpeg
|
||||
├── Hash: sha256:a3f7...
|
||||
├── GPS: 59.2371, 18.1456
|
||||
├── EXIF: Device=iPhone14,2, ISO=100, Exposure=1/120s
|
||||
├── Created: 2026-08-14 14:30:52 UTC
|
||||
├── Storage: s3://landvex-raw/2026/08/14/mission_20260814_000123/
|
||||
└── Version: 1
|
||||
```
|
||||
|
||||
Saves enormous time during debugging.
|
||||
|
||||
## Status
|
||||
|
||||
**READY FOR DEVELOPMENT — PR-001: Domain Model**
|
||||
|
||||
Reference in New Issue
Block a user