04 — Information Architecture (Files Module)
- 1. Domain model
- 2. Storage key space
- 3. Screens in IA
- 4. Navigation
- 5. Information flows
- 6. Retention & lifecycle
Global IA and nav patterns: 00-shared/05_Global_Information_Architecture. This file documents only the files domain — its record model, storage key space, and how file screens hang off context screens.
1. Domain model
FileRecord (collection: "files", file.schema.ts:7-8)
├── tenantId (inherited from BaseSchema — every business doc; auto-scoped)
├── isDeleted / timestamps (BaseSchema — soft delete; filtered by BaseRepository)
├── originalName String (user-supplied, used verbatim in Content-Disposition)
├── mimeType String (client-supplied — NOT verified server-side)
├── size Number
├── storageProvider String (STORAGE_DRIVER ?? 'local', files.service.ts:40)
├── storageFileId String (provider object key/id; download by this)
├── storagePath String (= storageFileId today, files.service.ts:41-42)
└── optional, never populated today:
etag, thumbnailFileId, thumbnailStoragePath, thumbnailSize, width, height
(file.schema.ts:27-43) — (forward-looking)
Notes:
width/heightare declarednumberbut typedStringin the schema prop (file.schema.ts:39-43) — schema bug to fix when thumbnails land(planned).- Files are context-agnostic documents: no
folderId, nomodule, noentityReffield. A file's "context" (fee record, student, circular) exists only on the client or in the calling module's own linkage. Any folder/bucket UI is(planned).
2. Storage key space
| Layer | Key shape | Source |
|---|---|---|
| Local driver | storage/<tenantId>/<uuid>--<originalName> | local-storage.provider.ts:24-27 |
| R2 driver | <tenantId>/<uuid>--<originalName> | r2.provider.ts:39 |
| Appwrite driver | bucket APPWRITE_BUCKET_ID, object id = plain UUID | appwrite-storage.provider.ts:38-44 |
| Blueprint target | sl/{tenantId}/{type}/{uuid} | STORAGE_ARCHITECTURE.md:34 (planned) |
- Tenant isolation: mandatory key prefix (R2/local) OR bucket isolation; Appwrite relies on
a single bucket + tenant-scoped metadata only (blueprint: "prefixing is mandatory",
STORAGE_ARCHITECTURE.md:58-59— Appwrite driver does not prefix, gap). storageFileIddoubles asstoragePathin the service (files.service.ts:41-42); thefilenameon the key is the raw original name — no sanitization oforiginalNameanywhere (files.service.ts:31).
3. Screens in IA
Files have no top-level tab. They appear as:
┌─ Module context screen (fees / student profile / circulars …)
│ └─ "Files" section or list (reads GET /files, client-filtered)
│ ├─ Upload sheet (POST /files/upload)
│ ├─ File detail sheet (GET /files/:id)
│ ├─ Download flow (GET /files/:id/download)
│ └─ Delete confirm (DELETE /files/:id)
Client-side grouping key: none server-side; the client may keep files.byContext
local index (see 13_State_Management.md).
4. Navigation
- Deep links
(forward-looking):/files/:id(detail),/files/:id/download(direct download intent). - After upload: stay on context screen, tile appears (optimistic; rollback on failure).
- After delete: tile removed; snackbar with no undo (no restore endpoint)
(proposed: undo).
5. Information flows
| Flow | Read | Write |
|---|---|---|
| Upload | — | Storage upload → Mongo create |
| List | Mongo find (tenant-scoped, createdAt desc) | — |
| Download | Mongo findById → Storage download | — |
| Delete | Mongo findById | Storage delete → Mongo softDelete |
6. Retention & lifecycle
- No TTL on file records today. Global plan: 3-day retention tier for soft-deleted cleanup,
GDPR erasure endpoint, cold storage (
IMPLEMENTATION_PLAN.md:176)(planned). - Temp-upload expiry / cleanup job per blueprint
STORAGE_ARCHITECTURE.md:66(planned).