.claude/skills/minside/SKILL.md
# Min Side Expert Context > Use this skill when working on `/min-side/` routes, user authentication, access control, or member portal features in BIM Verdi. --- ## 1. Architecture Overview ### Router System Min Side uses a single router template that maps URL paths to part files: ``` template-minside-router.php ↓ inc/minside-helpers.php (route definitions) ↓ parts/minside/{part-file}.php ``` **Key files:** - `template-minside-router.php` - Main router template - `inc/minside-helper
npx skillsauth add aharstad91/bimverdi-v2 .claude/skills/minsideInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill when working on
/min-side/routes, user authentication, access control, or member portal features in BIM Verdi.
Min Side uses a single router template that maps URL paths to part files:
template-minside-router.php
↓
inc/minside-helpers.php (route definitions)
↓
parts/minside/{part-file}.php
Key files:
template-minside-router.php - Main router templateinc/minside-helpers.php - Route definitions + helper functionsheader-minside.php - Authenticated headerparts/minside/*.php - Individual view templatesbimverdi_get_minside_routes() in inc/minside-helpers.php:'my-route' => 'my-route', // Simple route
'parent/child' => 'parent-child', // Nested route
Create template file: parts/minside/{part-file}.php
Optionally add to navigation in bimverdi_get_minside_nav()
| URL Path | Part File | Description |
|----------|-----------|-------------|
| /min-side/ | dashboard.php | Main dashboard |
| /min-side/profil/ | profil.php | View profile |
| /min-side/profil/rediger/ | profil-rediger.php | Edit profile |
| /min-side/profil/passord/ | profil-passord.php | Change password |
| /min-side/foretak/ | foretak-detail.php | View company |
| /min-side/foretak/rediger/ | foretak-rediger.php | Edit company (hovedkontakt only) |
| /min-side/verktoy/ | verktoy-list.php | List tools |
| /min-side/verktoy/registrer/ | verktoy-registrer.php | Register new tool |
| /min-side/verktoy/rediger/ | verktoy-rediger.php | Edit tool (?id=X) |
| /min-side/kunnskapskilder/ | kunnskapskilder-list.php | List knowledge sources |
| /min-side/kunnskapskilder/registrer/ | kunnskapskilder-registrer.php | Register knowledge source |
| /min-side/kunnskapskilder/rediger/ | kunnskapskilder-rediger.php | Edit knowledge source |
| /min-side/artikler/ | artikler-list.php | List articles |
| /min-side/artikler/skriv/ | artikler-skriv.php | Write new article |
| /min-side/arrangementer/ | arrangementer-list.php | Events list |
| /min-side/prosjektideer/ | prosjektideer-list.php | Project ideas list |
| /min-side/invitasjoner/ | invitasjoner-list.php | Invite colleagues (hovedkontakt only) |
These redirect to new routes for backward compatibility:
/min-side/mine-verktoy/ → verktoy-list/min-side/registrer-verktoy/ → verktoy-registrer/min-side/rediger-verktoy/ → verktoy-rediger/min-side/rediger-foretak/ → foretak-rediger/min-side/rediger-profil/ → profil-rediger/min-side/endre-passord/ → profil-passord/min-side/skriv-artikkel/ → artikler-skriv| Type | Definition | Access Level |
|------|------------|--------------|
| profil | User without company | Limited - can browse, attend events |
| foretak | User linked to company | Full - can create content |
| guest | Not logged in | No Min Side access |
| Role | Description | Has Company |
|------|-------------|-------------|
| medlem | Free member | Optional |
| tilleggskontakt | Invited by hovedkontakt | Yes (required) |
| deltaker | Paying member (standard) | Yes (required) |
| prosjektdeltaker | Paying member (mid-tier) | Yes (required) |
| partner | Paying member (top tier) | Yes (required) |
Important: deltaker, prosjektdeltaker, and partner have IDENTICAL capabilities. The difference is business/pricing only.
| Capability | Tilleggskontakt | Hovedkontakt | |------------|-----------------|--------------| | Create tools | Yes | Yes | | Write articles | Yes | Yes | | Register knowledge sources | Yes | Yes | | Submit project ideas | Yes | Yes | | Edit own content | Yes | Yes | | Delete content | No (admin) | No (admin) | | Edit company profile | No | Yes | | View team members | Yes | Yes | | Remove team members | No | Yes | | Transfer hovedkontakt | No | Yes | | Invite colleagues | No | Yes |
Requires Company (foretak account type):
const COMPANY_REQUIRED_FEATURES = [
'register_tool', // Registrere verktøy
'edit_tool', // Redigere verktøy
'write_article', // Skrive artikler
'submit_case', // Sende inn prosjektidéer
'join_temagruppe', // Velge temagrupper
'company_profile', // Redigere foretaksprofil
'view_members_full', // Se fullt medlemsinnhold
];
Open to All Logged-In Users:
const OPEN_FEATURES = [
'view_dashboard', // Se Min Side dashboard
'edit_profile', // Redigere egen profil
'view_catalog', // Se medlemskatalog
'view_tools', // Se verktøykatalog
'register_event', // Melde seg på arrangementer
'view_events', // Se arrangementer
'connect_company', // Koble til foretak
];
// Get Min Side base URL
bimverdi_minside_base_url(); // Returns: https://site.com/min-side
// Generate Min Side URL
bimverdi_minside_url('verktoy'); // /min-side/verktoy/
bimverdi_minside_url('verktoy/rediger', ['id' => 123]); // /min-side/verktoy/rediger/?id=123
// Get current route
bimverdi_get_current_route(); // Returns: 'verktoy/rediger'
// Check if on specific route
bimverdi_is_minside_route('verktoy'); // true for /verktoy/ and /verktoy/rediger/
bimverdi_is_minside_route(['profil', 'foretak']); // Multiple routes
// Get primary route segment
bimverdi_get_primary_route(); // 'verktoy' from 'verktoy/rediger'
// Check if user has company
bimverdi_user_has_company($user_id); // Returns: bool
// Get user's company ID
bimverdi_get_user_company($user_id); // Returns: int|false
// Check if user is hovedkontakt
bimverdi_is_hovedkontakt($user_id, $company_id); // Returns: bool
// Check if company is active/approved
bimverdi_is_company_active($company_id); // Returns: bool
// Get account type
bimverdi_get_account_type($user_id); // Returns: 'profil', 'foretak', or 'guest'
// Check feature access
bimverdi_can_access('register_tool'); // Returns: bool
// Render locked feature UI
BIMVerdi_Access_Control::render_locked_ui('register_tool', 'Custom message');
// Render locked card component
bimverdi_locked_card('Title', 'Description', 'icon-name', 'feature');
// Render "connect to company" CTA
bimverdi_connect_company_cta();
// Get navigation structure
$nav = bimverdi_get_minside_nav();
// Returns array with: label, url, icon, badge, routes
User's company is stored in user_meta. Check these keys in order:
bimverdi_company_id (new standard)bim_verdi_company_id (legacy)tilknyttet_foretak (fallback)Always use the helper function bimverdi_get_user_company() which handles all three.
foretakget_field('hovedkontaktperson', $company_id); // User ID of primary contact
get_field('bv_rolle', $company_id); // Deltaker|Prosjektdeltaker|Partner|Ikke deltaker
get_field('organisasjonsnummer', $company_id); // Norwegian org number
get_field('bedriftsnavn', $company_id); // Company name (or post_title)
get_field('beskrivelse', $company_id); // Company description
get_field('logo', $company_id); // Attachment ID
get_field('adresse', $company_id); // Street address
get_field('postnummer', $company_id); // Postal code
get_field('poststed', $company_id); // City
get_field('land', $company_id); // Country
get_field('telefon', $company_id); // Phone
get_field('epost', $company_id); // Email
get_field('nettside', $company_id); // Website URL
verktoyget_field('tilknyttet_foretak', $tool_id); // Company ID that owns the tool
get_field('eier_leverandor', $tool_id); // Owner/vendor company
get_field('logo', $tool_id); // Tool logo
get_field('vendor', $tool_id); // Vendor name
get_field('type_verktoey', $tool_id); // Tool type
get_field('plattform', $tool_id); // Platform(s)
kunnskapskildeget_field('registrert_av', $kilde_id); // User ID who registered
get_field('tilknyttet_bedrift', $kilde_id); // Company ID
get_field('kunnskapskilde_navn', $kilde_id); // Name
get_field('kildetype', $kilde_id); // Type (standard, veileder, etc.)
get_field('utgiver', $kilde_id); // Publisher
get_field('ekstern_lenke', $kilde_id); // External URL
get_field('kort_beskrivelse', $kilde_id); // Short description
arrangementget_field('arrangement_dato', $event_id); // Date
get_field('tidspunkt_start', $event_id); // Start time
get_field('tidspunkt_slutt', $event_id); // End time
get_field('arrangement_type', $event_id); // Type (digitalt, fysisk, hybrid)
get_field('sted_by', $event_id); // City
get_field('sted_adresse', $event_id); // Address
get_field('pamelding_url', $event_id); // Registration URL
get_field('maks_deltakere', $event_id); // Max participants
caseget_field('temagruppe', $idea_id); // Related theme group
get_field('tilknyttet_foretak', 'user_' . $user_id); // Company ID
Defined in bim-verdi-core/includes/class-content-types.php:
BV_CPT_COMPANY = 'foretak' // Member companies
BV_CPT_TOOL = 'verktoy' // Software tools
BV_CPT_EVENT = 'arrangement' // Events/meetings
BV_CPT_REGISTRATION = 'pamelding' // Event registrations
BV_CPT_IDEA = 'case' // Project ideas (private)
BV_CPT_PROJECT = 'prosjekt' // Pilot projects
BV_CPT_THEME_GROUP = 'theme_group' // Temagrupper
BV_CPT_ARTICLE = 'artikkel' // Member articles
Located in mu-plugins/bimverdi-email-verification.php and bimverdi-gforms-setup.php.
Forms are embedded via PHP or shortcode in registration flows, not typically in Min Side views.
Always follow claude/UI-CONTRACT.md when building Min Side templates.
max-width: 1200-1280pxmax-width: 960pxText Primary: #1A1A1A text-[#1A1A1A]
Text Secondary: #5A5A5A text-[#5A5A5A]
Dividers: #D6D1C6 border-[#D6D1C6]
Background: #F7F5EF bg-[#F7F5EF]
CTA/Orange: #FF8B5E bg-[#FF8B5E]
Use bimverdi_button() from parts/components/button.php:
bimverdi_button([
'text' => 'Lagre',
'variant' => 'primary', // primary, secondary, tertiary, danger
'size' => 'medium', // small, medium, large
'icon' => 'save', // Lucide icon name
'href' => '/url', // Makes it a link
]);
Use Lucide icons (https://lucide.dev):
layout-dashboard - Dashboardwrench - Toolsfile-text - Articleslightbulb - Ideascalendar - Eventsbuilding-2 - Companyuser-plus - Invitationschevron-right - NavigateImportant: Temagrupper are linked to foretak (companies), NOT individual users.
<?php
// At top of template part
$user_id = get_current_user_id();
$company_id = bimverdi_get_user_company($user_id);
// Require company
if (!$company_id) {
bimverdi_connect_company_cta();
return;
}
// Require hovedkontakt
if (!bimverdi_is_hovedkontakt($user_id, $company_id)) {
wp_redirect(bimverdi_minside_url('foretak'));
exit;
}
?>
get_template_part('parts/components/page-header', null, [
'title' => 'Page Title',
'description' => 'Optional subtitle text',
'icon' => 'wrench', // Lucide icon
'actions' => [
[
'text' => 'Primary Action',
'href' => '/url',
'variant' => 'primary',
'icon' => 'plus',
],
],
]);
<nav class="text-sm mb-6" aria-label="Brødsmulesti">
<ol class="flex items-center gap-2 text-[#5A5A5A]">
<li><a href="<?php echo bimverdi_minside_url(); ?>" class="hover:text-[#1A1A1A]">Min side</a></li>
<li><span class="text-[#D6D1C6]">/</span></li>
<li><a href="<?php echo bimverdi_minside_url('parent'); ?>" class="hover:text-[#1A1A1A]">Parent</a></li>
<li><span class="text-[#D6D1C6]">/</span></li>
<li class="text-[#1A1A1A] font-medium">Current Page</li>
</ol>
</nav>
<div class="overflow-x-auto">
<table class="w-full">
<thead>
<tr class="border-b border-[#D6D1C6]">
<th class="text-left py-3 px-4 text-xs font-medium text-[#5A5A5A] uppercase tracking-wide">Column</th>
</tr>
</thead>
<tbody class="divide-y divide-[#E5E2DB]">
<tr class="hover:bg-[#F7F5EF]/50">
<td class="py-4 px-4">Content</td>
</tr>
</tbody>
</table>
</div>
Add ?debug_router=1 to any Min Side URL (admin only) to see:
| Purpose | File Path |
|---------|-----------|
| Router template | template-minside-router.php |
| Route definitions | inc/minside-helpers.php |
| Access control | mu-plugins/bimverdi-access-control.php |
| Role definitions | mu-plugins/bimverdi-custom-roles.php |
| Authenticated header | header-minside.php |
| View templates | parts/minside/*.php |
| Button component | parts/components/button.php |
| Page header | parts/components/page-header.php |
| Design rules | claude/UI-CONTRACT.md |
development
Generate BIM Verdi UI components and pages following the established design system. Use when building templates, components, or any frontend for bimverdi.no. Enforces enterprise-calm aesthetics and avoids generic AI patterns.
tools
Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layers like Lobster, ACPX, plugins, or plain code. Keep conditional logic in the caller; use TaskFlow for flow identity, child-task linkage, waiting state, revision-checked mutations, and user-facing emergence.
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------