Schema: portalFeatures-Zustände und newsPosts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c55e6f2dfe
commit
85bee3190c
3 files changed
+73
-1
No files matched your search
@@ -1,7 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Wartungs-Abo: legt die Collections subscriptions, hourCredits, takeoverCredits
|
||||
* (Uebernahmegutschriften) und aboOffers (individuelle Angebote) in woms-database an und
|
||||
* (Uebernahmegutschriften), aboOffers (individuelle Angebote), portalFeatures (Portal-Funktionen je
|
||||
* Projekt) und newsPosts (News-Pinnwand) in woms-database an und
|
||||
* ergaenzt worksheets um das Flag countsToPlan ("zaehlt aufs Abo-Stundenkonto").
|
||||
* Idempotent: existierende Collection/Attribute/Indexe werden uebersprungen.
|
||||
* Usage (im Container): docker exec -w /app webklar-kundenbereich-server node scripts/setup-abo-collections.mjs
|
||||
@@ -244,6 +245,64 @@ await ensureCollection(
|
||||
]
|
||||
)
|
||||
|
||||
// Portal-Funktionen je Projekt (Zustand, Kauf, Zustimmungsnachweis). Die Collection existiert in
|
||||
// Produktion teils schon; ensureCollection ueberspringt Vorhandenes (409) und ergaenzt Fehlendes.
|
||||
await ensureCollection(
|
||||
'portalFeatures',
|
||||
'Portal-Funktionen',
|
||||
[
|
||||
{ type: 'string', key: 'customerId', size: 64 },
|
||||
{ type: 'string', key: 'projectId', size: 64 },
|
||||
{ type: 'string', key: 'featureKey', size: 64 },
|
||||
{ type: 'boolean', key: 'enabled' },
|
||||
{ type: 'boolean', key: 'unlockedByPurchase' },
|
||||
{ type: 'string', key: 'purchaseStatus', size: 64 },
|
||||
{ type: 'string', key: 'state', size: 16 },
|
||||
{ type: 'string', key: 'siteKey', size: 16 },
|
||||
{ type: 'string', key: 'ticketId', size: 64 },
|
||||
{ type: 'string', key: 'stripeSessionId', size: 64 },
|
||||
{ type: 'string', key: 'stripeInvoiceId', size: 64 },
|
||||
{ type: 'string', key: 'invoiceUrl', size: 500 },
|
||||
{ type: 'datetime', key: 'orderedAt' },
|
||||
{ type: 'datetime', key: 'activatedAt' },
|
||||
{ type: 'datetime', key: 'disabledAt' },
|
||||
{ type: 'string', key: 'consentText', size: 1000 },
|
||||
{ type: 'datetime', key: 'consentAt' },
|
||||
{ type: 'string', key: 'consentIp', size: 64 },
|
||||
{ type: 'string', key: 'consentUserAgent', size: 300 },
|
||||
{ type: 'string', key: 'adminNote', size: 300 },
|
||||
],
|
||||
[
|
||||
{ key: 'idx_customer', type: 'key', attributes: ['customerId'] },
|
||||
{ key: 'idx_state', type: 'key', attributes: ['state'] },
|
||||
{ key: 'idx_sitekey', type: 'unique', attributes: ['siteKey'] },
|
||||
]
|
||||
)
|
||||
|
||||
// News-Pinnwand: Beitraege je Projekt
|
||||
await ensureCollection(
|
||||
'newsPosts',
|
||||
'News-Beiträge',
|
||||
[
|
||||
{ type: 'string', key: 'customerId', size: 64 },
|
||||
{ type: 'string', key: 'projectId', size: 64 },
|
||||
{ type: 'string', key: 'type', size: 8 },
|
||||
{ type: 'string', key: 'title', size: 60 },
|
||||
{ type: 'string', key: 'text', size: 400 },
|
||||
{ type: 'string', key: 'imageId', size: 64 },
|
||||
{ type: 'string', key: 'paper', size: 8 },
|
||||
{ type: 'string', key: 'duration', size: 8 },
|
||||
{ type: 'datetime', key: 'visibleFrom' },
|
||||
{ type: 'datetime', key: 'visibleUntil' },
|
||||
{ type: 'datetime', key: 'takenDownAt' },
|
||||
{ type: 'datetime', key: 'createdAt' },
|
||||
{ type: 'datetime', key: 'updatedAt' },
|
||||
],
|
||||
[
|
||||
{ key: 'idx_project_from', type: 'key', attributes: ['projectId', 'visibleFrom'] },
|
||||
]
|
||||
)
|
||||
|
||||
// Worksheet-Flag: nur markierte Arbeitszeit wird vom Abo-Guthaben abgezogen
|
||||
await ensure('worksheets.countsToPlan', () =>
|
||||
aw(`${col('worksheets')}/attributes/boolean`, {
|
||||
|
||||
@@ -118,6 +118,7 @@ export const config = {
|
||||
takeoverCredits: process.env.APPWRITE_COLLECTION_TAKEOVER_CREDITS || 'takeoverCredits',
|
||||
aboOffers: process.env.APPWRITE_COLLECTION_ABO_OFFERS || 'aboOffers',
|
||||
contractEvents: process.env.APPWRITE_COLLECTION_CONTRACT_EVENTS || 'contractEvents',
|
||||
newsPosts: process.env.APPWRITE_COLLECTION_NEWS_POSTS || 'newsPosts',
|
||||
},
|
||||
|
||||
publicBaseUrl: (process.env.PORTAL_PUBLIC_URL || 'https://project.webklar.com').replace(/\/$/, ''),
|
||||
|
||||
@@ -287,3 +287,15 @@ test('Stripe-Nachbau: failNext lässt den nächsten passenden Aufruf scheitern',
|
||||
await assert.rejects(stripe.subscriptions.update('sub_f', { metadata: { a: 'd' } }), (e) => e.statusCode === 402)
|
||||
assert.equal((await stripe.subscriptions.retrieve('sub_f')).metadata.a, 'c')
|
||||
})
|
||||
|
||||
test('schema_funktionen_news', async () => {
|
||||
const { schemaKeys } = await import('./support/schema.js')
|
||||
const features = schemaKeys('portalFeatures')
|
||||
for (const k of ['customerId', 'projectId', 'featureKey', 'enabled', 'unlockedByPurchase', 'purchaseStatus', 'state', 'siteKey', 'ticketId', 'stripeSessionId', 'stripeInvoiceId', 'invoiceUrl', 'orderedAt', 'activatedAt', 'disabledAt', 'consentText', 'consentAt', 'consentIp', 'consentUserAgent', 'adminNote']) {
|
||||
assert.ok(features.includes(k), `portalFeatures.${k}`)
|
||||
}
|
||||
const news = schemaKeys('newsPosts')
|
||||
for (const k of ['customerId', 'projectId', 'type', 'title', 'text', 'imageId', 'paper', 'duration', 'visibleFrom', 'visibleUntil', 'takenDownAt', 'createdAt', 'updatedAt']) {
|
||||
assert.ok(news.includes(k), `newsPosts.${k}`)
|
||||
}
|
||||
})
|
||||
Reference in new issue
Block a user