Skip to content

Develop - #48

Merged
jhosepmyr merged 47 commits into
mainfrom
develop
Oct 7, 2026
Merged

jhosepmyr merged 47 commits into
mainfrom
develop

Conversation

@jhosepmyr

Copy link
Copy Markdown
Contributor

Description

Release of the MVP to main:

Feature module / area: discovery / core / layout / shared / workspace / ci


How to Test

After merging, the "Deploy" workflow on main triggers "Deploy MVP" in Kntro-Soft/reqsai-infra. Check https://reqsai.tech: the audio source picker, the MVP-only navigation and the polished session and stories pages.

Introduce a single source of truth for hiding non-MVP areas: a `features`
map in both environment files (all off), typed by the `FeatureKey` union
and checked with `satisfies FeatureFlagMap`, read through the
`FeatureFlags.isEnabled()` service. Tests override flags with
`provideFeatureFlags()`.

`featureGuard(key, next?)` is a functional canMatch guard: while the flag
is off the route does not match, so the URL falls through to the wildcard
fallback like an unknown path (no blank page, no lazy chunk). An existing
canMatch guard is chained through `next` because Angular runs every guard
of a canMatch array eagerly.
Gate every non-MVP route with featureGuard so a disabled feature's URLs
fall through to the `**` -> /projects fallback like unknown paths:
billing (settings page + checkout success/cancel), usage, integrations
(org + project pages and the Jira OAuth callback), members (org + project
pages and the invitation landing), customRoles (roles list/new/edit) and
the notifications/tokens account placeholders. Routes that already had a
permission canMatch chain it through featureGuard so a hidden page never
fetches permissions or toasts a denial.

The invitation landing follows `members`: with it off nobody can invite
from the UI and an owner has no screen to see or remove whoever joins, so
a stale link must not add people to an org.

The project settings landing skips members/roles while their feature is
off. A spec drives the real route table to pin both directions.
Move the nav segment lists and their visibility rule into shell-nav.ts so
they can be unit-tested, and add an optional `feature` to NavSeg that
visibleNavSegs checks alongside role/permission. Flagged entries: org
members/billing/integrations/usage, project roles/members/integrations
and the account notifications/tokens placeholders.

A "Settings" root entry with no reachable sub-page is now dropped, and
the org one opens the first reachable sub-page instead of the owner-only
General, so an admin never lands on a "no access" toast. The Jira job
banner only mounts while integrations are on.
…menu

The palette's "Members" quick action and backend MEMBER hits (both open
/settings/members) only appear while `members` is on; the user menu's
"Upgrade" CTA only while `billing` is on.
Wrap the backlog's Import from Jira / Push all / Push selected buttons and
the story detail's Push to Jira in the `integrations` flag, skip the
backlog's Jira-target lookup, and only let INTEGRATION_SYNC reveal the
row-selection column while bulk push exists (bulk delete still needs
STORY_DELETE).
The project overview drops its Members card (and no longer counts
members/roles toward the Settings card) while `members` / `customRoles`
are off. Org General hides the Transfer ownership card, and skips the
member fetch that only feeds it, while `members` is off: without members
there is nobody to pick and its empty state asks to invite someone.
Usage and billing are separate flags; keep the usage page free of a dead
link to /settings/billing when only `usage` is turned on.
Add docs/FEATURE-FLAGS.md (each flag, what it hides, how to turn it on or
add one, the invitation/ownership decisions and the backend FREE-plan
limits) and link it from the README environments section.
Adds a `meeting` audio source for virtual calls (Zoom / Meet / Teams): the
recorder opens the screen-share picker first (it needs the click's transient
activation), keeps the shared surface's audio with voice processing off,
stops the unused video track and then takes the mic. Both sources feed one
mono GainNode mixer (explicit 1 channel, speakers down-mix) that drives the
level meter and the PCM worklet, so `/ws/stt` still gets 16 kHz Int16 mono.

- Sharing without "Share tab audio" stops the tracks and sets a notice; a
  dismissed picker stays idle without messages.
