L
Back to Index
Build Reports & Field Transmissions

Rawdocumentationfromthetrenches

Technical deep-dives, architectural decisions, and lessons from the process of building real things.

0

Entries

0

Categories

0

Active Since

01

Transmissions

Field reports

#012
Architecture6 min

Shipping the Permission Graph

Context

Fyboard's permission system needed field-level access control across 8 modules, 4 roles, and tenant isolation — all resolved at request time.

Problem

Permission checks were taking 120ms+ per request under load. Every API call triggered a cascading set of policy evaluations against the role hierarchy.

Root Cause

We were checking permissions top-down: for each field, walk the role tree to see if the user has access. O(fields × depth) on every request.

Fix / Refactor

Inverted the lookup. On authentication, pre-compute the full accessible field set per role into a Redis bitmap. Permission checks became a single bitwise AND — O(1).

Architectural Change

Moved from runtime policy evaluation to a pre-computed permission cache with invalidation on role/policy mutations. Added a migration to backfill bitmaps for existing roles.

Long-term Implication

This pattern generalizes. Any permission system that checks per-resource can be flipped into a pre-computed set. We now resolve field-level access in under 5ms at any scale.

PermissionsPerformancePostgreSQL
#011
Engineering

Why I Rebuilt the Task Engine Three Times

Context

Fyboard's core is a task engine. It needs to model statuses, transitions, dependencies, recurring schedules, and integrations — without becoming a maintenance nightmare.

Problem

Version 1 was a CRUD app with status strings. It couldn't express 'blocked by' or 'recurs every Tuesday'. Version 2 used a full state machine library — but the abstraction was heavier than the feature.

Root Cause

I was over-indexing on generality. The state machine handled every theoretical transition, but 90% of tasks only needed 3 states. The abstraction cost more than the flexibility it provided.

Fix

Version 3: a thin state machine for the 3 common states (todo/active/done) with an escape hatch to a full DAG for complex workflows. Two layers, one interface.

8 min
FyboardState MachinesIteration
#010
AI

Vector Embeddings for Context Memory

Context

Building an AI memory layer that persists context across conversations. The model needs to recall previous decisions, user preferences, and ongoing project state.

Problem

Naive full-context injection hit the token limit after 3 conversations. Summarization lost critical details. The model kept re-asking questions it had already resolved.

Root Cause

Text summarization is lossy — it preserves narrative but drops structured facts. 'The user prefers TypeScript over Python' gets averaged out of a summary about a coding session.

Fix

Built a retrieval pipeline using Pinecone vector embeddings. Each conversation turn gets embedded and scored on three axes: semantic relevance, temporal recency, and declared importance.

7 min
EmbeddingsPineconeLangChain
#009
Design

OKLCh: The Color Space That Changed Everything

Context

Every project had inconsistent color palettes. Generating shades from HSL produced muddy mid-tones and unpredictable contrast ratios between steps.

Problem

HSL(210, 80%, 50%) and HSL(60, 80%, 50%) have the same 'lightness' but wildly different perceived brightness. Palette generation was trial-and-error, not systematic.

Root Cause

HSL lightness isn't perceptually uniform. A 10% lightness step at hue 60 (yellow) looks nothing like a 10% step at hue 240 (blue). The math doesn't match human vision.

Fix

Switched the entire design system to OKLCh. Defined all colors as oklch(L C H) with consistent lightness steps (0.15 increments). Accent, muted, dim — all derived from the same L/C curves.

5 min
ColorOKLChCSS
#008
Frontend

Scroll-Driven Animations Without the Jank

Context

This site needed layered scroll animations — parallax backgrounds, reveal-on-scroll content, and choreographed section transitions. All at 60fps on mobile.

Problem

Initial implementation used scroll event listeners with direct DOM manipulation. Jittery on mobile, layout thrashing on resize, and impossible to coordinate timing across sections.

Root Cause

Scroll events fire on the main thread. Any work in the handler blocks paint. Combined with getBoundingClientRect calls (forcing layout recalc), every frame was a full reflow.

Fix

Replaced everything with Framer Motion's useScroll + useTransform pipeline. Scroll progress drives motion values through spring transforms — all computed off-thread via WAAPI.

6 min
AnimationPerformanceFramer Motion
#007
Architecture

Modular Architecture: Lessons from Fyboard

Context

Fyboard grew from a task manager to a full productivity suite. Every new feature (notes, calendar, integrations) was coupling deeper into the core schema.

Problem

Adding a calendar feature required modifying the task table, the API router, the permission system, and the UI shell. A 'simple' feature touched 40+ files.

Root Cause

Monolithic coupling. The task schema had become a god table with optional columns for every feature. The API router mixed concerns. No feature boundary existed.

Fix

Extracted each feature into a self-contained module: own schema, own API routes, own UI components, own permission definitions. The core provides a module registry and shared auth — nothing else.

9 min
ArchitectureModularityScale
#006
Engineering

Building a Real-Time Workflow Engine

Context

Fyboard needed to automate multi-step processes: 'when a task moves to Done, update the project progress, notify the team, and trigger the next task in the pipeline.'

Problem

Chained event handlers created invisible execution paths. Errors in step 3 left steps 1-2 committed. No retry logic. No way to inspect the current state of an in-flight workflow.

Root Cause

Event-driven chains without explicit state. Each handler knew about the next step but had no concept of the overall workflow, its progress, or how to recover from partial failure.

Fix

Replaced event chains with XState state machines for workflow definitions and BullMQ for durable job execution. Each workflow step is a job with explicit success/failure transitions.

10 min
BullMQXStateAsync
#005
Frontend

Canvas Particle Systems at 60fps

Context

Needed an interactive background for this site — thousands of particles with physics-based mouse repulsion, connection lines between neighbors, and smooth 60fps on all devices.

Problem

Naive implementation with Array.forEach and distance checks between all particle pairs ran at 8fps with 5,000 particles. GC pauses caused visible stutters every 2-3 seconds.

Root Cause

O(n²) neighbor lookups with no spatial indexing. Plus, creating new objects every frame for position vectors triggered garbage collection storms.

Fix

Implemented spatial hashing (divide canvas into grid cells, only check neighbors in adjacent cells). Object pooling for all vector math — zero allocations per frame. Delta timing for frame-rate independence.

7 min
CanvasPerformancePhysics
The best documentation is written while building, not after.