Custom Post Types
- Task (pl_task) – one task per record
- Decision (pl_decision) – one project decision per record
- Change (pl_change) – one completed website/project change per record
- Technical Note (pl_technote) – hosting, Search Console, security, plugin notes
- Competitor (pl_competitor) – one competitor profile per record
- Knowledge Article (pl_article) – long-form documentation (e.g. Project Bible, Homepage Blueprint, AI Knowledge)
Purpose
This site is a private internal project management and knowledge base for PassLee, supporting collaboration between the site owner and AI assistants. It is not a public site or a traditional knowledge base plugin – it uses native WordPress content types only.
URL Structure
- /tasks/ (archive) – /tasks/example-slug/ (single)
- /decisions/ (archive) – /decisions/example-slug/ (single)
- /changes/ (archive) – /changes/example-slug/ (single)
- /technical/ (archive) – /technical/example-slug/ (single)
- /competitors/ (archive) – /competitors/example-slug/ (single)
- /knowledge/ (archive) – /knowledge/example-slug/ (single)
Permalinks use the Post name structure. Each post type has its own rewrite slug and archive, registered in code rather than through a CPT plugin.
Design Principles
- Native WordPress only – no CPT, page builder, or knowledge base plugins
- All post types registered via code in wp-content/novamira-sandbox/passlee-cpts.php
- Default theme (Twenty Twenty-Five), no styling or visual polish at this phase
- Clean, predictable URLs for every post type
- Admin post types grouped under a single “PassLee KB” top-level menu
- Simplicity and scalability prioritised over speed or added functionality
- Site is set to discourage search engine indexing; this is an internal system, not a public site
Structured Data Layer (Phase 3)
All metadata is implemented natively using WordPress post meta and custom meta boxes registered in wp-content/novamira-sandbox/passlee-meta.php. No custom field plugin (ACF, Meta Box, Pods) is used. Fields are rendered in a single “PassLee Details” meta box per post type, saved via a standard save_post handler with nonce verification and per-field sanitisation.
Task fields
- task_status – select (Not Started, In Progress, Waiting, Completed)
- task_priority – select (Low, Normal, High, Critical)
- task_category – select (Homepage, SEO, Technical, Google Business Profile, Content, Security, General)
- task_target_date – date (Y-m-d)
- task_actual_date – date (Y-m-d)
- task_owner – text
Decision fields
- decision_date – date
- decision_status – select (Proposed, Accepted, Superseded)
- decision_impact – select (Low, Medium, High)
- decision_related_task – post reference (optional, stores a Task post ID)
Change fields
- change_date – date
- change_type – select (Website, SEO, Technical, Security, Content)
- change_related_task – post reference (stores a Task post ID)
Technical Note fields
- technote_system – select (WordPress, Hosting, DNS, Security, Search Console, Google Business Profile, Plugins, Performance, Email)
- technote_status – select (Current, Historical)
Competitor fields
- competitor_url – URL
- competitor_strength – integer, 1–10
- competitor_threat – select (Low, Medium, High)
- competitor_notes – text area (free text)
Knowledge Article fields
- article_category – text
- article_version – text
- article_last_reviewed – date
Admin columns
- Tasks: Status, Priority, Category, Target Date
- Decisions: Status, Date
- Changes: Change Type, Date
- Technical Notes: System
- Competitors: Threat Level
Design rationale
- Post meta keeps every record queryable via standard WP_Query meta_query, which underpins future filtering, reporting, and AI-assisted retrieval without a plugin dependency.
- Select-type fields use fixed option lists to keep data consistent for later aggregation (e.g. counting tasks by status).
- Relational fields (Related Task) store a plain post ID rather than a plugin-specific relationship format, keeping the data portable.
- Meta boxes use plain HTML form fields with no JS framework, matching the “simple editing experience” requirement.
- Admin columns surface the fields most useful for at-a-glance triage without opening each record.
Relationship Model (Phase 4)
Relationship storage
Relationships are stored as native post meta, no plugin. Each relationship field is a single meta key on the source post holding a plain PHP array of related post IDs (WordPress serialises this automatically). No junction tables, no external libraries, no AJAX – the checklist UI in the “Relationships” meta box is rendered and saved with standard POST form submission on save_post, reusing the same nonce as the Details meta box.
A record’s full relationship graph is computed on read by passlee_get_related_posts(), which combines two sources: forward links (the relationship fields stored directly on that post) and reverse links (other posts elsewhere in the system whose own relationship fields point back to it). This means editing a relationship from either side makes it visible from both sides without needing to write to two records at once.
Supported relationships
- Task ↔ Decisions, Changes, Technical Notes, Knowledge Articles, Competitors
- Decision ↔ Tasks, Changes, Knowledge Articles
- Change ↔ Tasks, Decisions, Technical Notes
- Technical Note ↔ Tasks, Changes, Knowledge Articles
- Competitor ↔ Tasks, Knowledge Articles
- Knowledge Article ↔ Tasks, Decisions, Changes, Technical Notes, Competitors
Every field is defined once in a single relationship map (passlee_relationship_map()) inside wp-content/novamira-sandbox/passlee-relationships.php, which drives the admin checklist UI, the save handler, the read-only Related Content panel, and the front-end display – one source of truth for the whole graph.
Display
- Admin: a read-only “Related Content” meta box at the bottom of every edit screen lists each related record’s title, content type, status (where the type has one), and an edit link. Server-rendered only, no AJAX.
- Front-end: a “Related Items” block is appended to the bottom of every single view via the_content, grouped by content type, linking to each related record’s public URL.
Future expansion strategy
Because every relationship resolves through one function and one map, later features can build on this without touching the storage layer:
- Dashboard widgets and progress reports can call passlee_get_related_posts() to build task/decision/change counts per record.
- AI summaries and automatic timelines can walk the graph outward from any record (e.g. Task → Decision → Change → Technical Note) since forward and reverse links are already unified.
- Dependency tracking can reuse the same map to flag records with no relationships, or Tasks blocked on unresolved Decisions.
- If the relationship volume grows large enough that the reverse lookup (which scans other post types) becomes slow, the same map can be used to add a lightweight reverse-index meta key without changing any of the calling code.
Editor Experience & Data Integrity (Phase 5)
Validation
Required fields are enforced via the wp_insert_post_data filter in wp-content/novamira-sandbox/passlee-editor.php. If a record is set to Publish but is missing a required field, WordPress silently saves it as a Draft instead and shows an admin notice listing what’s missing. This is a soft block rather than a hard stop – no data is lost, the author just needs to complete the record and republish. Required fields: Task (Title, Status, Priority, Category), Decision (Title, Decision Date, Status), Change (Title, Change Date, Change Type), Technical Note (Title, System).
Defaults
New (auto-draft) records are pre-filled with sensible defaults so most fields don’t need to be touched for routine entries: Task (Status: Not Started, Priority: Normal, Owner: Lee), Decision (Status: Proposed), Technical Note (Status: Current), Knowledge Article (Version: 1.0). Defaults only apply before a value has been saved – once a record has real data, its own saved value always takes precedence.
Integrity rules
- Duplicate-title warning: on save, if another record of the same content type already has the same title, an admin notice warns the editor. This never blocks saving – it’s advisory only.
- Timestamps: Created and Last Updated are WordPress’s own native post_date/post_modified fields, displayed read-only in the Record Info panel and on the front end – no separate meta fields needed since WordPress already maintains these automatically.
- Record Health: a rough completeness score (filled fields ÷ total fields, including relationships) plus a list of what’s missing and a live relationship count, shown in the Record Info sidebar panel. It’s a guide for editors, not a strict validation gate.
Revision model
An optional “Revision Summary” text field (post meta key revision_summary) lets an editor leave a short human note about what changed and why (e.g. “Updated Homepage Blueprint after SEO review”). It’s stored alongside the record rather than as a separate log, keeping the model simple; a dedicated changelog/history feature can be layered on top later without altering this field.
Navigation
A Quick Navigation bar at the top of every edit screen links to the previous and next record of the same type, that type’s archive, and the Dashboard, to reduce clicking back and forth through admin lists while working through a batch of records.
Dashboard Intelligence (Phase 6)
The Dashboard page (ID 7) is no longer static. Its stored content is a placeholder only – on every page load, a the_content filter (priority 20, wp-content/novamira-sandbox/passlee-dashboard.php) completely replaces it with HTML generated live from current records. Nothing on this page is manually entered; every figure is calculated at request time. No AI is used anywhere in this phase – every number is a plain count, filter, sort, or average over existing post meta and relationships.
Data gathering & performance
passlee_gather_all_posts() runs exactly six get_posts() queries per request (one per content type, publish+draft, meta cache primed automatically), cached in a static variable so every section and metric on the page reuses the same in-memory arrays – no per-section, per-row, or nested queries. No external caching plugin is used; the cache only lives for the duration of the single page load.
Every query and metric
- Current Tasks – all Tasks where task_status !== Completed, sorted in PHP by a fixed rank (Critical, High, Normal, Low).
- Recent Decisions / Changes – top 10 by decision_date / change_date (falling back to post date if empty), newest first.
- Technical Notes – all Technical Notes where technote_status !== Historical.
- Knowledge Articles – every article, sorted alphabetically by title.
- Statistics Panel – Open/Completed Tasks (task_status), and plain counts of Decisions, Changes, Technical Notes, Knowledge Articles, Competitors.
- Priority Panel – Critical/High Tasks (non-completed, by task_priority), Waiting Tasks (task_status), Completed This Month (task_actual_date falling in the current calendar month, falling back to the post’s modified date if no actual date was recorded).
- Relationship Summary – for Tasks, Decisions, and Knowledge Articles, the record with the highest combined forward+reverse relationship count from passlee_get_related_posts(), and that count.
- Recently Updated – every record across all six types, sorted by post_modified, top 15.
- System Health – Total Records (sum across all types); Average Task Completion (Completed Tasks ÷ Total Tasks); Average Record Health (mean of passlee_record_health() percent across every record); Broken Relationships (relationship meta entries whose stored ID no longer exists or no longer matches the expected target type – should normally read zero); Draft Records (post_status = draft across all types).
Calculation methods
All calculations are plain PHP over the arrays from passlee_gather_all_posts(): array_filter for exclusions, usort with small comparator functions for ordering, and simple counters for statistics. Percentages are rounded to the nearest whole number and are explicitly approximate guides (as with Record Health in Phase 5), not exact scientific measurements. The Broken Relationships check is the one integrity-style calculation: it walks every relationship field on every record and verifies the stored post ID still exists and is still the expected content type.
Navigation
A “Project Overview” link was added to the Knowledge Base menu, pointing to the same Dashboard page, alongside the existing “Dashboard” link.
Mission Control Dashboard (Phase 7)
The Dashboard page now leads with a “Mission Control” block (Sections 1-5) answering where the project stands, what’s being worked on, and what’s next, with everything from Phase 6 moved below a divider as “Detailed Records”. All of it is generated by the same the_content filter as Phase 6, in wp-content/novamira-sandbox/passlee-dashboard.php.
Project Status (new CPT)
A new post type, Project Status (pl_status), registered in wp-content/novamira-sandbox/passlee-project-status.php, is the single source of truth for Mission Control. It’s deliberately kept separate from the Phase 4 relationship engine and the Phase 3/5/6 shared maps, so Mission Control’s data can’t be disturbed by unrelated changes elsewhere in the system. Only one record is intended to exist; the Dashboard reads the earliest one by ID, and the editor shows a warning if a second record is created.
Fields on the Project Status record: Current Phase, Current Objective, Current Milestone, Overall Completion % (0-100), Project Health (On Track / At Risk / Delayed / Blocked / Complete), Target Completion Date, Current Sprint, Sprint Goal, Current Focus, and Roadmap. Sprint Tasks is a checklist of Task records (stored as an array of post IDs in rel_sprint_tasks), giving the Current Sprint section something concrete to calculate completion from. Every field is editable in the normal WordPress editor – no code changes needed to update Mission Control.
Roadmap storage
Rather than three separate fields for items/order/state, the roadmap is one textarea (status_roadmap) with one line per item in the format “Label|state” (state is completed, current, or planned). Line order in the textarea is roadmap order. This keeps roadmap items, their order, and their state editable as a single natural-to-edit field rather than a repeater UI, which WordPress has no native equivalent for. passlee_parse_roadmap() turns this into a structured list at render time.
Mission Control sections
- Project Status card – Current Phase, Current Objective, Current Milestone, Project Status (Project Health, colour-coded), Overall Progress, Target Completion, all read live from the Project Status record.
- Roadmap – a horizontal, wrapping row of items with a completed/current/planned marker (✓ / ● / ○) and a legend, built with plain CSS (flexbox), no images, no JavaScript.
- Current Sprint – Current Sprint name, Sprint Goal, the list of Sprint Tasks with their status, and Sprint Completion % (Completed sprint Tasks ÷ total sprint Tasks).
- Recently Completed – the last 5 Tasks with Status = Completed, newest first by Actual Completion Date (falling back to last-modified date).
- Next Up – open Tasks with Priority = High, soonest Target Completion Date first.
Colour and responsiveness
The only colours used are green (On Track / Complete), amber (At Risk / Delayed / Blocked), grey (neutral text and planned roadmap items), and white card backgrounds – no gradients, no animations. Layout uses CSS Grid (auto-fit columns) for the status card and flexbox (wrap) for the roadmap, with two breakpoints (782px, 480px) collapsing the grid and stacking the roadmap for tablet and mobile.
Navigation
The Knowledge Base menu’s “Dashboard” entry was replaced with “Project Overview” (both pointed at the same homepage) – one entry now, per the simplification request.
Design System (Phase 8)
Phase 8 is a pure redesign of the Mission Control dashboard: no new data, no new post types, no new queries. The same the_content filter, same passlee_gather_all_posts() cache, and the same Project Status record from Phase 7 now render as an application-style interface instead of a document. All CSS lives in one function, passlee_mc_css_v2(), scoped under the .passlee-mc wrapper so it can’t leak into the rest of the theme.
Typography
Exactly three font sizes, set as CSS variables and reused everywhere: –mc-text-hero (2.5rem, the project name and stat numbers), –mc-text-heading (1.25rem, section headings and sprint name), –mc-text-body (1rem, everything else – labels, values, dates, badges). Hierarchy comes from weight and colour, not extra sizes: bold charcoal for primary values, a soft grey (–mc-charcoal-soft) for secondary labels and metadata.
Spacing
Sections are separated by margin (48px between major sections) rather than borders. Cards use consistent 24px internal padding. The hero uses top padding and vertical rhythm instead of a bordered box, per the brief’s “use spacing rather than borders.”
Cards
One shared .passlee-mc-card style: 12px rounded corners, a subtle two-layer shadow, a hairline border (not a heavy one), white background. Status cards, the sprint card, the two activity cards, and the priorities card all reuse this one class, so equal height and consistent styling come for free from the grid/flex layout around them rather than per-card rules.
Roadmap
Rebuilt as connected milestone items joined by connector lines (flexbox, no images). Completed items are muted green, planned items are grey, and the current item is visually larger (bigger marker and bold, full-size heading text) so it reads as “you are here” at a glance. The connector immediately before/after the current item is drawn thicker to mark the transition into the active milestone. On narrow screens the same markup switches to a vertical stack via a media query, with vertical connector lines.
Colour
- White (card backgrounds)
- Very light grey (page/track backgrounds, muted chips)
- Dark charcoal (primary text)
- Green (On Track / Complete health, progress bars, completed roadmap items)
- Amber (At Risk / Delayed / Blocked health)
- Blue (links only)
No other colours, no gradients, and no animations or transitions anywhere in the stylesheet.
Component philosophy
- The Hero answers “where are we” in one glance: name, health pill, phase, one progress bar, then objective/milestone/focus as quiet label-value pairs.
- Status cards answer “what’s the shape of the data” – icon, number, label, nothing else, so they scan instantly.
- Current Sprint answers “what are we doing right now” with its own progress bar and task list.
- Recent Activity and Current Priorities answer “what’s next / what changed” without needing tables.
- Detailed Project Data (the whole of Phase 6) is collapsed into a native <details> accordion, closed by default, for the minority of visits that need the full record-by-record view. No JavaScript is used for the toggle – it’s a native, keyboard-accessible HTML element.
Accessibility: visible focus outlines on links and the accordion summary, colour is never the only signal (health and roadmap states also use text/position), and layout collapses gracefully at 782px and 600px breakpoints for tablet and mobile.
Visual Command Centre (Phase 9)
Phase 9 is a further pure visual layer on top of Phases 6-8: no new post types, no new fields, no new queries beyond what already existed. A handful of new metrics are computed heuristically from existing data and are documented explicitly below so it’s clear which numbers are direct fields versus derived signals.
App shell and header
A full-bleed light-grey (#F5F7FA) band now sits behind the whole dashboard (breaking out of the theme’s normal content width via a negative-margin/100vw technique), with a full-bleed PassLee Blue (#1B57D6) application header above it showing “PassLee Control Centre”, “Mission Control”, a live health pill, and the current phase. This header is rendered by the_content filter, the same as the rest of the dashboard – it does not modify the theme’s actual site header/navigation template, which still sits above it unchanged. The theme’s default footer is hidden specifically on this page via a small page-scoped inline style, so the dashboard ends naturally after the last widget.
Hero and progress visualisation
The hero now includes a circular SVG progress ring for Overall Completion (pure SVG stroke-dasharray/offset, no JavaScript, no animation) alongside Mission Status, Current Phase, Current Mission, Next Milestone, and Current Focus arranged as a label/value grid. A new “Progress” section shows four horizontal bars:
- Overall Progress – direct from status_overall_completion.
- Sprint Progress – Completed sprint Tasks ÷ total sprint Tasks (same calculation as the Current Sprint card).
- Knowledge Growth – Knowledge Articles ÷ total records across all six content types, i.e. what share of the knowledge base is made up of articles. This is a derived metric, not a stored field.
- Project Health – the same Average Record Health used in System Health (Phase 6).
Category colours
- Website – blue
- SEO – green
- Technical – purple
- Knowledge – teal
- Competitors – orange
- Urgent – red
Applied as top-border accents on the status cards: Open Tasks (Website blue), Completed (green), Knowledge (teal), Technical (purple), and Health (dynamic – green/amber/red depending on its own percentage, since it represents a live health state rather than a fixed category).
Roadmap
Rebuilt with larger circular nodes joined by a connecting line: completed nodes are green, the current node is a large blue circle, future nodes are grey. Hovering a node adds a focus ring via CSS :hover with no transition duration, so the effect is instant rather than animated, honouring “hover effects acceptable, no animations.”
Today’s Mission (new)
A new card that surfaces one concrete next action: the most urgent open Task in the current sprint (by priority rank), falling back to the most urgent open Task overall if the sprint has none. “Why it matters” reuses the Sprint Goal. “Related Sprint” reuses Current Sprint. There is no “estimated effort” field anywhere in the data model, so rather than inventing a number this shows “Not tracked yet” – kept honest rather than fabricated.
Project Health signals (new)
Four coloured indicators, all derived from existing data:
- Overall Health – direct from status_project_health.
- Momentum – the share of open Tasks that are “In Progress” versus “Not Started” (excluding Waiting/Completed). ≥50% in progress = green, 20-49% = amber, below 20% = red.
- Risk – red if Project Health is Delayed/Blocked or any Broken Relationships exist; amber if At Risk; otherwise green.
- Confidence – Average Record Health (Phase 6): ≥80% green, 50-79% amber, below 50% red. Represents how complete the underlying records are, not a subjective judgement.
Activity Timeline (replaces Recent Activity)
The two-column Decisions/Changes layout from Phase 8 is replaced with a single chronological list, grouped into Today / Yesterday / Earlier, covering all six content types (not just Decisions and Changes), using the same Recently Updated data as Phase 6. Each entry is labelled “added” if the post’s modified time is within a minute of its created time, or “updated” otherwise – derived from existing post_date/post_modified timestamps, not a new field.
Quick Actions (new)
Five buttons linking directly to each content type’s native “Add New” admin screen (e.g. wp-admin/post-new.php?post_type=pl_task). No plugin, no JavaScript – plain links using admin_url().
Visual Priority
Rather than adding a separate duplicate section, the Critical=red / High=amber / Normal=blue / Completed=green colour system is applied as pills wherever a Task’s priority or status already appears – the Current Priorities rows and the Current Sprint task list – so urgency reads visually before the text does, in both places it matters.
Insights (placeholder)
An empty, clearly-labelled “Coming soon” section reserved for future AI-generated project summaries. No functionality yet.