Culture & Arts
The Culture vertical powers museums, theaters, galleries, cultural centers, and performing arts venues with three integrated systems: exhibition curation, artist profiles, and cultural event programming. Malet Owners configure these features via the Storefront Window layout system.
NOTE
These features live in the experiences subgraph โ the same cross-vertical Feature Plane that houses Entertainment & Experiences, Professional Services, and Wellness & Beauty. The architecture is documented in docs/architecture/18-progressive-vertical-extraction.md.
Architecture: Two-Plane Design
The Culture vertical uses the same Control + Feature plane separation as its sibling verticals:
- Control Plane (
maletssubgraph): VerticalConfig feature flags decide which Culture modules are enabled per Malet โexhibitionCuration,artistProfiles,seasonPasses,culturalCommerce. - Feature Plane (
experiencessubgraph): Self-containedExhibitionModuleandArtistProfileModule. Each can be extracted to its own subgraph when a dedicated Culture vertical Team forms. - Extensions (
servicessubgraph): Cultural event type and seating fields on existing Service entities.
Three new Storefront Window layout slot types are available: EXHIBITION_GALLERY, ARTIST_SPOTLIGHT, and SEASON_CALENDAR.
What Culture Reuses
TIP
Culture is the most reuse-heavy vertical. Three major systems come "for free" from earlier verticals:
| Reused System | From Vertical | Culture Use Case |
|---|---|---|
| Event Ticketing | Entertainment | Shows, workshops, screenings, festivals โ full lifecycle + QR check-in |
| Gamified Loyalty | Entertainment | Reward repeat attendees, artwork buyers, and season pass holders |
| Membership Engine | Wellness | Season passes as membership plans with event quotas per season |
Exhibition Curation
Create virtual gallery exhibitions with curated artwork collections, provenance tracking, and direct-sale capabilities.
Exhibition Types
| Type | Use Case |
|---|---|
VISUAL_ART |
Paintings, drawings, sculptures |
PHOTOGRAPHY |
Photo exhibitions, documentary series |
MIXED_MEDIA |
Multi-format exhibitions combining various media |
INSTALLATION |
Site-specific installations, immersive experiences |
DIGITAL |
Digital art, NFT showcases, generative art |
Exhibition Lifecycle
DRAFT โ OPEN โ CLOSED โ ARCHIVED
Exhibitions start as DRAFT while the curator arranges artwork. Once ready, they're OPEN for public viewing and sales. After the run ends, they move to CLOSED and can later be ARCHIVED for historical records.
Mutations
# Create a new exhibition (Malet Owner)
mutation {
createExhibition(
maletId: "m_soweto_theater"
title: "Impressions of Light"
slug: "impressions-of-light"
type: VISUAL_ART
description: "A celebration of contemporary South African painting"
coverImageUrl: "https://r2.mallnline.com/exhibitions/impressions.jpg"
) {
id
title
type
status
}
}
# Add artwork to the exhibition
mutation {
addExhibitionArtwork(
exhibitionId: "exh_1"
title: "Sunset Over Soweto"
artist: "Naledi Mokoena"
imageUrl: "https://r2.mallnline.com/art/sunset_soweto.jpg"
medium: "Oil on Canvas"
dimensions: "36x48 inches"
provenance: "Commissioned 2025. First exhibited at Johannesburg Art Fair."
) {
id
artworks {
title
artist
medium
provenance
isSold
}
}
}
# Open for public viewing
mutation {
openExhibition(exhibitionId: "exh_1") {
id
status
}
}
# Mark an artwork as sold
mutation {
markArtworkSold(exhibitionId: "exh_1", artworkTitle: "Sunset Over Soweto") {
id
artworks {
title
isSold
price
}
}
}
# Close the exhibition
mutation {
closeExhibition(exhibitionId: "exh_1") {
id
status
}
}
# Archive for historical records
mutation {
archiveExhibition(exhibitionId: "exh_1") {
id
status
}
}
# Update curator notes (private, Malet Owner only)
mutation {
updateCuratorNotes(
exhibitionId: "exh_1"
curatorNotes: "Strong opening night. 3 pieces sold. Consider extending run."
) {
id
curatorNotes
}
}
Queries
# All open exhibitions for a Malet (public โ storefront display)
query {
activeExhibitions(maletId: "m_soweto_theater") {
id
title
type
coverImageUrl
startsAt
endsAt
artworks {
title
artist
imageUrl
medium
price
isSold
}
}
}
# All exhibitions for a Malet (Malet Owner โ includes drafts/archived)
query {
maletExhibitions(maletId: "m_soweto_theater", status: DRAFT) {
id
title
status
artworks {
title
artist
}
}
}
# Single exhibition by ID
query {
exhibition(id: "exh_1") {
id
title
description
type
status
curatorNotes
artworks {
title
artist
medium
dimensions
year
imageUrl
price
isSold
provenance
}
}
}
ExhibitionArtwork Fields
Each artwork embedded in an exhibition tracks:
| Field | Type | Description |
|---|---|---|
title |
String! |
Artwork title |
artist |
String! |
Artist name |
artistProfileId |
ID |
Link to on-platform ArtistProfile (optional) |
medium |
String |
Material/medium (e.g., "Oil on Canvas", "Bronze") |
dimensions |
String |
Physical size (e.g., "36x48 inches") |
year |
Int |
Year created |
imageUrl |
String! |
High-resolution image for display |
price |
Float |
Sale price in cents (null = Not For Sale) |
isSold |
Boolean! |
Whether the piece has been sold |
provenance |
String |
Origin/ownership history |
sortOrder |
Int! |
Display order in the gallery |
Artist Profiles
Public showcase pages for performing artists, visual artists, and instructors. Each profile is scoped per Malet โ the same artist exhibiting at multiple venues has separate profiles per Malet.
Mutations
# Create an artist profile (Malet Owner)
mutation {
createArtistProfile(
maletId: "m_soweto_theater"
name: "Naledi Mokoena"
slug: "naledi-mokoena"
bio: "Contemporary South African painter known for vibrant township scenes."
photoUrl: "https://r2.mallnline.com/artists/naledi.jpg"
portfolioUrl: "https://naledi.art"
) {
id
name
slug
isActive
}
}
# Update artist bio
mutation {
updateArtistProfile(
artistId: "art_1"
bio: "Award-winning South African painter. Featured at Johannesburg Art Fair 2025."
) {
id
bio
}
}
# Deactivate profile (soft-disable โ not publicly visible)
mutation {
deactivateArtistProfile(artistId: "art_1") {
id
isActive
}
}
Queries
# All active artists for a Malet (public โ artist spotlight carousel)
query {
maletArtists(maletId: "m_soweto_theater") {
id
name
slug
bio
specialties
photoUrl
portfolioUrl
socialLinks {
platform
url
}
}
}
# Single artist by ID
query {
artistProfile(id: "art_1") {
id
name
bio
specialties
socialLinks {
platform
url
}
isActive
}
}
# Artist by slug (for SEO-friendly URLs)
query {
artistBySlug(maletId: "m_soweto_theater", slug: "naledi-mokoena") {
id
name
bio
portfolioUrl
}
}
Social Links
Each artist profile supports an array of social media links:
# Example social links structure
socialLinks: [
{ platform: "Instagram", url: "https://instagram.com/naledi_art" }
{ platform: "Behance", url: "https://behance.net/naledi" }
{ platform: "X", url: "https://x.com/naledi_mokoena" }
]
Cultural Event Programming
Extended service fields for cultural events on the existing services subgraph:
Service Fields
| Field | Type | Description |
|---|---|---|
culturalEventType |
CulturalEventType |
SHOW, EXHIBITION, WORKSHOP, SCREENING, FESTIVAL |
seatingType |
SeatingType |
RESERVED, GENERAL_ADMISSION, TIMED_ENTRY |
Cultural Event Types
| Type | Example | Seating Model |
|---|---|---|
SHOW |
Theater production, concert, dance recital | Usually RESERVED |
EXHIBITION |
Art exhibition, museum display | Usually TIMED_ENTRY |
WORKSHOP |
Art class, writing workshop | Usually GENERAL_ADMISSION |
SCREENING |
Film screening, documentary showing | RESERVED or GENERAL_ADMISSION |
FESTIVAL |
Multi-day cultural festival, art fair | GENERAL_ADMISSION |
Seating Types
| Type | Description |
|---|---|
RESERVED |
Specific seats assigned at purchase โ for venues with seat maps |
GENERAL_ADMISSION |
First-come, first-served entry โ capacity tracked but no assigned seats |
TIMED_ENTRY |
Entry within a specific time window โ for exhibitions and museums |
Example: Create a Cultural Event
mutation {
createOneService(
input: {
service: {
name: "Hamlet โ Opening Night"
description: "Shakespeare's tragedy performed by the Soweto Players"
price: 15000 # R150.00 (cents)
maletId: "m_soweto_theater"
culturalEventType: SHOW
seatingType: RESERVED
}
}
) {
id
name
culturalEventType
seatingType
}
}
TIP
Cultural events integrate with the existing Event Ticketing system. Use Event + EventTicket entities for tiered pricing (General, VIP, Patron), atomic capacity tracking, and QR check-in at the venue.
Season Passes
Season passes are powered by the Membership Engine from the Wellness vertical โ reused as multi-event subscriptions with event quotas.
How It Works
A "Gold Season Pass" is a MembershipPlan with a WellnessPlanTier and a sessionsPerMonth quota representing events per season:
# Create a season pass plan
mutation {
createMembershipPlan(
maletId: "m_soweto_theater"
name: "Gold Season Pass"
tier: GOLD
sessionsPerMonth: 12 # 12 events per season
monthlyPrice: 30000 # R300/month
productDiscountPercent: 15 # 15% off merchandise
) {
id
name
tier
sessionsPerMonth
}
}
Each time a season pass holder attends an event, recordMembershipUsage decrements their remaining quota. When the season ends, renewMembershipPeriod resets the counter.
Workroom Steps
The Culture vertical ships with 4 default Workroom steps for exhibition/show lifecycle management:
| Step | Type | Assignee | Description |
|---|---|---|---|
| Exhibition Setup | APPROVAL |
Malet Owner | Curate artwork, set pricing for pieces available for sale |
| Artist Coordination | FORM |
Malet Owner | Confirm artist profiles, bios, and portfolio links for the event program |
| Event Program | FORM |
Malet Owner | Finalize show schedule, ticket tiers, and seating arrangements |
| Post-Event Review | FORM |
Malet Owner | Record attendance, artwork sales, and feedback for future programming |
These steps are automatically configured on new Culture Malets via the vertical seed (indigo/amber branding).
Deferred Features
The following capabilities are planned for future phases using in-house, open-source/standard solutions โ no third-party SaaS dependencies:
| Feature | Phase | Approach |
|---|---|---|
| Interactive Seat Maps | Phase 2 | SVG-based seat map renderer with zone selection (in-house) |
| Recurring Events | Phase 2 | rrule (RFC 5545 / iCalendar) on Service for weekly/monthly recurrence |
| Digital Content DRM | Phase 2 | Signed URLs with time-limited access tokens via media subgraph |
| Season Pass Auto-Renewal | Phase 2 | Stripe Billing via existing MembershipSubscription.stripeSubscriptionId |
TIP
All Phase 2 deferred features are tracked in the consolidated docs/PHASE2_BACKLOG.md. The seasonPasses and culturalCommerce feature flags are already present in the Control Plane.
Frontend Implementation
Three Svelte 5 storefront widgets render the Culture vertical in the Visitor-facing storefront:
Components
| Widget | File | Description |
|---|---|---|
ExhibitionGallery |
src/lib/components/culture/ExhibitionGallery.svelte |
Exhibition cards with cover images, type badges (Visual Art/Photography/Mixed Media/Installation/Digital), status indicators (Now Open/Coming Soon/Closed/Archived), date ranges, and artwork counts with availability. |
ArtistShowcase |
src/lib/components/culture/ArtistShowcase.svelte |
Artist profile cards with circular photos, specialty tags, bio previews, and social media platform icons. Links to artist detail pages. |
SeasonCalendar |
src/lib/components/culture/SeasonCalendar.svelte |
Vertical timeline of exhibitions sorted chronologically with color-coded status dots, date ranges, and artwork counts. |
File Map
| File | Purpose |
|---|---|
src/lib/queries/culture.ts |
GraphQL queries (GET_ACTIVE_EXHIBITIONS, GET_EXHIBITION, GET_MALET_ARTISTS) + TypeScript interfaces |
src/lib/utils/cultureUtils.ts |
11 utility functions โ exhibition type labels/icons, status display, artwork pricing (NFS handling), date ranges, social platform icons |
src/lib/components/storefront/WidgetRegistry.svelte |
Widget registration: EXHIBITION_GALLERY, ARTIST_SHOWCASE, SEASON_CALENDAR |
tests/cultureUtils.test.ts |
16 unit tests covering all utility functions |
Layout Slot Types
| Slot Type | Widget | Auth Required |
|---|---|---|
EXHIBITION_GALLERY |
ExhibitionGallery |
No |
ARTIST_SHOWCASE |
ArtistShowcase |
No |
SEASON_CALENDAR |
SeasonCalendar |
No |
NOTE
For Visitor-facing documentation on exhibitions, artworks, and artist profiles, see the Support Manual: Exhibitions & Artists.
Related
- Entertainment & Experiences โ Provides Event Ticketing and Gamified Loyalty that Culture reuses directly
- Wellness & Beauty โ Provides the Membership Engine reused as season passes
- Professional Services โ Sibling vertical in the shared
experiencessubgraph Feature Plane - Storefront Sections โ Configure
EXHIBITION_GALLERY,ARTIST_SHOWCASE, andSEASON_CALENDARlayout slots - Teams & Sub-Groups โ Organize curators and artists with the org โ team โ member hierarchy
- Tech & Electronics โ Sibling vertical with spec engine and warranty management in the shared
experiencessubgraph - Arcade & Gaming โ Sibling vertical with digital key vaults for game distribution in the shared
experiencessubgraph - Support: Exhibitions & Artists โ Visitor-facing guide