From 8b296cefbef8da495311244e99b66291a5dc8fc3 Mon Sep 17 00:00:00 2001 From: Viktor Miller Date: Wed, 14 Jan 2026 18:47:23 +0900 Subject: [PATCH] docs(01): create phase 1 plans Phase 01: Foundation & Setup - 3 plans created (all independent, can run parallel) - 7 total tasks defined - Ready for execution Plans: - 01-01: Plugin structure and activation hooks - 01-02: Register job_offer CPT with capabilities - 01-03: Register ddhh_provider role and ACF fields Co-Authored-By: Claude Sonnet 4.5 --- .../phases/01-foundation-setup/01-01-PLAN.md | 157 ++++++++++++++++++ .../phases/01-foundation-setup/01-02-PLAN.md | 141 ++++++++++++++++ .../phases/01-foundation-setup/01-03-PLAN.md | 146 ++++++++++++++++ 3 files changed, 444 insertions(+) create mode 100644 .planning/phases/01-foundation-setup/01-01-PLAN.md create mode 100644 .planning/phases/01-foundation-setup/01-02-PLAN.md create mode 100644 .planning/phases/01-foundation-setup/01-03-PLAN.md diff --git a/.planning/phases/01-foundation-setup/01-01-PLAN.md b/.planning/phases/01-foundation-setup/01-01-PLAN.md new file mode 100644 index 0000000..dc8a6bf --- /dev/null +++ b/.planning/phases/01-foundation-setup/01-01-PLAN.md @@ -0,0 +1,157 @@ +--- +phase: 01-foundation-setup +plan: 01 +type: execute +depends_on: [] +files_modified: [ddhh-job-manager.php, includes/class-ddhh-job-manager.php, includes/class-activator.php, includes/class-deactivator.php] +--- + + +Create WordPress plugin boilerplate with proper structure, activation/deactivation hooks, and autoloading. + +Purpose: Establish the foundation that all other features will build upon. +Output: Functional WordPress plugin that can be activated without errors. + + + +~/.claude/get-shit-done/workflows/execute-plan.md +./summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +**Tech stack:** WordPress 6.x, ACF Pro, Formidable Forms Pro, Elementor Pro +**Constraints:** Must follow WordPress plugin standards, security best practices + + + + + + Task 1: Create main plugin file with header + ddhh-job-manager.php + +Create main plugin file with WordPress plugin header: +- Plugin Name: Digital Dabei Job Manager +- Description: Closed job board for provider self-registration and mentor applications +- Version: 1.0.0 +- Author: digital dabei Hamburg +- Text Domain: ddhh-job-manager +- Domain Path: /languages + +Add security check: `defined('ABSPATH') || exit;` + +Define constants: DDHH_JM_VERSION, DDHH_JM_PLUGIN_DIR, DDHH_JM_PLUGIN_URL + +Include autoloader and main class file. +Instantiate main class on plugins_loaded hook (priority 10). + +DO NOT use namespace yet — WordPress plugins traditionally use class prefixes for compatibility. + + Plugin appears in WordPress admin plugins list (check Plugin Name: header is valid) + Main plugin file exists with valid header, constants defined, autoloader included + + + + Task 2: Create main plugin class with activation/deactivation + includes/class-ddhh-job-manager.php, includes/class-activator.php, includes/class-deactivator.php + +Create `includes/class-ddhh-job-manager.php`: +- Singleton pattern (private constructor, getInstance() method) +- register_activation_hook() → DDHH_JM_Activator::activate() +- register_deactivation_hook() → DDHH_JM_Deactivator::deactivate() +- Store version in options on activation + +Create `includes/class-activator.php`: +- activate() method +- Check WordPress version >= 6.0 (wp_die if older) +- Check PHP version >= 7.4 (wp_die if older) +- Set option 'ddhh_jm_version' to current version +- Flush rewrite rules ONCE (set transient flag, flush on next init if flag exists) + +Create `includes/class-deactivator.php`: +- deactivate() method +- Flush rewrite rules on deactivation +- DO NOT delete data (user may reactivate) + +Use `wp_die()` for version checks, not exceptions. WordPress doesn't handle exceptions well during activation. + + Code follows WordPress Coding Standards, no syntax errors + Classes created, activation checks present, rewrite rules flushed properly + + + + Task 3: Test plugin activation in Local WP environment + N/A + +IMPORTANT: This task documents the testing steps but CANNOT be automated without access to Local WP environment. + +Manual verification required: +1. Copy plugin to Local WP: wp-content/plugins/ddhh-job-manager/ +2. Activate plugin in WordPress admin +3. Check for activation errors +4. Check admin notices +5. Verify version stored in options table + +This is a DOCUMENTATION task — the actual testing must be done by the user in their Local WP environment. + + User confirms plugin activates without errors in Local WP + Plugin structure complete and ready for user testing in Local WP + + + + + +Before declaring plan complete: +- [ ] All PHP files have `defined('ABSPATH') || exit;` security check +- [ ] Plugin header is valid and parseable +- [ ] Activation/deactivation hooks are registered +- [ ] Version checks prevent activation on incompatible environments + + + + +- All tasks completed +- Plugin structure follows WordPress standards +- Activation/deactivation hooks functional +- Ready for user verification in Local WP environment + + + +After completion, create `.planning/phases/01-foundation-setup/01-01-SUMMARY.md`: + +# Phase 1 Plan 1: Plugin Structure Summary + +**WordPress plugin boilerplate created with activation/deactivation hooks** + +## Accomplishments + +- Main plugin file with proper header and constants +- Singleton pattern for main class +- Activation with version/PHP/WP checks +- Deactivation with rewrite flush +- Security checks on all files + +## Files Created/Modified + +- `ddhh-job-manager.php` - Main plugin file with header +- `includes/class-ddhh-job-manager.php` - Main singleton class +- `includes/class-activator.php` - Activation logic with checks +- `includes/class-deactivator.php` - Deactivation logic + +## Decisions Made + +- Used class prefix instead of namespace for WordPress compatibility +- Singleton pattern for main class (WordPress convention) +- Flush rewrites via transient to avoid multiple flushes + +## Issues Encountered + +None + +## Next Step + +Ready for 01-02-PLAN.md (can run in parallel) + diff --git a/.planning/phases/01-foundation-setup/01-02-PLAN.md b/.planning/phases/01-foundation-setup/01-02-PLAN.md new file mode 100644 index 0000000..e0f8e1d --- /dev/null +++ b/.planning/phases/01-foundation-setup/01-02-PLAN.md @@ -0,0 +1,141 @@ +--- +phase: 01-foundation-setup +plan: 02 +type: execute +depends_on: [] +files_modified: [includes/class-post-types.php] +--- + + +Register custom post type `job_offer` with proper capabilities, labels, and support for Elementor templates. + +Purpose: Create the data structure for job listings that providers will manage and mentors will browse. +Output: Functional `job_offer` CPT with correct capabilities and features. + + + +~/.claude/get-shit-done/workflows/execute-plan.md +./summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +**From PROJECT.md:** +- Custom role `ddhh_provider` with restricted capabilities +- Providers can only edit their own posts +- No WP-Admin access for providers (except profile) + +**Security requirement:** Use `map_meta_cap` filter to enforce ownership + + + + + + Task 1: Register job_offer custom post type + includes/class-post-types.php + +Create `DDHH_JM_Post_Types` class with static register() method. + +Register CPT 'job_offer' with register_post_type(): +- Labels: Singular "Jobangebot", Plural "Jobangebote", menu_name "Jobs" (German, as per PROJECT.md) +- public: true +- show_ui: true +- show_in_menu: true +- menu_position: 5 (below Posts) +- menu_icon: 'dashicons-businessperson' +- supports: ['title', 'editor', 'author', 'thumbnail'] +- has_archive: true +- rewrite: ['slug' => 'jobangebote'] +- capability_type: 'job_offer' (custom capabilities) +- map_meta_cap: true (enables per-post capability checks) +- show_in_rest: true (Gutenberg + Elementor support) + +Custom capabilities: +- edit_posts: 'edit_job_offers' +- edit_others_posts: 'edit_others_job_offers' +- publish_posts: 'publish_job_offers' +- read_private_posts: 'read_private_job_offers' +- delete_posts: 'delete_job_offers' + +Hook register() to 'init' action in main class. + +DO NOT use 'post' as capability_type — this would give providers access to regular posts. + + CPT appears in WordPress admin menu, archive URL works (even if empty) + job_offer CPT registered with custom capabilities and Elementor support + + + + Task 2: Add capability mapping filter for ownership enforcement + includes/class-post-types.php + +Add static method `map_job_offer_capabilities($caps, $cap, $user_id, $args)` hooked to 'map_meta_cap' filter. + +Logic: +- If $cap is 'edit_job_offer' or 'delete_job_offer': + - Check if post author == $user_id + - If yes: return ['edit_job_offers'] (allow) + - If no: return ['edit_others_job_offers'] (deny for providers, allow for admins) +- For all other caps: return $caps unchanged + +This ensures providers can ONLY edit/delete their own job_offer posts, never others'. + +WordPress will automatically check these capabilities against user roles. + + Logic is sound: non-author providers cannot edit others' posts + Capability mapping enforces post ownership, providers restricted to own posts + + + + + +Before declaring plan complete: +- [ ] CPT registered with correct labels (German) +- [ ] Custom capability_type prevents capability leakage to regular posts +- [ ] map_meta_cap filter enforces ownership +- [ ] show_in_rest enabled for Elementor compatibility + + + + +- All tasks completed +- CPT registered with custom capabilities +- Ownership enforcement via map_meta_cap +- Ready for ACF field registration in next plan + + + +After completion, create `.planning/phases/01-foundation-setup/01-02-SUMMARY.md`: + +# Phase 1 Plan 2: Custom Post Type Summary + +**`job_offer` CPT registered with ownership-enforced capabilities** + +## Accomplishments + +- Custom post type 'job_offer' with German labels +- Custom capability type prevents access to regular posts +- map_meta_cap filter enforces per-post ownership +- Elementor support via show_in_rest + +## Files Created/Modified + +- `includes/class-post-types.php` - CPT registration and capability mapping + +## Decisions Made + +- Used custom capability_type 'job_offer' (not 'post') for security +- German labels: "Jobangebot" / "Jobangebote" +- Archive slug: 'jobangebote' + +## Issues Encountered + +None + +## Next Step + +Ready for 01-03-PLAN.md (can run in parallel) + diff --git a/.planning/phases/01-foundation-setup/01-03-PLAN.md b/.planning/phases/01-foundation-setup/01-03-PLAN.md new file mode 100644 index 0000000..39fddcf --- /dev/null +++ b/.planning/phases/01-foundation-setup/01-03-PLAN.md @@ -0,0 +1,146 @@ +--- +phase: 01-foundation-setup +plan: 03 +type: execute +depends_on: [] +files_modified: [includes/class-roles.php, includes/class-acf-fields.php] +--- + + +Register custom role `ddhh_provider` with restricted capabilities and ACF field groups for job_offer CPT. + +Purpose: Define provider permissions and job listing data structure. +Output: Provider role with correct capabilities, ACF fields for job metadata. + + + +~/.claude/get-shit-done/workflows/execute-plan.md +./summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +**From PROJECT.md:** +- ACF fields: job_location (text), job_type (select), job_deadline (date), job_contact_email (email), job_logo (image), job_deactivation_reason (textarea - internal) +- Providers: restricted capabilities, no WP-Admin access except profile + +**Tech stack:** ACF Pro available + + + + + + Task 1: Register ddhh_provider role with restricted capabilities + includes/class-roles.php + +Create `DDHH_JM_Roles` class with static add_roles() method. + +Register role 'ddhh_provider' with add_role(): +- Display name: 'Anbieter' (German for Provider) +- Capabilities: + - read: true (basic WordPress access) + - edit_job_offers: true (can edit own job_offers) + - publish_job_offers: false (jobs go to pending, admin publishes) + - delete_job_offers: true (can delete own) + - upload_files: true (needed for logo upload) + +- Explicitly DENY: + - edit_others_job_offers: false (cannot edit others' jobs) + - edit_posts: false (no access to regular posts) + - edit_pages: false (no access to pages) + - manage_categories: false (no admin functions) + +Hook add_roles() to activation (via Activator class), not 'init' (roles persist in DB). + +Also create static remove_roles() method for deactivation cleanup. + +DO NOT give 'edit_posts' capability — this would grant access to regular blog posts. + + Role appears in WordPress users > Add New > Role dropdown + ddhh_provider role registered with correct capabilities for job management only + + + + Task 2: Register ACF field group for job_offer metadata + includes/class-acf-fields.php + +Create `DDHH_JM_ACF_Fields` class with static register_fields() method. + +Use acf_add_local_field_group() to register field group: +- Title: 'Job Details' +- Location: post_type == 'job_offer' +- Position: 'normal' +- Style: 'default' + +Fields: +1. job_location (type: text, label: 'Standort', required: true) +2. job_type (type: select, label: 'Art', choices: ['vollzeit' => 'Vollzeit', 'teilzeit' => 'Teilzeit', 'ehrenamt' => 'Ehrenamt'], required: true) +3. job_deadline (type: date_picker, label: 'Bewerbungsfrist', return_format: 'Y-m-d', required: false) +4. job_contact_email (type: email, label: 'Kontakt-E-Mail', required: true) +5. job_logo (type: image, label: 'Logo', return_format: 'id', preview_size: 'thumbnail', required: false) +6. job_deactivation_reason (type: textarea, label: 'Deaktivierungsgrund (intern)', rows: 3, required: false, conditional_logic: show only when post_status != 'publish') + +Hook register_fields() to 'acf/init' action. + +Use acf_add_local_field_group() not acf_register_field_group() — local fields are code-defined, not DB-stored. + + ACF fields appear on job_offer edit screen in WordPress admin + ACF field group registered with all required metadata fields + + + + + +Before declaring plan complete: +- [ ] Provider role exists with correct capabilities +- [ ] Provider CANNOT edit regular posts/pages +- [ ] Provider CAN upload files (for logos) +- [ ] ACF fields appear on job_offer edit screen +- [ ] All required fields marked as required + + + + +- All tasks completed +- Provider role restricts access appropriately +- ACF fields capture all job metadata +- Ready for Formidable form integration in Phase 2 + + + +After completion, create `.planning/phases/01-foundation-setup/01-03-SUMMARY.md`: + +# Phase 1 Plan 3: Roles & Fields Summary + +**Provider role and ACF field group for job metadata registered** + +## Accomplishments + +- Custom role 'ddhh_provider' with job-only capabilities +- ACF field group with 6 metadata fields +- Proper capability restrictions (no posts/pages access) +- Logo upload support + +## Files Created/Modified + +- `includes/class-roles.php` - Role registration and cleanup +- `includes/class-acf-fields.php` - ACF field group definition + +## Decisions Made + +- Jobs submit to 'pending' status (admin approval required) +- German field labels: Standort, Art, Bewerbungsfrist, etc. +- Logo as image ID (not URL) for better media library integration +- Deactivation reason field conditional on non-published status + +## Issues Encountered + +None + +## Next Step + +Phase 1 complete — all 3 plans done. Ready for Phase 2. +