Alice Technical Journal – 2026-01-28

What I have done

Homework publish scheduling (published_at)

  • Implemented published_at consistently across:
    • Teachers > Homework Create / Edit
    • Admin > Academic > Homework Edit
    • Admin > Academic > Homework Assign modal
  • Enforced customer visibility strictly on the backend:
    • Customer queries filter: published_at IS NULL OR published_at <= now()
    • Direct URL access blocked when not yet published
  • Standardized semantics:
    • null = immediate visibility
    • future datetime = hidden
  • Fixed edge case where clearing published_at resulted in 0 affected rows, which was incorrectly treated as an error.
  • Ensured all update flows send explicit published_at values (ISO string or null).

Homework cloning (backend-first)

  • Removed frontend “Copy” logic where backend clone already exists.
  • Implemented Admin Homework clone by reusing Teachers’ clone logic:
    • Single transaction
    • Clones homework core fields + links/skills
    • Does NOT clone submissions, proofs, or completion state
  • Ensured Admin clone follows exact Teachers behavior (no semantic drift).
  • Verified clone endpoints return new homework IDs for redirect/list refresh.

Teacher Homework Edit stability & UX

  • Restored missing student assignment section.
  • Implemented class-based filtering and bulk assign/unassign:
    • Avoided incorrect students.class_id assumptions
    • Used relationship-derived class mapping instead
  • Fixed Radix Select runtime crashes:
    • Removed value="" from <SelectItem>
    • Introduced explicit sentinel value ("__all__")
  • Fixed silent save bug:
    • Root cause: PUT requests sent empty payloads
    • Solution: ensure useForm state is bound to inputs and passed explicitly to router.put
  • Removed all temporary debug logging after verification.
  • Adjusted sidebar behavior as page complexity increased, then reverted sticky behavior when it became counterproductive.

Direct upload experiments (and rollback)

  • Attempted direct-to-R2 upload:
    • Introduced upload init/finalize flow
    • Generated presigned PUT URLs
    • Hit Flysystem limitation: adapter does not expose S3Client
    • Reimplemented presigning with explicit AWS SDK client
  • Encountered R2 browser constraints:
    • CORS configuration subtleties (OPTIONS handling, allowed headers)
    • Browser masking auth failures as CORS errors
  • Attempted Google Drive fallback:
    • Integrated Google Drive service account backend
    • Verified connection via Artisan command
    • Hit Google Picker complexity (OAuth, API enablement, origin restrictions)
  • Made a deliberate rollback decision:
    • Hard reset to stable commits when upload paths became too risky
    • Preserved system integrity over partial success

Infrastructure & safety discipline

  • Performed multiple controlled git hard resets to known good commits.
  • Reinforced rule: experiments must not pollute mainline stability.
  • Ensured queue workers, caches, and config were reset after each rollback.

What I have learned

Backend truth > UI assumptions

  • Many “working” UIs were lying:
    • Success toasts fired without DB writes
    • Update endpoints returning 200 while doing nothing
  • Logging request payloads + DB effects is the fastest way to kill these bugs.

SQL semantics matter

  • UPDATE ... SET column = NULL returning 0 rows is not an error.
  • Treating “rows affected” as a success signal is dangerous without context.

Abstractions break at infrastructure boundaries

  • Flysystem is fine for storage, but:
    • Presigned URLs
    • Browser uploads
    • Advanced cloud behavior
      require native SDK control.
  • Assuming adapters expose internals leads to dead ends.

CORS errors are often lies

  • Browser CORS errors frequently hide:
    • Signature mismatch
    • Header mismatch
    • Permission errors
  • Real debugging requires:
    • curl with the presigned URL
    • Inspecting raw S3/R2 XML error responses

Google Drive has a hard auth split

  • Service account = backend automation
  • Browser uploads = user OAuth
  • Google Picker increases surface area and fragility
  • Trying to “simplify” Drive uploads without respecting this split causes instability

Resetting is an engineering skill

  • Knowing when to stop and reset prevented Alice from becoming untestable.
  • Hard resets are cheaper than weeks of duct-tape fixes.
  • Stability is a feature.

Reuse beats speed

  • Reusing Teachers flows for Admin (clone, scheduling, assignments) reduced bugs.
  • Any divergence between Admin and Teacher behavior is technical debt waiting to explode.