- "Stop sharing" (audio track `ended`) disconnects the meeting audio and
  keeps streaming the mic with a notice; `shareMeetingAudio()` re-shares.
- `pauseStreaming()` keeps the shared surface so a resume never re-opens
  the picker; `stopStreaming()` releases everything.
- Socket handlers are detached before closing so a late close event can't
  tear down the next socket, and a session that fails to start releases
  the capture.
…ecorder

Mocks navigator.mediaDevices to cover the picker-before-mic ordering (no
await before getDisplayMedia), the display constraints, the dropped video
track, the no-audio-track warning, silent picker dismissal, real capture
failures, a missing getDisplayMedia, mic denial releasing the shared tab,
the "Stop sharing" mic-only fallback and re-share, and pause vs. stop
release. A real Web Audio graph with a fake socket checks that both
sources feed the mono mixer, which drives the meter and the worklet.
Also covers the desktop-Chromium support check and dismissal detection.
A compact segmented control next to the record button picks where the
next recording takes its audio from: "In person (microphone)" or "Virtual
meeting (microphone + meeting audio)". The choice is remembered per user
in localStorage (try/catch) and locked while starting or once a session
is live; the record click passes it to the recorder before any await so
the screen-share picker keeps the click's activation, and a second click
can't stack another picker.

The virtual option stays visible but inert outside desktop Chromium, with
the reason as tooltip and, on tap, as the composer hint. With the virtual
source selected the hint explains to tick "Share tab audio" and to wear
headphones; recorder notices (amber) render in the same line.
Covers the pressed state, switching to the virtual source, the inert
virtual option (tooltip + unavailable event) where meeting audio is
unsupported, the lock during a live session, the per-user storage key
and the fallback to the microphone when a stored virtual choice can't
be honoured.
…e session bar

Virtual-meeting recordings show a meeting-audio badge next to the timer
while the shared audio is mixed in. Once the user clicks "Stop sharing"
(the recording carries on with the mic), the bar shows an amber "Share
again" action that re-opens the picker straight from the click and mixes
the new surface into the live (or paused) recording.
…hare

Covers that in-person recordings show no meeting controls, that the badge
shows while the meeting audio is captured, and that after "Stop sharing"
the bar offers an accessible "Share again" button that calls the recorder.
Adds ai / verified / pending and priority tokens (light + dark) so AI-originated,
human-validated and awaiting-review content stop sharing the brand red. The red
fill moves to #dc2626 so white button labels pass AA (4.83:1); in dark, red used
as text takes a lighter step. Muted text, the default focus outline and the
active sidebar item now meet AA, and the nav indicator animates with transform.
hlmInput gave textareas the inputs' fixed h-10, so rows were ignored and story
statements and Gherkin steps were clipped. Textareas now size to their content
(field-sizing) from a two-line minimum. hlmLabel also styles span and legend
labels, which rendered unstyled at 16px next to 14px labels.
AI status lines, review-tray and provenance labels, Gherkin hints, story status
explanations, the labelled audio-source picker and its two-step virtual-meeting
guidance, and the optional/required markers for the project forms. Speakers read
"Participante n" in Spanish so they no longer collide with the story role.
…dges

Shared presentational pieces: Given/When/Then steps behind a keyword gutter,
a priority chip with a direction glyph (critical red, high orange, medium and
low neutral), a review-status chip (draft = amber dashed, approved = emerald
check) and an origin chip (AI from a session vs manual). Backlog stories in the
chat store now keep their review status for the side panel.
…ions as AI

The decision queue no longer floats over the viewport: it docks to the feed
column, so the session bar (pause/stop), the header actions and the side panel
stay reachable. A tray header names it, carries the counter with prev/next and
minimize, and announces changes. Suggestion cards carry violet AI provenance,
read the story as its sentence and criteria as Gherkin steps, highlight every
field an update changes, edit in labelled auto-growing fields, and keep Discard
apart from Edit/Cancel.
…reams

