This commit is contained in:
m
2026-09-10 06:39:25 +02:00
parent 7dd29239b7
commit 85b1871c18
18 changed files with 783 additions and 147 deletions
+30 -13
View File
@@ -2,12 +2,12 @@
## Project Status
Project initialized — `webui/` (React Native) and `backend/` (Go) have scaffolding in place.
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), React Navigation, TanStack Query, react-native-image-picker
- **Frontend**: React Native (Expo SDK 57), expo-router, expo-sqlite, expo-file-system (SAF)
## Key Commands
@@ -19,10 +19,13 @@ cd backend && go run cmd/server/main.go
docker compose up postgres -d
# Frontend
cd webui && npx expo start
cd mobile && npx expo start
# Typecheck frontend
cd webui && npx tsc --noEmit
cd mobile && npx tsc --noEmit
# SQLite layer tests (migrations + repositories)
cd mobile && npm run test:db
```
## Backend Structure
@@ -38,18 +41,32 @@ cd webui && npx tsc --noEmit
## Frontend Structure
- Entry point: `webui/App.tsx` (React Navigation + TanStack Query providers)
- Screens: `app/index.tsx` (home), `app/upload.tsx`, `app/scan.tsx`, `app/search.tsx`
- Components: `components/FileCard.tsx`, `TagChip.tsx`, `UploadProgress.tsx`
- Hooks: `hooks/useFiles.ts`, `hooks/useSearch.ts`, `hooks/useUpload.ts`
- API client: `api/client.ts`, types: `types/index.ts`, constants: `constants/api.ts`
- No business logic on the client — all heavy processing server-side
- API base URL configured via `EXPO_PUBLIC_API_BASE_URL` env var
- 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
- 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)
Collaborative/multi-user, plugin system, complex offline sync, public sharing.
- 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
- `README.md` — full spec, API endpoints, data flow, folder structure, iteration roadmap