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