docs: add project documentation and initial specs
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
# Architecture
|
||||
|
||||
## Stack
|
||||
|
||||
- Next.js (App Router)
|
||||
- TypeScript
|
||||
- next-intl
|
||||
- Prisma + PostgreSQL
|
||||
- Tailwind CSS
|
||||
- Radix UI (via local primitives)
|
||||
- framer-motion
|
||||
- nodemailer
|
||||
|
||||
---
|
||||
|
||||
# Application Structure
|
||||
|
||||
## Public application
|
||||
|
||||
Localized public pages live under:
|
||||
|
||||
app/[locale]/(site)
|
||||
|
||||
Locale routing and configuration are defined in:
|
||||
|
||||
i18n/routing.ts
|
||||
|
||||
The public layout checks the maintenance status and redirects visitors to:
|
||||
|
||||
/coming-soon
|
||||
|
||||
when maintenance mode is enabled.
|
||||
|
||||
---
|
||||
|
||||
## Admin application
|
||||
|
||||
Admin pages are implemented under:
|
||||
|
||||
app/_admin
|
||||
|
||||
Internal admin routing is rewritten to:
|
||||
|
||||
app/admin-internal
|
||||
|
||||
Development alias routes also exist under:
|
||||
|
||||
app/root
|
||||
|
||||
Routing decisions and host/path-based rewrites are implemented in:
|
||||
|
||||
lib/admin-routing.ts
|
||||
|
||||
The `_admin` structure should be treated as the canonical admin source.
|
||||
|
||||
---
|
||||
|
||||
# Core Modules
|
||||
|
||||
Application logic lives primarily in `lib/*`.
|
||||
|
||||
Important modules include:
|
||||
|
||||
lib/portfolio.ts
|
||||
Handles portfolio queries and localized mapping.
|
||||
|
||||
lib/app-config.ts
|
||||
Provides application-level configuration values.
|
||||
|
||||
lib/media.ts
|
||||
Handles media library queries and media bindings.
|
||||
|
||||
lib/mail.ts
|
||||
Handles SMTP delivery via nodemailer.
|
||||
|
||||
lib/contact-guard.ts
|
||||
Handles Turnstile verification and rate limiting for contact submissions.
|
||||
|
||||
These modules act as the primary server-side application layer.
|
||||
|
||||
---
|
||||
|
||||
# UI Layer
|
||||
|
||||
Shared UI primitives live in:
|
||||
|
||||
components/ui
|
||||
|
||||
These primitives wrap Radix UI components and define the shared design system.
|
||||
|
||||
Public site UI components live in:
|
||||
|
||||
components/site
|
||||
components/layout
|
||||
|
||||
Admin UI components live in:
|
||||
|
||||
components/admin
|
||||
components/dashboard
|
||||
|
||||
Shared primitives must always originate from `components/ui`.
|
||||
|
||||
Feature-level UI should reuse these primitives rather than reimplementing them.
|
||||
|
||||
---
|
||||
|
||||
# Persistence Layer
|
||||
|
||||
Database access is implemented using Prisma.
|
||||
|
||||
Prisma client lives in:
|
||||
|
||||
lib/prisma.ts
|
||||
|
||||
Configuration values are stored in the database via:
|
||||
|
||||
AppConfig
|
||||
|
||||
which acts as a key-value store for runtime configuration values.
|
||||
|
||||
Database access should always occur through server-side modules.
|
||||
|
||||
Client components must never access Prisma directly.
|
||||
|
||||
---
|
||||
|
||||
# Architectural Boundaries
|
||||
|
||||
The following boundaries must be respected:
|
||||
|
||||
- Client components must not access Prisma.
|
||||
- Business logic must not live inside UI components.
|
||||
- Shared UI must originate from `components/ui`.
|
||||
- Public site UI belongs in `components/site`.
|
||||
- Admin UI belongs in `components/admin` or `components/dashboard`.
|
||||
- Server actions act as request entry points for form submissions.
|
||||
- Server actions may call modules in `lib/*`.
|
||||
|
||||
Database queries should not be implemented directly inside route-level UI files.
|
||||
|
||||
---
|
||||
|
||||
# Request Flow Examples
|
||||
|
||||
## Contact submission
|
||||
|
||||
1. User submits the form on
|
||||
|
||||
app/[locale]/(site)/contact/page.tsx
|
||||
|
||||
2. Server action validates the input using Zod.
|
||||
3. Turnstile verification and rate limiting run via:
|
||||
|
||||
lib/contact-guard.ts
|
||||
|
||||
4. Email is sent through:
|
||||
|
||||
lib/mail.ts
|
||||
|
||||
5. The user is redirected to:
|
||||
|
||||
/success
|
||||
|
||||
or back to the form with an error state.
|
||||
|
||||
---
|
||||
|
||||
## Portfolio publishing
|
||||
|
||||
1. Admin edits a project form.
|
||||
2. Server action validates categories, fields, sections, and assets.
|
||||
3. Media selections are resolved via:
|
||||
|
||||
lib/media.ts
|
||||
|
||||
4. Project data, sections, assets, and media usage are persisted via Prisma.
|
||||
5. Public and admin paths are revalidated.
|
||||
|
||||
---
|
||||
|
||||
# Canonical Sources
|
||||
|
||||
The following files should be treated as canonical sources for specific domains:
|
||||
|
||||
Routing
|
||||
i18n/routing.ts
|
||||
|
||||
Admin routing
|
||||
lib/admin-routing.ts
|
||||
|
||||
Prisma access
|
||||
lib/prisma.ts
|
||||
|
||||
Application configuration
|
||||
lib/app-config.ts
|
||||
|
||||
Portfolio logic
|
||||
lib/portfolio.ts
|
||||
|
||||
Media handling
|
||||
lib/media.ts
|
||||
|
||||
---
|
||||
|
||||
# Proposed Future Improvements (Not Implemented)
|
||||
|
||||
These ideas are **not currently implemented** but may be introduced later:
|
||||
|
||||
- Split `app-config` concerns into smaller modules if additional domains are added.
|
||||
- Introduce dedicated models instead of expanding the `AppConfig` key-value store.
|
||||
- Introduce explicit service boundaries if the application grows significantly.ڑ
|
||||
@@ -0,0 +1,92 @@
|
||||
# Domain Rules
|
||||
|
||||
## Portfolio
|
||||
|
||||
### Current implementation
|
||||
|
||||
- A project must belong to one category
|
||||
- Categories cannot be deleted while linked projects exist
|
||||
- Public portfolio pages only show published projects
|
||||
- Category filters only use active categories
|
||||
- Project content is localized across
|
||||
|
||||
`ar`
|
||||
|
||||
,
|
||||
|
||||
`en`
|
||||
|
||||
,
|
||||
|
||||
`de`
|
||||
|
||||
- Project sections and assets are ordered by
|
||||
|
||||
`sortOrder`
|
||||
|
||||
- Project view mode is limited to:
|
||||
- `GRID`
|
||||
- `STORY`
|
||||
- `CASE_STUDY`
|
||||
|
||||
## Media
|
||||
|
||||
### Current implementation
|
||||
|
||||
- Media assets are tracked separately from portfolio records
|
||||
- Media usage bindings connect assets to entity fields
|
||||
- Usage binding is unique by
|
||||
|
||||
`usageType + entityType + entityId + fieldKey`
|
||||
|
||||
- Media is currently used by:
|
||||
- portfolio cover
|
||||
- portfolio sections
|
||||
- portfolio assets
|
||||
- site settings
|
||||
|
||||
## Contact
|
||||
|
||||
### Current implementation
|
||||
|
||||
- Contact submission requires valid name, email, and message
|
||||
- Turnstile is optional and controlled by settings
|
||||
- Rate limiting is optional and keyed by hashed client IP plus time window
|
||||
- Successful submission sends email only
|
||||
- No submission record is stored in the database
|
||||
|
||||
## Admin
|
||||
|
||||
### Current implementation
|
||||
|
||||
- Admin access depends on environment configuration
|
||||
- Middleware can require HTTP Basic Auth before app access
|
||||
- In-app admin session is cookie-based
|
||||
- Repeated failed password attempts trigger temporary lockout
|
||||
|
||||
## Configuration
|
||||
|
||||
### Current implementation
|
||||
|
||||
- Global settings are stored in
|
||||
|
||||
`AppConfig`
|
||||
|
||||
- Site settings, SMTP settings, contact protection, marquee settings, and maintenance mode all depend on configuration keys
|
||||
|
||||
## Recommended Improvements
|
||||
|
||||
- Add explicit domain rules for future
|
||||
|
||||
`products`
|
||||
|
||||
,
|
||||
|
||||
`orders`
|
||||
|
||||
,
|
||||
|
||||
`downloads`
|
||||
|
||||
only after data models exist
|
||||
- Introduce database retention and moderation rules for contact or inquiry submissions if they become persisted
|
||||
@@ -0,0 +1,63 @@
|
||||
# Features
|
||||
|
||||
## Current Implementation
|
||||
|
||||
### Public site
|
||||
|
||||
- Localized homepage with service positioning and marquee content
|
||||
- About page with profile-oriented content
|
||||
- Portfolio list with category filtering
|
||||
- Portfolio detail pages with multiple view modes:
|
||||
- `GRID`
|
||||
- `STORY`
|
||||
- `CASE_STUDY`
|
||||
- Contact form with:
|
||||
- validation
|
||||
- optional Turnstile
|
||||
- rate limiting
|
||||
- email delivery
|
||||
- Success page after contact submission
|
||||
- Maintenance redirect flow
|
||||
|
||||
### Admin
|
||||
|
||||
- Password-based app login plus optional Basic Auth gateway
|
||||
- Dashboard summary cards
|
||||
- Portfolio category management
|
||||
- Portfolio project creation and editing
|
||||
- Section and asset management inside each project
|
||||
- Media library with usage bindings
|
||||
- Site settings management
|
||||
- SMTP settings and test email
|
||||
- Contact protection settings
|
||||
- Marquee settings
|
||||
- Maintenance toggle
|
||||
- UI Kit preview page
|
||||
|
||||
## Present But Not Implemented As Full Features
|
||||
|
||||
- `Products`
|
||||
- only appears as a disabled navigation label
|
||||
- `Downloads`
|
||||
- document assets can be opened from portfolio detail pages, but there is no standalone downloads domain
|
||||
|
||||
## Not Currently Implemented
|
||||
|
||||
- `Orders`
|
||||
- `Project Inquiry` as a separate workflow or model
|
||||
- Customer accounts
|
||||
- Checkout or payment handling
|
||||
|
||||
## Recommended Improvements
|
||||
|
||||
- Add explicit feature boundaries between
|
||||
|
||||
`portfolio`
|
||||
|
||||
content and future
|
||||
|
||||
`products/orders/downloads`
|
||||
|
||||
domains
|
||||
- Store inbound contact submissions if business follow-up requires history
|
||||
- Add tests for admin server actions and middleware routing
|
||||
@@ -0,0 +1,138 @@
|
||||
# Project Overview
|
||||
|
||||
## Summary
|
||||
|
||||
This project is a multilingual
|
||||
|
||||
`Next.js`
|
||||
|
||||
portfolio website with an authenticated
|
||||
|
||||
`admin`
|
||||
|
||||
workspace.
|
||||
|
||||
The current implementation centers on:
|
||||
|
||||
- Public marketing pages
|
||||
- Portfolio listing and portfolio detail pages
|
||||
- Contact form submission by email
|
||||
- Global site configuration stored in
|
||||
|
||||
`AppConfig`
|
||||
|
||||
- Media library management
|
||||
- Portfolio content management
|
||||
- Maintenance mode
|
||||
|
||||
## Current Implementation
|
||||
|
||||
### Public site
|
||||
|
||||
- Localized routes for
|
||||
|
||||
`de`
|
||||
|
||||
,
|
||||
|
||||
`en`
|
||||
|
||||
,
|
||||
|
||||
`ar`
|
||||
|
||||
- Main pages:
|
||||
|
||||
`/`
|
||||
|
||||
,
|
||||
|
||||
`/about`
|
||||
|
||||
,
|
||||
|
||||
`/portfolio`
|
||||
|
||||
,
|
||||
|
||||
`/portfolio/category/[slug]`
|
||||
|
||||
,
|
||||
|
||||
`/portfolio/[slug]`
|
||||
|
||||
,
|
||||
|
||||
`/contact`
|
||||
|
||||
,
|
||||
|
||||
`/success`
|
||||
|
||||
,
|
||||
|
||||
`/coming-soon`
|
||||
|
||||
- Header includes a disabled
|
||||
|
||||
`/products`
|
||||
|
||||
navigation item marked as
|
||||
|
||||
`Soon`
|
||||
|
||||
### Admin workspace
|
||||
|
||||
- Login protected by Basic Auth at middleware level and password session inside the app
|
||||
- Dedicated sections for:
|
||||
- Overview
|
||||
- Maintenance
|
||||
- UI Kit
|
||||
- Media Library
|
||||
- Site Settings
|
||||
- Marquee Settings
|
||||
- SMTP Settings
|
||||
- Contact Protection
|
||||
- Portfolio management
|
||||
|
||||
### Data model
|
||||
|
||||
Current persistent entities in
|
||||
|
||||
`prisma/schema.prisma`
|
||||
|
||||
:
|
||||
|
||||
- `AppConfig`
|
||||
- `Category`
|
||||
- `PortfolioProject`
|
||||
- `PortfolioSection`
|
||||
- `PortfolioAsset`
|
||||
- `MediaAsset`
|
||||
- `MediaUsage`
|
||||
|
||||
No current models exist for:
|
||||
|
||||
- `Product`
|
||||
- `Order`
|
||||
- `Download`
|
||||
- `ProjectInquiry`
|
||||
|
||||
## Recommended Improvements
|
||||
|
||||
- Replace the placeholder
|
||||
|
||||
`README.md`
|
||||
|
||||
with project-specific onboarding
|
||||
- Add explicit domain documentation for current
|
||||
|
||||
`portfolio`
|
||||
|
||||
versus planned future commerce features
|
||||
- Add persistent storage for inbound contact and inquiry submissions if auditability is required
|
||||
- Add role separation if the
|
||||
|
||||
`admin`
|
||||
|
||||
area will be used by more than one operator
|
||||
@@ -0,0 +1,48 @@
|
||||
# Admin Feature Spec
|
||||
|
||||
## Current Implementation
|
||||
|
||||
### Access model
|
||||
|
||||
- Middleware can protect admin routes with Basic Auth
|
||||
- App login requires configured password and signed cookie session
|
||||
- Failed password attempts trigger lockout
|
||||
|
||||
### Routing
|
||||
|
||||
- Source pages live in
|
||||
|
||||
`app/_admin`
|
||||
|
||||
- Middleware rewrites to
|
||||
|
||||
`app/admin-internal`
|
||||
|
||||
- Development compatibility routes exist under
|
||||
|
||||
`app/root`
|
||||
|
||||
### Capabilities
|
||||
|
||||
- Overview dashboard
|
||||
- Maintenance mode
|
||||
- Media Library
|
||||
- Site Settings
|
||||
- Marquee Settings
|
||||
- SMTP Settings
|
||||
- Contact Protection
|
||||
- Portfolio categories
|
||||
- Portfolio projects
|
||||
- UI Kit page
|
||||
|
||||
## Constraints
|
||||
|
||||
- Admin currently assumes a single shared operator credential model
|
||||
- No role-based access control exists
|
||||
- No audit log exists
|
||||
|
||||
## Recommended Improvements
|
||||
|
||||
- Add per-user authentication if multiple operators are expected
|
||||
- Add action audit logging for content and configuration changes
|
||||
- Add tests around middleware rewriting and auth edge cases
|
||||
@@ -0,0 +1,59 @@
|
||||
# Contact Feature Spec
|
||||
|
||||
## Current Implementation
|
||||
|
||||
### Public flow
|
||||
|
||||
- Public contact page exists at
|
||||
|
||||
`/contact`
|
||||
|
||||
- Form fields:
|
||||
- name
|
||||
- email
|
||||
- phone
|
||||
- company
|
||||
- message
|
||||
- Submission uses a server action
|
||||
- Success redirects to
|
||||
|
||||
`/success`
|
||||
|
||||
### Protection
|
||||
|
||||
- Validation uses
|
||||
|
||||
`zod`
|
||||
|
||||
- Optional Cloudflare Turnstile verification
|
||||
- Optional rate limiting by IP window
|
||||
|
||||
### Delivery
|
||||
|
||||
- Messages are sent by SMTP through
|
||||
|
||||
`nodemailer`
|
||||
|
||||
- Recipient configuration comes from admin settings
|
||||
- Messages are not persisted in the database
|
||||
|
||||
### Admin controls
|
||||
|
||||
- SMTP settings page
|
||||
- Test email action
|
||||
- Contact protection settings page
|
||||
|
||||
## Risks
|
||||
|
||||
- Contact history is lost if email delivery succeeds but later needs auditing
|
||||
- Rate-limit counters are stored in
|
||||
|
||||
`AppConfig`
|
||||
|
||||
which mixes operational and business configuration
|
||||
|
||||
## Recommended Improvements
|
||||
|
||||
- Store contact submissions if the business needs pipeline visibility
|
||||
- Add spam and abuse observability
|
||||
- Add structured delivery error reporting
|
||||
@@ -0,0 +1,39 @@
|
||||
# Downloads Feature Spec
|
||||
|
||||
## Current Implementation
|
||||
|
||||
- Portfolio assets support
|
||||
|
||||
`DOCUMENT`
|
||||
|
||||
files
|
||||
- Portfolio detail pages expose document links with an
|
||||
|
||||
`Open document`
|
||||
|
||||
action
|
||||
- Media library can store document assets
|
||||
|
||||
## Gaps
|
||||
|
||||
- No standalone downloads index exists
|
||||
- No download access rules exist
|
||||
- No download analytics or gating exists
|
||||
- No dedicated
|
||||
|
||||
`Download`
|
||||
|
||||
model exists
|
||||
|
||||
## Proposed Scope
|
||||
|
||||
This is a proposed feature, not an implemented one.
|
||||
|
||||
- Central downloads listing
|
||||
- Optional download categories
|
||||
- Optional gated download access
|
||||
- Download tracking
|
||||
|
||||
## Recommended First Step
|
||||
|
||||
- Decide whether downloads remain a portfolio asset type or become their own domain
|
||||
@@ -0,0 +1,29 @@
|
||||
# Orders Feature Spec
|
||||
|
||||
## Current Implementation
|
||||
|
||||
- No
|
||||
|
||||
`Order`
|
||||
|
||||
model exists
|
||||
- No checkout flow exists
|
||||
- No payment integration exists
|
||||
- No admin order management exists
|
||||
|
||||
## Proposed Scope
|
||||
|
||||
This is a proposed feature, not an implemented one.
|
||||
|
||||
- Order creation from products or inquiry conversions
|
||||
- Order status lifecycle
|
||||
- Admin order review and fulfillment tracking
|
||||
- Email notifications for order events
|
||||
|
||||
## Recommended First Step
|
||||
|
||||
- Clarify whether
|
||||
|
||||
`orders`
|
||||
|
||||
means ecommerce checkout, service bookings, or manual sales records
|
||||
@@ -0,0 +1,40 @@
|
||||
# Products Feature Spec
|
||||
|
||||
## Current Implementation
|
||||
|
||||
- No
|
||||
|
||||
`Product`
|
||||
|
||||
model exists
|
||||
- No public
|
||||
|
||||
`/products`
|
||||
|
||||
route exists
|
||||
- No admin CRUD exists for products
|
||||
- The site header contains a disabled
|
||||
|
||||
`Products`
|
||||
|
||||
navigation item marked as
|
||||
|
||||
`Soon`
|
||||
|
||||
## Proposed Scope
|
||||
|
||||
This is a proposed feature, not an implemented one.
|
||||
|
||||
- Public product listing page
|
||||
- Product detail page
|
||||
- Product media and downloadable assets
|
||||
- Admin product CRUD
|
||||
- Optional relation from products to portfolio case studies
|
||||
|
||||
## Recommended First Step
|
||||
|
||||
- Define a dedicated
|
||||
|
||||
`Product`
|
||||
|
||||
data model before any UI work
|
||||
@@ -0,0 +1,32 @@
|
||||
# Project Inquiry Feature Spec
|
||||
|
||||
## Current Implementation
|
||||
|
||||
- No separate
|
||||
|
||||
`ProjectInquiry`
|
||||
|
||||
model exists
|
||||
- No dedicated project inquiry route exists
|
||||
- Current CTAs route users to the generic contact form
|
||||
|
||||
## Proposed Scope
|
||||
|
||||
This is a proposed feature, not an implemented one.
|
||||
|
||||
- Inquiry form specifically for new project leads
|
||||
- Optional prefilled source context from portfolio or homepage CTA
|
||||
- Inquiry status tracking in admin
|
||||
- Possible conversion into
|
||||
|
||||
`Order`
|
||||
|
||||
or CRM lead later
|
||||
|
||||
## Recommended First Step
|
||||
|
||||
- Decide whether project inquiry should stay a specialized
|
||||
|
||||
`contact`
|
||||
|
||||
variant or become a persisted lead-management feature
|
||||
@@ -0,0 +1,68 @@
|
||||
# Projects Feature Spec
|
||||
|
||||
## Scope
|
||||
|
||||
This spec documents the currently implemented
|
||||
|
||||
`portfolio projects`
|
||||
|
||||
domain.
|
||||
|
||||
## Current Implementation
|
||||
|
||||
### User-facing
|
||||
|
||||
- Users can browse published projects on
|
||||
|
||||
`/portfolio`
|
||||
|
||||
- Users can filter by category
|
||||
- Users can open a project detail page by slug
|
||||
- Project detail can render rich sections, galleries, stats, deliverables, and links
|
||||
- Document assets can be opened from project detail pages
|
||||
|
||||
### Admin-facing
|
||||
|
||||
- Admin can create, edit, publish, unpublish, and delete projects
|
||||
- Admin can assign one category per project
|
||||
- Admin can manage:
|
||||
- localized titles and summaries
|
||||
- client name
|
||||
- project year
|
||||
- service label
|
||||
- preview URL
|
||||
- cover image
|
||||
- sections
|
||||
- assets
|
||||
- featured flag
|
||||
- published flag
|
||||
- sort order
|
||||
- view mode
|
||||
|
||||
### Data model
|
||||
|
||||
- `PortfolioProject`
|
||||
- `PortfolioSection`
|
||||
- `PortfolioAsset`
|
||||
- `Category`
|
||||
|
||||
## Constraints
|
||||
|
||||
- Only published projects appear publicly
|
||||
- Category delete is blocked if projects exist
|
||||
- Each project must have exactly one category
|
||||
- View mode is limited to existing enum values
|
||||
|
||||
## Recommended Improvements
|
||||
|
||||
- Rename this feature from
|
||||
|
||||
`portfolio`
|
||||
|
||||
to
|
||||
|
||||
`projects`
|
||||
|
||||
only if the business wants portfolio and project management to be the same domain
|
||||
- Add preview workflow instead of relying only on publish state
|
||||
- Add revision history for content changes
|
||||
Reference in New Issue
Block a user