diff --git a/.gitignore b/.gitignore
index f8b367e..68bd285 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,4 @@
vendor/
node_modules/
data/*.json
-.direnv/
-cypress/screenshots/
-cypress/videos/
\ No newline at end of file
+.direnv/
\ No newline at end of file
diff --git a/.opencode/opencode.json b/.opencode/opencode.json
deleted file mode 100644
index e2342fc..0000000
--- a/.opencode/opencode.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "$schema": "https://opencode.ai/config.json",
- "plugin": [
- "caveman",
- "caveman-opencode-plugin@latest"
- ]
-}
\ No newline at end of file
diff --git a/AGENTS.md b/AGENTS.md
deleted file mode 100644
index 5dea88b..0000000
--- a/AGENTS.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Project context
-
-Read these on every session. Rules in them override defaults.
-
-@ai/shared.md
-@ai/backend-context.md
-@ai/frontend-context.md
diff --git a/DailyGoals.drawio b/DailyGoals.drawio
index aa76945..b0937cb 100644
--- a/DailyGoals.drawio
+++ b/DailyGoals.drawio
@@ -16,14 +16,11 @@
-
-
-
-
+
@@ -31,14 +28,14 @@
-
-
+
+
-
+
-
+
diff --git a/ai/backend-context.md b/ai/backend-context.md
deleted file mode 100644
index fca41f0..0000000
--- a/ai/backend-context.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# Backend context
-
-> Read `ai/shared.md` first. This file only covers backend-specific rules.
-
-## Project Context
-
-**Stack:** PHP 8.5, Slim 4, PHP-DI/Slim-Bridge, PHPUnit 13, Composer.
-Persistence is JSON-file based (see `Json*Repository` classes); no ORM.
-**Architecture:** Domain-Driven Design. Code is organized by domain entity
-under `app/` (Auth, Node, Plan, ScheduledNode, Text, User, View,
-ValueObjects) into Entities, DTOs, Repositories, Use Cases, and Fakes
-(in-memory repos for tests).
-
-## Code patterns
-
-- Look at similar entities (e.g. `Node`, `Text`) for reference
-- Entities: constructor with properties, getters
-- DTOs: simple data containers for creation (e.g. `CreateTextDto`)
-- Repositories: interfaces that define data access
- - Do not write unit tests for concrete repository implementations
- (e.g. `JsonNodeRepository`). They are exercised by e2e tests. Use
- cases are tested with fake repositories.
-- Use cases: business logic with Request objects
- - When throwing exceptions, add `@throws` docblock
-- Fakes: in-memory implementations for testing
- - Look at `tests/Fakes/` for examples
- - Find/lookup methods must return a new instance of the entity, not the
- stored reference
-- Tests: follow existing patterns in `tests/Unit/[Entity]/UseCases/`
- - In `setUp`, only use fake repositories for entities under test - construct
- dependency objects directly with `new` (e.g.
- `new Text(...)`) instead of creating them through their fake
- repositories
-
-## PHP rules
-
-- Imports: always put `use` statements at the top of the file, never use inline
- imports (e.g. `\App\Foo\Bar::class`)
-- Closures: never use arrow functions (`fn () =>`) - always use regular
- anonymous functions (`function () { return ...; }`)
-
-## Pre-commit
-
-Run `php-cs-fixer fix` on worked-on directories before committing (uses the
-existing `.php-cs-fixer.dist.php` config).
diff --git a/ai/backend_prompt_template.md b/ai/backend_prompt_template.md
new file mode 100644
index 0000000..c16ef26
--- /dev/null
+++ b/ai/backend_prompt_template.md
@@ -0,0 +1,68 @@
+# Entity Creation Prompt Template
+
+Follow the existing patterns in this codebase to:
+- create a new entity called [EntityName].
+
+Requirements:
+- The entity encapsulates [one or more Entities]
+- Include [any other fields]
+
+Process (TDD - Test Driven Development):
+1. Write a test first
+2. Run the test to confirm it fails
+3. Implement the code to make the test pass
+4. Run the test to confirm it passes
+5. Repeat for each new behavior
+
+Code patterns to follow:
+- First, explore the codebase to understand existing entity patterns
+- Look at similar entities (e.g. Node, Text, etc.) for reference
+- Entities: constructor with properties, getters
+- DTOs: simple data containers for creation
+- Repositories: interfaces that define data access
+ - Do not write unit tests for concrete repository implementations
+ (e.g., Doctrine/persistence-backed). They are exercised by e2e
+ tests. Use cases are tested with fake repositories.
+- Use cases: business logic with Request objects
+ - When throwing exceptions, add @throws docblock
+- Fakes: in-memory implementations for testing
+ - Look at tests/Fakes/ for examples
+ - Find/lookup methods must return a new instance of the entity, not the stored reference
+- Tests: follow existing patterns in tests/Unit/[Entity]/UseCases/
+ - In setUp, only use fake repositories for entities under test - construct dependency objects directly with `new` (e.g., `new Text(....)`) instead of creating them through their fake repositories
+- Lines should not exceed 80 columns, but should use up to 80 columns when possible - do not split lines unnecessarily
+- Imports: always put use statements at the top of the file, never use inline imports (e.g., \App\Foo\Bar::class)
+- Variable names: use explicit, descriptive names - never single-letter or abbreviated variables (e.g., use $sponsorship not $s, $event not $e)
+- Never use em-dashes (—) in code, comments, commit messages, or any
+ written output. Use a regular hyphen (-), a colon, or rephrase
+ with parentheses instead.
+
+Git commit style:
+- Subject: present tense, imperative mood (add, create, test, fix)
+- Subject: lowercase, short (3-6 words)
+- Match subject patterns found in git history
+- Add a body when the change needs explanation beyond the subject -
+ e.g., why the change was made, non-obvious tradeoffs, or notable
+ implementation details. Skip the body for trivial/self-evident commits.
+- Separate subject and body with a blank line; wrap body at ~72 columns
+
+Git commits:
+- Tests should be committed first, before implementation
+- Group related changes together in a single commit (e.g., a new class
+ plus its registration, or a getter plus the property it exposes).
+ Avoid mixing unrelated concerns in one commit.
+- Keep commits small and focused - prefer many small commits over few
+ large ones, but don't artificially split a single logical change
+ across multiple commits
+- Commits are for reviewing and documenting the development of code
+- Don't wait to commit - commit as you go
+- Run `php-cs-fixer fix` on worked on directories before committing
+
+Branch naming:
+- Use kebab-case (e.g., presenting-track, agenda-slots)
+- Use descriptive feature names
+- Examples: "presenting-track", "agenda-slots", "confirm-application"
+- Or use type/description: "feature/presenting-track", "fix/bug-name"
+- NEVER work directly on master/main - always create and work on a branch
+
+Do not push anything. Make commits as you go.
diff --git a/ai/frontend-context.md b/ai/frontend-context.md
deleted file mode 100644
index 8757e1f..0000000
--- a/ai/frontend-context.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# Frontend context
-
-> Read `ai/shared.md` first. This file only covers frontend-specific rules.
-
-## Project Context
-
-**Stack:** vanilla PHP templates in `views/templates/`, plain ES JavaScript in
-`public/js/`, no framework, no build step. Cypress 15 for E2E.
-**Entry point:** `public/index.php` (Slim app); page templates are rendered
-via the existing templating layer.
-
-## Code patterns
-
-- Look at existing pages (`home.php`/`home.js`, `text.php`/`text.js`,
- `today.php`/`today.js`) for reference before writing anything
-- **Templates:** `views/templates/.php`, one file per page
-- **Page JS:** `public/js/.js`, one file per page, paired with the
- matching template
-- **Testing:** Cypress E2E only, mirror existing `cypress/e2e/*.cy.js` style
- (note: this project uses `.cy.js`, not `.cy.ts`)
-- **Imports / script tags:** keep at the top of the file
-- **Variable names:** explicit, descriptive (e.g. `text` not `t`)
-
-## Pre-commit
-
-No JS formatter or linter is configured yet; format manually for consistency
-with surrounding files. (TODO: wire up format/lint when added.)
-
-## Note on commit granularity
-
-Frontend changes are often a template plus its page-level JS counterpart -
-commit them together as a single logical unit, per the "one logical change
-per commit" rule in `shared.md`.
diff --git a/ai/frontend_prompt_template.md b/ai/frontend_prompt_template.md
new file mode 100644
index 0000000..a865577
--- /dev/null
+++ b/ai/frontend_prompt_template.md
@@ -0,0 +1,52 @@
+# Frontend Prompt Template
+
+Follow the existing patterns in this codebase to:
+- xxxxxxxx
+
+Requirements:
+- xxxxx
+
+Process (TDD - Test Driven Development):
+1. Write a test first
+2. Run the test to confirm it fails
+3. Implement the code to make the test pass
+4. Run the test to confirm it passes
+5. Repeat for each new behavior
+
+Code patterns to follow:
+- First, explore the codebase to understand existing entity patterns
+- Look at similar pages for reference
+- Tests: follow existing patterns in cypress/e2e/
+- Lines should not exceed 80 columns, but should use up to 80 columns when possible - do not split lines unnecessarily
+- Imports: always put imports at the top of the file
+- Variable names: use explicit, descriptive names - never single-letter or abbreviated variables (e.g., use sponsorship not s, event not e)
+- Never use em-dashes (—) in code, comments, commit messages, or any
+ written output. Use a regular hyphen (-), a colon, or rephrase
+ with parentheses instead.
+
+Git commit style:
+- Subject: present tense, imperative mood (add, create, test, fix)
+- Subject: lowercase, short (3-6 words)
+- Match subject patterns found in git history
+- Add a body when the change needs explanation beyond the subject -
+ e.g., why the change was made, non-obvious tradeoffs, or notable
+ implementation details. Skip the body for trivial/self-evident commits.
+- Separate subject and body with a blank line; wrap body at ~72 columns
+
+Git commits:
+- Tests should be committed first, before implementation
+- Group related changes together in a single commit (e.g., a new class
+ plus its registration, or a getter plus the property it exposes).
+ Avoid mixing unrelated concerns in one commit.
+- Keep commits small and focused - prefer many small commits over few
+ large ones, but don't artificially split a single logical change
+ across multiple commits
+- Commits are for reviewing and documenting the development of code
+- Don't wait to commit - commit as you go
+
+Branch naming:
+- Use kebab-case (e.g., node-page text-page)
+- Use descriptive feature names
+- NEVER work directly on master - always create and work on a branch
+
+Do not push anything. Make commits as you go.
diff --git a/ai/shared.md b/ai/shared.md
deleted file mode 100644
index cc85dd1..0000000
--- a/ai/shared.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# Shared rules
-
-Rules that apply to both backend and frontend work in this repo. Stack-specific
-guides (`backend-context.md`, `frontend-context.md`) extend these.
-
-## Process (TDD)
-
-0. Before editing any file, ensure you are on a feature branch
- (`git status` to confirm). If on master/main, create a branch
- first.
-1. Write the test first
-2. Run the test to confirm it fails
-3. Commit the failing test (the "tests committed first" rule in
- action - the test commit precedes the implementation commit, not
- merely the implementation lines)
-4. Implement the code to make the test pass
-5. Run the test to confirm it passes
-6. Commit the implementation
-7. Repeat for each new behavior
-
-## Code style
-
-- Lines should not exceed 80 columns, but should use up to 80 columns when
- possible - do not split lines unnecessarily
-- Variable names: use explicit, descriptive names - never single-letter or
- abbreviated variables (e.g. `$text` not `$t`, `$node` not `$n`)
-- Method/function/constructor parameters: do not use default values - every
- call site must pass every argument explicitly. This eliminates a class of
- bugs where an unintended default silently slips through (e.g. an
- `isAdmin=false` or an empty `passwordHash`). Apply the same rule in tests
- and fakes - if a helper accepts a value, every caller must supply it.
-- First, explore the codebase to understand existing patterns - look at similar
- files for reference before writing anything
-- Never use em dashes (—) in code, comments, or docblocks - use hyphens (-)
- instead
-
-## Git commit style
-
-- Present tense, imperative mood (add, create, wire, fix, test)
-- Lowercase
-- Short (3-6 words)
-- Match patterns found in git history
-- Do not add any section mentioning claude as a coauthor
-- Add a commit body when the subject alone cannot convey the change - e.g.
- non-obvious motivation, multi-file coordination, or notable complexity
-- Body: wrap at ~72 columns, separated from subject by a blank line, explain
- the why and any non-obvious what
-- Skip the body for trivial or self-explanatory commits
-
-## Git commits
-
-- Tests should be committed first, before implementation
-- One logical change per commit - a commit may span multiple files when they
- form a single logical unit (e.g. a use case with its request and exception,
- or a template with its page-level JS)
-- Keep commits focused: not one file per commit, not unrelated work batched
-- Make commits frequent - commit each meaningful logical step as you go
-- Commits are for reviewing and documenting the development of code
-- When the formatter or linter modifies files outside your intended
- change, either `git restore` them or land them as a separate
- `format ` / `lint ` commit - never bundle drive-by
- formatter churn into a feature commit
-- If pre-commit lint fails on code you did not touch, do not bundle
- the fix - either land the unrelated fix as its own commit first, or
- note the pre-existing failure and proceed
-
-## Branching
-
-- Use kebab-case (e.g. `text-page`, `scheduled-node`, `auth-flow`)
-- Use descriptive feature names
-- Or use type/description: `feature/text-page`, `fix/bug-name`
-- NEVER work directly on master/main - always create and work on a branch
-
-Do not push anything. Make commits as you go.
diff --git a/app/Plan/JsonPlanRepository.php b/app/Plan/JsonPlanRepository.php
index 8c73d8a..8a88838 100644
--- a/app/Plan/JsonPlanRepository.php
+++ b/app/Plan/JsonPlanRepository.php
@@ -90,29 +90,4 @@ class JsonPlanRepository implements PlanRepository
return $maxId + 1;
}
-
- public function findByUser(User $user): array
- {
- $plans = array_filter(
- $this->readPlans(),
- function ($data) use ($user) {
- return $data['userId'] === $user->getId();
- }
- );
-
- return array_map(
- function ($data) {
- $user = $this->userRepository->find($data['userId']);
- if ($user === null) {
- return null;
- }
- return new Plan(
- id: $data['id'],
- name: $data['name'],
- user: $user,
- );
- },
- $plans
- );
- }
}
diff --git a/app/Plan/PlanRepository.php b/app/Plan/PlanRepository.php
index 0585edc..a962c0f 100644
--- a/app/Plan/PlanRepository.php
+++ b/app/Plan/PlanRepository.php
@@ -2,14 +2,8 @@
namespace App\Plan;
-use App\User\User;
-
interface PlanRepository
{
public function create(CreatePlanDto $dto): Plan;
public function find(int $id): ?Plan;
- /**
- * @return Plan[]
- */
- public function findByUser(User $user): array;
}
diff --git a/app/Plan/UseCases/CreatePlan.php b/app/Plan/UseCases/CreatePlan.php
index 8a3cc91..b12fc50 100644
--- a/app/Plan/UseCases/CreatePlan.php
+++ b/app/Plan/UseCases/CreatePlan.php
@@ -64,7 +64,6 @@ class CreatePlan
new CreateScheduledNodeRequest(
date: $scheduledDate->format('Y-m-d'),
planId: $plan->getId(),
- nodeId: $node->getId(),
)
);
}
diff --git a/app/ScheduledNode/CreateScheduledNodeDto.php b/app/ScheduledNode/CreateScheduledNodeDto.php
index 086c975..5e7a695 100644
--- a/app/ScheduledNode/CreateScheduledNodeDto.php
+++ b/app/ScheduledNode/CreateScheduledNodeDto.php
@@ -2,7 +2,6 @@
namespace App\ScheduledNode;
-use App\Node\Node;
use App\Plan\Plan;
use DateTimeImmutable;
@@ -11,6 +10,5 @@ class CreateScheduledNodeDto
public function __construct(
public DateTimeImmutable $date,
public Plan $plan,
- public Node $node,
) {}
}
diff --git a/app/ScheduledNode/JsonScheduledNodeRepository.php b/app/ScheduledNode/JsonScheduledNodeRepository.php
index 1870844..bee31ea 100644
--- a/app/ScheduledNode/JsonScheduledNodeRepository.php
+++ b/app/ScheduledNode/JsonScheduledNodeRepository.php
@@ -2,19 +2,12 @@
namespace App\ScheduledNode;
-use App\Node\NodeRepository;
-use App\Plan\PlanRepository;
-use App\User\User;
-use DateTimeImmutable;
-
class JsonScheduledNodeRepository implements ScheduledNodeRepository
{
private string $filePath;
- public function __construct(
- private PlanRepository $planRepo,
- private NodeRepository $nodeRepo,
- ) {
+ public function __construct()
+ {
$this->filePath = __DIR__ . '/../../data/scheduledNodes.json';
}
@@ -27,8 +20,6 @@ class JsonScheduledNodeRepository implements ScheduledNodeRepository
'id' => $id,
'date' => $dto->date->format('Y-m-d'),
'planId' => $dto->plan->getId(),
- 'nodeId' => $dto->node->getId(),
- 'completed' => false,
];
$this->writeScheduledNodes($scheduledNodes);
@@ -36,8 +27,6 @@ class JsonScheduledNodeRepository implements ScheduledNodeRepository
id: $id,
date: $dto->date,
plan: $dto->plan,
- node: $dto->node,
- completed: false,
);
}
@@ -75,34 +64,4 @@ class JsonScheduledNodeRepository implements ScheduledNodeRepository
return $maxId + 1;
}
-
- public function findByUser(User $user): array
- {
- $allScheduledNodes = $this->readScheduledNodes();
- $planIds = array_map(
- function ($plan) {
- return $plan->getId();
- },
- $this->planRepo->findByUser($user)
- );
- $usersScheduledNodes = array_filter(
- $allScheduledNodes,
- function ($node) use ($planIds) {
- return in_array($node['planId'], $planIds);
- }
- );
-
- return array_map(
- function ($data) {
- return new ScheduledNode(
- id: $data['id'],
- date: new DateTimeImmutable($data['date']),
- plan: $this->planRepo->find($data['planId']),
- node: $this->nodeRepo->find($data['nodeId']),
- completed: $data['completed']
- );
- },
- $usersScheduledNodes
- );
- }
}
diff --git a/app/ScheduledNode/ScheduledNode.php b/app/ScheduledNode/ScheduledNode.php
index 83f29ef..7d479db 100644
--- a/app/ScheduledNode/ScheduledNode.php
+++ b/app/ScheduledNode/ScheduledNode.php
@@ -2,7 +2,6 @@
namespace App\ScheduledNode;
-use App\Node\Node;
use App\Plan\Plan;
use DateTimeImmutable;
@@ -12,8 +11,6 @@ class ScheduledNode
private int $id,
private DateTimeImmutable $date,
private Plan $plan,
- private Node $node,
- private bool $completed,
) {}
public function getId(): int
@@ -30,19 +27,4 @@ class ScheduledNode
{
return $this->date;
}
-
- public function getNode(): Node
- {
- return $this->node;
- }
-
- public function getCompleted(): bool
- {
- return $this->completed;
- }
-
- public function setCompleted(bool $complete): void
- {
- $this->completed = $complete;
- }
}
diff --git a/app/ScheduledNode/ScheduledNodeController.php b/app/ScheduledNode/ScheduledNodeController.php
deleted file mode 100644
index 3a71ccb..0000000
--- a/app/ScheduledNode/ScheduledNodeController.php
+++ /dev/null
@@ -1,73 +0,0 @@
-getAttribute('user');
- if (!$user instanceof User) {
- $response->getBody()->write(
- json_encode(['error' => 'unauthenticated'])
- );
- return $response->withStatus(401)
- ->withHeader('Content-Type', 'application/json');
- }
-
- $queryParams = $request->getQueryParams();
- $date = $queryParams['date'] ?? null;
- if ($date === '') {
- $date = null;
- }
-
- try {
- $scheduledNodes = $getTodaysSchedule->execute(
- new GetTodaysScheduleRequest(
- date: $date,
- userId: $user->getId(),
- )
- );
- } catch (BadRequestException $exception) {
- $response->getBody()->write(
- json_encode(['error' => $exception->getMessage()])
- );
- return $response->withStatus(400)
- ->withHeader('Content-Type', 'application/json');
- } catch (DomainException $exception) {
- $response->getBody()->write(
- json_encode(['error' => $exception->getMessage()])
- );
- return $response->withStatus(404)
- ->withHeader('Content-Type', 'application/json');
- }
-
- $data = array_values(array_map(
- function (ScheduledNode $scheduledNode) {
- return [
- 'id' => $scheduledNode->getId(),
- 'date' => $scheduledNode->getDate()->format('Y-m-d'),
- 'planName' => $scheduledNode->getPlan()->getName(),
- 'nodeTitle' => $scheduledNode->getNode()->getTitle(),
- 'completed' => $scheduledNode->getCompleted(),
- ];
- },
- $scheduledNodes,
- ));
-
- $response->getBody()->write(json_encode($data));
- return $response->withStatus(200)
- ->withHeader('Content-Type', 'application/json');
- }
-}
diff --git a/app/ScheduledNode/ScheduledNodeRepository.php b/app/ScheduledNode/ScheduledNodeRepository.php
index 055a939..b13b7c5 100644
--- a/app/ScheduledNode/ScheduledNodeRepository.php
+++ b/app/ScheduledNode/ScheduledNodeRepository.php
@@ -2,13 +2,7 @@
namespace App\ScheduledNode;
-use App\User\User;
-
interface ScheduledNodeRepository
{
public function create(CreateScheduledNodeDto $dto): ScheduledNode;
- /**
- * @return ScheduledNode[]
- */
- public function findByUser(User $user): array;
}
diff --git a/app/ScheduledNode/UseCases/CreateScheduledNode.php b/app/ScheduledNode/UseCases/CreateScheduledNode.php
index 444f4d0..752b658 100644
--- a/app/ScheduledNode/UseCases/CreateScheduledNode.php
+++ b/app/ScheduledNode/UseCases/CreateScheduledNode.php
@@ -3,7 +3,6 @@
namespace App\ScheduledNode\UseCases;
use App\Exceptions\BadRequestException;
-use App\Node\NodeRepository;
use App\Plan\PlanRepository;
use App\ScheduledNode\ScheduledNode;
use App\ScheduledNode\CreateScheduledNodeDto;
@@ -16,7 +15,6 @@ class CreateScheduledNode
public function __construct(
private ScheduledNodeRepository $scheduledNodeRepo,
private PlanRepository $planRepo,
- private NodeRepository $nodeRepo,
) {}
/**
@@ -26,40 +24,24 @@ class CreateScheduledNode
public function execute(
CreateScheduledNodeRequest $request
): ScheduledNode {
- $nodeId = $request->nodeId;
- $planId = $request->planId;
- $date = $request->date;
- if ($date === null) {
+ if ($request->date === null) {
throw new BadRequestException('date is required');
}
- if ($planId === null) {
+ if ($request->planId === null) {
throw new BadRequestException('planId is required');
}
- if ($nodeId === null) {
- throw new BadRequestException('nodeId is required');
- }
-
- $plan = $this->planRepo->find($planId);
+ $id = $request->planId;
+ $plan = $this->planRepo->find($id);
if ($plan === null) {
- throw new DomainException(
- "Plan with id: $planId doesnt exist"
- );
- }
-
- $node = $this->nodeRepo->find($nodeId);
- if ($node === null) {
- throw new DomainException(
- "Node with id: $nodeId doesnt exist"
- );
+ throw new DomainException("Plan with id: $id doesnt exist");
}
return $this->scheduledNodeRepo->create(
new CreateScheduledNodeDto(
- date: new DateTimeImmutable($date),
+ date: new DateTimeImmutable($request->date),
plan: $plan,
- node: $node,
)
);
}
diff --git a/app/ScheduledNode/UseCases/CreateScheduledNodeRequest.php b/app/ScheduledNode/UseCases/CreateScheduledNodeRequest.php
index 4c0a2fd..5931cb3 100644
--- a/app/ScheduledNode/UseCases/CreateScheduledNodeRequest.php
+++ b/app/ScheduledNode/UseCases/CreateScheduledNodeRequest.php
@@ -7,6 +7,5 @@ class CreateScheduledNodeRequest
public function __construct(
public ?string $date,
public ?int $planId,
- public ?int $nodeId,
) {}
}
diff --git a/app/ScheduledNode/UseCases/GetTodaysSchedule.php b/app/ScheduledNode/UseCases/GetTodaysSchedule.php
deleted file mode 100644
index 3301549..0000000
--- a/app/ScheduledNode/UseCases/GetTodaysSchedule.php
+++ /dev/null
@@ -1,51 +0,0 @@
-date === null) {
- throw new BadRequestException('date is required');
- }
- if ($request->userId === null) {
- throw new BadRequestException('userId is required');
- }
- $date = new DateTimeImmutable($request->date);
- $userId = $request->userId;
- $user = $this->userRepo->find($userId);
- if ($user === null) {
- throw new DomainException(
- "User with id: $userId doesnt exist"
- );
- }
- $scheduledNodes = $this->scheduledNodeRepo->findByUser($user);
-
- return array_filter(
- $scheduledNodes,
- function (ScheduledNode $node) use ($date) {
- return $node->getDate() <= $date
- && $node->getCompleted() === false;
- }
- );
- }
-}
diff --git a/app/ScheduledNode/UseCases/GetTodaysScheduleRequest.php b/app/ScheduledNode/UseCases/GetTodaysScheduleRequest.php
deleted file mode 100644
index ccb38b8..0000000
--- a/app/ScheduledNode/UseCases/GetTodaysScheduleRequest.php
+++ /dev/null
@@ -1,11 +0,0 @@
-getBody()->write($html);
-
- return $response;
- }
-
public function login(Response $response): Response
{
$html = file_get_contents(
diff --git a/bootstrap/app.php b/bootstrap/app.php
index b4e9907..c05dc0f 100644
--- a/bootstrap/app.php
+++ b/bootstrap/app.php
@@ -11,7 +11,6 @@ use App\View\ViewController;
use App\Text\TextController;
use App\Node\NodeController;
use App\Plan\PlanController;
-use App\ScheduledNode\ScheduledNodeController;
$container = require __DIR__ . '/container.php';
$app = Bridge::create($container);
@@ -28,7 +27,6 @@ $app->post('/api/auth/register', [AuthController::class, 'register']);
// Authenticated routes (any logged-in user)
$app->group('', function (RouteCollectorProxy $group) {
$group->get('/home', [ViewController::class, 'home']);
- $group->get('/today', [ViewController::class, 'today']);
$group->post('/api/auth/logout', [AuthController::class, 'logout']);
$group->get('/api/auth/me', [AuthController::class, 'me']);
@@ -45,11 +43,6 @@ $app->group('', function (RouteCollectorProxy $group) {
);
$group->post('/api/plans', [PlanController::class, 'createPlan']);
-
- $group->get(
- '/api/scheduled-nodes',
- [ScheduledNodeController::class, 'getScheduledNodes']
- );
})->add(AuthMiddleware::class);
// Admin-only routes
diff --git a/bootstrap/container.php b/bootstrap/container.php
index 02666ed..2ae6e4c 100644
--- a/bootstrap/container.php
+++ b/bootstrap/container.php
@@ -26,10 +26,10 @@ $container = new Container([
NodeRepository::class => DI\autowire(JsonNodeRepository::class),
PlanRepository::class => DI\autowire(JsonPlanRepository::class),
UserRepository::class => DI\autowire(JsonUserRepository::class),
- ScheduledNodeRepository::class
- => DI\autowire(JsonScheduledNodeRepository::class),
- SessionRepository::class
- => DI\autowire(JsonSessionRepository::class),
+ ScheduledNodeRepository::class =>
+ DI\autowire(JsonScheduledNodeRepository::class),
+ SessionRepository::class =>
+ DI\autowire(JsonSessionRepository::class),
TokenGenerator::class => DI\autowire(RandomTokenGenerator::class),
Clock::class => DI\autowire(SystemClock::class),
PasswordHasher::class => DI\autowire(BcryptPasswordHasher::class),
diff --git a/caveman.json b/caveman.json
deleted file mode 100644
index fb19545..0000000
--- a/caveman.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "enabled": true,
- "defaultMode": "full",
- "features": {
- "caveman": true,
- "commit": ,
- "review": true
- }
-}
diff --git a/cypress/e2e/today.cy.js b/cypress/e2e/today.cy.js
deleted file mode 100644
index 1f24450..0000000
--- a/cypress/e2e/today.cy.js
+++ /dev/null
@@ -1,75 +0,0 @@
-describe('The today page', () => {
- beforeEach(() => {
- cy.exec('npm run db:seed')
- })
-
- afterEach(() => {
- cy.exec('npm run db:wipe')
- })
-
- it('redirects to login when not authenticated', () => {
- cy.visit('/today')
- cy.url().should('include', '/login')
- })
-
- it('displays a Today heading when authenticated', () => {
- cy.loginAsUser()
- cy.visit('/today')
- cy.get('h1').should('contain', 'Today')
- })
-
- it('has a list element for scheduled nodes', () => {
- cy.loginAsUser()
- cy.visit('/today')
- cy.get('#scheduled-nodes-list').should('exist')
- })
-
- it('home page links to the today page', () => {
- cy.loginAsUser()
- cy.visit('/home')
- cy.get('a[href="/today"]').should('be.visible')
- })
-
- it('lists scheduled nodes for today', () => {
- const today = new Date()
- const year = today.getFullYear()
- const month = String(today.getMonth() + 1).padStart(2, '0')
- const day = String(today.getDate()).padStart(2, '0')
- const todayString = year + '-' + month + '-' + day
-
- cy.loginAsUser()
- cy.request({
- method: 'POST',
- url: '/api/plans',
- body: {
- textId: 0,
- name: 'My reading plan',
- dateStart: todayString,
- dateEnd: todayString,
- },
- })
-
- cy.intercept('GET', '/api/scheduled-nodes*')
- .as('getScheduledNodes')
- cy.visit('/today')
- cy.wait('@getScheduledNodes').then((interception) => {
- expect(interception.request.url).to.include(
- 'date=' + todayString
- )
- })
- cy.get('#scheduled-nodes-list').should(
- 'contain',
- 'My reading plan'
- )
- cy.get('#scheduled-nodes-list').should('contain', 'Bereishis')
- })
-
- it('shows an empty list when no nodes are scheduled today', () => {
- cy.loginAsUser()
- cy.intercept('GET', '/api/scheduled-nodes*')
- .as('getScheduledNodes')
- cy.visit('/today')
- cy.wait('@getScheduledNodes')
- cy.get('#scheduled-nodes-list li').should('have.length', 0)
- })
-})
diff --git a/public/js/today.js b/public/js/today.js
deleted file mode 100644
index 6f14627..0000000
--- a/public/js/today.js
+++ /dev/null
@@ -1,33 +0,0 @@
-document.addEventListener('DOMContentLoaded', () => {
- const scheduledNodesList = document.getElementById(
- 'scheduled-nodes-list'
- );
-
- function todayDateString() {
- const today = new Date();
- const year = today.getFullYear();
- const month = String(today.getMonth() + 1).padStart(2, '0');
- const day = String(today.getDate()).padStart(2, '0');
- return year + '-' + month + '-' + day;
- }
-
- async function loadScheduledNodes() {
- const date = todayDateString();
- const response = await fetch(
- '/api/scheduled-nodes?date=' + date,
- { credentials: 'same-origin' }
- );
- if (!response.ok) {
- return;
- }
- const scheduledNodes = await response.json();
- scheduledNodesList.innerHTML = scheduledNodes
- .map((scheduledNode) =>
- '