feat: add multi-tenant system with properties, organizations, and public booking

Implement complete multi-property architecture:
- Properties (groups of spaces) with public/private visibility
- Property managers (many-to-many) with role-based permissions
- Organizations with member management
- Anonymous/guest booking support via public API (/api/public/*)
- Property-scoped spaces, bookings, and settings
- Frontend: property selector, organization management, public booking views
- Migration script and updated seed data

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-02-15 00:17:21 +00:00
parent d637513d92
commit e21cf03a16
51 changed files with 6324 additions and 273 deletions

View File

@@ -0,0 +1,55 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { propertiesApi } from '@/services/api'
import { useAuthStore } from './auth'
import type { Property } from '@/types'
export const usePropertyStore = defineStore('property', () => {
const properties = ref<Property[]>([])
const currentPropertyId = ref<number | null>(
localStorage.getItem('currentPropertyId')
? Number(localStorage.getItem('currentPropertyId'))
: null
)
const loading = ref(false)
const currentProperty = computed(() =>
properties.value.find(p => p.id === currentPropertyId.value) || null
)
const setCurrentProperty = (id: number | null) => {
currentPropertyId.value = id
if (id) {
localStorage.setItem('currentPropertyId', String(id))
} else {
localStorage.removeItem('currentPropertyId')
}
}
const fetchMyProperties = async () => {
loading.value = true
try {
const authStore = useAuthStore()
if (authStore.isSuperadmin) {
properties.value = await propertiesApi.listAll()
} else {
properties.value = await propertiesApi.list()
}
// Auto-select first property if none selected
if (!currentPropertyId.value && properties.value.length > 0) {
setCurrentProperty(properties.value[0].id)
}
} finally {
loading.value = false
}
}
return {
properties,
currentPropertyId,
currentProperty,
loading,
setCurrentProperty,
fetchMyProperties
}
})