72 lines
3.4 KiB
Markdown
72 lines
3.4 KiB
Markdown
# VaultDrop
|
|
|
|
## Project Status
|
|
|
|
Project initialized — `mobile/` (React Native / Expo) and `backend/` (Go) have scaffolding in place. The SQLite layer (schema v4, migrations, repositories) is implemented and covered by tests.
|
|
|
|
## Architecture
|
|
|
|
- **Backend**: Go, Gin HTTP framework, PostgreSQL, Tesseract OCR (system call)
|
|
- **Frontend**: React Native (Expo SDK 57), expo-router, expo-sqlite, expo-file-system (SAF)
|
|
|
|
## Key Commands
|
|
|
|
```bash
|
|
# Backend
|
|
cd backend && go run cmd/server/main.go
|
|
|
|
# PostgreSQL (via docker-compose)
|
|
docker compose up postgres -d
|
|
|
|
# Frontend
|
|
cd mobile && npx expo start
|
|
|
|
# Typecheck frontend
|
|
cd mobile && npx tsc --noEmit
|
|
|
|
# SQLite layer tests (migrations + repositories)
|
|
cd mobile && npm run test:db
|
|
```
|
|
|
|
## Backend Structure
|
|
|
|
- Entry point: `backend/cmd/server/main.go`
|
|
- Internal packages: `handlers/`, `models/`, `repository/`, `service/`, `ocr/`
|
|
- Response helpers: `pkg/api/response.go`
|
|
- File uploads stored in `backend/uploads/`
|
|
- Standard JSON response envelope: `{ "data": ..., "meta": { "page": ..., "total": ... } }`
|
|
- Error format: `{ "error": { "code": "...", "message": "..." } }`
|
|
- OCR language: `fra+eng`
|
|
- Handlers are stub implementations (return not-implemented errors)
|
|
|
|
## Frontend Structure
|
|
|
|
- Entry point: `mobile/App.tsx` (expo-router layout + Auth context)
|
|
- Data layer — `mobile/services/`:
|
|
- `safDirectory.ts` + `safDirectory.types.ts`: physical access via `expo-file-system` (pick/list/create, Documents/SAF uris)
|
|
- `db/` — SQLite persistence, see `mobile/AGENTS.md` for the full contract (schema, migrations, repositories, tests)
|
|
- `localStorage.ts` — thin re-export of `services/db` (legacy alias)
|
|
- `features/syncDevice.ts` — device sync orchestration (two-pass SAF walk, single transaction per root, `exists = 0` reconciliation)
|
|
- `context/AuthContext.tsx` — session context: exposes `deviceUserId` (bootstrapped from `getDeviceUserId()`) and starts the background `syncDevice` loop
|
|
- No business logic on the client — heavy processing stays server-side
|
|
- API base URL configured via `EXPO_PUBLIC_API_BASE_URL` env var (client + hooks not yet built)
|
|
|
|
## Data Conventions
|
|
|
|
- Canonical identity for folders/files/shares/share_links is `resource_id`: opaque `lower(hex(randomblob(16)))`, generated locally, never reused. The physical `uri` is nullable (NULL = cloud-only) and is the reconciliation key for the SAF walk.
|
|
- `owner_id` is NOT NULL on every folder/file row, seeded from the device's `device_user_id`.
|
|
- Folder/file `sync_status` is a **placement** state: `local` | `cloud` | `local-cloud` (transitions via `transitionSyncStatus`). It is not a push progress marker.
|
|
- Shares/share_links carry no `sync_status`; their `pushStatus` (pending/synced/failed) is derived from the `pending_operations` outbox.
|
|
- Decisions are made **offline** from a cached `resource_permissions` snapshot pushed by the server; the server remains the source of truth. `canAccess` enforces ranking (viewer < commenter < editor < owner), `inherit`, `expires_at`, and a 24h stale-cache read-only downgrade.
|
|
- `password_hash` and download counters are **server-side only**; the client only stores the `has_password` boolean and a counter mirror.
|
|
|
|
## Non-Goals (V1)
|
|
|
|
- Plugin system
|
|
- On-device OCR
|
|
- Full multi-tenant federation / public discovery
|
|
- Multi-writer sync conflicts (single-owner device identity; device-local `device_user_id`)
|
|
|
|
## References
|
|
|
|
- `README.md` — full spec, API endpoints, data flow, folder structure, iteration roadmap |