Phases 1-5 + rooms/floors, accounts, custom types, users, notifications

Data model
- Properties, rooms (+optional floors), assets (typed custom fields + Zod
  runtime validator + move history), documents (polymorphic scope)
- Projects -> work packages -> tasks -> subtasks
- Decision events (scoped to project/property/asset/work_package)
- Checklist templates + instances, maintenance schedules (time + usage) with
  auto-materialized checklists on event recording
- Wiki (global + per-project) with revisions + tsvector FTS
- Property accounts (utility/meter numbers by kind)
- Notifications table + per-user channel prefs

Infra
- RBAC guards (requireCompany / requireAdmin)
- Storage abstraction: LocalDiskStorage (HMAC signed URLs) + S3Storage
  behind the same interface, switchable via STORAGE_BACKEND
- CSV export for assets / maintenance / decisions
- QR labels: /api/qr SVG endpoint + printable /assets/[id]/label
- Notifications: in-app + SMTP (own server via nodemailer) + Matrix
  (Client-Server API, per-company room) with opt-in per user
- Company switcher + auto-select first company on login

UI
- Topbar: bell with unread count, theme toggle, name, Sign Out (flat)
- Sidebar: main nav + dedicated Admin section (Asset types, Users, Company)
- Nested-route tabs on property / project / asset detail pages
- Admin UIs for users (invite, role, reset pw, deactivate) and company
  settings (default currency, Matrix room id)
- Custom asset type creation + field-def editor with immutable key/type
  guard and auto-deprecate when removing a field still referenced

Graph
- graphify-out/ committed: GRAPH_REPORT.md, graph.html, graph.json
This commit is contained in:
2026-04-23 15:18:11 +07:00
parent ad155d6344
commit b59904fdae
387 changed files with 70371 additions and 82 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+91
View File
@@ -8,6 +8,97 @@
"when": 1776760498088,
"tag": "0000_init",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1776912796532,
"tag": "0001_phase1_assets_properties_documents",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1776912900000,
"tag": "0002_phase1_constraints_and_search",
"breakpoints": true
},
{
"idx": 3,
"version": "7",
"when": 1776913896873,
"tag": "0003_phase2_checklists_and_maintenance",
"breakpoints": true
},
{
"idx": 4,
"version": "7",
"when": 1776913950000,
"tag": "0004_phase2_partial_indexes_and_triggers",
"breakpoints": true
},
{
"idx": 5,
"version": "7",
"when": 1776915278123,
"tag": "0005_phase3_projects_and_decisions",
"breakpoints": true
},
{
"idx": 6,
"version": "7",
"when": 1776915350000,
"tag": "0006_phase3_partial_index_and_triggers",
"breakpoints": true
},
{
"idx": 7,
"version": "7",
"when": 1776916197473,
"tag": "0007_phase4_wiki",
"breakpoints": true
},
{
"idx": 8,
"version": "7",
"when": 1776916020000,
"tag": "0008_phase4_wiki_fts_and_uniq",
"breakpoints": true
},
{
"idx": 9,
"version": "7",
"when": 1776918611593,
"tag": "0009_rooms_and_floors",
"breakpoints": true
},
{
"idx": 10,
"version": "7",
"when": 1776918700000,
"tag": "0010_rooms_check_and_triggers",
"breakpoints": true
},
{
"idx": 11,
"version": "7",
"when": 1776919853043,
"tag": "0011_property_accounts",
"breakpoints": true
},
{
"idx": 12,
"version": "7",
"when": 1776919900000,
"tag": "0012_accounts_updated_at_trigger",
"breakpoints": true
},
{
"idx": 13,
"version": "7",
"when": 1776930973516,
"tag": "0013_notifications",
"breakpoints": true
}
]
}