Feature-technical-documentation-OAA#86
Feature-technical-documentation-OAA#86OMAKALQANTARA wants to merge 3 commits intoLIDR-academy:mainfrom
Conversation
- Added complete project documentation (12 use cases, 15 user stories, 20 tickets) - Defined 4 epics across 4 sprints (8 weeks) - Documented architecture, data model, and API specification - Total: 89 story points for MVP
📝 WalkthroughWalkthroughThis pull request adds comprehensive project documentation for UNLOKD, including architecture diagrams (high-level, database, infrastructure), planning documents (sprints, epics, prioritized backlog), best practices guide, feature tickets (UNLOKD-001 through UNLOKD-020), use cases (UC-001 through UC-012), 15 user stories (HU-001 through HU-015), documentation templates, and an expanded prompts file for AI-assisted generation. A Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Pre-merge checks❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 14
🧹 Nitpick comments (35)
documentation/templates/userStory.md (1)
1-15: Template structure is clear and complete.The user story template includes all essential sections: title/role/action/benefit, acceptance criteria, notes, related stories, and technical details. The format aligns well with the project's Spanish documentation conventions.
Consider adding brief usage instructions at the top (e.g., "Replace [bracketed] placeholders with specific values") to guide first-time users. Alternatively, include a completed example file to demonstrate the template in context.
documentation/templates/bestPractices.md (1)
3-88: Template is awaiting content.This best practices template contains placeholder sections for DDD concepts and SOLID principles but no actual examples or explanations yet. While this may be intentional for an initial documentation commit, consider adding a note at the top indicating this is a work-in-progress template or tracking completion in a separate ticket.
documentation/tickets/UNLOKD-015-migraciones-conditions.md (1)
1-29: Add schema details and implementation guidance to migration ticket.The migration ticket covers the essentials (Prisma models, migrations, indexing, seed data) but lacks implementation specifics. For a 2 story-point database task, the acceptance criteria should include schema details to guide development.
🔎 Suggested additions for the ticket
Add a "Database Schema" section with details such as:
## Database Schema **MessageCondition:** - id (UUID, PK) - messageId (UUID, FK → MESSAGES) - conditionType (ENUM: TIME, PASSWORD, QUIZ) - availableFrom (DateTime, nullable for non-TIME conditions) - passwordHash (String, nullable, only for PASSWORD conditions) - quizId (UUID, nullable, FK → QUIZ, only for QUIZ conditions) - createdAt (DateTime) - updatedAt (DateTime) **MessageUnlockAttempt:** - id (UUID, PK) - messageId (UUID, FK → MESSAGES) - userId (UUID, FK → USERS) - conditionId (UUID, FK → MESSAGE_CONDITIONS) - attemptedAt (DateTime) - success (Boolean) - failureReason (String, nullable) - createdAt (DateTime) **Indexes:** - UNLOCK_ATTEMPTS (message_id, user_id) - for query optimization - UNLOCK_ATTEMPTS (message_id, created_at DESC) - for cleanup queriesAlso add:
- Data retention: Plan for archival or deletion of unlock attempts (e.g., delete after 90 days)
- Constraints: Specify NOT NULL, UNIQUE, and CHECK constraints
- Seed data: Outline structure of test data (e.g., "Create 10 messages with TIME conditions spanning future dates, 5 with PASSWORD conditions, 5 with QUIZ conditions")
documentation/tickets/UNLOKD-011-arquitectura-motor-condiciones.md (1)
40-52: Improve architecture documentation with Factory pattern example and clarify getRequiredData() usage.This architecture document provides a solid Strategy pattern foundation, and the requirements for TimeConditionStrategy are already well-documented in HU-007 and UNLOKD-012. However, two documentation improvements would strengthen the design reference:
Factory pattern example: The acceptance criteria (line 27) and technical tasks (line 37) mention implementing
ConditionFactory, but no code example is provided. Adding a factory implementation would complete the pattern reference and provide clear guidance for the follow-up implementation in UNLOKD-012.getRequiredData() usage: The interface defines
getRequiredData(): string[]but the TimeConditionStrategy doesn't implement it in the snippet. Clarifying the expected return value and how consumers should use this method would improve the design contract.The detailed requirements around timezone handling (UTC with client-side conversion) and validation constraints (available_from > NOW() and < NOW() + 1 year) are already properly captured in HU-007 and will be implemented in UNLOKD-012, so these don't need to be replicated in the architecture document itself.
documentation/use_cases/UC-008-enviar-mensaje-contraseña.md (1)
1-220: Well-structured use case with solid security considerations.The UC-008 document is comprehensive and technically sound. The security requirements are appropriately specified (bcrypt factor 10, no plaintext PIN storage, rate limiting), and the alternative flows cover important edge cases. The PlantUML diagram clearly illustrates the end-to-end workflow.
A few observations:
- Line 114: Rate limiting specification (3 attempts per 5 minutes) should be validated against actual implementation constraints and storage backend capacity, especially if this becomes a bottleneck under scale.
- Line 98: Bcrypt factor 10 is acceptable, though modern recommendations often suggest 10-12 depending on security requirements and performance trade-offs.
- Grammar/formatting: Static analysis flagged numerous punctuation and capitalization suggestions in list items (lines 46-107, etc.). While these don't affect technical clarity, consider addressing them in a follow-up cleanup pass for consistency with project documentation standards.
Consider whether the rate-limiting window (5 minutes) and attempt count (3) should be configurable per-message or per-user to accommodate future use cases or security policies.
documentation/tickets/UNLOKD-009-migraciones-messages.md (1)
1-28: Appropriately scoped migration ticket.The ticket clearly specifies the tables, schema models, and key index requirement. The 2-point estimate is reasonable for migrations of this scope.
Optional enhancement:
Consider cross-referencing related migration tickets (UNLOKD-004 for users, UNLOKD-015 for conditions) and the affected feature tickets (UNLOKD-006 for chats, UNLOKD-007 for messages) to provide developers with a complete picture of the messaging module dependencies.documentation/tickets/UNLOKD-010-tests-e2e-mensajeria.md (1)
15-16: Consider adding explicit dependencies and framework specification.The description mentions the test scope clearly, but the ticket lacks:
- Framework/tool specification: No mention of which E2E framework (Cypress, Playwright, etc.) will be used.
- Dependency callout: Should explicitly reference that this ticket depends on UNLOKD-006 (chats), UNLOKD-007 (messages), and UNLOKD-008 (WebSocket) being implemented first.
- Test environment: Unclear whether tests run against live infrastructure, mocked WebSocket, or embedded test server.
Add a "Dependencias" or "Prerequisitos" section listing related implementation tickets, and specify the E2E framework to be used.
documentation/tickets/UNLOKD-002-modulo-auth.md (1)
39-40: Ensure integration testing covers module dependencies.Test coverage "> 80%" is specified, but acceptance criteria don't explicitly mention integration tests between the auth module and external dependencies (MySQL, Redis). Add acceptance criteria for:
- AuthService + UsersRepository integration
- Rate limiting with Redis
- JWT validation in protected routes
documentation/planning/backlog-priorizado.md (6)
14-32: Document assumed team velocity for MVP sprints.Sprint 1 shows 21 story points and 2-week duration, but no explicit velocity assumption is stated (e.g., "assuming team velocity of X pts/week" or "assuming team capacity of Y pts/sprint"). Add a table or statement documenting the assumed team velocity and capacity per sprint to make sprint planning assumptions transparent.
37-52: Add risk mitigation guidance for high-complexity Sprint 2 features.Sprint 2 includes UNLOKD-008 (WebSocket gateway, 8 story points—the highest single item in MVP). This represents significant technical risk (concurrency, real-time messaging). Consider adding:
- Technical spike / spike acceptance criteria
- Stretch goal if implementation runs over
- Known dependencies or blockers
This guidance would help the team manage this critical feature.
58-72: Define contingency plan for Sprint 3 (differentiator) scope slippage.Sprint 3 contains 26 story points (highest of MVP) and is marked as "diferenciador clave" with explicit max-priority note. If this sprint slips:
- Which features would drop to post-MVP?
- Is there a minimum acceptable scope (e.g., TIME condition + PASSWORD condition)?
- What is the rollback plan if condition engine is incomplete?
Add a contingency/scope hierarchy to mitigate risk.
195-199: Cross-reference Definition of Ready/Done criteria.The Grooming section mentions ensuring "tickets cumplen Definition of Ready" but DoR/DoD criteria are not defined here. This document should either:
- Define DoR/DoD inline, or
- Cross-reference the template/guide where DoR/DoD is defined (e.g., documentation/templates/bestPractices.md)
Currently, developers must search elsewhere to understand DoR expectations.
99-135: Organize Post-MVP backlog into proposed iterations.Post-MVP features (lines 99–135) are listed as a flat prioritized list. To improve planning clarity, group these into proposed post-MVP sprints or iterations. For example:
Post-MVP Sprint 1 (Iteración 1): QUIZ + Groups + Statistics
Post-MVP Sprint 2 (Iteración 2): BIOMETRIC + Templates + Riddles
Post-MVP Sprint 3 (Iteración 3): Gamification + SocialThis organization would help stakeholders understand expected delivery windows post-MVP.
139-162: Clarify "Valor vs Esfuerzo" matrix mapping to acceptance.The matrix (lines 143–161) categorizes features but doesn't explicitly map all backlog items to these quadrants. For example:
- "Alto Valor, Bajo Esfuerzo" lists Sprint 1-3 features, which is correct.
- "Alto Valor, Alto Esfuerzo" mentions "Multimedia + Notificaciones" but these are in Sprint 4 (21 pts), not explicitly here.
- "Bajo Valor, Alto Esfuerzo (Evitar)" lists items like "Marketplace de plantillas," but these don't appear in the post-MVP backlog.
Add a footnote or legend mapping matrix quadrants to specific backlog items for clarity, or reorganize the matrix to explicitly show which backlog items fall into each quadrant.
documentation/diagrams/databaseDiagram.mmd (1)
115-116: Consider clarifying self-referencing relationship labels.The two relationships from
USERStoCONTACTSare technically correct for modeling a self-referencing many-to-many relationship, but the labels could be more descriptive to clarify the bidirectional nature.🔎 Suggested improvement
-USERS ||--o{ CONTACTS : "owns/contacts" -USERS ||--o{ CONTACTS : "is_contact_of" +USERS ||--o{ CONTACTS : "owner (via owner_user_id)" +USERS ||--o{ CONTACTS : "contact (via contact_user_id)"This makes it clearer which foreign key each relationship represents.
documentation/user_stories/HU-008-mensaje-contraseña.md (2)
28-28: Consider increasing bcrypt cost factor.The documentation specifies bcrypt factor 10+, which is functional but on the lower end. Modern security best practices recommend a bcrypt cost factor of at least 12 for better protection against brute-force attacks, especially for authentication-related data like PINs.
🔎 Suggested improvement
-- El PIN nunca se almacena en texto plano (solo hash bcrypt con factor 10+) +- El PIN nunca se almacena en texto plano (solo hash bcrypt con factor 12+)And update line 91:
-- Hash con bcrypt factor 10: `await bcrypt.hash(pin, 10)` +- Hash con bcrypt factor 12: `await bcrypt.hash(pin, 12)`Note: Higher factors increase security but also CPU time. Factor 12 is a good balance for modern systems.
47-59: Clarify that password transmission requires HTTPS.The request body example shows the PIN transmitted in plaintext JSON. While this is standard for REST APIs, the documentation should explicitly note that this transmission must occur over HTTPS to prevent interception.
Consider adding a note after the Request Body example:
**Nota de Seguridad:** El PIN se transmite en el cuerpo de la petición y debe enviarse exclusivamente sobre HTTPS/TLS para evitar interceptación. El backend debe rechazar conexiones no seguras.documentation/tickets/UNLOKD-006-modulo-chats.md (1)
29-29: Consider adding pagination requirements for the chat list endpoint.The
GET /api/v1/chatsendpoint will return all chats for a user. As the user accumulates more chats over time, this could lead to performance issues and poor UX. Consider adding pagination (cursor-based or offset-based) to the acceptance criteria.Suggested addition to acceptance criteria
Add to line 29:
- [ ] Endpoint `GET /api/v1/chats` (listar chats del usuario) + [ ] Endpoint `GET /api/v1/chats` (listar chats del usuario con paginación)And add a new technical task:
- [ ] Implementar paginación cursor-based para `getChatsByUserId` (usar `created_at` + `id` como cursor)documentation/tickets/UNLOKD-003-modulo-users.md (1)
31-31: Consider tightening display name minimum length.The validation allows display names as short as 1 character, which may lead to UX issues (users with names like "a" or "x"). Consider raising the minimum to 2-3 characters for better user experience.
Suggested adjustment
- [ ] Validación display_name (1-255 caracteres) + [ ] Validación display_name (3-255 caracteres)documentation/tickets/UNLOKD-001-setup-proyecto.md (1)
111-140: Add security warnings for example credentials.The example configurations contain hardcoded passwords (
MYSQL_ROOT_PASSWORD: unlokd2025) and weak secret placeholders (JWT_SECRET=your-secret-key-here). While these are clearly marked as examples, adding explicit warnings can prevent accidental use in production.Suggested additions
Add a comment block before the Docker Compose example:
### Docker Compose (servicios) +⚠️ **SECURITY**: The credentials below are for local development only. Never use these values in production. + ```yaml services:And update the JWT_SECRET line:
-JWT_SECRET=your-secret-key-here +JWT_SECRET=change-this-to-a-secure-random-string-for-production JWT_EXPIRATION=24hdocumentation/tickets/UNLOKD-004-migraciones-users.md (1)
43-59: Add the Contact model to complete the Prisma schema example.The description (line 19) specifies creating a "complete Prisma schema for USERS and CONTACTS tables," and the acceptance criteria (line 25) explicitly requires defining both User and Contact models. However, the example schema only shows the User model. Since this example guides implementation, add the Contact model definition to match the documented scope.
Per the database summary (line 62), CONTACTS should have 4 fields. Consider including the Contact model with fields such as
owner_user_id,contact_user_id,created_at, andupdated_atto provide clear implementation guidance.documentation/tickets/UNLOKD-007-modulo-messages.md (1)
28-34: Consider formalizing the API specification for the messaging endpoints.The acceptance criteria reference POST and GET endpoints (lines 29-30) but don't specify request/response schemas, HTTP status codes, or error handling details. While this ticket appropriately focuses on acceptance criteria rather than full OpenAPI specs, consider linking to or creating a separate API specification document that developers can reference during implementation.
This would clarify:
- Request body schemas for
POST /api/v1/messages- Response structure for
GET /api/v1/chats/{chatId}/messages(including pagination metadata)- Error codes and messages (e.g., 403 for permission denied)
This is especially useful given the dependency chain with UNLOKD-006 (chat module) and UNLOKD-009 (messages migrations).
documentation/use_cases/UC-009-desbloquear-mensaje.md (1)
9-9: Consider removing marketing language from the technical description.Line 9 includes the phrase "Este es el caso de uso central del diferenciador de UNLOKD" (central differentiator of UNLOKD). While the feature is indeed important, this subjective business language is better suited for product/marketing documentation rather than technical requirements. For a technical use case document, focus on functional and non-functional requirements without positioning language.
Suggested revision: Remove line 9 entirely, or replace it with objective technical context such as "This use case coordinates condition validation across TIME, PASSWORD, and QUIZ types, with audit logging and real-time notifications."
documentation/tickets/UNLOKD-012-condicion-time.md (1)
1-43: Documentation structure is solid; consider standardizing Spanish capitalization style.The ticket clearly defines the TIME condition feature with well-structured acceptance criteria and technical tasks. The BullMQ scheduler approach for automatic unlocks is appropriate. However, the static analysis flags several Spanish grammar and punctuation inconsistencies across section headers and list items (e.g., lines 7, 18, 24, 33, 42–43).
While not blocking, addressing these would improve consistency across the documentation set. This is particularly relevant since similar patterns appear in other use-case files in this PR.
🔎 Example style improvements (Spanish documentation standards)
Consider standardizing:
- Section headers: Use consistent capitalization (e.g.,
Épica→épicaper some Spanish style guides, or consistently capitalize all)- List punctuation: Add periods/commas consistently after list items
- Example from line 18:
## Historia de Usuario Relacionadafollowed by a dash could be- **Historia de Usuario Relacionada:**for consistency with other similar sectionsApply these conventions across all documentation files for uniformity.
Verify that the acceptance criteria and technical tasks align with the broader Condition Engine architecture (UNLOKD-011) documented elsewhere in this PR, particularly around the ConditionStrategy interface and factory pattern integration.
documentation/use_cases/UC-003-gestionar-perfil.md (1)
84-93: Avatar lifecycle rules are sound; clarify optional cleanup behavior.The business rules covering avatar management are well-defined: RN-7 specifies cleanup (delete old avatar on upload), and RN-8 provides a default avatar fallback. However, there's a minor gap in the documented flow:
- RN-7 says deletion is optional (postconditions line 79: "optional")
- The main flow (line 33) assumes avatar upload → S3 → cleanup, but doesn't explicitly cover user-initiated avatar deletion (revert to default)
Consider clarifying:
- Is avatar deletion always performed, or only when a new one is explicitly uploaded?
- Is there a separate use case or alternative flow for explicitly removing a custom avatar to revert to the default?
This will prevent ambiguity during implementation.
documentation/user_stories/HU-003-actualizar-perfil.md (1)
54-56: Add language specification to fenced code block.Line 54 contains a fenced code block without a language identifier, which may cause rendering or linting issues. Consider either adding a language hint or converting to a plain text block since this describes request format rather than executable code.
🔎 Proposed fix
Option 1: Add language hint (if treating as pseudo-code/documentation):
-``` +``` multipart/form-data con campo "avatar" -``` +```Option 2: Use plain text block (preferred for descriptive content):
--``` -multipart/form-data con campo "avatar" -``` +multipart/form-data con campo "avatar"documentation/use_cases/UC-007-enviar-mensaje-temporal.md (1)
182-217: PlantUML diagram is clear; consider clarifying service ownership of WebSocket emission.The sequence diagram effectively illustrates the message creation flow through services, DB interactions, and scheduler setup. However, the diagram shows
api -> ws: emit(lines 196) and laterscheduler -> ws: emit(lines 212), but the diagram doesn't explicitly label which service/component owns the WebSocket Gateway instance or how these emissions are routed. This is a minor clarification opportunity to ensure implementers understand whether emissions come directly from the API/Scheduler or are delegated to a dedicated WebSocket service.documentation/user_stories/HU-006-ver-timeline-mensajes.md (3)
96-104: Minor: Standardize terminology in Database Optimization section.The section mixes English technical terms (
Limit) with Spanish documentation. While this is a common pattern in technical docs, consider using a consistent convention (e.g., "Limit de 20-100 mensajes" or "Límite de 20-100 mensajes") throughout the document to match the predominantly Spanish tone. Similarly, line 99 uses "Limit" in English; standardizing to either "Límite" (Spanish) or keeping "Limit" consistently would improve clarity.
27-27: Consider documenting error handling and timeout scenarios.While the technical detail section includes performance target (< 500ms) and validation rules (lines 101-104), it lacks specification for what happens if:
- Query timeout/exceeds performance SLA
- Invalid pagination parameters (negative limit, invalid cursor format)
- Other error scenarios beyond 403 (membership check)
Adding a brief "Error Handling" or "Error Responses" section would align the spec with REST best practices and provide implementation guidance.
Also applies to: 101-104
1-124: Well-defined user story with clear acceptance criteria and comprehensive technical specification.HU-006 provides a detailed specification for message timeline pagination, including acceptance criteria, technical endpoint details, database optimization strategy, and multi-level test coverage (unit, integration, E2E). The response JSON examples clearly illustrate handling of different message visibility types (PLAIN vs CONDITIONAL). The pagination strategy (cursor-based with
beforeparameter) is efficient for large message histories.documentation/user_stories/HU-013-contador-regresivo.md (2)
155-160: Consider implementing Page Visibility API optimization mentioned in performance section.The acceptance criteria (line 27) requires 60fps performance, and the optimizations section (line 158) recommends pausing the countdown when the tab/app is not visible to optimize battery. However, the React component (lines 50-87) does not implement this optimization. While this is noted as a performance enhancement, consider adding Page Visibility API integration to the component example or explicitly documenting it as a future optimization phase.
1-164: Comprehensive countdown timer user story with practical React implementation.HU-013 provides detailed specifications for time-based message countdown with acceptance criteria covering display format, real-time updates, animations, accessibility, and performance targets. The technical section includes a realistic React component implementation, duration formatting logic, and CSS animations. Test strategy is comprehensive (unit, integration, E2E) and covers key scenarios.
documentation/use_cases/UC-011-subir-multimedia.md (1)
56-56: Minor text standardization issues in user-facing strings and style.Line 56: Use capitalized unit abbreviation in error message:
"XX MB"instead of"XXmb".Line 134: The term "Sanitizar" is flagged as a Spanish-language anglicism. Consider "higienizar" for formal documentation, though "sanitizar" is common in technical contexts.
Also applies to: 129-136
documentation/user_stories/HU-009-desbloquear-mensaje.md (1)
42-48: Ensure security notes remain visible in implementation.These critical notes (NUNCA enviar password_hash, validar en backend, bcrypt.compare) are essential and should be referenced in code reviews during development. Consider copying them into implementation tickets or developer guidelines.
documentation/use_cases/UC-006-ver-historial-mensajes.md (1)
103-109: Verify performance targets under realistic data volumes.The 500ms target for initial load of 20 messages is reasonable for modern systems, but should be revisited during implementation with:
- Actual message counts per chat (millions of historical messages in production)
- Media URL generation cost (signed URLs for each image/video)
- Database query performance with composite index (chat_id, created_at)
Consider adding performance monitoring/alerting for this critical path during development.
Would you like me to draft performance testing guidelines or monitoring specifications for this use case?
| # Database | ||
| *.sql | ||
| *.sqlite | ||
| *.db |
There was a problem hiding this comment.
The *.sql pattern will block Prisma migration files from being committed.
The broad *.sql pattern ignores all SQL files. Since the .gitignore includes prisma/.env (line 42), indicating active use of Prisma ORM, this pattern will prevent migration files in prisma/migrations/ from being committed to version control. Database migrations must be versioned for reproducibility and team collaboration.
🔎 Proposed fix
Refine the database section to exclude migration directories:
# Database
*.sql
+ !prisma/migrations/**/*.sql
*.sqlite
*.dbThis preserves Prisma migration files while still ignoring ad-hoc SQL files.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Database | |
| *.sql | |
| *.sqlite | |
| *.db | |
| # Database | |
| *.sql | |
| !prisma/migrations/**/*.sql | |
| *.sqlite | |
| *.db |
🤖 Prompt for AI Agents
.gitignore around lines 36 to 39: the current broad `*.sql` entry will ignore
all SQL files including Prisma migration SQL under prisma/migrations; update the
gitignore to stop ignoring migration files by narrowing the rule—remove or
modify the global `*.sql` entry and instead keep binary DB ignores (*.sqlite,
*.db) while explicitly negating or excluding Prisma migration paths (for example
allow prisma/migrations/**) so migration SQL files are committed while still
ignoring ad-hoc SQL dump files.
|
|
||
| ### 1.4. Servicios de Dominio | ||
|
|
||
| Los servicios de dominio encapsulan lógica de negocio que no pertenece naturalmente a una sola entidad o value object (por ejemplo, lógica que involucra varios agregados o políticas de negocio globales). |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add language identifiers to fenced code blocks.
Lines 143 and 235 contain code blocks without language specifications. Add typescript markers to improve readability and enable syntax highlighting.
🔎 Proposed fixes
Line 143 (before/after Value Objects example):
-```
+```typescript
// Antes (condiciones como tipos primitivos dispersos)Line 235 (switch/strategy pattern example):
-```
+```typescript
switch (condition.type) {Also applies to: 235-235
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
143-143: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
documentation/best_practices/bestPractices.md lines 143 and 235: the fenced code
blocks at these lines lack a language identifier; update the opening
triple-backtick fences to include "typescript" (i.e., replace ``` with
```typescript) for both code blocks so they get proper TypeScript syntax
highlighting and improved readability.
| MESSAGES ||--o{ MESSAGE_READ_EVENTS : "read events" | ||
| USERS ||--o{ MESSAGE_READ_EVENTS : "reads" | ||
|
|
||
| MESSAGES ||--o{ MEDIA_OBJECTS : "references media" |
There was a problem hiding this comment.
Incorrect relationship cardinality.
The relationship MESSAGES ||--o{ MEDIA_OBJECTS : "references media" indicates one-to-many (one message has many media objects), but the schema shows MESSAGES.media_id FK → MEDIA_OBJECTS.id, which is a many-to-one relationship (many messages can reference one media object).
🔎 Proposed fix
-MESSAGES ||--o{ MEDIA_OBJECTS : "references media"
+MESSAGES }o--|| MEDIA_OBJECTS : "references media"This correctly represents that many messages can reference one media object (many-to-one).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| MESSAGES ||--o{ MEDIA_OBJECTS : "references media" | |
| MESSAGES }o--|| MEDIA_OBJECTS : "references media" |
🤖 Prompt for AI Agents
In documentation/diagrams/databaseDiagram.mmd around line 132, the ER
relationship is reversed: it currently says MESSAGES ||--o{ MEDIA_OBJECTS which
implies one message has many media objects, but the schema shows
MESSAGES.media_id → MEDIA_OBJECTS.id (many messages reference one media object).
Replace the line so MEDIA_OBJECTS is on the 1-side and MESSAGES on the many-side
(e.g., MEDIA_OBJECTS ||--o{ MESSAGES) and update the label to something like
"referenced by messages" to reflect many-to-one correctly.
| S3["Almacenamiento S3-compatible\n(Backblaze/Wasabi/MinIO)"] | ||
| end | ||
|
|
||
| ClientSide -->|"HTTPS / WSS"| LB |
There was a problem hiding this comment.
Fix undefined node reference.
Line 18 references ClientSide, but this node is never defined in the diagram. This will cause the Mermaid diagram to fail rendering or produce unexpected results.
🔎 Proposed fix
Based on the context, you likely want to define the client nodes. Add this before the Edge subgraph:
+WebApp["Web Application"]
+MobileApp["Mobile Application"]
+
flowchart LR
subgraph Edge["Perímetro / Red"]
LB["Reverse proxy / Load Balancer (Nginx/Traefik)"]Then update line 18:
-ClientSide -->|"HTTPS / WSS"| LB
+WebApp -->|"HTTPS / WSS"| LB
+MobileApp -->|"HTTPS / WSS"| LBCommittable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
documentation/diagrams/infraestructure.mmd around line 18: the diagram
references a node named "ClientSide" that is not defined causing rendering
failures; define the client node(s) before the edge (for example add a node like
"ClientSide[Client Side]" or individual client nodes) and then update the edge
at line 18 to reference the defined node identifier (e.g., "ClientSide
-->|\"HTTPS / WSS\"| LB" using the same identifier you added); ensure the node
identifier matches exactly (case and spelling) and place the node definition
above the Edge subgraph so the reference resolves.
| ## Sprint 3: Motor de Condiciones (DIFERENCIADOR CLAVE) | ||
|
|
||
| ### Fechas | ||
| **Inicio**: Lunes 03/02/2025 | ||
| **Fin**: Domingo 16/02/2025 | ||
| **Duración**: 14 días | ||
|
|
||
| ### Objetivo del Sprint | ||
| Implementar el motor de condiciones de desbloqueo que diferencia a UNLOKD: mensajes temporizados (TIME) y protegidos por contraseña (PASSWORD). | ||
|
|
||
| **⚠️ Este es el sprint más crítico del MVP - contiene el diferenciador clave del producto.** | ||
|
|
||
| ### Story Points | ||
| **Comprometidos**: 26 puntos (mayor capacidad por importancia) | ||
|
|
||
| ### Tickets del Sprint | ||
| 1. **UNLOKD-011** (5 pts) - Diseñar arquitectura del motor de condiciones (Strategy Pattern) | ||
| 2. **UNLOKD-012** (5 pts) - Implementar condición TIME | ||
| 3. **UNLOKD-013** (8 pts) - Implementar condición PASSWORD | ||
| 4. **UNLOKD-014** (5 pts) - Implementar servicio de desbloqueo | ||
| 5. **UNLOKD-015** (2 pts) - Crear migraciones condiciones | ||
| 6. **UNLOKD-016** (1 pt) - Tests motor de condiciones | ||
|
|
||
| ### Historias de Usuario Cubiertas | ||
| - HU-007: Enviar mensaje con condición temporal | ||
| - HU-008: Enviar mensaje con contraseña de 4 dígitos | ||
| - HU-009: Intentar desbloquear mensaje condicionado | ||
| - HU-010: Recibir notificación push de mensaje nuevo | ||
|
|
||
| ### Criterios de Éxito | ||
| - [ ] Usuario puede enviar mensaje con fecha/hora de desbloqueo | ||
| - [ ] Usuario puede enviar mensaje con PIN de 4 dígitos | ||
| - [ ] Receptor puede intentar desbloquear con PIN | ||
| - [ ] Sistema valida intentos y aplica límites | ||
| - [ ] Scheduler desbloquea mensajes TIME automáticamente | ||
| - [ ] Notificaciones push funcionan correctamente | ||
| - [ ] Tests con cobertura > 80% | ||
|
|
||
| ### Riesgos Identificados | ||
| - **Crítico**: Arquitectura debe ser extensible para futuros tipos (QUIZ, BIOMETRIC, etc.) | ||
| - **Mitigación**: Aplicar Strategy Pattern estrictamente, code review exhaustivo | ||
| - **Alto**: Scheduler con BullMQ puede fallar en producción | ||
| - **Mitigación**: Tests de integración robustos, monitoreo de cola Redis | ||
| - **Alto**: Seguridad del motor (no exponer contraseñas, validar en backend) | ||
| - **Mitigación**: Security review específico, nunca enviar hashes al cliente | ||
|
|
||
| ### Dependencias | ||
| - Sprint 2 debe estar completo | ||
| - BullMQ configurado y funcionando | ||
| - Redis operativo | ||
|
|
There was a problem hiding this comment.
Sprint 3 capacity risk requires mitigation strategy.
Sprint 3 commits 26 story points (maximum capacity) and contains the core product differentiator (conditions engine) with multiple high/critical risks. For a single developer working on the most critical feature, this creates significant delivery risk.
Consider:
- Reducing scope to 21-23 points by deferring UNLOKD-016 (tests) or moving one condition type to Sprint 4
- Adding buffer time for the Strategy Pattern architecture review (line 121)
- Planning for mid-sprint checkpoint to assess progress
The risks around BullMQ scheduler reliability (line 146) and security (line 148) are well-identified but may require more time than estimated.
Would you like me to suggest a revised Sprint 3 ticket breakdown that balances risk and capacity?
🧰 Tools
🪛 LanguageTool
[grammar] ~107-~107: Agrega un signo de puntuación.
Context: ... Condiciones (DIFERENCIADOR CLAVE) ### Fechas Inicio: Lunes 03/02/2025 Fin: Domi...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
[grammar] ~112-~112: Oración con errores
Context: ...Duración: 14 días ### Objetivo del Sprint Implementar el motor de condiciones de d...
(QB_NEW_ES_OTHER_ERROR_IDS_REPLACEMENT_MULTITOKEN)
[grammar] ~115-~115: Cambia la palabra o signo.
Context: ... **
(QB_NEW_ES_OTHER_ERROR_IDS_REPLACEMENT_PUNCTUATION)
[grammar] ~128-~128: Corrige la mayúscula.
Context: ... motor de condiciones ### Historias de Usuario Cubiertas - HU-007: Enviar mensaje con ...
(QB_NEW_ES_OTHER_ERROR_IDS_REPLACEMENT_ORTHOGRAPHY_UPPERCASE)
[grammar] ~128-~128: Corrige la mayúscula.
Context: ...e condiciones ### Historias de Usuario Cubiertas - HU-007: Enviar mensaje con condición ...
(QB_NEW_ES_OTHER_ERROR_IDS_REPLACEMENT_ORTHOGRAPHY_UPPERCASE)
[grammar] ~134-~134: Cambia la palabra o signo.
Context: ...push de mensaje nuevo ### Criterios de Éxito - [ ] Usuario puede enviar mensaje con ...
(QB_NEW_ES_OTHER_ERROR_IDS_REPLACEMENT_OTHER)
[grammar] ~143-~143: Cambia la palabra o signo.
Context: ... Tests con cobertura > 80% ### Riesgos Identificados - Crítico: Arquitectura debe ser ex...
(QB_NEW_ES_OTHER_ERROR_IDS_REPLACEMENT_OTHER)
[grammar] ~144-~144: Agrega un signo de puntuación.
Context: ...para futuros tipos (QUIZ, BIOMETRIC, etc.) - Mitigación: Aplicar Strategy Pa...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
[grammar] ~145-~145: Agrega un signo de puntuación.
Context: ...tegy Pattern estrictamente, code review exhaustivo - Alto: Scheduler con BullMQ puede ...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
[grammar] ~146-~146: Agrega un signo de puntuación.
Context: ...*: Scheduler con BullMQ puede fallar en producción - Mitigación: Tests de integració...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
[grammar] ~147-~147: Agrega un signo de puntuación.
Context: ...integración robustos, monitoreo de cola Redis - Alto: Seguridad del motor (no exp...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
[grammar] ~148-~148: Agrega un signo de puntuación.
Context: ...tor (no exponer contraseñas, validar en backend) - Mitigación: Security review esp...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
[grammar] ~149-~149: Aquí puede haber un error.
Context: ...pecífico, nunca enviar hashes al cliente ### Dependencias - Sprint 2 debe estar compl...
(QB_NEW_ES)
[grammar] ~151-~151: Agrega un signo de puntuación.
Context: ...co, nunca enviar hashes al cliente ### Dependencias - Sprint 2 debe estar completo - BullMQ...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
[grammar] ~152-~152: Agrega un signo de puntuación.
Context: ... ### Dependencias - Sprint 2 debe estar completo - BullMQ configurado y funcionando - Re...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
[grammar] ~153-~153: Agrega un signo de puntuación.
Context: ...e estar completo - BullMQ configurado y funcionando - Redis operativo --- ## Sprint 4: Mu...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
[grammar] ~154-~154: Aquí puede haber un error.
Context: ...figurado y funcionando - Redis operativo --- ## Sprint 4: Multimedia, Notificaciones y U...
(QB_NEW_ES)
🤖 Prompt for AI Agents
documentation/planning/sprint-planning.md lines 105-155: Sprint 3 capacity and
risk callouts show an overload of 26 points for a single developer and tight
timelines (see architecture note at line 121 and BullMQ/security risks at lines
146 and 148); reduce scope to a safer 21–23 points by deferring UNLOKD-016
(tests) or moving one condition (TIME or PASSWORD) to Sprint 4, add a dedicated
1–2 day buffer for the Strategy Pattern architecture review and code
walkthrough, insert a mid-sprint checkpoint (day 7) to reassess progress and
reallocate work, and explicitly add small spike tasks or timeboxes for BullMQ
reliability testing and a security review (password handling/back-end
validation) so those high-risk items are scheduled and not assumed to fit in
existing estimates.
| ### FA-1: Email no registrado | ||
| - **Paso 7**: Si el usuario no existe en la base de datos | ||
| - El sistema muestra mensaje genérico: "Credenciales inválidas" | ||
| - El sistema registra intento fallido en logs | ||
| - El flujo termina sin autenticar |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n documentation/use_cases/UC-002-iniciar-sesion.mdRepository: LIDR-academy/AI4Devs-finalproject
Length of output: 8272
FA-1 and FA-2 handle rate limiting inconsistently—fix the asymmetry.
FA-1 (non-existent email) does not increment the failed attempt counter, but FA-2 (wrong password) explicitly does (line 48: "El sistema incrementa contador de intentos fallidos (Redis)"). This asymmetry enables email enumeration: an attacker can probe for valid emails indefinitely while legitimate users hit the 5-attempt limit. The PlantUML diagram (lines 140–151) confirms the code path omits incrementFailedAttempts() for non-existent users.
Both FA-1 and FA-2 should increment the counter on the same IP/email, making enumeration attacks equally expensive as password guessing. Update FA-1 to explicitly state: "El sistema incrementa contador de intentos fallidos (Redis)".
🧰 Tools
🪛 LanguageTool
[grammar] ~40-~40: Agrega un signo de puntuación.
Context: ...: Si el usuario no existe en la base de datos - El sistema muestra mensaje genérico...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
[grammar] ~42-~42: Agrega un signo de puntuación.
Context: ... El sistema registra intento fallido en logs - El flujo termina sin autenticar ##...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
[grammar] ~43-~43: Aquí puede haber un error.
Context: ...logs - El flujo termina sin autenticar ### FA-2: Contraseña incorrecta - Paso 9...
(QB_NEW_ES)
🤖 Prompt for AI Agents
documentation/use_cases/UC-002-iniciar-sesion.md around lines 39–43: FA-1 (Email
no registrado) currently omits incrementing the failed-attempt counter, creating
asymmetry with FA-2 and enabling email enumeration; update the FA-1 steps to
explicitly state "El sistema incrementa contador de intentos fallidos (Redis)"
for the same key (IP/email) and also update the PlantUML path around lines
140–151 to include the call to incrementFailedAttempts() so both non-existent
email and wrong-password flows increment the same Redis counter.
|
|
||
| ## Postcondiciones | ||
| - El usuario queda autenticado en el sistema | ||
| - Se genera un JWT válido con expiración de 24 horas |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, check if the file exists and get its total line count
wc -l documentation/use_cases/UC-002-iniciar-sesion.mdRepository: LIDR-academy/AI4Devs-finalproject
Length of output: 129
🏁 Script executed:
# Read the postcondiciones section around line 72
sed -n '70,85p' documentation/use_cases/UC-002-iniciar-sesion.mdRepository: LIDR-academy/AI4Devs-finalproject
Length of output: 953
🏁 Script executed:
# Read the business rules section around lines 78-84
sed -n '75,90p' documentation/use_cases/UC-002-iniciar-sesion.mdRepository: LIDR-academy/AI4Devs-finalproject
Length of output: 960
Resolve inconsistency in JWT expiration requirements.
The postcondiciones section (line 72) states the JWT expires in 24 hours, but RN-1 (line 78) specifies different expiration times: 24 hours for web and 30 days for mobile. Update the postcondiciones to reflect the platform-specific expiration policy defined in RN-1.
🧰 Tools
🪛 LanguageTool
[grammar] ~72-~72: Agrega un signo de puntuación.
Context: ...nera un JWT válido con expiración de 24 horas - Se actualiza last_login_at en la tabl...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
🤖 Prompt for AI Agents
documentation/use_cases/UC-002-iniciar-sesion.md around line 72: the
postcondiciones currently state a single JWT expiration of 24 hours which
conflicts with RN-1 (line 78) that mandates platform-specific expirations;
update the postcondiciones to state that a JWT is generated with
platform-specific expirations: 24 hours for web and 30 days for mobile, matching
RN-1 wording and, if present, add a note that the client type determines the
expiration.
| - El login debe completarse en menos de 1 segundo | ||
| - La comparación de hash debe ser no bloqueante |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find and explore the documentation files mentioned
find . -type f -name "*UC-002*" -o -name "*UNLOKD-002*" | head -20Repository: LIDR-academy/AI4Devs-finalproject
Length of output: 177
🏁 Script executed:
#!/bin/bash
# Search for documentation directory structure
ls -la documentation/ 2>/dev/null || echo "No documentation dir"
find . -type d -name "use_cases" 2>/dev/null | head -5Repository: LIDR-academy/AI4Devs-finalproject
Length of output: 621
🏁 Script executed:
#!/bin/bash
# Look for the specific file mentioned in the review
find . -type f -name "UC-002-iniciar-sesion.md" -o -name "*iniciar-sesion*"Repository: LIDR-academy/AI4Devs-finalproject
Length of output: 127
🏁 Script executed:
#!/bin/bash
# Search for any bcrypt-related references and factor configurations
rg "bcrypt|factor.*10|hash.*factor" --type md -A 3 -B 3Repository: LIDR-academy/AI4Devs-finalproject
Length of output: 33090
🏁 Script executed:
cat -n documentation/use_cases/UC-002-iniciar-sesion.md | head -120Repository: LIDR-academy/AI4Devs-finalproject
Length of output: 5751
🏁 Script executed:
cat -n documentation/tickets/UNLOKD-002-modulo-auth.md | sed -n '25,45p'Repository: LIDR-academy/AI4Devs-finalproject
Length of output: 1243
🌐 Web query:
bcrypt factor 10 milliseconds timing performance benchmark
💡 Result:
Typical single-hash timings for bcrypt cost (work factor) = 10 vary by CPU, but are generally on the order of tens-to-a few-hundred milliseconds:
- Modern laptop/desktop CPUs: ~50–150 ms per hash. [1][2]
- Example measurements: Apple M1 Pro ≈ 61–107 ms (different tests), Intel i7-2700K ≈ 152 ms. [2][3]
- PHP RFC benchmarking shows cost=10 times roughly in the 39–80 ms range on several server CPUs and ~61 ms on an M1 Pro in their table (times scale ~2× per +1 cost). [1]
Because results depend strongly on CPU model, core frequency, OS and bcrypt implementation, you should run a local benchmark (repeating many iterations) on your target hardware to get an accurate ms measurement. [1][2]
Sources: [1] PHP bcrypt-cost benchmarks (RFC / summary). [2] M1 Pro bcrypt benchmark (Zoran Juric). [3] community/desktop i7 benchmark example.
🌐 Web query:
bcrypt hash time cost factor 10 comparison duration
💡 Result:
Short answer: bcrypt cost = 10 means 2^10 = 1,024 internal iterations. Typical hash time for cost=10 is on the order of tens-to-low-hundreds of milliseconds depending on CPU — common published numbers range ~15–160 ms (modern fast CPUs ~15–80 ms; older/modest servers ~80–160 ms). Each +1 cost doubles the time (cost 11 ≈ 2×, cost 12 ≈ 4×). [1][2][3]
Sources:
- Explanation + per-CPU table (examples showing cost=10 ~15–80 ms on modern CPUs, ~39–80+ ms on others). [1]
- Benchmarks (M1 Pro example: cost=10 ≈ 107 ms; cost=12 ≈ 429 ms). [2]
- Summary table showing cost 10 = 1,024 iterations and example durations (illustrative numbers ~152 ms on one test). [3]
🏁 Script executed:
#!/bin/bash
# Search for any performance testing or timing references in the codebase
rg "performance|timing|benchmark|millisecond|ms\)" --type md -i | head -30Repository: LIDR-academy/AI4Devs-finalproject
Length of output: 2223
Verify performance target against deployment hardware constraints.
The 1-second login requirement (line 95) is achievable with bcrypt factor 10+ on modern CPUs (~50–150ms for hash comparison alone), leaving adequate time for email validation, database query, and JWT generation. However, on older or modest server hardware, bcrypt at cost 10 can take 100–160ms, reducing the available budget significantly.
Before finalizing this requirement, confirm:
- Target hardware specifications for production deployment
- Whether the 1-second SLA applies to all deployment scenarios (edge cases, peak load, slower regions)
- If stricter timing is needed, consider whether bcrypt factor could be lowered (though this reduces security) or timeout increased
The async/non-blocking requirement for hash comparison (line 96) is appropriate and aligns with bcrypt.compare() usage.
🧰 Tools
🪛 LanguageTool
[grammar] ~95-~95: Agrega un signo de puntuación.
Context: ...El login debe completarse en menos de 1 segundo - La comparación de hash debe ser no bl...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
[grammar] ~96-~96: Agrega un signo de puntuación.
Context: ...do - La comparación de hash debe ser no bloqueante - El sistema debe soportar 100 logins c...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_PUNCTUATION)
🤖 Prompt for AI Agents
In documentation/use_cases/UC-002-iniciar-sesion.md around lines 95 to 96, the
performance requirement "El login debe completarse en menos de 1 segundo" and
the note "La comparación de hash debe ser no bloqueante" need clarification to
avoid unrealistic guarantees across different hardware: update the text to (1)
require confirmation of target production hardware and explicitly state whether
the 1s SLA applies to all deployment scenarios (regional/edge/peak), (2) add a
recommended bcrypt cost factor range (and note its impact on latency/security)
or mark the SLA as "target" rather than strict for slower hardware, (3) keep and
clarify that hash comparison must be asynchronous/non-blocking (e.g., use
bcrypt.compare or equivalent async API), and (4) add an action item to measure
and document real-world login latency on target hardware and adjust the SLA
accordingly.
| - Tap en notificación abre chat correcto | ||
| - No envía notificación si usuario online | ||
|
|
||
| **Prioridad:** P1 - High (Sprint 3) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's verify the sprint assignments mentioned in the review
rg -n "Sprint [0-9]" documentation/tickets/UNLOKD-018-worker-notificaciones.md documentation/user_stories/HU-010-notificacion-push.mdRepository: LIDR-academy/AI4Devs-finalproject
Length of output: 241
🏁 Script executed:
# Let's also check the story points and use case references
rg -n "Puntos de Historia|Story Points|UC-010|UNLOKD-018" documentation/user_stories/HU-010-notificacion-push.mdRepository: LIDR-academy/AI4Devs-finalproject
Length of output: 191
🏁 Script executed:
# And for the ticket file
rg -n "Puntos de Historia|Story Points|UC-010|HU-010" documentation/tickets/UNLOKD-018-worker-notificaciones.mdRepository: LIDR-academy/AI4Devs-finalproject
Length of output: 206
Resolve sprint assignment inconsistency.
HU-010-notificacion-push.md specifies Sprint 3 (line 122), but UNLOKD-018-worker-notificaciones.md specifies Sprint 4 (line 10). Both documents reference the same use case (UC-010), have matching story points (5 SP), and UNLOKD-018 explicitly references HU-010. Align the sprint assignment across both documents.
🧰 Tools
🪛 LanguageTool
[grammar] ~122-~122: Agrega una palabra o signo.
Context: ...envía notificación si usuario online Prioridad: P1 - High (Sprint 3) Estimación: ...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_OTHER)
🤖 Prompt for AI Agents
documentation/user_stories/HU-010-notificacion-push.md around line 122: the
sprint assignment reads "Sprint 3" but the corresponding document
UNLOKD-018-worker-notificaciones.md (line 10) assigns the same use case to
Sprint 4; update HU-010-notificacion-push.md to match UNLOKD-018 by changing the
priority/sprint line to "Sprint 4" (or alternatively update UNLOKD-018 to Sprint
3 if the project plan dictates) so both documents reference the same sprint for
UC-010; ensure the change is reflected in the metadata header and any
cross-references mentioning the sprint.
| **Componente React:** | ||
| ```typescript | ||
| function Countdown({ availableFrom }: { availableFrom: string }) { | ||
| const [timeRemaining, setTimeRemaining] = useState<Duration | null>(null); | ||
| const [isAvailable, setIsAvailable] = useState(false); | ||
|
|
||
| useEffect(() => { | ||
| const interval = setInterval(() => { | ||
| const now = Date.now(); | ||
| const target = new Date(availableFrom).getTime(); | ||
| const remaining = target - now; | ||
|
|
||
| if (remaining <= 0) { | ||
| setIsAvailable(true); | ||
| clearInterval(interval); | ||
| } else { | ||
| setTimeRemaining(calculateDuration(remaining)); | ||
| } | ||
| }, 1000); | ||
|
|
||
| return () => clearInterval(interval); | ||
| }, [availableFrom]); | ||
|
|
||
| if (isAvailable) { | ||
| return <UnlockNowButton animated />; | ||
| } | ||
|
|
||
| return ( | ||
| <div className="countdown-container"> | ||
| <ClockIcon animated /> | ||
| <span className="countdown-text"> | ||
| {formatDuration(timeRemaining)} | ||
| </span> | ||
| <span className="exact-date"> | ||
| Disponible el {formatDate(availableFrom)} | ||
| </span> | ||
| </div> | ||
| ); | ||
| } | ||
| ``` | ||
|
|
||
| **Formateo de Duración:** | ||
| ```typescript | ||
| function formatDuration(ms: number): string { | ||
| const days = Math.floor(ms / (1000 * 60 * 60 * 24)); | ||
| const hours = Math.floor((ms % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); | ||
| const minutes = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60)); | ||
| const seconds = Math.floor((ms % (1000 * 60)) / 1000); | ||
|
|
||
| if (days > 0) return `${days}d ${hours}h`; | ||
| if (hours > 0) return `${hours}h ${minutes}m`; | ||
| if (minutes > 0) return `${minutes}m ${seconds}s`; | ||
| return `${seconds}s`; | ||
| } | ||
| ``` | ||
|
|
||
| **Estilos CSS (animaciones):** | ||
| ```css | ||
| @keyframes countdown-pulse { | ||
| 0%, 100% { transform: scale(1); } | ||
| 50% { transform: scale(1.05); } | ||
| } | ||
|
|
||
| .countdown-text { | ||
| font-size: 24px; | ||
| font-weight: bold; | ||
| animation: countdown-pulse 2s infinite; | ||
| color: #667eea; | ||
| } | ||
|
|
||
| .unlock-now-button { | ||
| background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%); | ||
| animation: attention-pulse 1s infinite; | ||
| } | ||
|
|
||
| @keyframes attention-pulse { | ||
| 0%, 100% { box-shadow: 0 0 0 0 rgba(56, 239, 125, 0.7); } | ||
| 50% { box-shadow: 0 0 0 10px rgba(56, 239, 125, 0); } | ||
| } | ||
| ``` | ||
|
|
||
| **Accesibilidad:** | ||
| ```html | ||
| <div | ||
| role="timer" | ||
| aria-live="polite" | ||
| aria-label={`Mensaje se desbloqueará en ${formatDuration(remaining)}`} | ||
| > | ||
| {countdownUI} | ||
| </div> | ||
| ``` | ||
|
|
||
| **Tests:** | ||
| - **Unitarios (Frontend)**: | ||
| - Cálculo correcto de tiempo restante | ||
| - Formateo correcto según rangos (días/horas/minutos/segundos) | ||
| - Detección correcta cuando countdown llega a 0 | ||
| - **Integración**: | ||
| - Actualización cada segundo | ||
| - Limpieza de interval al desmontar componente | ||
| - Cambio de estado a "disponible" al llegar a 0 | ||
| - **E2E**: | ||
| - Visualización de countdown en mensaje TIME | ||
| - Countdown actualizado en tiempo real | ||
| - Transición a "Ya puedes desbloquear" cuando llega a 0 | ||
| - Habilitación de botón "Desbloquear" al llegar a 0 | ||
|
|
||
| **Optimizaciones:** | ||
| - Usar `requestAnimationFrame` en lugar de `setInterval` para mejor performance | ||
| - Pausar countdown cuando tab/app no está visible (Page Visibility API) | ||
| - Batch updates para evitar re-renders innecesarios | ||
| - Considerar Web Workers para cálculos pesados (probablemente overkill) | ||
|
|
||
| **Prioridad:** P1 - Medium (Sprint 4) | ||
| **Estimación:** 3 Story Points | ||
| **Caso de Uso Relacionado:** Parte de UC-007 (Enviar Mensaje Temporal) y UC-012 (Ver Previsualización) |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add language identifiers to all fenced code blocks in technical detail section.
The technical detail section (lines 49-164) contains code examples without language specifications. Add typescript for JavaScript/TypeScript blocks and css for CSS blocks to enable syntax highlighting and improve readability.
🔎 Code blocks requiring language specification
- Lines 50-87: React component (needs
typescript) - Lines 91-102: Duration formatting function (needs
typescript) - Lines 106-128: CSS animations (needs
css) - Lines 131-139: Accessibility HTML/JSX (needs
htmlorjsx)
🧰 Tools
🪛 LanguageTool
[grammar] ~90-~90: Corrige la mayúscula.
Context: ...n> ); } **Formateo de Duración:**typescript function formatDuration(ms: number): string { const days = Math.floor(ms / (1000 * 60 * 60 * 24)); const hours = Math.floor((ms % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const minutes = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((ms % (1000 * 60)) / 1000); if (days > 0) return ${days}d ${hours}h; if (hours > 0) return ${hours}h ${minutes}m; if (minutes > 0) return ${minutes}m ${seconds}s; return ${seconds}s; } **Estilos CSS (animaciones):**css @key...
(QB_NEW_ES_OTHER_ERROR_IDS_REPLACEMENT_ORTHOGRAPHY_UPPERCASE)
[grammar] ~157-~157: Cambia la palabra o signo.
Context: ... de setInterval para mejor performance - Pausar countdown cuando tab/app no está ...
(QB_NEW_ES_OTHER_ERROR_IDS_REPLACEMENT_OTHER)
[grammar] ~158-~158: Cambia la palabra o signo.
Context: ...pp no está visible (Page Visibility API) - Batch updates para evitar re-renders inn...
(QB_NEW_ES_OTHER_ERROR_IDS_REPLACEMENT_OTHER)
[grammar] ~159-~159: Cambia la palabra o signo.
Context: ...ates para evitar re-renders innecesarios - Considerar Web Workers para cálculos pes...
(QB_NEW_ES_OTHER_ERROR_IDS_REPLACEMENT_OTHER)
[grammar] ~160-~160: Aquí puede haber un error.
Context: ...álculos pesados (probablemente overkill) Prioridad: P1 - Medium (Sprint 4) **Es...
(QB_NEW_ES)
[grammar] ~162-~162: Agrega una palabra o signo.
Context: ...los pesados (probablemente overkill) Prioridad: P1 - Medium (Sprint 4) **Estimación:*...
(QB_NEW_ES_OTHER_ERROR_IDS_MISSING_OTHER)
🤖 Prompt for AI Agents
documentation/user_stories/HU-013-contador-regresivo.md lines 49-164: Code
fences in the technical detail section lack language identifiers; update each
fenced block to include the correct language (add "typescript" to the React
component block at ~50-87 and the duration function at ~91-102, add "css" to the
styles block at ~106-128, and add "html" or "jsx" to the accessibility block at
~131-139) so syntax highlighting and readability are enabled.
|
Por favor considerar lo siguiente. |
Initial project documentation with MVP planning
Summary by CodeRabbit
Release Notes
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.