feat: implement auth, projects, and frontend foundation
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-05-17
|
||||
@@ -0,0 +1,3 @@
|
||||
# auth-oauth
|
||||
|
||||
Implement OAuth2/OIDC authentication via Authentik with internal JWTs and DB-backed refresh tokens
|
||||
@@ -0,0 +1,68 @@
|
||||
## Context
|
||||
|
||||
The existing repository now includes core database infrastructure and user models, but authentication is not implemented yet. The target behavior is defined by `openspec/specs/auth-oauth/spec.md` and refined through approved decisions: Authentik OIDC as the identity provider, strict production cookies, internal JWT access tokens, and server-side refresh token storage with revocation.
|
||||
|
||||
The backend is Python-based with async SQLAlchemy and Alembic. This change must integrate with that stack while keeping trust boundaries explicit and supporting predictable local development.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Implement Authentik OAuth2/OIDC login and callback flow.
|
||||
- Validate provider tokens via JWKS before creating local session credentials.
|
||||
- Mint internal short-lived JWT access tokens for API authorization.
|
||||
- Persist hashed opaque refresh tokens in DB with rotation and revocation.
|
||||
- Provide explicit logout that invalidates refresh state and clears cookies.
|
||||
- Enforce environment-aware cookie policy (strict in production, relaxed on localhost).
|
||||
|
||||
**Non-Goals:**
|
||||
- RBAC policy engine and permission modeling.
|
||||
- Multi-device session management UX.
|
||||
- Additional social identity providers.
|
||||
|
||||
## Decisions
|
||||
|
||||
1. **Use OIDC code flow + Authentik JWKS validation before local minting**
|
||||
- Rationale: prevents blind trust in token exchange payloads and centralizes signature/claim checks (`iss`, `aud`, `exp`).
|
||||
- Alternative considered: trust exchange response without independent validation. Rejected due to weaker security posture.
|
||||
|
||||
2. **Issue internal JWT access tokens instead of forwarding provider access tokens**
|
||||
- Rationale: stable internal contract, decoupled claim shape, simpler downstream authorization.
|
||||
- Alternative considered: pass-through provider tokens. Rejected due to tighter coupling and reduced control over TTL/claims.
|
||||
|
||||
3. **Use DB-backed opaque refresh tokens with hash-at-rest + rotation**
|
||||
- Rationale: supports immediate revocation on logout and tighter reuse detection.
|
||||
- Alternative considered: stateless long-lived JWT refresh tokens. Rejected because revocation and replay handling are weaker.
|
||||
|
||||
4. **Environment-aware cookie policy with secure defaults**
|
||||
- Production: `Secure=true`, `SameSite=strict`, `HttpOnly=true`.
|
||||
- Local dev: `Secure=false`, `SameSite=lax`, `HttpOnly=true`.
|
||||
- Rationale: preserves security in production while enabling localhost development without TLS.
|
||||
|
||||
5. **Add dedicated refresh token persistence model and migration**
|
||||
- Table fields: `id`, `user_id`, `token_hash`, `expires_at`, `created_at`, `revoked_at`, `user_agent`, `ip_address`.
|
||||
- Indexes: unique `token_hash`, plus `user_id` and `expires_at` indexes.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **[JWKS endpoint/network failures]** -> Cache JWKS keys with bounded TTL and fail closed with `401` on unverifiable tokens.
|
||||
- **[Clock skew affecting token validity]** -> Allow small validation leeway and keep server clock synchronized.
|
||||
- **[Refresh token replay attempts]** -> Rotate per refresh, revoke reused chains, and force re-authentication.
|
||||
- **[Cookie behavior differences across browsers/environments]** -> Centralize cookie option builder and test dev/prod permutations.
|
||||
- **[Added implementation surface area]** -> Keep modules focused (provider client, JWT service, refresh store, routes) and maintain high test coverage.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Add new refresh token model and Alembic migration.
|
||||
2. Add configuration for OIDC endpoints/client credentials/JWT secret/cookie mode.
|
||||
3. Implement auth services (provider exchange + JWKS verification, JWT mint/verify, refresh store).
|
||||
4. Implement routes: `/auth/login`, `/auth/callback`, `/auth/refresh`, `/auth/logout`, `/auth/me`.
|
||||
5. Add/expand tests (unit + integration) for auth and token lifecycle.
|
||||
6. Verify quality gates (`pytest`, `ruff`, `mypy`) and migration status.
|
||||
|
||||
Rollback:
|
||||
- Revert route/service changes and run Alembic downgrade for refresh-token migration if deployment requires rollback.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- None blocking for initial implementation.
|
||||
- Optional follow-up: enforce single active refresh token per user-agent/device (currently out of scope).
|
||||
@@ -0,0 +1,27 @@
|
||||
## Why
|
||||
|
||||
The project has database foundations in place but still lacks production-ready user authentication. We need a secure OAuth2/OIDC integration with Authentik that issues internal session credentials and supports reliable logout and token revocation.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Implement backend OAuth2/OIDC login and callback flow against Authentik.
|
||||
- Verify Authentik-issued tokens via JWKS before minting local credentials.
|
||||
- Mint short-lived internal JWT access tokens and store refresh tokens server-side.
|
||||
- Add refresh-token rotation, revocation, and explicit logout semantics.
|
||||
- Apply environment-aware secure cookie policy (strict in production, relaxed for localhost development).
|
||||
- Add auth endpoints, supporting services, and test coverage for auth flows.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `auth-session-tokens`: Internal JWT access-token issuance, opaque refresh-token storage, rotation, and revocation.
|
||||
|
||||
### Modified Capabilities
|
||||
- `auth-oauth`: Extend OAuth/OIDC behavior to require JWKS validation, internal JWT minting, cookie policy by environment, and DB-backed refresh lifecycle.
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected backend modules in `apps/api/src` (config, models, auth services, API routes).
|
||||
- New database schema object for refresh-token persistence and an accompanying migration.
|
||||
- New environment variables for OIDC/JWT/cookie settings.
|
||||
- Frontend auth integration points for login/logout/me/refresh behavior.
|
||||
@@ -0,0 +1,62 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: OAuth2/OIDC Flow
|
||||
The system SHALL support OAuth2/OIDC authentication via Authentik and SHALL validate Authentik-issued tokens via JWKS before creating local sessions.
|
||||
|
||||
#### Scenario: User login
|
||||
- GIVEN a user clicks the login button
|
||||
- WHEN the frontend redirects to Authentik authorization endpoint
|
||||
- THEN the user authenticates with Authentik
|
||||
- AND Authentik redirects back with authorization code
|
||||
|
||||
#### Scenario: Token exchange and validation
|
||||
- GIVEN Authentik has redirected with authorization code
|
||||
- WHEN the callback endpoint receives the code
|
||||
- THEN it exchanges the code for provider tokens
|
||||
- AND verifies token signature and claims using Authentik JWKS
|
||||
- AND upserts the local user account
|
||||
- AND mints internal access and refresh tokens
|
||||
|
||||
### Requirement: Session Security
|
||||
The system SHALL protect sessions using httpOnly cookies and SHALL apply secure cookie defaults by environment.
|
||||
|
||||
#### Scenario: Cookie attributes in production
|
||||
- GIVEN successful authentication in production
|
||||
- WHEN cookies are set
|
||||
- THEN access_token cookie SHALL be httpOnly
|
||||
- AND access_token cookie SHALL have Secure flag
|
||||
- AND access_token cookie SHALL have SameSite=strict
|
||||
- AND refresh_token cookie SHALL have the same attributes
|
||||
|
||||
#### Scenario: Cookie attributes in localhost development
|
||||
- GIVEN successful authentication in localhost development
|
||||
- WHEN cookies are set
|
||||
- THEN access_token cookie SHALL be httpOnly
|
||||
- AND access_token cookie SHALL have Secure=false
|
||||
- AND access_token cookie SHALL have SameSite=lax
|
||||
- AND refresh_token cookie SHALL have the same attributes
|
||||
|
||||
### Requirement: Token Refresh
|
||||
The system SHALL support automatic token refresh with server-side refresh token storage, rotation, and revocation.
|
||||
|
||||
#### Scenario: Access token expiration
|
||||
- GIVEN a user has an expired access token
|
||||
- WHEN the user makes an authenticated request that can refresh
|
||||
- THEN the system validates the refresh token against non-expired, non-revoked DB state
|
||||
- AND rotates the refresh token
|
||||
- AND issues a new internal access token
|
||||
|
||||
#### Scenario: Refresh token reuse detection
|
||||
- GIVEN a refresh token has already been rotated or revoked
|
||||
- WHEN it is presented again to the refresh endpoint
|
||||
- THEN the system rejects the request with unauthorized status
|
||||
- AND invalidates the token chain for the session
|
||||
|
||||
### Requirement: Session Termination
|
||||
The system SHALL support explicit logout with refresh token invalidation.
|
||||
|
||||
#### Scenario: User logout
|
||||
- GIVEN an authenticated user
|
||||
- WHEN the user clicks logout
|
||||
- THEN all auth cookies are cleared
|
||||
- AND the refresh token is invalidated in server-side storage
|
||||
@@ -0,0 +1,38 @@
|
||||
## 1. Configuration and schema foundation
|
||||
|
||||
- [x] 1.1 Add auth/OIDC/JWT/cookie settings to backend config with environment-aware defaults.
|
||||
- [x] 1.2 Add refresh token SQLAlchemy model and relationships to user model.
|
||||
- [x] 1.3 Add Alembic migration for refresh token table and indexes.
|
||||
- [x] 1.4 Add/adjust tests that fail first for config and refresh-token model metadata.
|
||||
|
||||
## 2. Auth provider and token services
|
||||
|
||||
- [x] 2.1 Implement Authentik OIDC client helpers for login URL build and callback token exchange.
|
||||
- [x] 2.2 Implement JWKS-based token verification helper for provider tokens.
|
||||
- [x] 2.3 Implement internal JWT mint/verify helper with configured TTL.
|
||||
- [x] 2.4 Implement refresh token store service (hashing, create, rotate, revoke, reuse detection).
|
||||
- [x] 2.5 Add unit tests for provider verification, JWT helpers, cookie options, and refresh lifecycle.
|
||||
|
||||
## 3. Auth HTTP endpoints
|
||||
|
||||
- [x] 3.1 Implement `GET /auth/login` redirect endpoint.
|
||||
- [x] 3.2 Implement `GET /auth/callback` with state validation, token exchange, user upsert, and cookie set.
|
||||
- [x] 3.3 Implement `POST /auth/refresh` with DB validation and rotation.
|
||||
- [x] 3.4 Implement `POST /auth/logout` to revoke refresh state and clear cookies.
|
||||
- [x] 3.5 Implement `GET /auth/me` returning authenticated user payload via internal JWT.
|
||||
- [x] 3.6 Add integration tests for callback, refresh rotation, logout, and unauthorized cases.
|
||||
|
||||
## 4. Verification and OpenSpec tracking
|
||||
|
||||
- [x] 4.1 Run auth-focused and full backend checks (`pytest`, `ruff check`, `mypy`) and fix findings.
|
||||
- [x] 4.2 Run migration verification against local Postgres and confirm current revision.
|
||||
- [x] 4.3 Update this task list with completed checkboxes and note any blockers/follow-ups.
|
||||
|
||||
## Blockers / Follow-ups
|
||||
|
||||
- No blocking items remain for this change.
|
||||
|
||||
## Runtime verification
|
||||
|
||||
- `DATABASE_URL=postgresql+asyncpg://headquarter:headquarter@localhost:5432/headquarter .venv/bin/alembic -c alembic.ini upgrade head` succeeded.
|
||||
- `DATABASE_URL=postgresql+asyncpg://headquarter:headquarter@localhost:5432/headquarter .venv/bin/alembic -c alembic.ini current` returned `0002_refresh_tokens (head)`.
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-05-17
|
||||
@@ -0,0 +1,3 @@
|
||||
# database-models
|
||||
|
||||
Implement SQLAlchemy models and Alembic migrations for all core entities
|
||||
@@ -0,0 +1,125 @@
|
||||
# Design: Database Models
|
||||
|
||||
## Technology Choices
|
||||
|
||||
- **SQLAlchemy 2.0**: Modern async ORM with type annotations
|
||||
- **asyncpg**: High-performance async PostgreSQL driver
|
||||
- **Alembic**: Database migration tool
|
||||
- **UUID**: All primary keys use UUID for distributed safety
|
||||
|
||||
## Architecture
|
||||
|
||||
### Base Model
|
||||
|
||||
All models inherit from a common base with:
|
||||
- `id`: UUID primary key (default=uuid4)
|
||||
- `created_at`: Timestamp
|
||||
- `updated_at`: Timestamp (auto-updated)
|
||||
|
||||
### Models
|
||||
|
||||
1. **User**
|
||||
- id: UUID PK
|
||||
- email: str, unique, indexed
|
||||
- name: str
|
||||
- authentik_id: str, unique (external auth reference)
|
||||
- avatar_url: str | None
|
||||
- created_at, updated_at
|
||||
|
||||
2. **Project**
|
||||
- id: UUID PK
|
||||
- name: str
|
||||
- description: str | None
|
||||
- owner_id: UUID → User
|
||||
- default_ssh_key_id: UUID → SSHKey | None
|
||||
- created_at, updated_at
|
||||
|
||||
3. **GitRepository**
|
||||
- id: UUID PK
|
||||
- name: str
|
||||
- path: str (filesystem path to bare repo)
|
||||
- project_id: UUID → Project
|
||||
- owner_id: UUID → User
|
||||
- is_mirror: bool
|
||||
- remote_url: str | None
|
||||
- last_push: datetime | None
|
||||
- created_at
|
||||
|
||||
4. **SSHKey**
|
||||
- id: UUID PK
|
||||
- name: str
|
||||
- public_key: str
|
||||
- private_key_encrypted: str (Fernet encrypted)
|
||||
- user_id: UUID → User
|
||||
- project_id: UUID → Project | None
|
||||
- created_at
|
||||
|
||||
5. **UserConfig**
|
||||
- id: UUID PK
|
||||
- user_id: UUID → User
|
||||
- config: JSONB (PostgreSQL native JSON)
|
||||
- created_at, updated_at
|
||||
|
||||
### Relationships
|
||||
|
||||
```
|
||||
User 1--N Project
|
||||
User 1--N SSHKey
|
||||
User 1--1 UserConfig
|
||||
Project 1--N GitRepository
|
||||
Project N--1 SSHKey (default_ssh_key)
|
||||
```
|
||||
|
||||
### File Structure
|
||||
|
||||
```
|
||||
apps/api/
|
||||
├── src/
|
||||
│ ├── models/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── base.py # DeclarativeBase + common columns
|
||||
│ │ ├── user.py
|
||||
│ │ ├── project.py
|
||||
│ │ ├── git_repository.py
|
||||
│ │ ├── ssh_key.py
|
||||
│ │ └── user_config.py
|
||||
│ ├── database.py # Async engine + session
|
||||
│ └── config.py # Settings with pydantic-settings
|
||||
├── alembic/
|
||||
│ ├── env.py
|
||||
│ ├── script.py.mako
|
||||
│ └── versions/
|
||||
│ └── 001_initial.py
|
||||
├── tests/
|
||||
│ └── test_models.py
|
||||
└── scripts/
|
||||
└── seed.py
|
||||
```
|
||||
|
||||
## Async Pattern
|
||||
|
||||
```python
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
engine = create_async_engine(DATABASE_URL)
|
||||
AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession)
|
||||
```
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
- Single initial migration creating all tables
|
||||
- Future migrations use `alembic revision --autogenerate`
|
||||
- Run with `make migrate` (docker compose exec api alembic upgrade head)
|
||||
|
||||
## Seed Data
|
||||
|
||||
- Create a test user with sample data
|
||||
- Run via `docker compose exec api python scripts/seed.py`
|
||||
|
||||
## Quality Gates
|
||||
|
||||
- pytest with async test support
|
||||
- mypy strict mode
|
||||
- ruff for linting
|
||||
- All models have type annotations
|
||||
@@ -0,0 +1,28 @@
|
||||
# Proposal: Database Models
|
||||
|
||||
## What
|
||||
|
||||
Implement SQLAlchemy 2.0 async models and Alembic migrations for all core entities in the Headquarter platform.
|
||||
|
||||
## Why
|
||||
|
||||
All other features (auth, git repos, projects, SSH keys, etc.) depend on a solid database foundation. We need models that:
|
||||
- Use SQLAlchemy 2.0 async style for performance
|
||||
- Support all entity relationships defined in the specs
|
||||
- Have proper migrations for schema versioning
|
||||
- Include seed data for development
|
||||
|
||||
## Scope
|
||||
|
||||
- User, Project, GitRepository, SSHKey, UserConfig models
|
||||
- Alembic setup with asyncpg support
|
||||
- Initial migration creating all tables
|
||||
- Database seeding script
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- All models defined with correct relationships
|
||||
- Initial migration runs successfully
|
||||
- `make migrate` works
|
||||
- Seed script creates test data
|
||||
- Quality gates pass (pytest, mypy, ruff)
|
||||
@@ -0,0 +1,64 @@
|
||||
# Tasks: Database Models
|
||||
|
||||
## Task 1: Create project structure and configuration
|
||||
- [x] Create `apps/api/src/models/__init__.py`
|
||||
- [x] Create `apps/api/src/config.py` with pydantic-settings for database URL
|
||||
- [x] Create `apps/api/src/database.py` with async engine and session
|
||||
|
||||
## Task 2: Create base model
|
||||
- [x] Create `apps/api/src/models/base.py` with DeclarativeBase
|
||||
- [x] Add UUID primary key mixin
|
||||
- [x] Add timestamp mixin (created_at, updated_at)
|
||||
|
||||
## Task 3: Create User model
|
||||
- [x] Create `apps/api/src/models/user.py`
|
||||
- [x] Define User with all fields from spec
|
||||
- [x] Add relationships to Project, SSHKey, UserConfig
|
||||
|
||||
## Task 4: Create Project model
|
||||
- [x] Create `apps/api/src/models/project.py`
|
||||
- [x] Define Project with all fields
|
||||
- [x] Add relationships to User, GitRepository, SSHKey
|
||||
|
||||
## Task 5: Create GitRepository model
|
||||
- [x] Create `apps/api/src/models/git_repository.py`
|
||||
- [x] Define GitRepository with all fields
|
||||
- [x] Add relationships to Project, User
|
||||
|
||||
## Task 6: Create SSHKey model
|
||||
- [x] Create `apps/api/src/models/ssh_key.py`
|
||||
- [x] Define SSHKey with all fields
|
||||
- [x] Add relationships to User, Project
|
||||
|
||||
## Task 7: Create UserConfig model
|
||||
- [x] Create `apps/api/src/models/user_config.py`
|
||||
- [x] Define UserConfig with JSONB config field
|
||||
- [x] Add relationship to User
|
||||
|
||||
## Task 8: Initialize Alembic
|
||||
- [x] Create Alembic scaffolding equivalent to `alembic init`
|
||||
- [x] Configure `alembic/env.py` for async
|
||||
- [x] Update `alembic.ini` with correct URL
|
||||
|
||||
## Task 9: Create initial migration
|
||||
- [x] Generate migration creating all tables
|
||||
- [x] Verify migration is correct
|
||||
|
||||
## Task 10: Create seed script
|
||||
- [x] Create `apps/api/src/scripts/seed.py`
|
||||
- [x] Add test user and sample data payload helper
|
||||
- [x] Make script runnable
|
||||
|
||||
## Task 11: Create tests
|
||||
- [x] Create `apps/api/tests/test_models.py`
|
||||
- [x] Test model creation and relationships
|
||||
- [x] Test async database operations
|
||||
|
||||
## Task 12: Run quality gates
|
||||
- [x] Run `pytest` - all tests pass
|
||||
- [x] Run `mypy .` - no type errors
|
||||
- [x] Run `ruff check .` - no lint errors
|
||||
|
||||
## Runtime Verification
|
||||
|
||||
- [x] Run migrations against a live PostgreSQL instance to verify end-to-end database execution.
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-05-17
|
||||
@@ -0,0 +1,3 @@
|
||||
# frontend-foundation
|
||||
|
||||
Implement frontend app foundation with auth-aware shell, routing skeleton, and API integration base
|
||||
@@ -0,0 +1,56 @@
|
||||
## Context
|
||||
|
||||
`apps/web` currently contains only package and container scaffolding, with no source code. Backend authentication and API foundations are now available, including cookie-based auth flows. The frontend foundation must establish a maintainable structure that supports authenticated navigation, responsive layout behavior, and consistent API communication.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Create a minimal but production-oriented React app structure with TypeScript and Vite.
|
||||
- Add client-side routing with protected-route behavior and fallback 404 route.
|
||||
- Provide an authenticated shell layout with desktop sidebar and mobile navigation affordances.
|
||||
- Add a shared API client that sends credentials and handles unauthorized responses.
|
||||
- Provide a starter dashboard page with loading and error-safe patterns.
|
||||
|
||||
**Non-Goals:**
|
||||
- Full feature implementation for projects/repositories/ssh keys/settings pages.
|
||||
- Pixel-perfect final design system and component library.
|
||||
- Advanced state-management framework adoption beyond required foundation.
|
||||
|
||||
## Decisions
|
||||
|
||||
1. **Route-centric app composition with `react-router-dom` data boundaries kept simple**
|
||||
- Rationale: aligns with existing dependency set and keeps first milestone small.
|
||||
- Alternative: add heavier route/data framework patterns now. Rejected as unnecessary for foundation stage.
|
||||
|
||||
2. **Auth state bootstraps from `/auth/me` and routes guard against missing session**
|
||||
- Rationale: backend is source of truth for cookie-backed identity; avoids duplicative token logic in browser.
|
||||
- Alternative: local token/session storage. Rejected for weaker security and mismatch with cookie strategy.
|
||||
|
||||
3. **Single API client module wrapping Axios defaults and 401 interception**
|
||||
- Rationale: centralizes credential behavior and unauthorized handling.
|
||||
- Alternative: per-request fetch wrappers across pages. Rejected due to duplication risk.
|
||||
|
||||
4. **App shell-first approach before deep page content**
|
||||
- Rationale: navigation and responsive structure are prerequisites for all future feature pages.
|
||||
- Alternative: implement pages first then refactor into shell. Rejected due to avoidable churn.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **[Auth bootstrap flicker on first load]** -> use explicit loading screen until session check resolves.
|
||||
- **[401 redirect loops]** -> add interceptor guard and avoid redirecting when already on public/auth routes.
|
||||
- **[Responsive nav complexity early]** -> keep mobile behavior minimal (toggleable drawer) and iterate later.
|
||||
- **[Frontend/backend contract drift]** -> codify expected endpoint behavior in integration-oriented frontend tests.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Scaffold source tree (`main.tsx`, app router, shell, pages, API client, styles).
|
||||
2. Implement auth context + protected route guard and login/logout wiring.
|
||||
3. Implement responsive shell and dashboard placeholder content.
|
||||
4. Add checks/tests and run `npm run typecheck`, `npm run lint`, `npm run build`.
|
||||
|
||||
Rollback:
|
||||
- Remove added source tree and revert package/config changes if foundation rollout is paused.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Whether to include React Query in the next frontend increment (deferred; not required for foundation).
|
||||
@@ -0,0 +1,26 @@
|
||||
## Why
|
||||
|
||||
The project has backend foundations and authentication flows, but the frontend currently has no application code to consume them. We need a usable React foundation so users can authenticate, navigate core areas, and interact with APIs consistently across desktop and mobile.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Establish the initial React + TypeScript app structure in `apps/web` with Vite conventions.
|
||||
- Add routing skeleton with protected routes, not-found handling, and auth-aware redirects.
|
||||
- Implement a baseline app shell (header, sidebar/mobile nav, content area) for authenticated screens.
|
||||
- Add shared API client configuration for cookie-based auth and 401 handling.
|
||||
- Add initial dashboard scaffolding with loading/error states and placeholder summary cards.
|
||||
- Add frontend quality gates and tests/checks for routing/auth behaviors and build integrity.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `frontend-auth-shell`: Auth-aware layout primitives and guarded route flow for the web app.
|
||||
|
||||
### Modified Capabilities
|
||||
- `frontend-foundation`: Tighten requirements around route protection, API credential handling, and responsive authenticated shell behavior.
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected app code under `apps/web` (new source tree, routes, layout, API client, styles).
|
||||
- Depends on backend auth endpoints (`/auth/login`, `/auth/logout`, `/auth/me`, `/auth/refresh`) for session flow.
|
||||
- Introduces frontend config conventions for API base URL and runtime auth assumptions.
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: React Application Setup
|
||||
The system SHALL use React 18+ with TypeScript and SHALL provide a runnable application source structure in `apps/web/src`.
|
||||
|
||||
#### Scenario: Frontend build
|
||||
- GIVEN the frontend codebase
|
||||
- THEN it SHALL:
|
||||
- Use React 18+ with TypeScript 5+
|
||||
- Use Vite as the build tool
|
||||
- Support Hot Module Replacement (HMR)
|
||||
- Output optimized production builds
|
||||
- Include a concrete entrypoint, app composition, and route tree
|
||||
|
||||
### Requirement: Client-Side Routing
|
||||
The system SHALL implement client-side routing with authenticated route guards and explicit not-found handling.
|
||||
|
||||
#### Scenario: Navigation
|
||||
- GIVEN the frontend application
|
||||
- THEN React Router SHALL:
|
||||
- Define routes for all foundation pages
|
||||
- Support protected routes (require authentication)
|
||||
- Handle 404 errors
|
||||
- Support route parameters for feature pages
|
||||
|
||||
#### Scenario: Protected routes
|
||||
- GIVEN an unauthenticated user
|
||||
- WHEN they access a protected route
|
||||
- THEN they are redirected to login flow
|
||||
- AND post-auth navigation returns them to an authenticated landing route
|
||||
|
||||
### Requirement: Layout Component
|
||||
The system SHALL provide a consistent application layout for authenticated screens across desktop and mobile sizes.
|
||||
|
||||
#### Scenario: Application shell
|
||||
- GIVEN the frontend application
|
||||
- THEN a Layout component SHALL:
|
||||
- Display a header with user info and logout
|
||||
- Display sidebar navigation on desktop
|
||||
- Show main content area
|
||||
- Collapse sidebar into a mobile menu toggle on small viewports
|
||||
|
||||
#### Scenario: Navigation links
|
||||
- GIVEN the sidebar navigation
|
||||
- THEN it SHALL include links to:
|
||||
- Dashboard
|
||||
- Projects
|
||||
- Repositories
|
||||
- SSH Keys
|
||||
- Settings
|
||||
|
||||
### Requirement: HTTP Client Configuration
|
||||
The system SHALL configure HTTP requests for cookie-based auth and unauthorized-session recovery.
|
||||
|
||||
#### Scenario: API communication
|
||||
- GIVEN the frontend application
|
||||
- THEN Axios/fetch SHALL:
|
||||
- Send credentials (cookies) with requests
|
||||
- Handle 401 responses by redirecting to login
|
||||
- Set appropriate content-type headers
|
||||
- Support request/response interception in a shared client module
|
||||
|
||||
### Requirement: Loading States
|
||||
The system SHALL handle asynchronous operations gracefully during auth bootstrap and dashboard fetches.
|
||||
|
||||
#### Scenario: Data fetching
|
||||
- GIVEN a page loading data
|
||||
- THEN:
|
||||
- Loading states are shown while requests are in flight
|
||||
- Errors are shown with retry affordance
|
||||
- Initial auth-check loading prevents protected-layout flicker
|
||||
@@ -0,0 +1,28 @@
|
||||
## 1. Frontend app scaffold and routing
|
||||
|
||||
- [x] 1.1 Create `apps/web/src` app entrypoint, base styles, and root render wiring.
|
||||
- [x] 1.2 Add router configuration with dashboard, projects, repositories, ssh keys, settings, and not-found routes.
|
||||
- [x] 1.3 Add protected-route guard and login redirect behavior for unauthenticated access.
|
||||
|
||||
## 2. Auth-aware shell and API client
|
||||
|
||||
- [x] 2.1 Implement shared API client with credentialed requests and 401 handling strategy.
|
||||
- [x] 2.2 Implement auth session bootstrap (`/auth/me`) and lightweight auth context/provider.
|
||||
- [x] 2.3 Implement app shell layout (header, desktop sidebar, mobile menu toggle, content outlet).
|
||||
- [x] 2.4 Wire logout action to backend endpoint and session-state reset.
|
||||
|
||||
## 3. Dashboard and UX states
|
||||
|
||||
- [x] 3.1 Implement dashboard placeholder page with summary cards and quick actions.
|
||||
- [x] 3.2 Add loading, empty, and error-retry states for dashboard/auth bootstrap paths.
|
||||
- [x] 3.3 Ensure responsive behavior for mobile viewport navigation and touch targets.
|
||||
|
||||
## 4. Verification and OpenSpec tracking
|
||||
|
||||
- [x] 4.1 Add/update frontend tests for protected routing and auth/session behaviors.
|
||||
- [x] 4.2 Run frontend quality gates (`npm run typecheck`, `npm run lint`, `npm run build`) and fix findings.
|
||||
- [x] 4.3 Update this tasks file with completed checkboxes and note blockers/follow-ups.
|
||||
|
||||
## Blockers / Follow-ups
|
||||
|
||||
- None at this stage.
|
||||
Reference in New Issue
Block a user