A status line at the live edge of each session says whether the AI is listening
(with the last suggestion's age), paused, generating the final stories after
Stop, or failed (with the backend reason). The transcript recedes into neutral
bubbles with always-visible speaker and time; human decisions become compact
rows ("accepted/resolved by the analyst"); AI-generated stories carry violet
provenance plus "awaiting review". Accepting confirms where the content went,
the load error offers a retry, and screen readers hear the review count. The
side panel gains tab semantics, labelled filters, Gherkin steps and status chips.
…te announced

The picker becomes a labelled segmented control (In person / Virtual meeting)
so it is never confused with the record button, which now shows a record dot
and a "Record" label. The virtual-meeting guidance is a calm two-step note
(share the meeting tab with its audio; wear headphones), and the missing-audio
notice offers "Share again" in place. The session bar keeps its status label
for screen readers on mobile and shows the meeting-audio badge on every width.
Sortable column headers with a direction arrow and aria-sort, plus a visible
"sorted by" caption. Priority sorting is re-ordered by meaning on the page,
since the API sorts the enum alphabetically. Rows show priority, review status
and origin (AI from a session vs manual) chips, link their title for keyboard
users, collapse into a chip row below sm, and use unambiguous dates. The empty
state offers next steps and load errors offer a retry.
…d state

The detail page leads with the story's title, review status (with what it
means) and origin, linking an AI story back to its capture session. Role,
action and benefit read top-down as the story sentence in full-width,
auto-growing fields; Save enables only once something changed. Criteria use a
Gherkin keyword gutter with labelled fields, flag new or edited rows as unsaved
and only enable their own Save then. The create page shares the layout.
…tings

Only the name is required, and both forms now say so. The technical profile is
one clearly optional section grouped into business context (domain,
architecture) and tech stack (chip lists, with an Enter-to-add hint), with
placeholders that read as examples. Settings drop from eight one-field cards to
General and Technical profile, each with its own Save, and the logo card is
titled for the project. Chip inputs accept an id for their label, describe their
hint and name each remove button.
The projects page was the only module without a visible heading; it now opens
with its title and subtitle like the others, and the search field shows focus.
Light theme, 1440x900, Spanish demo data: projects list, new project and
project settings, the live session (review tray, suggestion editing, an update
diff, an AI question, processing after Stop), both audio sources, the backlog
(default and by priority) and the story detail with its Gherkin criteria.
Tailwind's utilities are imported unlayered, so the layered override lost to
.text-primary and red links stayed at 3.3:1 on navy. The override is now
unlayered and wins by specificity (4.5:1 or better).
Also rewords the draft status hint so it no longer contradicts "accepted by
the analyst": a draft is simply not approved yet.
…edge visible

Arrow keys browse the tray and Escape minimizes it (ignored while typing);
after a decision focus returns to the tray instead of the page body; focusing
a feed control the tray covers minimizes it (WCAG 2.4.11). From sm the tray
stops short of the feed bottom so the latest lines and the AI status stay in
view; on phones its title is shortened. The audio picker no longer truncates
its labels on desktop.
… fields

Below sm the backlog page scrolls instead of a nested box that showed about one
row. Draft status becomes an amber dashed outline so it is not mistaken for the
filled orange High priority beside it. Story create/edit fields now say inline
when a required field is left empty (aria-invalid + described message).
Both options split the picker evenly, which truncated "Reunión virtual". From
sm each option takes its own width; on phones they still share the full row.
feat(discovery): capture virtual-meeting audio alongside the mic
feat(core): MVP feature flags that hide non-MVP areas
feat(ui): MVP UX polish from the heuristic evaluation
…nd CloudFront

The S3 bucket and CloudFront distribution the old workflow targeted no
longer exist. A push to main now dispatches deploy-mvp.yml in
Kntro-Soft/reqsai-infra with web_ref set to the pushed commit, using the
INFRA_DEPLOY_TOKEN secret; without the secret the job only logs a notice.
ci: deploy main through the reqsai-infra MVP pipeline
fix(ci): keep the running API image when the web triggers a deploy
@jhosepmyr
jhosepmyr merged commit 640536f into main Oct 7, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant